18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * net/sched/em_nbyte.c N-Byte ematch 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Authors: Thomas Graf <tgraf@suug.ch> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/gfp.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/types.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/string.h> 138c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 148c2ecf20Sopenharmony_ci#include <linux/tc_ematch/tc_em_nbyte.h> 158c2ecf20Sopenharmony_ci#include <net/pkt_cls.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistruct nbyte_data { 188c2ecf20Sopenharmony_ci struct tcf_em_nbyte hdr; 198c2ecf20Sopenharmony_ci char pattern[]; 208c2ecf20Sopenharmony_ci}; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic int em_nbyte_change(struct net *net, void *data, int data_len, 238c2ecf20Sopenharmony_ci struct tcf_ematch *em) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci struct tcf_em_nbyte *nbyte = data; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci if (data_len < sizeof(*nbyte) || 288c2ecf20Sopenharmony_ci data_len < (sizeof(*nbyte) + nbyte->len)) 298c2ecf20Sopenharmony_ci return -EINVAL; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci em->datalen = sizeof(*nbyte) + nbyte->len; 328c2ecf20Sopenharmony_ci em->data = (unsigned long)kmemdup(data, em->datalen, GFP_KERNEL); 338c2ecf20Sopenharmony_ci if (em->data == 0UL) 348c2ecf20Sopenharmony_ci return -ENOBUFS; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci return 0; 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic int em_nbyte_match(struct sk_buff *skb, struct tcf_ematch *em, 408c2ecf20Sopenharmony_ci struct tcf_pkt_info *info) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct nbyte_data *nbyte = (struct nbyte_data *) em->data; 438c2ecf20Sopenharmony_ci unsigned char *ptr = tcf_get_base_ptr(skb, nbyte->hdr.layer); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci ptr += nbyte->hdr.off; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (!tcf_valid_offset(skb, ptr, nbyte->hdr.len)) 488c2ecf20Sopenharmony_ci return 0; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci return !memcmp(ptr, nbyte->pattern, nbyte->hdr.len); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic struct tcf_ematch_ops em_nbyte_ops = { 548c2ecf20Sopenharmony_ci .kind = TCF_EM_NBYTE, 558c2ecf20Sopenharmony_ci .change = em_nbyte_change, 568c2ecf20Sopenharmony_ci .match = em_nbyte_match, 578c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 588c2ecf20Sopenharmony_ci .link = LIST_HEAD_INIT(em_nbyte_ops.link) 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic int __init init_em_nbyte(void) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci return tcf_em_register(&em_nbyte_ops); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic void __exit exit_em_nbyte(void) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci tcf_em_unregister(&em_nbyte_ops); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cimodule_init(init_em_nbyte); 748c2ecf20Sopenharmony_cimodule_exit(exit_em_nbyte); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ciMODULE_ALIAS_TCF_EMATCH(TCF_EM_NBYTE); 77