2005-04-17 02:20:36 +04:00
/*
* net / sched / em_cmp . c Simple packet data comparison 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 < tgraf @ suug . ch >
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/skbuff.h>
# include <linux/tc_ematch/tc_em_cmp.h>
2008-09-23 06:20:51 +04:00
# include <asm/unaligned.h>
2005-04-17 02:20:36 +04:00
# include <net/pkt_cls.h>
static inline int cmp_needs_transformation ( struct tcf_em_cmp * cmp )
{
return unlikely ( cmp - > flags & TCF_EM_CMP_TRANS ) ;
}
static int em_cmp_match ( struct sk_buff * skb , struct tcf_ematch * em ,
struct tcf_pkt_info * info )
{
struct tcf_em_cmp * cmp = ( struct tcf_em_cmp * ) em - > data ;
unsigned char * ptr = tcf_get_base_ptr ( skb , cmp - > layer ) + cmp - > off ;
u32 val = 0 ;
if ( ! tcf_valid_offset ( skb , ptr , cmp - > align ) )
return 0 ;
switch ( cmp - > align ) {
2011-01-19 22:26:56 +03:00
case TCF_EM_ALIGN_U8 :
val = * ptr ;
break ;
2005-04-17 02:20:36 +04:00
2011-01-19 22:26:56 +03:00
case TCF_EM_ALIGN_U16 :
val = get_unaligned_be16 ( ptr ) ;
2005-04-17 02:20:36 +04:00
2011-01-19 22:26:56 +03:00
if ( cmp_needs_transformation ( cmp ) )
val = be16_to_cpu ( val ) ;
break ;
2005-04-17 02:20:36 +04:00
2011-01-19 22:26:56 +03:00
case TCF_EM_ALIGN_U32 :
/* Worth checking boundries? The branching seems
* to get worse . Visit again .
*/
val = get_unaligned_be32 ( ptr ) ;
2005-04-17 02:20:36 +04:00
2011-01-19 22:26:56 +03:00
if ( cmp_needs_transformation ( cmp ) )
val = be32_to_cpu ( val ) ;
break ;
2005-04-17 02:20:36 +04:00
2011-01-19 22:26:56 +03:00
default :
return 0 ;
2005-04-17 02:20:36 +04:00
}
if ( cmp - > mask )
val & = cmp - > mask ;
switch ( cmp - > opnd ) {
2011-01-19 22:26:56 +03:00
case TCF_EM_OPND_EQ :
return val = = cmp - > val ;
case TCF_EM_OPND_LT :
return val < cmp - > val ;
case TCF_EM_OPND_GT :
return val > cmp - > val ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
static struct tcf_ematch_ops em_cmp_ops = {
. kind = TCF_EM_CMP ,
. datalen = sizeof ( struct tcf_em_cmp ) ,
. match = em_cmp_match ,
. owner = THIS_MODULE ,
. link = LIST_HEAD_INIT ( em_cmp_ops . link )
} ;
static int __init init_em_cmp ( void )
{
return tcf_em_register ( & em_cmp_ops ) ;
}
2007-02-09 17:25:16 +03:00
static void __exit exit_em_cmp ( void )
2005-04-17 02:20:36 +04:00
{
tcf_em_unregister ( & em_cmp_ops ) ;
}
MODULE_LICENSE ( " GPL " ) ;
module_init ( init_em_cmp ) ;
module_exit ( exit_em_cmp ) ;
2007-07-12 06:46:26 +04:00
MODULE_ALIAS_TCF_EMATCH ( TCF_EM_CMP ) ;