Home | History | Annotate | Download | only in ipf
      1      0    stevel /*
      2      0    stevel  * Copyright (C) 1993-2003 by Darren Reed.
      3      0    stevel  *
      4      0    stevel  * See the IPFILTER.LICENCE file for details on licencing.
      5   2393  yz155240  *
      6   8624    Darren  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
      7      0    stevel  * Use is subject to license terms.
      8      0    stevel  */
      9      0    stevel 
     10      0    stevel #if defined(KERNEL) || defined(_KERNEL)
     11      0    stevel # undef KERNEL
     12      0    stevel # undef _KERNEL
     13      0    stevel # define        KERNEL	1
     14      0    stevel # define        _KERNEL	1
     15      0    stevel #endif
     16      0    stevel #include <sys/errno.h>
     17      0    stevel #include <sys/types.h>
     18      0    stevel #include <sys/param.h>
     19      0    stevel #include <sys/time.h>
     20      0    stevel #if defined(__NetBSD__)
     21      0    stevel # if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL)
     22      0    stevel #  include "opt_ipfilter_log.h"
     23      0    stevel # endif
     24      0    stevel #endif
     25      0    stevel #if defined(_KERNEL) && defined(__FreeBSD_version) && \
     26      0    stevel     (__FreeBSD_version >= 220000)
     27      0    stevel # if (__FreeBSD_version >= 400000)
     28      0    stevel #  if !defined(IPFILTER_LKM)
     29      0    stevel #   include "opt_inet6.h"
     30      0    stevel #  endif
     31      0    stevel #  if (__FreeBSD_version == 400019)
     32      0    stevel #   define CSUM_DELAY_DATA
     33      0    stevel #  endif
     34      0    stevel # endif
     35      0    stevel # include <sys/filio.h>
     36      0    stevel #else
     37      0    stevel # include <sys/ioctl.h>
     38      0    stevel #endif
     39   2393  yz155240 #if !defined(_AIX51)
     40   2393  yz155240 # include <sys/fcntl.h>
     41   2393  yz155240 #endif
     42      0    stevel #if defined(_KERNEL)
     43      0    stevel # include <sys/systm.h>
     44      0    stevel # include <sys/file.h>
     45      0    stevel #else
     46      0    stevel # include <stdio.h>
     47      0    stevel # include <string.h>
     48      0    stevel # include <stdlib.h>
     49   2393  yz155240 # include <stddef.h>
     50      0    stevel # include <sys/file.h>
     51      0    stevel # define _KERNEL
     52      0    stevel # ifdef __OpenBSD__
     53      0    stevel struct file;
     54      0    stevel # endif
     55      0    stevel # include <sys/uio.h>
     56      0    stevel # undef _KERNEL
     57      0    stevel #endif
     58   2393  yz155240 #if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux) && \
     59   2393  yz155240     !defined(linux)
     60      0    stevel # include <sys/mbuf.h>
     61      0    stevel #else
     62   2393  yz155240 # if !defined(linux)
     63   2393  yz155240 #  include <sys/byteorder.h>
     64   2393  yz155240 # endif
     65      0    stevel # if (SOLARIS2 < 5) && defined(sun)
     66      0    stevel #  include <sys/dditypes.h>
     67      0    stevel # endif
     68      0    stevel #endif
     69      0    stevel #ifdef __hpux
     70      0    stevel # define _NET_ROUTE_INCLUDED
     71      0    stevel #endif
     72   2393  yz155240 #if !defined(linux)
     73   2393  yz155240 # include <sys/protosw.h>
     74   2393  yz155240 #endif
     75      0    stevel #include <sys/socket.h>
     76      0    stevel #include <net/if.h>
     77      0    stevel #ifdef sun
     78      0    stevel # include <net/af.h>
     79      0    stevel #endif
     80   2393  yz155240 #if !defined(_KERNEL) && defined(__FreeBSD__)
     81   2393  yz155240 # include "radix_ipf.h"
     82   2393  yz155240 #endif
     83      0    stevel #include <net/route.h>
     84      0    stevel #include <netinet/in.h>
     85      0    stevel #include <netinet/in_systm.h>
     86      0    stevel #include <netinet/ip.h>
     87   2393  yz155240 #if !defined(linux)
     88   2393  yz155240 # include <netinet/ip_var.h>
     89   2393  yz155240 #endif
     90      0    stevel #if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */
     91      0    stevel # include <sys/hashing.h>
     92      0    stevel # include <netinet/in_var.h>
     93      0    stevel #endif
     94      0    stevel #include <netinet/tcp.h>
     95   2393  yz155240 #if (!defined(__sgi) && !defined(AIX)) || defined(_KERNEL)
     96   2393  yz155240 # include <netinet/udp.h>
     97   2393  yz155240 # include <netinet/ip_icmp.h>
     98   2393  yz155240 #endif
     99      0    stevel #ifdef __hpux
    100      0    stevel # undef _NET_ROUTE_INCLUDED
    101      0    stevel #endif
    102   2393  yz155240 #include "netinet/ip_compat.h"
    103      0    stevel #ifdef	USE_INET6
    104      0    stevel # include <netinet/icmp6.h>
    105   2393  yz155240 # if !SOLARIS && defined(_KERNEL) && !defined(__osf__) && !defined(__hpux)
    106      0    stevel #  include <netinet6/in6_var.h>
    107      0    stevel # endif
    108      0    stevel #endif
    109      0    stevel #include <netinet/tcpip.h>
    110      0    stevel #include "netinet/ip_fil.h"
    111      0    stevel #include "netinet/ip_nat.h"
    112      0    stevel #include "netinet/ip_frag.h"
    113      0    stevel #include "netinet/ip_state.h"
    114      0    stevel #include "netinet/ip_proxy.h"
    115      0    stevel #include "netinet/ip_auth.h"
    116   3448  dh155122 #include "netinet/ipf_stack.h"
    117      0    stevel #ifdef IPFILTER_SCAN
    118      0    stevel # include "netinet/ip_scan.h"
    119      0    stevel #endif
    120   2393  yz155240 #ifdef IPFILTER_SYNC
    121   2393  yz155240 # include "netinet/ip_sync.h"
    122   2393  yz155240 #endif
    123      0    stevel #include "netinet/ip_pool.h"
    124      0    stevel #include "netinet/ip_htable.h"
    125   2393  yz155240 #ifdef IPFILTER_COMPILED
    126   2393  yz155240 # include "netinet/ip_rules.h"
    127   2393  yz155240 #endif
    128   2393  yz155240 #if defined(IPFILTER_BPF) && defined(_KERNEL)
    129      0    stevel # include <net/bpf.h>
    130      0    stevel #endif
    131      0    stevel #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
    132      0    stevel # include <sys/malloc.h>
    133      0    stevel # if defined(_KERNEL) && !defined(IPFILTER_LKM)
    134      0    stevel #  include "opt_ipfilter.h"
    135      0    stevel # endif
    136      0    stevel #endif
    137      0    stevel #include "netinet/ipl.h"
    138   2393  yz155240 /* END OF INCLUDES */
    139      0    stevel 
    140      0    stevel #if !defined(lint)
    141      0    stevel static const char sccsid[] = "@(#)fil.c	1.36 6/5/96 (C) 1993-2000 Darren Reed";
    142   2393  yz155240 static const char rcsid[] = "@(#)$Id: fil.c,v 2.243.2.64 2005/08/13 05:19:59 darrenr Exp $";
    143      0    stevel #endif
    144      0    stevel 
    145      0    stevel #ifndef	_KERNEL
    146      0    stevel # include "ipf.h"
    147      0    stevel # include "ipt.h"
    148   2393  yz155240 # include "bpf-ipf.h"
    149      0    stevel extern	int	opts;
    150      0    stevel 
    151      0    stevel # define	FR_VERBOSE(verb_pr)			verbose verb_pr
    152      0    stevel # define	FR_DEBUG(verb_pr)			debug verb_pr
    153      0    stevel #else /* #ifndef _KERNEL */
    154      0    stevel # define	FR_VERBOSE(verb_pr)
    155      0    stevel # define	FR_DEBUG(verb_pr)
    156      0    stevel #endif /* _KERNEL */
    157      0    stevel 
    158      0    stevel 
    159   2393  yz155240 char	ipfilter_version[] = IPL_VERSION;
    160   2393  yz155240 int	fr_features = 0
    161   2393  yz155240 #ifdef	IPFILTER_LKM
    162   2393  yz155240 		| IPF_FEAT_LKM
    163   2393  yz155240 #endif
    164   2393  yz155240 #ifdef	IPFILTER_LOG
    165   2393  yz155240 		| IPF_FEAT_LOG
    166   2393  yz155240 #endif
    167   2393  yz155240 #ifdef	IPFILTER_LOOKUP
    168   2393  yz155240 		| IPF_FEAT_LOOKUP
    169   2393  yz155240 #endif
    170   2393  yz155240 #ifdef	IPFILTER_BPF
    171   2393  yz155240 		| IPF_FEAT_BPF
    172   2393  yz155240 #endif
    173   2393  yz155240 #ifdef	IPFILTER_COMPILED
    174   2393  yz155240 		| IPF_FEAT_COMPILED
    175   2393  yz155240 #endif
    176   2393  yz155240 #ifdef	IPFILTER_CKSUM
    177   2393  yz155240 		| IPF_FEAT_CKSUM
    178   2393  yz155240 #endif
    179   2393  yz155240 #ifdef	IPFILTER_SYNC
    180   2393  yz155240 		| IPF_FEAT_SYNC
    181   2393  yz155240 #endif
    182   2393  yz155240 #ifdef	IPFILTER_SCAN
    183   2393  yz155240 		| IPF_FEAT_SCAN
    184   2393  yz155240 #endif
    185   2393  yz155240 #ifdef	USE_INET6
    186   2393  yz155240 		| IPF_FEAT_IPV6
    187   2393  yz155240 #endif
    188   2393  yz155240 	;
    189      0    stevel 
    190   7131  dr146992 #define	IPF_BUMP(x)	(x)++
    191   7131  dr146992 
    192   7131  dr146992 static	INLINE int	fr_ipfcheck __P((fr_info_t *, frentry_t *, int));
    193      0    stevel static	INLINE int	fr_ipfcheck __P((fr_info_t *, frentry_t *, int));
    194      0    stevel static	int		fr_portcheck __P((frpcmp_t *, u_short *));
    195   3448  dh155122 static	int		frflushlist __P((int, minor_t, int *, frentry_t **,
    196   3448  dh155122 					 ipf_stack_t *));
    197      0    stevel static	ipfunc_t	fr_findfunc __P((ipfunc_t));
    198      0    stevel static	frentry_t	*fr_firewall __P((fr_info_t *, u_32_t *));
    199   3448  dh155122 static	int		fr_funcinit __P((frentry_t *fr, ipf_stack_t *));
    200   2393  yz155240 static	INLINE void	frpr_ah __P((fr_info_t *));
    201    637   ml37995 static	INLINE void	frpr_esp __P((fr_info_t *));
    202    637   ml37995 static	INLINE void	frpr_gre __P((fr_info_t *));
    203      0    stevel static	INLINE void	frpr_udp __P((fr_info_t *));
    204      0    stevel static	INLINE void	frpr_tcp __P((fr_info_t *));
    205      0    stevel static	INLINE void	frpr_icmp __P((fr_info_t *));
    206      0    stevel static	INLINE void	frpr_ipv4hdr __P((fr_info_t *));
    207    637   ml37995 static	INLINE int	frpr_pullup __P((fr_info_t *, int));
    208    637   ml37995 static	INLINE void	frpr_short __P((fr_info_t *, int));
    209      0    stevel static	INLINE void	frpr_tcpcommon __P((fr_info_t *));
    210      0    stevel static	INLINE void	frpr_udpcommon __P((fr_info_t *));
    211      0    stevel static	INLINE int	fr_updateipid __P((fr_info_t *));
    212      0    stevel #ifdef	IPFILTER_LOOKUP
    213   3448  dh155122 static	int		fr_grpmapinit __P((frentry_t *fr, ipf_stack_t *));
    214   3448  dh155122 static	INLINE void	*fr_resolvelookup __P((u_int, u_int, lookupfunc_t *,
    215   3448  dh155122 					       ipf_stack_t *));
    216   3448  dh155122 #endif
    217   3448  dh155122 static	void		frsynclist __P((int, int, void *, char *, frentry_t *,
    218   3448  dh155122     ipf_stack_t *));
    219   2958  dr146992 static	void		*fr_ifsync __P((int, int, char *, char *,
    220   3448  dh155122 					void *, void *, ipf_stack_t *));
    221   3448  dh155122 static	ipftuneable_t	*fr_findtunebyname __P((const char *, ipf_stack_t *));
    222   3448  dh155122 static	ipftuneable_t	*fr_findtunebycookie __P((void *, void **, ipf_stack_t *));
    223      0    stevel 
    224      0    stevel /*
    225      0    stevel  * bit values for identifying presence of individual IP options
    226   2393  yz155240  * All of these tables should be ordered by increasing key value on the left
    227   2393  yz155240  * hand side to allow for binary searching of the array and include a trailer
    228   2393  yz155240  * with a 0 for the bitmask for linear searches to easily find the end with.
    229   2393  yz155240  */
    230   2393  yz155240 const	struct	optlist	ipopts[20] = {
    231      0    stevel 	{ IPOPT_NOP,	0x000001 },
    232      0    stevel 	{ IPOPT_RR,	0x000002 },
    233      0    stevel 	{ IPOPT_ZSU,	0x000004 },
    234      0    stevel 	{ IPOPT_MTUP,	0x000008 },
    235      0    stevel 	{ IPOPT_MTUR,	0x000010 },
    236      0    stevel 	{ IPOPT_ENCODE,	0x000020 },
    237      0    stevel 	{ IPOPT_TS,	0x000040 },
    238      0    stevel 	{ IPOPT_TR,	0x000080 },
    239      0    stevel 	{ IPOPT_SECURITY, 0x000100 },
    240      0    stevel 	{ IPOPT_LSRR,	0x000200 },
    241      0    stevel 	{ IPOPT_E_SEC,	0x000400 },
    242      0    stevel 	{ IPOPT_CIPSO,	0x000800 },
    243      0    stevel 	{ IPOPT_SATID,	0x001000 },
    244      0    stevel 	{ IPOPT_SSRR,	0x002000 },
    245      0    stevel 	{ IPOPT_ADDEXT,	0x004000 },
    246      0    stevel 	{ IPOPT_VISA,	0x008000 },
    247      0    stevel 	{ IPOPT_IMITD,	0x010000 },
    248      0    stevel 	{ IPOPT_EIP,	0x020000 },
    249      0    stevel 	{ IPOPT_FINN,	0x040000 },
    250      0    stevel 	{ 0,		0x000000 }
    251      0    stevel };
    252      0    stevel 
    253      0    stevel #ifdef USE_INET6
    254      0    stevel struct optlist ip6exthdr[] = {
    255      0    stevel 	{ IPPROTO_HOPOPTS,		0x000001 },
    256    637   ml37995 	{ IPPROTO_IPV6,			0x000002 },
    257    637   ml37995 	{ IPPROTO_ROUTING,		0x000004 },
    258    637   ml37995 	{ IPPROTO_FRAGMENT,		0x000008 },
    259    637   ml37995 	{ IPPROTO_ESP,			0x000010 },
    260    637   ml37995 	{ IPPROTO_AH,			0x000020 },
    261    637   ml37995 	{ IPPROTO_NONE,			0x000040 },
    262    637   ml37995 	{ IPPROTO_DSTOPTS,		0x000080 },
    263    637   ml37995 	{ 0,				0 }
    264      0    stevel };
    265      0    stevel #endif
    266      0    stevel 
    267      0    stevel struct optlist tcpopts[] = {
    268      0    stevel 	{ TCPOPT_NOP,			0x000001 },
    269      0    stevel 	{ TCPOPT_MAXSEG,		0x000002 },
    270      0    stevel 	{ TCPOPT_WINDOW,		0x000004 },
    271      0    stevel 	{ TCPOPT_SACK_PERMITTED,	0x000008 },
    272      0    stevel 	{ TCPOPT_SACK,			0x000010 },
    273      0    stevel 	{ TCPOPT_TIMESTAMP,		0x000020 },
    274      0    stevel 	{ 0,				0x000000 }
    275      0    stevel };
    276      0    stevel 
    277      0    stevel /*
    278      0    stevel  * bit values for identifying presence of individual IP security options
    279      0    stevel  */
    280   2393  yz155240 const	struct	optlist	secopt[8] = {
    281      0    stevel 	{ IPSO_CLASS_RES4,	0x01 },
    282      0    stevel 	{ IPSO_CLASS_TOPS,	0x02 },
    283      0    stevel 	{ IPSO_CLASS_SECR,	0x04 },
    284      0    stevel 	{ IPSO_CLASS_RES3,	0x08 },
    285      0    stevel 	{ IPSO_CLASS_CONF,	0x10 },
    286      0    stevel 	{ IPSO_CLASS_UNCL,	0x20 },
    287      0    stevel 	{ IPSO_CLASS_RES2,	0x40 },
    288      0    stevel 	{ IPSO_CLASS_RES1,	0x80 }
    289      0    stevel };
    290      0    stevel 
    291      0    stevel 
    292      0    stevel /*
    293      0    stevel  * Table of functions available for use with call rules.
    294      0    stevel  */
    295      0    stevel static ipfunc_resolve_t fr_availfuncs[] = {
    296      0    stevel #ifdef	IPFILTER_LOOKUP
    297      0    stevel 	{ "fr_srcgrpmap", fr_srcgrpmap, fr_grpmapinit },
    298      0    stevel 	{ "fr_dstgrpmap", fr_dstgrpmap, fr_grpmapinit },
    299      0    stevel #endif
    300      0    stevel 	{ "", NULL }
    301      0    stevel };
    302      0    stevel 
    303      0    stevel 
    304      0    stevel /*
    305   8170      John  * Below we declare a list of constants used only by the ipf_extraflush()
    306   8170      John  * routine.  We are placing it here, instead of in ipf_extraflush() itself,
    307   8170      John  * because we want to make it visible to tools such as mdb, nm etc., so the
    308   8170      John  * values can easily be altered during debugging.
    309   8170      John  */
    310   8170      John static	const	int	idletime_tab[] = {
    311   8170      John 	IPF_TTLVAL(30),		/* 30 seconds */
    312   8170      John 	IPF_TTLVAL(1800),	/* 30 minutes */
    313   8170      John 	IPF_TTLVAL(43200),	/* 12 hours */
    314   8170      John 	IPF_TTLVAL(345600),	/* 4 days */
    315   8170      John };
    316   8170      John 
    317   8170      John 
    318   8170      John /*
    319      0    stevel  * The next section of code is a a collection of small routines that set
    320      0    stevel  * fields in the fr_info_t structure passed based on properties of the
    321      0    stevel  * current packet.  There are different routines for the same protocol
    322      0    stevel  * for each of IPv4 and IPv6.  Adding a new protocol, for which there
    323      0    stevel  * will "special" inspection for setup, is now more easily done by adding
    324      0    stevel  * a new routine and expanding the frpr_ipinit*() function rather than by
    325      0    stevel  * adding more code to a growing switch statement.
    326      0    stevel  */
    327      0    stevel #ifdef USE_INET6
    328   2393  yz155240 static	INLINE int	frpr_ah6 __P((fr_info_t *));
    329   2393  yz155240 static	INLINE void	frpr_esp6 __P((fr_info_t *));
    330   2393  yz155240 static	INLINE void	frpr_gre6 __P((fr_info_t *));
    331      0    stevel static	INLINE void	frpr_udp6 __P((fr_info_t *));
    332      0    stevel static	INLINE void	frpr_tcp6 __P((fr_info_t *));
    333      0    stevel static	INLINE void	frpr_icmp6 __P((fr_info_t *));
    334   8624    Darren static	INLINE void	frpr_ipv6hdr __P((fr_info_t *));
    335      0    stevel static	INLINE void	frpr_short6 __P((fr_info_t *, int));
    336    637   ml37995 static	INLINE int	frpr_hopopts6 __P((fr_info_t *));
    337    637   ml37995 static	INLINE int	frpr_routing6 __P((fr_info_t *));
    338    637   ml37995 static	INLINE int	frpr_dstopts6 __P((fr_info_t *));
    339    637   ml37995 static	INLINE int	frpr_fragment6 __P((fr_info_t *));
    340   2393  yz155240 static	INLINE int	frpr_ipv6exthdr __P((fr_info_t *, int, int));
    341      0    stevel 
    342      0    stevel 
    343      0    stevel /* ------------------------------------------------------------------------ */
    344      0    stevel /* Function:    frpr_short6                                                 */
    345      0    stevel /* Returns:     void                                                        */
    346      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
    347      0    stevel /*                                                                          */
    348      0    stevel /* IPv6 Only                                                                */
    349      0    stevel /* This is function enforces the 'is a packet too short to be legit' rule   */
    350   2393  yz155240 /* for IPv6 and marks the packet with FI_SHORT if so.  See function comment */
    351   2393  yz155240 /* for frpr_short() for more details.                                       */
    352   2393  yz155240 /* ------------------------------------------------------------------------ */
    353   2393  yz155240 static INLINE void frpr_short6(fin, xmin)
    354   2393  yz155240 fr_info_t *fin;
    355   2393  yz155240 int xmin;
    356   2393  yz155240 {
    357   2393  yz155240 
    358   2393  yz155240 	if (fin->fin_dlen < xmin)
    359   2393  yz155240 		fin->fin_flx |= FI_SHORT;
    360      0    stevel }
    361      0    stevel 
    362      0    stevel 
    363      0    stevel /* ------------------------------------------------------------------------ */
    364      0    stevel /* Function:    frpr_ipv6hdr                                                */
    365   8624    Darren /* Returns:     Nil                                                         */
    366      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
    367      0    stevel /*                                                                          */
    368      0    stevel /* IPv6 Only                                                                */
    369      0    stevel /* Copy values from the IPv6 header into the fr_info_t struct and call the  */
    370      0    stevel /* per-protocol analyzer if it exists.                                      */
    371      0    stevel /* ------------------------------------------------------------------------ */
    372   8624    Darren static INLINE void frpr_ipv6hdr(fin)
    373      0    stevel fr_info_t *fin;
    374      0    stevel {
    375      0    stevel 	ip6_t *ip6 = (ip6_t *)fin->fin_ip;
    376   2393  yz155240 	int p, go = 1, i, hdrcount;
    377      0    stevel 	fr_ip_t *fi = &fin->fin_fi;
    378      0    stevel 
    379      0    stevel 	fin->fin_off = 0;
    380      0    stevel 
    381      0    stevel 	fi->fi_tos = 0;
    382      0    stevel 	fi->fi_optmsk = 0;
    383      0    stevel 	fi->fi_secmsk = 0;
    384      0    stevel 	fi->fi_auth = 0;
    385      0    stevel 
    386      0    stevel 	p = ip6->ip6_nxt;
    387      0    stevel 	fi->fi_ttl = ip6->ip6_hlim;
    388      0    stevel 	fi->fi_src.in6 = ip6->ip6_src;
    389      0    stevel 	fi->fi_dst.in6 = ip6->ip6_dst;
    390    637   ml37995 	fin->fin_id = 0;
    391      0    stevel 
    392      0    stevel 	hdrcount = 0;
    393    637   ml37995 	while (go && !(fin->fin_flx & (FI_BAD|FI_SHORT))) {
    394      0    stevel 		switch (p)
    395      0    stevel 		{
    396      0    stevel 		case IPPROTO_UDP :
    397      0    stevel 			frpr_udp6(fin);
    398      0    stevel 			go = 0;
    399      0    stevel 			break;
    400    637   ml37995 
    401      0    stevel 		case IPPROTO_TCP :
    402      0    stevel 			frpr_tcp6(fin);
    403      0    stevel 			go = 0;
    404      0    stevel 			break;
    405    637   ml37995 
    406      0    stevel 		case IPPROTO_ICMPV6 :
    407      0    stevel 			frpr_icmp6(fin);
    408      0    stevel 			go = 0;
    409      0    stevel 			break;
    410    637   ml37995 
    411    637   ml37995 		case IPPROTO_GRE :
    412   2393  yz155240 			frpr_gre6(fin);
    413    637   ml37995 			go = 0;
    414    637   ml37995 			break;
    415    637   ml37995 
    416      0    stevel 		case IPPROTO_HOPOPTS :
    417      0    stevel 			/*
    418   2393  yz155240 			 * hop by hop ext header is only allowed
    419   2393  yz155240 			 * right after IPv6 header.
    420   2393  yz155240 			 */
    421   2393  yz155240 			if (hdrcount != 0) {
    422    637   ml37995 				fin->fin_flx |= FI_BAD;
    423   2393  yz155240 				p = IPPROTO_NONE;
    424   2393  yz155240 			} else {
    425   2393  yz155240 				p = frpr_hopopts6(fin);
    426   2393  yz155240 			}
    427    637   ml37995 			break;
    428    637   ml37995 
    429      0    stevel 		case IPPROTO_DSTOPTS :
    430    637   ml37995 			p = frpr_dstopts6(fin);
    431    637   ml37995 			break;
    432    637   ml37995 
    433      0    stevel 		case IPPROTO_ROUTING :
    434    637   ml37995 			p = frpr_routing6(fin);
    435    637   ml37995 			break;
    436    637   ml37995 
    437   2393  yz155240 		case IPPROTO_AH :
    438   2393  yz155240 			p = frpr_ah6(fin);
    439   2393  yz155240 			break;
    440   2393  yz155240 
    441      0    stevel 		case IPPROTO_ESP :
    442   2393  yz155240 			frpr_esp6(fin);
    443   2393  yz155240 			go = 0;
    444   2393  yz155240 			break;
    445   2393  yz155240 
    446   2393  yz155240 		case IPPROTO_IPV6 :
    447    637   ml37995 			for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
    448    637   ml37995 				if (ip6exthdr[i].ol_val == p) {
    449   2393  yz155240 					fin->fin_flx |= ip6exthdr[i].ol_bit;
    450    637   ml37995 					break;
    451    637   ml37995 				}
    452    637   ml37995 			go = 0;
    453    637   ml37995 			break;
    454    637   ml37995 
    455   2393  yz155240 		case IPPROTO_NONE :
    456    637   ml37995 			go = 0;
    457    637   ml37995 			break;
    458    637   ml37995 
    459    637   ml37995 		case IPPROTO_FRAGMENT :
    460   2393  yz155240 			p = frpr_fragment6(fin);
    461   2393  yz155240 			if (fin->fin_off != 0)  /* Not the first frag */
    462    637   ml37995 				go = 0;
    463    637   ml37995 			break;
    464    637   ml37995 
    465    637   ml37995 		default :
    466    637   ml37995 			go = 0;
    467    637   ml37995 			break;
    468    637   ml37995 		}
    469      0    stevel 		hdrcount++;
    470   2393  yz155240 
    471   2393  yz155240 		/*
    472   2393  yz155240 		 * It is important to note that at this point, for the
    473   2393  yz155240 		 * extension headers (go != 0), the entire header may not have
    474   2393  yz155240 		 * been pulled up when the code gets to this point.  This is
    475   2393  yz155240 		 * only done for "go != 0" because the other header handlers
    476   2393  yz155240 		 * will all pullup their complete header.  The other indicator
    477   2393  yz155240 		 * of an incomplete packet is that this was just an extension
    478   2393  yz155240 		 * header.
    479   2393  yz155240 		 */
    480   2393  yz155240 		if ((go != 0) && (p != IPPROTO_NONE) &&
    481   2393  yz155240 		    (frpr_pullup(fin, 0) == -1)) {
    482   2393  yz155240 			p = IPPROTO_NONE;
    483   2393  yz155240 			go = 0;
    484   2393  yz155240 		}
    485   2393  yz155240 	}
    486    637   ml37995 	fi->fi_p = p;
    487   2393  yz155240 }
    488   2393  yz155240 
    489   2393  yz155240 
    490   2393  yz155240 /* ------------------------------------------------------------------------ */
    491   2393  yz155240 /* Function:    frpr_ipv6exthdr                                             */
    492    637   ml37995 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
    493   2393  yz155240 /* Parameters:  fin(I)      - pointer to packet information                 */
    494   2393  yz155240 /*              multiple(I) - flag indicating yes/no if multiple occurances */
    495   2393  yz155240 /*                            of this extension header are allowed.         */
    496   2393  yz155240 /*              proto(I)    - protocol number for this extension header     */
    497   2393  yz155240 /*                                                                          */
    498   2393  yz155240 /* IPv6 Only                                                                */
    499   9876    Darren /* This function expects to find an IPv6 extension header at fin_dp.        */
    500   9876    Darren /* There must be at least 8 bytes of data at fin_dp for there to be a valid */
    501   9876    Darren /* extension header present. If a good one is found, fin_dp is advanced to  */
    502   9876    Darren /* point at the first piece of data after the extension header, fin_exthdr  */
    503   9876    Darren /* points to the start of the extension header and the "protocol" of the    */
    504   9876    Darren /* *NEXT* header is returned.                                               */
    505   2393  yz155240 /* ------------------------------------------------------------------------ */
    506   2393  yz155240 static INLINE int frpr_ipv6exthdr(fin, multiple, proto)
    507   2393  yz155240 fr_info_t *fin;
    508   2393  yz155240 int multiple, proto;
    509      0    stevel {
    510      0    stevel 	struct ip6_ext *hdr;
    511      0    stevel 	u_short shift;
    512      0    stevel 	int i;
    513      0    stevel 
    514      0    stevel 	fin->fin_flx |= FI_V6EXTHDR;
    515      0    stevel 
    516   2393  yz155240 				/* 8 is default length of extension hdr */
    517   2393  yz155240 	if ((fin->fin_dlen - 8) < 0) {
    518   2393  yz155240 		fin->fin_flx |= FI_SHORT;
    519   2393  yz155240 		return IPPROTO_NONE;
    520   2393  yz155240 	}
    521    637   ml37995 
    522    637   ml37995 	if (frpr_pullup(fin, 8) == -1)
    523    637   ml37995 		return IPPROTO_NONE;
    524      0    stevel 
    525      0    stevel 	hdr = fin->fin_dp;
    526      0    stevel 	shift = 8 + (hdr->ip6e_len << 3);
    527      0    stevel 	if (shift > fin->fin_dlen) {	/* Nasty extension header length? */
    528      0    stevel 		fin->fin_flx |= FI_BAD;
    529    637   ml37995 		return IPPROTO_NONE;
    530    637   ml37995 	}
    531    637   ml37995 
    532    637   ml37995 	for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
    533   2393  yz155240 		if (ip6exthdr[i].ol_val == proto) {
    534   2393  yz155240 			/*
    535   2393  yz155240 			 * Most IPv6 extension headers are only allowed once.
    536   2393  yz155240 			 */
    537   2393  yz155240 			if ((multiple == 0) &&
    538   2393  yz155240 			    ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0))
    539   2393  yz155240 				fin->fin_flx |= FI_BAD;
    540   2393  yz155240 			else
    541   2393  yz155240 				fin->fin_optmsk |= ip6exthdr[i].ol_bit;
    542    637   ml37995 			break;
    543    637   ml37995 		}
    544    637   ml37995 
    545    637   ml37995 	fin->fin_dp = (char *)fin->fin_dp + shift;
    546    637   ml37995 	fin->fin_dlen -= shift;
    547    637   ml37995 
    548    637   ml37995 	return hdr->ip6e_nxt;
    549    637   ml37995 }
    550    637   ml37995 
    551    637   ml37995 
    552    637   ml37995 /* ------------------------------------------------------------------------ */
    553   2393  yz155240 /* Function:    frpr_hopopts6                                               */
    554   2393  yz155240 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
    555   2393  yz155240 /* Parameters:  fin(I) - pointer to packet information                      */
    556   2393  yz155240 /*                                                                          */
    557   2393  yz155240 /* IPv6 Only                                                                */
    558   2393  yz155240 /* This is function checks pending hop by hop options extension header      */
    559   2393  yz155240 /* ------------------------------------------------------------------------ */
    560   2393  yz155240 static INLINE int frpr_hopopts6(fin)
    561   2393  yz155240 fr_info_t *fin;
    562   2393  yz155240 {
    563   2393  yz155240 	return frpr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
    564   2393  yz155240 }
    565   2393  yz155240 
    566   2393  yz155240 
    567   2393  yz155240 /* ------------------------------------------------------------------------ */
    568    637   ml37995 /* Function:    frpr_routing6                                               */
    569    637   ml37995 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
    570    637   ml37995 /* Parameters:  fin(I) - pointer to packet information                      */
    571    637   ml37995 /*                                                                          */
    572    637   ml37995 /* IPv6 Only                                                                */
    573    637   ml37995 /* This is function checks pending routing extension header                 */
    574    637   ml37995 /* ------------------------------------------------------------------------ */
    575    637   ml37995 static INLINE int frpr_routing6(fin)
    576    637   ml37995 fr_info_t *fin;
    577    637   ml37995 {
    578    637   ml37995 	struct ip6_ext *hdr;
    579   2393  yz155240 	int shift;
    580   2393  yz155240 
    581    637   ml37995 	hdr = fin->fin_dp;
    582   2393  yz155240 	if (frpr_ipv6exthdr(fin, 0, IPPROTO_ROUTING) == IPPROTO_NONE)
    583   2393  yz155240 		return IPPROTO_NONE;
    584    637   ml37995 
    585    637   ml37995 	shift = 8 + (hdr->ip6e_len << 3);
    586    637   ml37995 	/*
    587    637   ml37995 	 * Nasty extension header length?
    588    637   ml37995 	 */
    589   2393  yz155240 	if ((hdr->ip6e_len << 3) & 15) {
    590   2393  yz155240 		fin->fin_flx |= FI_BAD;
    591   2393  yz155240 		/*
    592   2393  yz155240 		 * Compensate for the changes made in frpr_ipv6exthdr()
    593   2393  yz155240 		 */
    594   2393  yz155240 		fin->fin_dlen += shift;
    595   2393  yz155240 		fin->fin_dp = (char *)fin->fin_dp - shift;
    596   2393  yz155240 		return IPPROTO_NONE;
    597   2393  yz155240 	}
    598    637   ml37995 
    599    637   ml37995 	return hdr->ip6e_nxt;
    600    637   ml37995 }
    601    637   ml37995 
    602    637   ml37995 
    603    637   ml37995 /* ------------------------------------------------------------------------ */
    604    637   ml37995 /* Function:    frpr_fragment6                                              */
    605    637   ml37995 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
    606    637   ml37995 /* Parameters:  fin(I) - pointer to packet information                      */
    607    637   ml37995 /*                                                                          */
    608    637   ml37995 /* IPv6 Only                                                                */
    609    637   ml37995 /* Examine the IPv6 fragment header and extract fragment offset information.*/
    610   2393  yz155240 /*                                                                          */
    611   2393  yz155240 /* We don't know where the transport layer header (or whatever is next is), */
    612   2393  yz155240 /* as it could be behind destination options (amongst others).  Because     */
    613   2393  yz155240 /* there is no fragment cache, there is no knowledge about whether or not an*/
    614   2393  yz155240 /* upper layer header has been seen (or where it ends) and thus we are not  */
    615   2393  yz155240 /* able to continue processing beyond this header with any confidence.      */
    616    637   ml37995 /* ------------------------------------------------------------------------ */
    617    637   ml37995 static INLINE int frpr_fragment6(fin)
    618    637   ml37995 fr_info_t *fin;
    619    637   ml37995 {
    620    637   ml37995 	struct ip6_frag *frag;
    621   2393  yz155240 
    622   2393  yz155240 	fin->fin_flx |= FI_FRAG;
    623   2393  yz155240 
    624   9876    Darren 	/*
    625   9876    Darren 	 * A fragmented IPv6 packet implies that there must be something
    626   9876    Darren 	 * else after the fragment.
    627   9876    Darren 	 */
    628   2393  yz155240 	if (frpr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT) == IPPROTO_NONE)
    629  11043    Darren 		return IPPROTO_NONE;
    630   2393  yz155240 
    631   2393  yz155240 	frag = (struct ip6_frag *)((char *)fin->fin_dp - sizeof(*frag));
    632  11043    Darren 
    633  11043    Darren 	/*
    634  11043    Darren 	 * If this fragment isn't the last then the packet length must
    635  11043    Darren 	 * be a multiple of 8.
    636  11043    Darren 	 */
    637  11043    Darren 	if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0) {
    638  11043    Darren 		fin->fin_flx |= FI_MOREFRAG;
    639  11043    Darren 
    640  11043    Darren 		if ((fin->fin_plen & 0x7) != 0)
    641  11043    Darren 			fin->fin_flx |= FI_BAD;
    642  11043    Darren 	}
    643   9876    Darren 
    644   9876    Darren 	fin->fin_id = frag->ip6f_ident;
    645   9876    Darren 	fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK);
    646   2393  yz155240 	if (fin->fin_off != 0)
    647   2393  yz155240 		fin->fin_flx |= FI_FRAGBODY;
    648   2393  yz155240 
    649    637   ml37995 	return frag->ip6f_nxt;
    650    637   ml37995 }
    651    637   ml37995 
    652    637   ml37995 
    653    637   ml37995 /* ------------------------------------------------------------------------ */
    654    637   ml37995 /* Function:    frpr_dstopts6                                               */
    655    637   ml37995 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
    656    637   ml37995 /* Parameters:  fin(I) - pointer to packet information                      */
    657    637   ml37995 /*              nextheader(I) - stores next header value                    */
    658    637   ml37995 /*                                                                          */
    659    637   ml37995 /* IPv6 Only                                                                */
    660    637   ml37995 /* This is function checks pending destination options extension header     */
    661    637   ml37995 /* ------------------------------------------------------------------------ */
    662    637   ml37995 static INLINE int frpr_dstopts6(fin)
    663    637   ml37995 fr_info_t *fin;
    664    637   ml37995 {
    665   2393  yz155240 	return frpr_ipv6exthdr(fin, 1, IPPROTO_DSTOPTS);
    666      0    stevel }
    667      0    stevel 
    668      0    stevel 
    669      0    stevel /* ------------------------------------------------------------------------ */
    670      0    stevel /* Function:    frpr_icmp6                                                  */
    671      0    stevel /* Returns:     void                                                        */
    672      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
    673      0    stevel /*                                                                          */
    674      0    stevel /* IPv6 Only                                                                */
    675      0    stevel /* This routine is mainly concerned with determining the minimum valid size */
    676      0    stevel /* for an ICMPv6 packet.                                                    */
    677      0    stevel /* ------------------------------------------------------------------------ */
    678      0    stevel static INLINE void frpr_icmp6(fin)
    679      0    stevel fr_info_t *fin;
    680      0    stevel {
    681      0    stevel 	int minicmpsz = sizeof(struct icmp6_hdr);
    682      0    stevel 	struct icmp6_hdr *icmp6;
    683    637   ml37995 
    684   2393  yz155240 	if (frpr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1)
    685    637   ml37995 		return;
    686      0    stevel 
    687      0    stevel 	if (fin->fin_dlen > 1) {
    688      0    stevel 		icmp6 = fin->fin_dp;
    689      0    stevel 
    690      0    stevel 		fin->fin_data[0] = *(u_short *)icmp6;
    691      0    stevel 
    692   7176  yx160601 		if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0)
    693   7176  yx160601 			fin->fin_flx |= FI_ICMPQUERY;
    694   7176  yx160601 
    695      0    stevel 		switch (icmp6->icmp6_type)
    696      0    stevel 		{
    697      0    stevel 		case ICMP6_ECHO_REPLY :
    698      0    stevel 		case ICMP6_ECHO_REQUEST :
    699   7176  yx160601 			if (fin->fin_dlen >= 6)
    700   7176  yx160601 				fin->fin_data[1] = icmp6->icmp6_id;
    701      0    stevel 			minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t);
    702      0    stevel 			break;
    703      0    stevel 		case ICMP6_DST_UNREACH :
    704      0    stevel 		case ICMP6_PACKET_TOO_BIG :
    705      0    stevel 		case ICMP6_TIME_EXCEEDED :
    706      0    stevel 		case ICMP6_PARAM_PROB :
    707      0    stevel 			if ((fin->fin_m != NULL) &&
    708      0    stevel 			    (M_LEN(fin->fin_m) < fin->fin_plen)) {
    709    637   ml37995 				if (fr_coalesce(fin) != 1)
    710      0    stevel 					return;
    711      0    stevel 			}
    712      0    stevel 			fin->fin_flx |= FI_ICMPERR;
    713      0    stevel 			minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t);
    714      0    stevel 			break;
    715      0    stevel 		default :
    716      0    stevel 			break;
    717      0    stevel 		}
    718      0    stevel 	}
    719      0    stevel 
    720      0    stevel 	frpr_short6(fin, minicmpsz);
    721      0    stevel }
    722      0    stevel 
    723      0    stevel 
    724      0    stevel /* ------------------------------------------------------------------------ */
    725      0    stevel /* Function:    frpr_udp6                                                   */
    726      0    stevel /* Returns:     void                                                        */
    727      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
    728      0    stevel /*                                                                          */
    729      0    stevel /* IPv6 Only                                                                */
    730      0    stevel /* Analyse the packet for IPv6/UDP properties.                              */
    731   2393  yz155240 /* Is not expected to be called for fragmented packets.                     */
    732      0    stevel /* ------------------------------------------------------------------------ */
    733      0    stevel static INLINE void frpr_udp6(fin)
    734      0    stevel fr_info_t *fin;
    735      0    stevel {
    736      0    stevel 
    737      0    stevel 	fr_checkv6sum(fin);
    738      0    stevel 
    739      0    stevel 	frpr_short6(fin, sizeof(struct udphdr));
    740    674  yz155240 	if (frpr_pullup(fin, sizeof(struct udphdr)) == -1)
    741    674  yz155240 		return;
    742      0    stevel 
    743      0    stevel 	frpr_udpcommon(fin);
    744      0    stevel }
    745      0    stevel 
    746      0    stevel 
    747      0    stevel /* ------------------------------------------------------------------------ */
    748      0    stevel /* Function:    frpr_tcp6                                                   */
    749      0    stevel /* Returns:     void                                                        */
    750      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
    751      0    stevel /*                                                                          */
    752      0    stevel /* IPv6 Only                                                                */
    753      0    stevel /* Analyse the packet for IPv6/TCP properties.                              */
    754   2393  yz155240 /* Is not expected to be called for fragmented packets.                     */
    755      0    stevel /* ------------------------------------------------------------------------ */
    756      0    stevel static INLINE void frpr_tcp6(fin)
    757      0    stevel fr_info_t *fin;
    758      0    stevel {
    759      0    stevel 
    760      0    stevel 	fr_checkv6sum(fin);
    761      0    stevel 
    762      0    stevel 	frpr_short6(fin, sizeof(struct tcphdr));
    763    674  yz155240 	if (frpr_pullup(fin, sizeof(struct tcphdr)) == -1)
    764    674  yz155240 		return;
    765    637   ml37995 
    766      0    stevel 	frpr_tcpcommon(fin);
    767   2393  yz155240 }
    768   2393  yz155240 
    769   2393  yz155240 
    770   2393  yz155240 /* ------------------------------------------------------------------------ */
    771   2393  yz155240 /* Function:    frpr_esp6                                                   */
    772   2393  yz155240 /* Returns:     void                                                        */
    773   2393  yz155240 /* Parameters:  fin(I) - pointer to packet information                      */
    774   2393  yz155240 /*                                                                          */
    775   2393  yz155240 /* IPv6 Only                                                                */
    776   2393  yz155240 /* Analyse the packet for ESP properties.                                   */
    777   2393  yz155240 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits)  */
    778   2393  yz155240 /* even though the newer ESP packets must also have a sequence number that  */
    779   2393  yz155240 /* is 32bits as well, it is not possible(?) to determine the version from a */
    780   2393  yz155240 /* simple packet header.                                                    */
    781   2393  yz155240 /* ------------------------------------------------------------------------ */
    782   2393  yz155240 static INLINE void frpr_esp6(fin)
    783   2393  yz155240 fr_info_t *fin;
    784   2393  yz155240 {
    785   2393  yz155240 	int i;
    786   2393  yz155240 	frpr_short6(fin, sizeof(grehdr_t));
    787   2393  yz155240 
    788   2393  yz155240 	(void) frpr_pullup(fin, 8);
    789   2393  yz155240 
    790   2393  yz155240 	for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
    791   2393  yz155240 		if (ip6exthdr[i].ol_val == IPPROTO_ESP) {
    792   2393  yz155240 			fin->fin_optmsk |= ip6exthdr[i].ol_bit;
    793   2393  yz155240 			break;
    794   2393  yz155240 		}
    795   2393  yz155240 }
    796   2393  yz155240 
    797   2393  yz155240 
    798   2393  yz155240 /* ------------------------------------------------------------------------ */
    799   2393  yz155240 /* Function:    frpr_ah6                                                    */
    800   2393  yz155240 /* Returns:     void                                                        */
    801   2393  yz155240 /* Parameters:  fin(I) - pointer to packet information                      */
    802   2393  yz155240 /*                                                                          */
    803   2393  yz155240 /* IPv6 Only                                                                */
    804   2393  yz155240 /* Analyse the packet for AH properties.                                    */
    805   2393  yz155240 /* The minimum length is taken to be the combination of all fields in the   */
    806   2393  yz155240 /* header being present and no authentication data (null algorithm used.)   */
    807   2393  yz155240 /* ------------------------------------------------------------------------ */
    808   2393  yz155240 static INLINE int frpr_ah6(fin)
    809   2393  yz155240 fr_info_t *fin;
    810   2393  yz155240 {
    811   2393  yz155240 	authhdr_t *ah;
    812   2393  yz155240 	int i, shift;
    813   2393  yz155240 
    814   2393  yz155240 	frpr_short6(fin, 12);
    815   2393  yz155240 
    816   2393  yz155240 	if (frpr_pullup(fin, sizeof(*ah)) == -1)
    817   2393  yz155240 		return IPPROTO_NONE;
    818   2393  yz155240 
    819   2393  yz155240 	for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
    820   2393  yz155240 		if (ip6exthdr[i].ol_val == IPPROTO_AH) {
    821   2393  yz155240 			fin->fin_optmsk |= ip6exthdr[i].ol_bit;
    822   2393  yz155240 			break;
    823   2393  yz155240 		}
    824   2393  yz155240 
    825   2393  yz155240 	ah = (authhdr_t *)fin->fin_dp;
    826   2393  yz155240 
    827   2393  yz155240 	shift = (ah->ah_plen + 2) * 4;
    828   2393  yz155240 	fin->fin_dlen -= shift;
    829   2393  yz155240 	fin->fin_dp = (char*)fin->fin_dp + shift;
    830   2393  yz155240 
    831   2393  yz155240 	return ah->ah_next;
    832   2393  yz155240 }
    833   2393  yz155240 
    834   2393  yz155240 
    835   2393  yz155240 /* ------------------------------------------------------------------------ */
    836   2393  yz155240 /* Function:    frpr_gre6                                                   */
    837   2393  yz155240 /* Returns:     void                                                        */
    838   2393  yz155240 /* Parameters:  fin(I) - pointer to packet information                      */
    839   2393  yz155240 /*                                                                          */
    840   2393  yz155240 /* Analyse the packet for GRE properties.                                   */
    841   2393  yz155240 /* ------------------------------------------------------------------------ */
    842   2393  yz155240 static INLINE void frpr_gre6(fin)
    843   2393  yz155240 fr_info_t *fin;
    844   2393  yz155240 {
    845   2393  yz155240 	grehdr_t *gre;
    846   2393  yz155240 
    847   2393  yz155240 	frpr_short6(fin, sizeof(grehdr_t));
    848   2393  yz155240 
    849   2393  yz155240 	if (frpr_pullup(fin, sizeof(grehdr_t)) == -1)
    850   2393  yz155240 		return;
    851   2393  yz155240 
    852   2393  yz155240 	gre = fin->fin_dp;
    853   2393  yz155240 	if (GRE_REV(gre->gr_flags) == 1)
    854   2393  yz155240 		fin->fin_data[0] = gre->gr_call;
    855      0    stevel }
    856      0    stevel #endif	/* USE_INET6 */
    857    637   ml37995 
    858    637   ml37995 
    859    637   ml37995 /* ------------------------------------------------------------------------ */
    860    637   ml37995 /* Function:    frpr_pullup                                                 */
    861    637   ml37995 /* Returns:     int     - 0 == pullup succeeded, -1 == failure              */
    862    637   ml37995 /* Parameters:  fin(I)  - pointer to packet information                     */
    863    637   ml37995 /*              plen(I) - length (excluding L3 header) to pullup            */
    864    637   ml37995 /*                                                                          */
    865    637   ml37995 /* Short inline function to cut down on code duplication to perform a call  */
    866    637   ml37995 /* to fr_pullup to ensure there is the required amount of data,             */
    867    637   ml37995 /* consecutively in the packet buffer.                                      */
    868    637   ml37995 /* ------------------------------------------------------------------------ */
    869    637   ml37995 static INLINE int frpr_pullup(fin, plen)
    870    637   ml37995 fr_info_t *fin;
    871    637   ml37995 int plen;
    872    637   ml37995 {
    873   2393  yz155240 #if defined(_KERNEL)
    874    637   ml37995 	if (fin->fin_m != NULL) {
    875   7704  Alexandr 		int ipoff;
    876   7704  Alexandr 
    877   7704  Alexandr 		ipoff = (char *)fin->fin_ip - MTOD(fin->fin_m, char *);
    878   7704  Alexandr 
    879    637   ml37995 		if (fin->fin_dp != NULL)
    880    637   ml37995 			plen += (char *)fin->fin_dp -
    881    637   ml37995 				((char *)fin->fin_ip + fin->fin_hlen);
    882   7704  Alexandr 		plen += fin->fin_hlen;
    883   7704  Alexandr 		/*
    884   7704  Alexandr 		 * We don't do 'plen += ipoff;' here. The fr_pullup() will
    885   7704  Alexandr 		 * do it for us.
    886   7704  Alexandr 		 */
    887   7704  Alexandr 		if (M_LEN(fin->fin_m) < plen + ipoff) {
    888    637   ml37995 			if (fr_pullup(fin->fin_m, fin, plen) == NULL)
    889    637   ml37995 				return -1;
    890    637   ml37995 		}
    891    637   ml37995 	}
    892    637   ml37995 #endif
    893    637   ml37995 	return 0;
    894    637   ml37995 }
    895      0    stevel 
    896      0    stevel 
    897      0    stevel /* ------------------------------------------------------------------------ */
    898      0    stevel /* Function:    frpr_short                                                  */
    899      0    stevel /* Returns:     void                                                        */
    900   2393  yz155240 /* Parameters:  fin(I)  - pointer to packet information                     */
    901   2393  yz155240 /*              xmin(I) - minimum header size                               */
    902   2393  yz155240 /*                                                                          */
    903   2393  yz155240 /* Check if a packet is "short" as defined by xmin.  The rule we are        */
    904   2393  yz155240 /* applying here is that the packet must not be fragmented within the layer */
    905   2393  yz155240 /* 4 header.  That is, it must not be a fragment that has its offset set to */
    906   2393  yz155240 /* start within the layer 4 header (hdrmin) or if it is at offset 0, the    */
    907   2393  yz155240 /* entire layer 4 header must be present (min).                             */
    908   2393  yz155240 /* ------------------------------------------------------------------------ */
    909   2393  yz155240 static INLINE void frpr_short(fin, xmin)
    910   2393  yz155240 fr_info_t *fin;
    911   2393  yz155240 int xmin;
    912   2393  yz155240 {
    913   2393  yz155240 
    914   2393  yz155240 	if (fin->fin_off == 0) {
    915   2393  yz155240 		if (fin->fin_dlen < xmin)
    916   2393  yz155240 			fin->fin_flx |= FI_SHORT;
    917   2393  yz155240 	} else if (fin->fin_off < xmin) {
    918   2393  yz155240 		fin->fin_flx |= FI_SHORT;
    919      0    stevel 	}
    920      0    stevel }
    921      0    stevel 
    922      0    stevel 
    923      0    stevel /* ------------------------------------------------------------------------ */
    924      0    stevel /* Function:    frpr_icmp                                                   */
    925      0    stevel /* Returns:     void                                                        */
    926      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
    927      0    stevel /*                                                                          */
    928      0    stevel /* IPv4 Only                                                                */
    929      0    stevel /* Do a sanity check on the packet for ICMP (v4).  In nearly all cases,     */
    930      0    stevel /* except extrememly bad packets, both type and code will be present.       */
    931   2393  yz155240 /* The expected minimum size of an ICMP packet is very much dependent on    */
    932      0    stevel /* the type of it.                                                          */
    933      0    stevel /*                                                                          */
    934      0    stevel /* XXX - other ICMP sanity checks?                                          */
    935      0    stevel /* ------------------------------------------------------------------------ */
    936      0    stevel static INLINE void frpr_icmp(fin)
    937      0    stevel fr_info_t *fin;
    938      0    stevel {
    939      0    stevel 	int minicmpsz = sizeof(struct icmp);
    940      0    stevel 	icmphdr_t *icmp;
    941   2393  yz155240 	ip_t *oip;
    942   3448  dh155122 	ipf_stack_t *ifs = fin->fin_ifs;
    943      0    stevel 
    944    780   ml37995 	if (fin->fin_off != 0) {
    945    780   ml37995 		frpr_short(fin, ICMPERR_ICMPHLEN);
    946    780   ml37995 		return;
    947    780   ml37995 	}
    948   2393  yz155240 
    949   2393  yz155240 	if (frpr_pullup(fin, ICMPERR_ICMPHLEN) == -1)
    950   2393  yz155240 		return;
    951    780   ml37995 
    952      0    stevel 	fr_checkv4sum(fin);
    953      0    stevel 
    954   9029  Alexandr 	/*
    955   9029  Alexandr 	 * This is a right place to set icmp pointer, since the memory
    956   9029  Alexandr 	 * referenced by fin_dp could get reallocated. The code down below can
    957   9029  Alexandr 	 * rely on fact icmp variable always points to ICMP header.
    958   9029  Alexandr 	 */
    959   9029  Alexandr 	icmp = fin->fin_dp;
    960   9029  Alexandr 	fin->fin_data[0] = *(u_short *)icmp;
    961   9029  Alexandr 	fin->fin_data[1] = icmp->icmp_id;
    962   9029  Alexandr 
    963   9029  Alexandr 	switch (icmp->icmp_type)
    964   9029  Alexandr 	{
    965   9029  Alexandr 	case ICMP_ECHOREPLY :
    966   9029  Alexandr 	case ICMP_ECHO :
    967   9029  Alexandr 	/* Router discovery messaes - RFC 1256 */
    968   9029  Alexandr 	case ICMP_ROUTERADVERT :
    969   9029  Alexandr 	case ICMP_ROUTERSOLICIT :
    970   9029  Alexandr 		minicmpsz = ICMP_MINLEN;
    971   9029  Alexandr 		break;
    972   9029  Alexandr 	/*
    973   9029  Alexandr 	 * type(1) + code(1) + cksum(2) + id(2) seq(2) +
    974   9029  Alexandr 	 * 3 * timestamp(3 * 4)
    975   9029  Alexandr 	 */
    976   9029  Alexandr 	case ICMP_TSTAMP :
    977   9029  Alexandr 	case ICMP_TSTAMPREPLY :
    978   9029  Alexandr 		minicmpsz = 20;
    979   9029  Alexandr 		break;
    980   9029  Alexandr 	/*
    981   9029  Alexandr 	 * type(1) + code(1) + cksum(2) + id(2) seq(2) +
    982   9029  Alexandr 	 * mask(4)
    983   9029  Alexandr 	 */
    984   9029  Alexandr 	case ICMP_MASKREQ :
    985   9029  Alexandr 	case ICMP_MASKREPLY :
    986      0    stevel 			minicmpsz = 12;
    987      0    stevel 			break;
    988   9029  Alexandr 	/*
    989   9029  Alexandr 	 * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+)
    990   9029  Alexandr 	 */
    991   9029  Alexandr 	case ICMP_UNREACH :
    992   9029  Alexandr 		if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) {
    993   9029  Alexandr 			if (icmp->icmp_nextmtu < ifs->ifs_fr_icmpminfragmtu)
    994   2393  yz155240 				fin->fin_flx |= FI_BAD;
    995   9029  Alexandr 		}
    996   9029  Alexandr 		/* FALLTHRU */
    997   9029  Alexandr 	case ICMP_SOURCEQUENCH :
    998   9029  Alexandr 	case ICMP_REDIRECT :
    999   9029  Alexandr 	case ICMP_TIMXCEED :
   1000   9029  Alexandr 	case ICMP_PARAMPROB :
   1001   9029  Alexandr 		fin->fin_flx |= FI_ICMPERR;
   1002   9029  Alexandr 		if (fr_coalesce(fin) != 1)
   1003   9029  Alexandr 			return;
   1004   9029  Alexandr 		/*
   1005   9029  Alexandr 		 * ICMP error packets should not be generated for IP
   1006   9029  Alexandr 		 * packets that are a fragment that isn't the first
   1007   9029  Alexandr 		 * fragment.
   1008   9029  Alexandr 		 */
   1009   9029  Alexandr 		oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN);
   1010   9029  Alexandr 		if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0)
   1011   9029  Alexandr 			fin->fin_flx |= FI_BAD;
   1012   9029  Alexandr 		break;
   1013   9029  Alexandr 	default :
   1014   9029  Alexandr 		break;
   1015      0    stevel 	}
   1016      0    stevel 
   1017    637   ml37995 	frpr_short(fin, minicmpsz);
   1018      0    stevel }
   1019      0    stevel 
   1020      0    stevel 
   1021      0    stevel /* ------------------------------------------------------------------------ */
   1022      0    stevel /* Function:    frpr_tcpcommon                                              */
   1023      0    stevel /* Returns:     void                                                        */
   1024      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
   1025      0    stevel /*                                                                          */
   1026      0    stevel /* TCP header sanity checking.  Look for bad combinations of TCP flags,     */
   1027      0    stevel /* and make some checks with how they interact with other fields.           */
   1028      0    stevel /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is     */
   1029      0    stevel /* valid and mark the packet as bad if not.                                 */
   1030      0    stevel /* ------------------------------------------------------------------------ */
   1031      0    stevel static INLINE void frpr_tcpcommon(fin)
   1032      0    stevel fr_info_t *fin;
   1033      0    stevel {
   1034      0    stevel 	int flags, tlen;
   1035      0    stevel 	tcphdr_t *tcp;
   1036    780   ml37995 
   1037    780   ml37995 	fin->fin_flx |= FI_TCPUDP;
   1038    780   ml37995 	if (fin->fin_off != 0)
   1039    780   ml37995 		return;
   1040    780   ml37995 
   1041   2393  yz155240 	if (frpr_pullup(fin, sizeof(*tcp)) == -1)
   1042   2393  yz155240 		return;
   1043      0    stevel 	tcp = fin->fin_dp;
   1044      0    stevel 
   1045    780   ml37995 	if (fin->fin_dlen > 3) {
   1046      0    stevel 		fin->fin_sport = ntohs(tcp->th_sport);
   1047      0    stevel 		fin->fin_dport = ntohs(tcp->th_dport);
   1048      0    stevel 	}
   1049      0    stevel 
   1050   2393  yz155240 	if ((fin->fin_flx & FI_SHORT) != 0)
   1051   2393  yz155240 		return;
   1052   2393  yz155240 
   1053   2393  yz155240 	/*
   1054   2393  yz155240 	 * Use of the TCP data offset *must* result in a value that is at
   1055   2393  yz155240 	 * least the same size as the TCP header.
   1056   2393  yz155240 	 */
   1057   2393  yz155240 	tlen = TCP_OFF(tcp) << 2;
   1058   2393  yz155240 	if (tlen < sizeof(tcphdr_t)) {
   1059   2393  yz155240 		fin->fin_flx |= FI_BAD;
   1060   2393  yz155240 		return;
   1061   2393  yz155240 	}
   1062   2393  yz155240 
   1063   2393  yz155240 	flags = tcp->th_flags;
   1064   2393  yz155240 	fin->fin_tcpf = tcp->th_flags;
   1065   2393  yz155240 
   1066   2393  yz155240 	/*
   1067   2393  yz155240 	 * If the urgent flag is set, then the urgent pointer must
   1068   2393  yz155240 	 * also be set and vice versa.  Good TCP packets do not have
   1069   2393  yz155240 	 * just one of these set.
   1070   2393  yz155240 	 */
   1071   2393  yz155240 	if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) {
   1072   2393  yz155240 		fin->fin_flx |= FI_BAD;
   1073   2393  yz155240 	} else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) {
   1074   2393  yz155240 		/* Ignore this case, it shows up in "real" traffic with */
   1075   2393  yz155240 		/* bogus values in the urgent pointer field. */
   1076   2393  yz155240 		flags = flags; /* LINT */
   1077   2393  yz155240 	} else if (((flags & (TH_SYN|TH_FIN)) != 0) &&
   1078   2393  yz155240 		   ((flags & (TH_RST|TH_ACK)) == TH_RST)) {
   1079   2393  yz155240 		/* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */
   1080   2393  yz155240 		fin->fin_flx |= FI_BAD;
   1081   2393  yz155240 	} else if (!(flags & TH_ACK)) {
   1082   2393  yz155240 		/*
   1083   2393  yz155240 		 * If the ack bit isn't set, then either the SYN or
   1084   2393  yz155240 		 * RST bit must be set.  If the SYN bit is set, then
   1085   2393  yz155240 		 * we expect the ACK field to be 0.  If the ACK is
   1086   2393  yz155240 		 * not set and if URG, PSH or FIN are set, consdier
   1087   2393  yz155240 		 * that to indicate a bad TCP packet.
   1088   2393  yz155240 		 */
   1089   2393  yz155240 		if ((flags == TH_SYN) && (tcp->th_ack != 0)) {
   1090   2393  yz155240 			/*
   1091   2393  yz155240 			 * Cisco PIX sets the ACK field to a random value.
   1092   2393  yz155240 			 * In light of this, do not set FI_BAD until a patch
   1093   2393  yz155240 			 * is available from Cisco to ensure that
   1094   2393  yz155240 			 * interoperability between existing systems is
   1095   2393  yz155240 			 * achieved.
   1096   2393  yz155240 			 */
   1097   2393  yz155240 			/*fin->fin_flx |= FI_BAD*/;
   1098   2393  yz155240 			flags = flags; /* LINT */
   1099   2393  yz155240 		} else if (!(flags & (TH_RST|TH_SYN))) {
   1100   2393  yz155240 			fin->fin_flx |= FI_BAD;
   1101   2393  yz155240 		} else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) {
   1102   2393  yz155240 			fin->fin_flx |= FI_BAD;
   1103   2393  yz155240 		}
   1104   2393  yz155240 	}
   1105   2393  yz155240 
   1106      0    stevel 	/*
   1107      0    stevel 	 * At this point, it's not exactly clear what is to be gained by
   1108      0    stevel 	 * marking up which TCP options are and are not present.  The one we
   1109      0    stevel 	 * are most interested in is the TCP window scale.  This is only in
   1110      0    stevel 	 * a SYN packet [RFC1323] so we don't need this here...?
   1111      0    stevel 	 * Now if we were to analyse the header for passive fingerprinting,
   1112      0    stevel 	 * then that might add some weight to adding this...
   1113      0    stevel 	 */
   1114   2393  yz155240 	if (tlen == sizeof(tcphdr_t))
   1115   2393  yz155240 		return;
   1116   2393  yz155240 
   1117   2393  yz155240 	if (frpr_pullup(fin, tlen) == -1)
   1118   2393  yz155240 		return;
   1119   2393  yz155240 
   1120   2393  yz155240 #if 0
   1121   2393  yz155240 	ip = fin->fin_ip;
   1122      0    stevel 	s = (u_char *)(tcp + 1);
   1123      0    stevel 	off = IP_HL(ip) << 2;
   1124      0    stevel # ifdef _KERNEL
   1125      0    stevel 	if (fin->fin_mp != NULL) {
   1126      0    stevel 		mb_t *m = *fin->fin_mp;
   1127      0    stevel 
   1128   2393  yz155240 		if (off + tlen > M_LEN(m))
   1129      0    stevel 			return;
   1130      0    stevel 	}
   1131      0    stevel # endif
   1132   2393  yz155240 	for (tlen -= (int)sizeof(*tcp); tlen > 0; ) {
   1133      0    stevel 		opt = *s;
   1134      0    stevel 		if (opt == '\0')
   1135      0    stevel 			break;
   1136      0    stevel 		else if (opt == TCPOPT_NOP)
   1137      0    stevel 			ol = 1;
   1138      0    stevel 		else {
   1139   2393  yz155240 			if (tlen < 2)
   1140      0    stevel 				break;
   1141      0    stevel 			ol = (int)*(s + 1);
   1142   2393  yz155240 			if (ol < 2 || ol > tlen)
   1143      0    stevel 				break;
   1144      0    stevel 		}
   1145      0    stevel 
   1146      0    stevel 		for (i = 9, mv = 4; mv >= 0; ) {
   1147      0    stevel 			op = ipopts + i;
   1148      0    stevel 			if (opt == (u_char)op->ol_val) {
   1149      0    stevel 				optmsk |= op->ol_bit;
   1150      0    stevel 				break;
   1151      0    stevel 			}
   1152      0    stevel 		}
   1153   2393  yz155240 		tlen -= ol;
   1154      0    stevel 		s += ol;
   1155      0    stevel 	}
   1156      0    stevel #endif /* 0 */
   1157      0    stevel }
   1158      0    stevel 
   1159      0    stevel 
   1160      0    stevel 
   1161      0    stevel /* ------------------------------------------------------------------------ */
   1162      0    stevel /* Function:    frpr_udpcommon                                              */
   1163      0    stevel /* Returns:     void                                                        */
   1164      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
   1165      0    stevel /*                                                                          */
   1166      0    stevel /* Extract the UDP source and destination ports, if present.  If compiled   */
   1167      0    stevel /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid.          */
   1168      0    stevel /* ------------------------------------------------------------------------ */
   1169      0    stevel static INLINE void frpr_udpcommon(fin)
   1170      0    stevel fr_info_t *fin;
   1171      0    stevel {
   1172      0    stevel 	udphdr_t *udp;
   1173    780   ml37995 
   1174    780   ml37995 	fin->fin_flx |= FI_TCPUDP;
   1175      0    stevel 
   1176      0    stevel 	if (!fin->fin_off && (fin->fin_dlen > 3)) {
   1177   2393  yz155240 		if (frpr_pullup(fin, sizeof(*udp)) == -1) {
   1178   2393  yz155240 			fin->fin_flx |= FI_SHORT;
   1179   2393  yz155240 			return;
   1180   2393  yz155240 		}
   1181   2393  yz155240 
   1182    780   ml37995 		udp = fin->fin_dp;
   1183    780   ml37995 
   1184      0    stevel 		fin->fin_sport = ntohs(udp->uh_sport);
   1185      0    stevel 		fin->fin_dport = ntohs(udp->uh_dport);
   1186      0    stevel 	}
   1187      0    stevel }
   1188      0    stevel 
   1189      0    stevel 
   1190      0    stevel /* ------------------------------------------------------------------------ */
   1191      0    stevel /* Function:    frpr_tcp                                                    */
   1192      0    stevel /* Returns:     void                                                        */
   1193      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
   1194      0    stevel /*                                                                          */
   1195      0    stevel /* IPv4 Only                                                                */
   1196      0    stevel /* Analyse the packet for IPv4/TCP properties.                              */
   1197      0    stevel /* ------------------------------------------------------------------------ */
   1198      0    stevel static INLINE void frpr_tcp(fin)
   1199      0    stevel fr_info_t *fin;
   1200      0    stevel {
   1201      0    stevel 
   1202      0    stevel 	fr_checkv4sum(fin);
   1203      0    stevel 
   1204   2393  yz155240 	frpr_short(fin, sizeof(tcphdr_t));
   1205      0    stevel 
   1206      0    stevel 	frpr_tcpcommon(fin);
   1207      0    stevel }
   1208      0    stevel 
   1209      0    stevel 
   1210      0    stevel /* ------------------------------------------------------------------------ */
   1211      0    stevel /* Function:    frpr_udp                                                    */
   1212      0    stevel /* Returns:     void                                                        */
   1213      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
   1214      0    stevel /*                                                                          */
   1215      0    stevel /* IPv4 Only                                                                */
   1216      0    stevel /* Analyse the packet for IPv4/UDP properties.                              */
   1217      0    stevel /* ------------------------------------------------------------------------ */
   1218      0    stevel static INLINE void frpr_udp(fin)
   1219      0    stevel fr_info_t *fin;
   1220      0    stevel {
   1221      0    stevel 
   1222      0    stevel 	fr_checkv4sum(fin);
   1223      0    stevel 
   1224   2393  yz155240 	frpr_short(fin, sizeof(udphdr_t));
   1225      0    stevel 
   1226      0    stevel 	frpr_udpcommon(fin);
   1227    637   ml37995 }
   1228    637   ml37995 
   1229    637   ml37995 
   1230    637   ml37995 /* ------------------------------------------------------------------------ */
   1231    637   ml37995 /* Function:    frpr_esp                                                    */
   1232    637   ml37995 /* Returns:     void                                                        */
   1233    637   ml37995 /* Parameters:  fin(I) - pointer to packet information                      */
   1234    637   ml37995 /*                                                                          */
   1235    637   ml37995 /* Analyse the packet for ESP properties.                                   */
   1236    637   ml37995 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits)  */
   1237    637   ml37995 /* even though the newer ESP packets must also have a sequence number that  */
   1238    637   ml37995 /* is 32bits as well, it is not possible(?) to determine the version from a */
   1239    637   ml37995 /* simple packet header.                                                    */
   1240    637   ml37995 /* ------------------------------------------------------------------------ */
   1241    637   ml37995 static INLINE void frpr_esp(fin)
   1242    637   ml37995 fr_info_t *fin;
   1243    637   ml37995 {
   1244   2393  yz155240 	if ((fin->fin_off == 0) && (frpr_pullup(fin, 8) == -1))
   1245   2393  yz155240 		return;
   1246   2393  yz155240 
   1247   2393  yz155240 	frpr_short(fin, 8);
   1248   2393  yz155240 }
   1249   2393  yz155240 
   1250   2393  yz155240 
   1251   2393  yz155240 /* ------------------------------------------------------------------------ */
   1252   2393  yz155240 /* Function:    frpr_ah                                                     */
   1253   2393  yz155240 /* Returns:     void                                                        */
   1254   2393  yz155240 /* Parameters:  fin(I) - pointer to packet information                      */
   1255   2393  yz155240 /*                                                                          */
   1256   2393  yz155240 /* Analyse the packet for AH properties.                                    */
   1257   2393  yz155240 /* The minimum length is taken to be the combination of all fields in the   */
   1258   2393  yz155240 /* header being present and no authentication data (null algorithm used.)   */
   1259   2393  yz155240 /* ------------------------------------------------------------------------ */
   1260   2393  yz155240 static INLINE void frpr_ah(fin)
   1261   2393  yz155240 fr_info_t *fin;
   1262   2393  yz155240 {
   1263   2393  yz155240 	authhdr_t *ah;
   1264   2393  yz155240 	int len;
   1265   2393  yz155240 
   1266   2393  yz155240 	if ((fin->fin_off == 0) && (frpr_pullup(fin, sizeof(*ah)) == -1))
   1267   2393  yz155240 		return;
   1268   2393  yz155240 
   1269   2393  yz155240 	ah = (authhdr_t *)fin->fin_dp;
   1270   2393  yz155240 
   1271   2393  yz155240 	len = (ah->ah_plen + 2) << 2;
   1272   2393  yz155240 	frpr_short(fin, len);
   1273    637   ml37995 }
   1274    637   ml37995 
   1275    637   ml37995 
   1276    637   ml37995 /* ------------------------------------------------------------------------ */
   1277    637   ml37995 /* Function:    frpr_gre                                                    */
   1278    637   ml37995 /* Returns:     void                                                        */
   1279    637   ml37995 /* Parameters:  fin(I) - pointer to packet information                      */
   1280    637   ml37995 /*                                                                          */
   1281    637   ml37995 /* Analyse the packet for GRE properties.                                   */
   1282    637   ml37995 /* ------------------------------------------------------------------------ */
   1283    637   ml37995 static INLINE void frpr_gre(fin)
   1284    637   ml37995 fr_info_t *fin;
   1285    637   ml37995 {
   1286   2393  yz155240 	grehdr_t *gre;
   1287   2393  yz155240 
   1288   2393  yz155240 	if ((fin->fin_off == 0) && (frpr_pullup(fin, sizeof(grehdr_t)) == -1))
   1289   2393  yz155240 		return;
   1290   2393  yz155240 
   1291   2393  yz155240 	frpr_short(fin, sizeof(grehdr_t));
   1292   2393  yz155240 
   1293   2393  yz155240 	if (fin->fin_off == 0) {
   1294   2393  yz155240 		gre = fin->fin_dp;
   1295   2393  yz155240 		if (GRE_REV(gre->gr_flags) == 1)
   1296   2393  yz155240 			fin->fin_data[0] = gre->gr_call;
   1297   2393  yz155240 	}
   1298      0    stevel }
   1299      0    stevel 
   1300      0    stevel 
   1301      0    stevel /* ------------------------------------------------------------------------ */
   1302      0    stevel /* Function:    frpr_ipv4hdr                                                */
   1303      0    stevel /* Returns:     void                                                        */
   1304      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
   1305      0    stevel /*                                                                          */
   1306      0    stevel /* IPv4 Only                                                                */
   1307      0    stevel /* Analyze the IPv4 header and set fields in the fr_info_t structure.       */
   1308      0    stevel /* Check all options present and flag their presence if any exist.          */
   1309      0    stevel /* ------------------------------------------------------------------------ */
   1310      0    stevel static INLINE void frpr_ipv4hdr(fin)
   1311      0    stevel fr_info_t *fin;
   1312      0    stevel {
   1313      0    stevel 	u_short optmsk = 0, secmsk = 0, auth = 0;
   1314      0    stevel 	int hlen, ol, mv, p, i;
   1315   2393  yz155240 	const struct optlist *op;
   1316      0    stevel 	u_char *s, opt;
   1317      0    stevel 	u_short off;
   1318      0    stevel 	fr_ip_t *fi;
   1319      0    stevel 	ip_t *ip;
   1320      0    stevel 
   1321      0    stevel 	fi = &fin->fin_fi;
   1322      0    stevel 	hlen = fin->fin_hlen;
   1323      0    stevel 
   1324      0    stevel 	ip = fin->fin_ip;
   1325      0    stevel 	p = ip->ip_p;
   1326      0    stevel 	fi->fi_p = p;
   1327      0    stevel 	fi->fi_tos = ip->ip_tos;
   1328      0    stevel 	fin->fin_id = ip->ip_id;
   1329      0    stevel 	off = ip->ip_off;
   1330      0    stevel 
   1331      0    stevel 	/* Get both TTL and protocol */
   1332      0    stevel 	fi->fi_p = ip->ip_p;
   1333      0    stevel 	fi->fi_ttl = ip->ip_ttl;
   1334      0    stevel #if 0
   1335      0    stevel 	(*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4));
   1336      0    stevel #endif
   1337      0    stevel 
   1338      0    stevel 	/* Zero out bits not used in IPv6 address */
   1339      0    stevel 	fi->fi_src.i6[1] = 0;
   1340      0    stevel 	fi->fi_src.i6[2] = 0;
   1341      0    stevel 	fi->fi_src.i6[3] = 0;
   1342      0    stevel 	fi->fi_dst.i6[1] = 0;
   1343      0    stevel 	fi->fi_dst.i6[2] = 0;
   1344      0    stevel 	fi->fi_dst.i6[3] = 0;
   1345      0    stevel 
   1346      0    stevel 	fi->fi_saddr = ip->ip_src.s_addr;
   1347      0    stevel 	fi->fi_daddr = ip->ip_dst.s_addr;
   1348      0    stevel 
   1349      0    stevel 	/*
   1350      0    stevel 	 * set packet attribute flags based on the offset and
   1351      0    stevel 	 * calculate the byte offset that it represents.
   1352      0    stevel 	 */
   1353      0    stevel 	off &= IP_MF|IP_OFFMASK;
   1354      0    stevel 	if (off != 0) {
   1355   9876    Darren 		int morefrag = off & IP_MF;
   1356   9876    Darren 
   1357      0    stevel 		fi->fi_flx |= FI_FRAG;
   1358   9876    Darren 		if (morefrag)
   1359   9876    Darren 			fi->fi_flx |= FI_MOREFRAG;
   1360      0    stevel 		off &= IP_OFFMASK;
   1361      0    stevel 		if (off != 0) {
   1362   2393  yz155240 			fin->fin_flx |= FI_FRAGBODY;
   1363      0    stevel 			off <<= 3;
   1364   2393  yz155240 			if ((off + fin->fin_dlen > 65535) ||
   1365   2393  yz155240 			    (fin->fin_dlen == 0) ||
   1366   9876    Darren 			    ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) {
   1367   2393  yz155240 				/*
   1368   2393  yz155240 				 * The length of the packet, starting at its
   1369   2393  yz155240 				 * offset cannot exceed 65535 (0xffff) as the
   1370   2393  yz155240 				 * length of an IP packet is only 16 bits.
   1371   2393  yz155240 				 *
   1372   2393  yz155240 				 * Any fragment that isn't the last fragment
   1373   2393  yz155240 				 * must have a length greater than 0 and it
   1374   2393  yz155240 				 * must be an even multiple of 8.
   1375   2393  yz155240 				 */
   1376      0    stevel 				fi->fi_flx |= FI_BAD;
   1377   2393  yz155240 			}
   1378      0    stevel 		}
   1379      0    stevel 	}
   1380      0    stevel 	fin->fin_off = off;
   1381      0    stevel 
   1382      0    stevel 	/*
   1383      0    stevel 	 * Call per-protocol setup and checking
   1384      0    stevel 	 */
   1385      0    stevel 	switch (p)
   1386      0    stevel 	{
   1387      0    stevel 	case IPPROTO_UDP :
   1388      0    stevel 		frpr_udp(fin);
   1389      0    stevel 		break;
   1390      0    stevel 	case IPPROTO_TCP :
   1391      0    stevel 		frpr_tcp(fin);
   1392      0    stevel 		break;
   1393      0    stevel 	case IPPROTO_ICMP :
   1394      0    stevel 		frpr_icmp(fin);
   1395   2393  yz155240 		break;
   1396   2393  yz155240 	case IPPROTO_AH :
   1397   2393  yz155240 		frpr_ah(fin);
   1398   2393  yz155240 		break;
   1399   2393  yz155240 	case IPPROTO_ESP :
   1400   2393  yz155240 		frpr_esp(fin);
   1401   2393  yz155240 		break;
   1402   2393  yz155240 	case IPPROTO_GRE :
   1403   2393  yz155240 		frpr_gre(fin);
   1404      0    stevel 		break;
   1405      0    stevel 	}
   1406      0    stevel 
   1407      0    stevel 	ip = fin->fin_ip;
   1408      0    stevel 	if (ip == NULL)
   1409      0    stevel 		return;
   1410      0    stevel 
   1411      0    stevel 	/*
   1412      0    stevel 	 * If it is a standard IP header (no options), set the flag fields
   1413      0    stevel 	 * which relate to options to 0.
   1414      0    stevel 	 */
   1415      0    stevel 	if (hlen == sizeof(*ip)) {
   1416      0    stevel 		fi->fi_optmsk = 0;
   1417      0    stevel 		fi->fi_secmsk = 0;
   1418      0    stevel 		fi->fi_auth = 0;
   1419      0    stevel 		return;
   1420      0    stevel 	}
   1421      0    stevel 
   1422      0    stevel 	/*
   1423      0    stevel 	 * So the IP header has some IP options attached.  Walk the entire
   1424      0    stevel 	 * list of options present with this packet and set flags to indicate
   1425      0    stevel 	 * which ones are here and which ones are not.  For the somewhat out
   1426      0    stevel 	 * of date and obscure security classification options, set a flag to
   1427      0    stevel 	 * represent which classification is present.
   1428      0    stevel 	 */
   1429      0    stevel 	fi->fi_flx |= FI_OPTIONS;
   1430      0    stevel 
   1431      0    stevel 	for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) {
   1432      0    stevel 		opt = *s;
   1433      0    stevel 		if (opt == '\0')
   1434      0    stevel 			break;
   1435      0    stevel 		else if (opt == IPOPT_NOP)
   1436      0    stevel 			ol = 1;
   1437      0    stevel 		else {
   1438      0    stevel 			if (hlen < 2)
   1439      0    stevel 				break;
   1440      0    stevel 			ol = (int)*(s + 1);
   1441      0    stevel 			if (ol < 2 || ol > hlen)
   1442      0    stevel 				break;
   1443      0    stevel 		}
   1444      0    stevel 		for (i = 9, mv = 4; mv >= 0; ) {
   1445      0    stevel 			op = ipopts + i;
   1446      0    stevel 			if ((opt == (u_char)op->ol_val) && (ol > 4)) {
   1447      0    stevel 				optmsk |= op->ol_bit;
   1448      0    stevel 				if (opt == IPOPT_SECURITY) {
   1449   2393  yz155240 					const struct optlist *sp;
   1450      0    stevel 					u_char	sec;
   1451      0    stevel 					int j, m;
   1452      0    stevel 
   1453      0    stevel 					sec = *(s + 2);	/* classification */
   1454      0    stevel 					for (j = 3, m = 2; m >= 0; ) {
   1455      0    stevel 						sp = secopt + j;
   1456      0    stevel 						if (sec == sp->ol_val) {
   1457      0    stevel 							secmsk |= sp->ol_bit;
   1458      0    stevel 							auth = *(s + 3);
   1459      0    stevel 							auth *= 256;
   1460      0    stevel 							auth += *(s + 4);
   1461      0    stevel 							break;
   1462      0    stevel 						}
   1463      0    stevel 						if (sec < sp->ol_val)
   1464      0    stevel 							j -= m;
   1465      0    stevel 						else
   1466      0    stevel 							j += m;
   1467      0    stevel 						m--;
   1468      0    stevel 					}
   1469      0    stevel 				}
   1470      0    stevel 				break;
   1471      0    stevel 			}
   1472      0    stevel 			if (opt < op->ol_val)
   1473      0    stevel 				i -= mv;
   1474      0    stevel 			else
   1475      0    stevel 				i += mv;
   1476      0    stevel 			mv--;
   1477      0    stevel 		}
   1478      0    stevel 		hlen -= ol;
   1479      0    stevel 		s += ol;
   1480      0    stevel 	}
   1481      0    stevel 
   1482      0    stevel 	/*
   1483   2393  yz155240 	 *
   1484      0    stevel 	 */
   1485      0    stevel 	if (auth && !(auth & 0x0100))
   1486      0    stevel 		auth &= 0xff00;
   1487      0    stevel 	fi->fi_optmsk = optmsk;
   1488      0    stevel 	fi->fi_secmsk = secmsk;
   1489      0    stevel 	fi->fi_auth = auth;
   1490      0    stevel }
   1491      0    stevel 
   1492      0    stevel 
   1493      0    stevel /* ------------------------------------------------------------------------ */
   1494      0    stevel /* Function:    fr_makefrip                                                 */
   1495    674  yz155240 /* Returns:     int - 1 == hdr checking error, 0 == OK                      */
   1496      0    stevel /* Parameters:  hlen(I) - length of IP packet header                        */
   1497      0    stevel /*              ip(I)   - pointer to the IP header                          */
   1498   2393  yz155240 /*              fin(IO) - pointer to packet information                     */
   1499      0    stevel /*                                                                          */
   1500      0    stevel /* Compact the IP header into a structure which contains just the info.     */
   1501      0    stevel /* which is useful for comparing IP headers with and store this information */
   1502      0    stevel /* in the fr_info_t structure pointer to by fin.  At present, it is assumed */
   1503      0    stevel /* this function will be called with either an IPv4 or IPv6 packet.         */
   1504      0    stevel /* ------------------------------------------------------------------------ */
   1505      0    stevel int	fr_makefrip(hlen, ip, fin)
   1506      0    stevel int hlen;
   1507      0    stevel ip_t *ip;
   1508      0    stevel fr_info_t *fin;
   1509      0    stevel {
   1510      0    stevel 	int v;
   1511      0    stevel 
   1512      0    stevel 	fin->fin_depth = 0;
   1513      0    stevel 	fin->fin_hlen = (u_short)hlen;
   1514      0    stevel 	fin->fin_ip = ip;
   1515      0    stevel 	fin->fin_rule = 0xffffffff;
   1516      0    stevel 	fin->fin_group[0] = -1;
   1517      0    stevel 	fin->fin_group[1] = '\0';
   1518      0    stevel 	fin->fin_dlen = fin->fin_plen - hlen;
   1519      0    stevel 	fin->fin_dp = (char *)ip + hlen;
   1520      0    stevel 
   1521      0    stevel 	v = fin->fin_v;
   1522      0    stevel 	if (v == 4)
   1523      0    stevel 		frpr_ipv4hdr(fin);
   1524      0    stevel #ifdef	USE_INET6
   1525   8624    Darren 	else if (v == 6)
   1526   8624    Darren 		frpr_ipv6hdr(fin);
   1527      0    stevel #endif
   1528      0    stevel 	if (fin->fin_ip == NULL)
   1529      0    stevel 		return -1;
   1530      0    stevel 	return 0;
   1531      0    stevel }
   1532      0    stevel 
   1533      0    stevel 
   1534      0    stevel /* ------------------------------------------------------------------------ */
   1535      0    stevel /* Function:    fr_portcheck                                                */
   1536      0    stevel /* Returns:     int - 1 == port matched, 0 == port match failed             */
   1537      0    stevel /* Parameters:  frp(I) - pointer to port check `expression'                 */
   1538      0    stevel /*              pop(I) - pointer to port number to evaluate                 */
   1539      0    stevel /*                                                                          */
   1540      0    stevel /* Perform a comparison of a port number against some other(s), using a     */
   1541      0    stevel /* structure with compare information stored in it.                         */
   1542      0    stevel /* ------------------------------------------------------------------------ */
   1543      0    stevel static INLINE int fr_portcheck(frp, pop)
   1544      0    stevel frpcmp_t *frp;
   1545      0    stevel u_short *pop;
   1546      0    stevel {
   1547      0    stevel 	u_short tup, po;
   1548      0    stevel 	int err = 1;
   1549      0    stevel 
   1550      0    stevel 	tup = *pop;
   1551      0    stevel 	po = frp->frp_port;
   1552      0    stevel 
   1553      0    stevel 	/*
   1554      0    stevel 	 * Do opposite test to that required and continue if that succeeds.
   1555      0    stevel 	 */
   1556      0    stevel 	switch (frp->frp_cmp)
   1557      0    stevel 	{
   1558      0    stevel 	case FR_EQUAL :
   1559      0    stevel 		if (tup != po) /* EQUAL */
   1560      0    stevel 			err = 0;
   1561      0    stevel 		break;
   1562      0    stevel 	case FR_NEQUAL :
   1563      0    stevel 		if (tup == po) /* NOTEQUAL */
   1564      0    stevel 			err = 0;
   1565      0    stevel 		break;
   1566      0    stevel 	case FR_LESST :
   1567      0    stevel 		if (tup >= po) /* LESSTHAN */
   1568      0    stevel 			err = 0;
   1569      0    stevel 		break;
   1570      0    stevel 	case FR_GREATERT :
   1571      0    stevel 		if (tup <= po) /* GREATERTHAN */
   1572      0    stevel 			err = 0;
   1573      0    stevel 		break;
   1574      0    stevel 	case FR_LESSTE :
   1575      0    stevel 		if (tup > po) /* LT or EQ */
   1576      0    stevel 			err = 0;
   1577      0    stevel 		break;
   1578      0    stevel 	case FR_GREATERTE :
   1579      0    stevel 		if (tup < po) /* GT or EQ */
   1580      0    stevel 			err = 0;
   1581      0    stevel 		break;
   1582      0    stevel 	case FR_OUTRANGE :
   1583      0    stevel 		if (tup >= po && tup <= frp->frp_top) /* Out of range */
   1584      0    stevel 			err = 0;
   1585      0    stevel 		break;
   1586      0    stevel 	case FR_INRANGE :
   1587      0    stevel 		if (tup <= po || tup >= frp->frp_top) /* In range */
   1588      0    stevel 			err = 0;
   1589      0    stevel 		break;
   1590      0    stevel 	case FR_INCRANGE :
   1591      0    stevel 		if (tup < po || tup > frp->frp_top) /* Inclusive range */
   1592      0    stevel 			err = 0;
   1593      0    stevel 		break;
   1594      0    stevel 	default :
   1595      0    stevel 		break;
   1596      0    stevel 	}
   1597      0    stevel 	return err;
   1598      0    stevel }
   1599      0    stevel 
   1600      0    stevel 
   1601      0    stevel /* ------------------------------------------------------------------------ */
   1602      0    stevel /* Function:    fr_tcpudpchk                                                */
   1603      0    stevel /* Returns:     int - 1 == protocol matched, 0 == check failed              */
   1604      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
   1605      0    stevel /*              ft(I)  - pointer to structure with comparison data          */
   1606      0    stevel /*                                                                          */
   1607      0    stevel /* Compares the current pcket (assuming it is TCP/UDP) information with a   */
   1608      0    stevel /* structure containing information that we want to match against.          */
   1609      0    stevel /* ------------------------------------------------------------------------ */
   1610      0    stevel int fr_tcpudpchk(fin, ft)
   1611      0    stevel fr_info_t *fin;
   1612      0    stevel frtuc_t *ft;
   1613      0    stevel {
   1614      0    stevel 	int err = 1;
   1615      0    stevel 
   1616      0    stevel 	/*
   1617      0    stevel 	 * Both ports should *always* be in the first fragment.
   1618      0    stevel 	 * So far, I cannot find any cases where they can not be.
   1619      0    stevel 	 *
   1620      0    stevel 	 * compare destination ports
   1621      0    stevel 	 */
   1622      0    stevel 	if (ft->ftu_dcmp)
   1623      0    stevel 		err = fr_portcheck(&ft->ftu_dst, &fin->fin_dport);
   1624      0    stevel 
   1625      0    stevel 	/*
   1626      0    stevel 	 * compare source ports
   1627      0    stevel 	 */
   1628      0    stevel 	if (err && ft->ftu_scmp)
   1629      0    stevel 		err = fr_portcheck(&ft->ftu_src, &fin->fin_sport);
   1630      0    stevel 
   1631      0    stevel 	/*
   1632      0    stevel 	 * If we don't have all the TCP/UDP header, then how can we
   1633      0    stevel 	 * expect to do any sort of match on it ?  If we were looking for
   1634      0    stevel 	 * TCP flags, then NO match.  If not, then match (which should
   1635      0    stevel 	 * satisfy the "short" class too).
   1636      0    stevel 	 */
   1637      0    stevel 	if (err && (fin->fin_p == IPPROTO_TCP)) {
   1638      0    stevel 		if (fin->fin_flx & FI_SHORT)
   1639      0    stevel 			return !(ft->ftu_tcpf | ft->ftu_tcpfm);
   1640      0    stevel 		/*
   1641      0    stevel 		 * Match the flags ?  If not, abort this match.
   1642      0    stevel 		 */
   1643      0    stevel 		if (ft->ftu_tcpfm &&
   1644      0    stevel 		    ft->ftu_tcpf != (fin->fin_tcpf & ft->ftu_tcpfm)) {
   1645      0    stevel 			FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf,
   1646      0    stevel 				 ft->ftu_tcpfm, ft->ftu_tcpf));
   1647      0    stevel 			err = 0;
   1648      0    stevel 		}
   1649      0    stevel 	}
   1650      0    stevel 	return err;
   1651      0    stevel }
   1652      0    stevel 
   1653      0    stevel 
   1654      0    stevel /* ------------------------------------------------------------------------ */
   1655      0    stevel /* Function:    fr_ipfcheck                                                 */
   1656      0    stevel /* Returns:     int - 0 == match, 1 == no match                             */
   1657      0    stevel /* Parameters:  fin(I)     - pointer to packet information                  */
   1658      0    stevel /*              fr(I)      - pointer to filter rule                         */
   1659      0    stevel /*              portcmp(I) - flag indicating whether to attempt matching on */
   1660      0    stevel /*                           TCP/UDP port data.                             */
   1661      0    stevel /*                                                                          */
   1662      0    stevel /* Check to see if a packet matches an IPFilter rule.  Checks of addresses, */
   1663      0    stevel /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */
   1664      0    stevel /* this function.                                                           */
   1665      0    stevel /* ------------------------------------------------------------------------ */
   1666      0    stevel static INLINE int fr_ipfcheck(fin, fr, portcmp)
   1667      0    stevel fr_info_t *fin;
   1668      0    stevel frentry_t *fr;
   1669      0    stevel int portcmp;
   1670      0    stevel {
   1671      0    stevel 	u_32_t	*ld, *lm, *lip;
   1672      0    stevel 	fripf_t *fri;
   1673      0    stevel 	fr_ip_t *fi;
   1674      0    stevel 	int i;
   1675   3448  dh155122 	ipf_stack_t *ifs = fin->fin_ifs;
   1676      0    stevel 
   1677      0    stevel 	fi = &fin->fin_fi;
   1678      0    stevel 	fri = fr->fr_ipf;
   1679      0    stevel 	lip = (u_32_t *)fi;
   1680      0    stevel 	lm = (u_32_t *)&fri->fri_mip;
   1681      0    stevel 	ld = (u_32_t *)&fri->fri_ip;
   1682      0    stevel 
   1683      0    stevel 	/*
   1684      0    stevel 	 * first 32 bits to check coversion:
   1685      0    stevel 	 * IP version, TOS, TTL, protocol
   1686      0    stevel 	 */
   1687      0    stevel 	i = ((*lip & *lm) != *ld);
   1688      0    stevel 	FR_DEBUG(("0. %#08x & %#08x != %#08x\n",
   1689      0    stevel 		   *lip, *lm, *ld));
   1690      0    stevel 	if (i)
   1691      0    stevel 		return 1;
   1692      0    stevel 
   1693      0    stevel 	/*
   1694      0    stevel 	 * Next 32 bits is a constructed bitmask indicating which IP options
   1695      0    stevel 	 * are present (if any) in this packet.
   1696      0    stevel 	 */
   1697      0    stevel 	lip++, lm++, ld++;
   1698      0    stevel 	i |= ((*lip & *lm) != *ld);
   1699      0    stevel 	FR_DEBUG(("1. %#08x & %#08x != %#08x\n",
   1700      0    stevel 		   *lip, *lm, *ld));
   1701      0    stevel 	if (i)
   1702      0    stevel 		return 1;
   1703      0    stevel 
   1704      0    stevel 	lip++, lm++, ld++;
   1705      0    stevel 	/*
   1706      0    stevel 	 * Unrolled loops (4 each, for 32 bits) for address checks.
   1707      0    stevel 	 */
   1708      0    stevel 	/*
   1709      0    stevel 	 * Check the source address.
   1710      0    stevel 	 */
   1711      0    stevel #ifdef	IPFILTER_LOOKUP
   1712      0    stevel 	if (fr->fr_satype == FRI_LOOKUP) {
   1713   3448  dh155122 		i = (*fr->fr_srcfunc)(fr->fr_srcptr, fi->fi_v, lip, ifs);
   1714      0    stevel 		if (i == -1)
   1715      0    stevel 			return 1;
   1716      0    stevel 		lip += 3;
   1717      0    stevel 		lm += 3;
   1718      0    stevel 		ld += 3;
   1719      0    stevel 	} else {
   1720      0    stevel #endif
   1721      0    stevel 		i = ((*lip & *lm) != *ld);
   1722      0    stevel 		FR_DEBUG(("2a. %#08x & %#08x != %#08x\n",
   1723      0    stevel 			   *lip, *lm, *ld));
   1724      0    stevel 		if (fi->fi_v == 6) {
   1725      0    stevel 			lip++, lm++, ld++;
   1726      0    stevel 			i |= ((*lip & *lm) != *ld);
   1727      0    stevel 			FR_DEBUG(("2b. %#08x & %#08x != %#08x\n",
   1728      0    stevel 				   *lip, *lm, *ld));
   1729      0    stevel 			lip++, lm++, ld++;
   1730      0    stevel 			i |= ((*lip & *lm) != *ld);
   1731      0    stevel 			FR_DEBUG(("2c. %#08x & %#08x != %#08x\n",
   1732      0    stevel 				   *lip, *lm, *ld));
   1733      0    stevel 			lip++, lm++, ld++;
   1734      0    stevel 			i |= ((*lip & *lm) != *ld);
   1735      0    stevel 			FR_DEBUG(("2d. %#08x & %#08x != %#08x\n",
   1736      0    stevel 				   *lip, *lm, *ld));
   1737      0    stevel 		} else {
   1738      0    stevel 			lip += 3;
   1739      0    stevel 			lm += 3;
   1740      0    stevel 			ld += 3;
   1741      0    stevel 		}
   1742      0    stevel #ifdef	IPFILTER_LOOKUP
   1743      0    stevel 	}
   1744      0    stevel #endif
   1745      0    stevel 	i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6;
   1746      0    stevel 	if (i)
   1747      0    stevel 		return 1;
   1748      0    stevel 
   1749      0    stevel 	/*
   1750      0    stevel 	 * Check the destination address.
   1751      0    stevel 	 */
   1752      0    stevel 	lip++, lm++, ld++;
   1753      0    stevel #ifdef	IPFILTER_LOOKUP
   1754      0    stevel 	if (fr->fr_datype == FRI_LOOKUP) {
   1755   3448  dh155122 		i = (*fr->fr_dstfunc)(fr->fr_dstptr, fi->fi_v, lip, ifs);
   1756      0    stevel 		if (i == -1)
   1757      0    stevel 			return 1;
   1758      0    stevel 		lip += 3;
   1759      0    stevel 		lm += 3;
   1760      0    stevel 		ld += 3;
   1761      0    stevel 	} else {
   1762      0    stevel #endif
   1763      0    stevel 		i = ((*lip & *lm) != *ld);
   1764      0    stevel 		FR_DEBUG(("3a. %#08x & %#08x != %#08x\n",
   1765      0    stevel 			   *lip, *lm, *ld));
   1766      0    stevel 		if (fi->fi_v == 6) {
   1767      0    stevel 			lip++, lm++, ld++;
   1768      0    stevel 			i |= ((*lip & *lm) != *ld);
   1769      0    stevel 			FR_DEBUG(("3b. %#08x & %#08x != %#08x\n",
   1770      0    stevel 				   *lip, *lm, *ld));
   1771      0    stevel 			lip++, lm++, ld++;
   1772      0    stevel 			i |= ((*lip & *lm) != *ld);
   1773      0    stevel 			FR_DEBUG(("3c. %#08x & %#08x != %#08x\n",
   1774      0    stevel 				   *lip, *lm, *ld));
   1775      0    stevel 			lip++, lm++, ld++;
   1776      0    stevel 			i |= ((*lip & *lm) != *ld);
   1777      0    stevel 			FR_DEBUG(("3d. %#08x & %#08x != %#08x\n",
   1778      0    stevel 				   *lip, *lm, *ld));
   1779      0    stevel 		} else {
   1780      0    stevel 			lip += 3;
   1781      0    stevel 			lm += 3;
   1782      0    stevel 			ld += 3;
   1783      0    stevel 		}
   1784      0    stevel #ifdef	IPFILTER_LOOKUP
   1785      0    stevel 	}
   1786      0    stevel #endif
   1787      0    stevel 	i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7;
   1788      0    stevel 	if (i)
   1789      0    stevel 		return 1;
   1790      0    stevel 	/*
   1791      0    stevel 	 * IP addresses matched.  The next 32bits contains:
   1792      0    stevel 	 * mast of old IP header security & authentication bits.
   1793      0    stevel 	 */
   1794      0    stevel 	lip++, lm++, ld++;
   1795      0    stevel 	i |= ((*lip & *lm) != *ld);
   1796      0    stevel 	FR_DEBUG(("4. %#08x & %#08x != %#08x\n",
   1797      0    stevel 		   *lip, *lm, *ld));
   1798      0    stevel 
   1799      0    stevel 	/*
   1800      0    stevel 	 * Next we have 32 bits of packet flags.
   1801      0    stevel 	 */
   1802      0    stevel 	lip++, lm++, ld++;
   1803      0    stevel 	i |= ((*lip & *lm) != *ld);
   1804      0    stevel 	FR_DEBUG(("5. %#08x & %#08x != %#08x\n",
   1805      0    stevel 		   *lip, *lm, *ld));
   1806      0    stevel 
   1807      0    stevel 	if (i == 0) {
   1808      0    stevel 		/*
   1809      0    stevel 		 * If a fragment, then only the first has what we're
   1810      0    stevel 		 * looking for here...
   1811      0    stevel 		 */
   1812      0    stevel 		if (portcmp) {
   1813      0    stevel 			if (!fr_tcpudpchk(fin, &fr->fr_tuc))
   1814      0    stevel 				i = 1;
   1815      0    stevel 		} else {
   1816      0    stevel 			if (fr->fr_dcmp || fr->fr_scmp ||
   1817      0    stevel 			    fr->fr_tcpf || fr->fr_tcpfm)
   1818      0    stevel 				i = 1;
   1819      0    stevel 			if (fr->fr_icmpm || fr->fr_icmp) {
   1820      0    stevel 				if (((fi->fi_p != IPPROTO_ICMP) &&
   1821      0    stevel 				     (fi->fi_p != IPPROTO_ICMPV6)) ||
   1822      0    stevel 				    fin->fin_off || (fin->fin_dlen < 2))
   1823      0    stevel 					i = 1;
   1824      0    stevel 				else if ((fin->fin_data[0] & fr->fr_icmpm) !=
   1825      0    stevel 					 fr->fr_icmp) {
   1826      0    stevel 					FR_DEBUG(("i. %#x & %#x != %#x\n",
   1827      0    stevel 						 fin->fin_data[0],
   1828      0    stevel 						 fr->fr_icmpm, fr->fr_icmp));
   1829      0    stevel 					i = 1;
   1830      0    stevel 				}
   1831      0    stevel 			}
   1832      0    stevel 		}
   1833      0    stevel 	}
   1834      0    stevel 	return i;
   1835      0    stevel }
   1836      0    stevel 
   1837      0    stevel 
   1838      0    stevel /* ------------------------------------------------------------------------ */
   1839      0    stevel /* Function:    fr_scanlist                                                 */
   1840      0    stevel /* Returns:     int - result flags of scanning filter list                  */
   1841      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
   1842      0    stevel /*              pass(I) - default result to return for filtering            */
   1843      0    stevel /*                                                                          */
   1844      0    stevel /* Check the input/output list of rules for a match to the current packet.  */
   1845      0    stevel /* If a match is found, the value of fr_flags from the rule becomes the     */
   1846      0    stevel /* return value and fin->fin_fr points to the matched rule.                 */
   1847      0    stevel /*                                                                          */
   1848      0    stevel /* This function may be called recusively upto 16 times (limit inbuilt.)    */
   1849      0    stevel /* When unwinding, it should finish up with fin_depth as 0.                 */
   1850      0    stevel /*                                                                          */
   1851      0    stevel /* Could be per interface, but this gets real nasty when you don't have,    */
   1852      0    stevel /* or can't easily change, the kernel source code to .                      */
   1853      0    stevel /* ------------------------------------------------------------------------ */
   1854      0    stevel int fr_scanlist(fin, pass)
   1855      0    stevel fr_info_t *fin;
   1856      0    stevel u_32_t pass;
   1857      0    stevel {
   1858      0    stevel 	int rulen, portcmp, off, logged, skip;
   1859      0    stevel 	struct frentry *fr, *fnext;
   1860   2393  yz155240 	u_32_t passt, passo;
   1861   3448  dh155122 	ipf_stack_t *ifs = fin->fin_ifs;
   1862      0    stevel 
   1863      0    stevel 	/*
   1864      0    stevel 	 * Do not allow nesting deeper than 16 levels.
   1865      0    stevel 	 */
   1866      0    stevel 	if (fin->fin_depth >= 16)
   1867      0    stevel 		return pass;
   1868      0    stevel 
   1869      0    stevel 	fr = fin->fin_fr;
   1870      0    stevel 
   1871      0    stevel 	/*
   1872      0    stevel 	 * If there are no rules in this list, return now.
   1873      0    stevel 	 */
   1874      0    stevel 	if (fr == NULL)
   1875      0    stevel 		return pass;
   1876      0    stevel 
   1877      0    stevel 	skip = 0;
   1878      0    stevel 	logged = 0;
   1879      0    stevel 	portcmp = 0;
   1880      0    stevel 	fin->fin_depth++;
   1881      0    stevel 	fin->fin_fr = NULL;
   1882      0    stevel 	off = fin->fin_off;
   1883      0    stevel 
   1884      0    stevel 	if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off)
   1885      0    stevel 		portcmp = 1;
   1886      0    stevel 
   1887      0    stevel 	for (rulen = 0; fr; fr = fnext, rulen++) {
   1888      0    stevel 		fnext = fr->fr_next;
   1889      0    stevel 		if (skip != 0) {
   1890      0    stevel 			FR_VERBOSE(("%d (%#x)\n", skip, fr->fr_flags));
   1891      0    stevel 			skip--;
   1892      0    stevel 			continue;
   1893      0    stevel 		}
   1894      0    stevel 
   1895      0    stevel 		/*
   1896      0    stevel 		 * In all checks below, a null (zero) value in the
   1897      0    stevel 		 * filter struture is taken to mean a wildcard.
   1898      0    stevel 		 *
   1899      0    stevel 		 * check that we are working for the right interface
   1900      0    stevel 		 */
   1901      0    stevel #ifdef	_KERNEL
   1902      0    stevel 		if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
   1903      0    stevel 			continue;
   1904      0    stevel #else
   1905      0    stevel 		if (opts & (OPT_VERBOSE|OPT_DEBUG))
   1906      0    stevel 			printf("\n");
   1907      0    stevel 		FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' :
   1908   2393  yz155240 				  FR_ISPASS(pass) ? 'p' :
   1909      0    stevel 				  FR_ISACCOUNT(pass) ? 'A' :
   1910      0    stevel 				  FR_ISAUTH(pass) ? 'a' :
   1911      0    stevel 				  (pass & FR_NOMATCH) ? 'n' :'b'));
   1912      0    stevel 		if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
   1913      0    stevel 			continue;
   1914      0    stevel 		FR_VERBOSE((":i"));
   1915      0    stevel #endif
   1916      0    stevel 
   1917      0    stevel 		switch (fr->fr_type)
   1918      0    stevel 		{
   1919      0    stevel 		case FR_T_IPF :
   1920      0    stevel 		case FR_T_IPF|FR_T_BUILTIN :
   1921      0    stevel 			if (fr_ipfcheck(fin, fr, portcmp))
   1922      0    stevel 				continue;
   1923      0    stevel 			break;
   1924   2393  yz155240 #if defined(IPFILTER_BPF)
   1925      0    stevel 		case FR_T_BPFOPC :
   1926      0    stevel 		case FR_T_BPFOPC|FR_T_BUILTIN :
   1927      0    stevel 		    {
   1928      0    stevel 			u_char *mc;
   1929      0    stevel 
   1930      0    stevel 			if (*fin->fin_mp == NULL)
   1931      0    stevel 				continue;
   1932      0    stevel 			if (fin->fin_v != fr->fr_v)
   1933      0    stevel 				continue;
   1934      0    stevel 			mc = (u_char *)fin->fin_m;
   1935   2393  yz155240 			if (!bpf_filter(fr->fr_data, mc, fin->fin_plen, 0))
   1936      0    stevel 				continue;
   1937      0    stevel 			break;
   1938      0    stevel 		    }
   1939      0    stevel #endif
   1940      0    stevel 		case FR_T_CALLFUNC|FR_T_BUILTIN :
   1941      0    stevel 		    {
   1942      0    stevel 			frentry_t *f;
   1943      0    stevel 
   1944      0    stevel 			f = (*fr->fr_func)(fin, &pass);
   1945      0    stevel 			if (f != NULL)
   1946      0    stevel 				fr = f;
   1947      0    stevel 			else
   1948      0    stevel 				continue;
   1949      0    stevel 			break;
   1950      0    stevel 		    }
   1951      0    stevel 		default :
   1952      0    stevel 			break;
   1953      0    stevel 		}
   1954      0    stevel 
   1955      0    stevel 		if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) {
   1956      0    stevel 			if (fin->fin_nattag == NULL)
   1957      0    stevel 				continue;
   1958      0    stevel 			if (fr_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0)
   1959      0    stevel 				continue;
   1960      0    stevel 		}
   1961      0    stevel 		FR_VERBOSE(("=%s.%d *", fr->fr_group, rulen));
   1962      0    stevel 
   1963      0    stevel 		passt = fr->fr_flags;
   1964      0    stevel 
   1965      0    stevel 		/*
   1966   2393  yz155240 		 * Allowing a rule with the "keep state" flag set to match
   1967   2393  yz155240 		 * packets that have been tagged "out of window" by the TCP
   1968   2393  yz155240 		 * state tracking is foolish as the attempt to add a new
   1969   2393  yz155240 		 * state entry to the table will fail.
   1970   2393  yz155240 		 */
   1971   2393  yz155240 		if ((passt & FR_KEEPSTATE) && (fin->fin_flx & FI_OOW))
   1972   2393  yz155240 			continue;
   1973   2393  yz155240 
   1974   2393  yz155240 		/*
   1975      0    stevel 		 * If the rule is a "call now" rule, then call the function
   1976      0    stevel 		 * in the rule, if it exists and use the results from that.
   1977      0    stevel 		 * If the function pointer is bad, just make like we ignore
   1978      0    stevel 		 * it, except for increasing the hit counter.
   1979      0    stevel 		 */
   1980      0    stevel 		if ((passt & FR_CALLNOW) != 0) {
   1981   7131  dr146992 			IPF_BUMP(fr->fr_hits);
   1982      0    stevel 			if ((fr->fr_func != NULL) &&
   1983      0    stevel 			    (fr->fr_func != (ipfunc_t)-1)) {
   1984      0    stevel 				frentry_t *frs;
   1985      0    stevel 
   1986      0    stevel 				frs = fin->fin_fr;
   1987      0    stevel 				fin->fin_fr = fr;
   1988      0    stevel 				fr = (*fr->fr_func)(fin, &passt);
   1989      0    stevel 				if (fr == NULL) {
   1990      0    stevel 					fin->fin_fr = frs;
   1991      0    stevel 					continue;
   1992      0    stevel 				}
   1993      0    stevel 				passt = fr->fr_flags;
   1994      0    stevel 				fin->fin_fr = fr;
   1995      0    stevel 			}
   1996      0    stevel 		} else {
   1997      0    stevel 			fin->fin_fr = fr;
   1998      0    stevel 		}
   1999      0    stevel 
   2000      0    stevel #ifdef  IPFILTER_LOG
   2001      0    stevel 		/*
   2002      0    stevel 		 * Just log this packet...
   2003      0    stevel 		 */
   2004      0    stevel 		if ((passt & FR_LOGMASK) == FR_LOG) {
   2005      0    stevel 			if (ipflog(fin, passt) == -1) {
   2006      0    stevel 				if (passt & FR_LOGORBLOCK) {
   2007      0    stevel 					passt &= ~FR_CMDMASK;
   2008      0    stevel 					passt |= FR_BLOCK|FR_QUICK;
   2009      0    stevel 				}
   2010   7131  dr146992 				IPF_BUMP(ifs->ifs_frstats[fin->fin_out].fr_skip);
   2011   7131  dr146992 			}
   2012   7131  dr146992 			IPF_BUMP(ifs->ifs_frstats[fin->fin_out].fr_pkl);
   2013      0    stevel 			logged = 1;
   2014      0    stevel 		}
   2015      0    stevel #endif /* IPFILTER_LOG */
   2016      0    stevel 		fr->fr_bytes += (U_QUAD_T)fin->fin_plen;
   2017   2393  yz155240 		passo = pass;
   2018      0    stevel 		if (FR_ISSKIP(passt))
   2019      0    stevel 			skip = fr->fr_arg;
   2020      0    stevel 		else if ((passt & FR_LOGMASK) != FR_LOG)
   2021      0    stevel 			pass = passt;
   2022      0    stevel 		if (passt & (FR_RETICMP|FR_FAKEICMP))
   2023      0    stevel 			fin->fin_icode = fr->fr_icode;
   2024      0    stevel 		FR_DEBUG(("pass %#x\n", pass));
   2025   7131  dr146992 		IPF_BUMP(fr->fr_hits);
   2026      0    stevel 		fin->fin_rule = rulen;
   2027      0    stevel 		(void) strncpy(fin->fin_group, fr->fr_group, FR_GROUPLEN);
   2028      0    stevel 		if (fr->fr_grp != NULL) {
   2029      0    stevel 			fin->fin_fr = *fr->fr_grp;
   2030      0    stevel 			pass = fr_scanlist(fin, pass);
   2031      0    stevel 			if (fin->fin_fr == NULL) {
   2032      0    stevel 				fin->fin_rule = rulen;
   2033      0    stevel 				(void) strncpy(fin->fin_group, fr->fr_group,
   2034      0    stevel 					       FR_GROUPLEN);
   2035      0    stevel 				fin->fin_fr = fr;
   2036      0    stevel 			}
   2037      0    stevel 			if (fin->fin_flx & FI_DONTCACHE)
   2038      0    stevel 				logged = 1;
   2039      0    stevel 		}
   2040   2393  yz155240 
   2041   2393  yz155240 		if (pass & FR_QUICK) {
   2042   2393  yz155240 			/*
   2043   2393  yz155240 			 * Finally, if we've asked to track state for this
   2044   2393  yz155240 			 * packet, set it up.  Add state for "quick" rules
   2045   2393  yz155240 			 * here so that if the action fails we can consider
   2046   2393  yz155240 			 * the rule to "not match" and keep on processing
   2047   2393  yz155240 			 * filter rules.
   2048   2393  yz155240 			 */
   2049   2393  yz155240 			if ((pass & FR_KEEPSTATE) &&
   2050   2393  yz155240 			    !(fin->fin_flx & FI_STATE)) {
   2051   2393  yz155240 				int out = fin->fin_out;
   2052   2393  yz155240 
   2053   2393  yz155240 				if (fr_addstate(fin, NULL, 0) != NULL) {
   2054   7131  dr146992 					IPF_BUMP(ifs->ifs_frstats[out].fr_ads);
   2055   2393  yz155240 				} else {
   2056   7131  dr146992 					IPF_BUMP(ifs->ifs_frstats[out].fr_bads);
   2057   2393  yz155240 					pass = passo;
   2058   2393  yz155240 					continue;
   2059   2393  yz155240 				}
   2060   2393  yz155240 			}
   2061   2393  yz155240 			break;
   2062   2393  yz155240 		}
   2063      0    stevel 	}
   2064      0    stevel 	if (logged)
   2065      0    stevel 		fin->fin_flx |= FI_DONTCACHE;
   2066      0    stevel 	fin->fin_depth--;
   2067      0    stevel 	return pass;
   2068      0    stevel }
   2069      0    stevel 
   2070      0    stevel 
   2071      0    stevel /* ------------------------------------------------------------------------ */
   2072      0    stevel /* Function:    fr_acctpkt                                                  */
   2073      0    stevel /* Returns:     frentry_t* - always returns NULL                            */
   2074      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
   2075      0    stevel /*              passp(IO) - pointer to current/new filter decision (unused) */
   2076      0    stevel /*                                                                          */
   2077      0    stevel /* Checks a packet against accounting rules, if there are any for the given */
   2078      0    stevel /* IP protocol version.                                                     */
   2079      0    stevel /*                                                                          */
   2080      0    stevel /* N.B.: this function returns NULL to match the prototype used by other    */
   2081      0    stevel /* functions called from the IPFilter "mainline" in fr_check().             */
   2082      0    stevel /* ------------------------------------------------------------------------ */
   2083      0    stevel frentry_t *fr_acctpkt(fin, passp)
   2084      0    stevel fr_info_t *fin;
   2085      0    stevel u_32_t *passp;
   2086      0    stevel {
   2087      0    stevel 	char group[FR_GROUPLEN];
   2088      0    stevel 	frentry_t *fr, *frsave;
   2089      0    stevel 	u_32_t pass, rulen;
   2090   3448  dh155122 	ipf_stack_t *ifs = fin->fin_ifs;
   2091      0    stevel 
   2092      0    stevel 	passp = passp;
   2093      0    stevel #ifdef	USE_INET6
   2094      0    stevel 	if (fin->fin_v == 6)
   2095   3448  dh155122 		fr = ifs->ifs_ipacct6[fin->fin_out][ifs->ifs_fr_active];
   2096      0    stevel 	else
   2097      0    stevel #endif
   2098   3448  dh155122 		fr = ifs->ifs_ipacct[fin->fin_out][ifs->ifs_fr_active];
   2099      0    stevel 
   2100      0    stevel 	if (fr != NULL) {
   2101      0    stevel 		frsave = fin->fin_fr;
   2102      0    stevel 		bcopy(fin->fin_group, group, FR_GROUPLEN);
   2103      0    stevel 		rulen = fin->fin_rule;
   2104      0    stevel 		fin->fin_fr = fr;
   2105      0    stevel 		pass = fr_scanlist(fin, FR_NOMATCH);
   2106      0    stevel 		if (FR_ISACCOUNT(pass)) {
   2107   7131  dr146992 			IPF_BUMP(ifs->ifs_frstats[0].fr_acct);
   2108      0    stevel 		}
   2109      0    stevel 		fin->fin_fr = frsave;
   2110      0    stevel 		bcopy(group, fin->fin_group, FR_GROUPLEN);
   2111      0    stevel 		fin->fin_rule = rulen;
   2112      0    stevel 	}
   2113      0    stevel 	return NULL;
   2114      0    stevel }
   2115      0    stevel 
   2116      0    stevel 
   2117      0    stevel /* ------------------------------------------------------------------------ */
   2118      0    stevel /* Function:    fr_firewall                                                 */
   2119      0    stevel /* Returns:     frentry_t* - returns pointer to matched rule, if no matches */
   2120      0    stevel /*                           were found, returns NULL.                      */
   2121      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
   2122      0    stevel /*              passp(IO) - pointer to current/new filter decision (unused) */
   2123      0    stevel /*                                                                          */
   2124      0    stevel /* Applies an appropriate set of firewall rules to the packet, to see if    */
   2125      0    stevel /* there are any matches.  The first check is to see if a match can be seen */
   2126      0    stevel /* in the cache.  If not, then search an appropriate list of rules.  Once a */
   2127      0    stevel /* matching rule is found, take any appropriate actions as defined by the   */
   2128      0    stevel /* rule - except logging.                                                   */
   2129      0    stevel /* ------------------------------------------------------------------------ */
   2130      0    stevel static frentry_t *fr_firewall(fin, passp)
   2131      0    stevel fr_info_t *fin;
   2132      0    stevel u_32_t *passp;
   2133      0    stevel {
   2134      0    stevel 	frentry_t *fr;
   2135  10587  Alexandr 	fr_info_t *fc;
   2136      0    stevel 	u_32_t pass;
   2137      0    stevel 	int out;
   2138   3448  dh155122 	ipf_stack_t *ifs = fin->fin_ifs;
   2139      0    stevel 
   2140      0    stevel 	out = fin->fin_out;
   2141      0    stevel 	pass = *passp;
   2142      0    stevel 
   2143   7131  dr146992 #ifdef	USE_INET6
   2144   7131  dr146992 	if (fin->fin_v == 6)
   2145   7131  dr146992 		fin->fin_fr = ifs->ifs_ipfilter6[out][ifs->ifs_fr_active];
   2146   7131  dr146992 	else
   2147   7131  dr146992 #endif
   2148   7131  dr146992 		fin->fin_fr = ifs->ifs_ipfilter[out][ifs->ifs_fr_active];
   2149  10587  Alexandr 
   2150  10587  Alexandr 	/*
   2151  10587  Alexandr 	 * If there are no rules loaded skip all checks and return.
   2152  10587  Alexandr 	 */
   2153  10587  Alexandr 	if (fin->fin_fr == NULL) {
   2154  10587  Alexandr 
   2155  10587  Alexandr 		if ((pass & FR_NOMATCH)) {
   2156  10587  Alexandr 			IPF_BUMP(ifs->ifs_frstats[out].fr_nom);
   2157  10587  Alexandr 		}
   2158  10587  Alexandr 
   2159  10587  Alexandr 		return (NULL);
   2160  10587  Alexandr 	}
   2161  10587  Alexandr 
   2162  10587  Alexandr 	fc = &ifs->ifs_frcache[out][CACHE_HASH(fin)];
   2163  10587  Alexandr 	READ_ENTER(&ifs->ifs_ipf_frcache);
   2164  10587  Alexandr 	if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) {
   2165  10587  Alexandr 		/*
   2166  10587  Alexandr 		 * copy cached data so we can unlock the mutexes earlier.
   2167  10587  Alexandr 		 */
   2168  10587  Alexandr 		bcopy((char *)fc, (char *)fin, FI_COPYSIZE);
   2169  10587  Alexandr 		RWLOCK_EXIT(&ifs->ifs_ipf_frcache);
   2170  10587  Alexandr 		IPF_BUMP(ifs->ifs_frstats[out].fr_chit);
   2171  10587  Alexandr 
   2172  10587  Alexandr 		if ((fr = fin->fin_fr) != NULL) {
   2173  10587  Alexandr 			IPF_BUMP(fr->fr_hits);
   2174  10587  Alexandr 			pass = fr->fr_flags;
   2175  10587  Alexandr 		}
   2176  10587  Alexandr 	} else {
   2177  10587  Alexandr 		RWLOCK_EXIT(&ifs->ifs_ipf_frcache);
   2178  10587  Alexandr 
   2179   7131  dr146992 		pass = fr_scanlist(fin, ifs->ifs_fr_pass);
   2180  10587  Alexandr 
   2181  10587  Alexandr 		if (((pass & FR_KEEPSTATE) == 0) &&
   2182  10587  Alexandr 		    ((fin->fin_flx & FI_DONTCACHE) == 0)) {
   2183  10587  Alexandr 			WRITE_ENTER(&ifs->ifs_ipf_frcache);
   2184  10587  Alexandr 			bcopy((char *)fin, (char *)fc, FI_COPYSIZE);
   2185  10587  Alexandr 			RWLOCK_EXIT(&ifs->ifs_ipf_frcache);
   2186  10587  Alexandr 		}
   2187  10587  Alexandr 
   2188  10587  Alexandr 		fr = fin->fin_fr;
   2189  10587  Alexandr 	}
   2190   7131  dr146992 
   2191   7131  dr146992 	if ((pass & FR_NOMATCH)) {
   2192   7131  dr146992 		IPF_BUMP(ifs->ifs_frstats[out].fr_nom);
   2193   7131  dr146992 	}
   2194      0    stevel 
   2195      0    stevel 	/*
   2196      0    stevel 	 * Apply packets per second rate-limiting to a rule as required.
   2197      0    stevel 	 */
   2198      0    stevel 	if ((fr != NULL) && (fr->fr_pps != 0) &&
   2199      0    stevel 	    !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) {
   2200      0    stevel 		pass &= ~(FR_CMDMASK|FR_DUP|FR_RETICMP|FR_RETRST);
   2201      0    stevel 		pass |= FR_BLOCK;
   2202   7131  dr146992 		IPF_BUMP(ifs->ifs_frstats[out].fr_ppshit);
   2203      0    stevel 	}
   2204      0    stevel 
   2205      0    stevel 	/*
   2206      0    stevel 	 * If we fail to add a packet to the authorization queue, then we
   2207      0    stevel 	 * drop the packet later.  However, if it was added then pretend
   2208      0    stevel 	 * we've dropped it already.
   2209      0    stevel 	 */
   2210      0    stevel 	if (FR_ISAUTH(pass)) {
   2211      0    stevel 		if (fr_newauth(fin->fin_m, fin) != 0) {
   2212      0    stevel #ifdef	_KERNEL
   2213      0    stevel 			fin->fin_m = *fin->fin_mp = NULL;
   2214      0    stevel #else
   2215      0    stevel 			;
   2216      0    stevel #endif
   2217      0    stevel 			fin->fin_error = 0;
   2218      0    stevel 		} else
   2219      0    stevel 			fin->fin_error = ENOSPC;
   2220      0    stevel 	}
   2221      0    stevel 
   2222      0    stevel 	if ((fr != NULL) && (fr->fr_func != NULL) &&
   2223      0    stevel 	    (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW))
   2224      0    stevel 		(void) (*fr->fr_func)(fin, &pass);
   2225      0    stevel 
   2226      0    stevel 	/*
   2227      0    stevel 	 * If a rule is a pre-auth rule, check again in the list of rules
   2228      0    stevel 	 * loaded for authenticated use.  It does not particulary matter
   2229      0    stevel 	 * if this search fails because a "preauth" result, from a rule,
   2230      0    stevel 	 * is treated as "not a pass", hence the packet is blocked.
   2231      0    stevel 	 */
   2232      0    stevel 	if (FR_ISPREAUTH(pass)) {
   2233   3448  dh155122 		if ((fin->fin_fr = ifs->ifs_ipauth) != NULL)
   2234   3448  dh155122 			pass = fr_scanlist(fin, ifs->ifs_fr_pass);
   2235      0    stevel 	}
   2236      0    stevel 
   2237      0    stevel 	/*
   2238      0    stevel 	 * If the rule has "keep frag" and the packet is actually a fragment,
   2239      0    stevel 	 * then create a fragment state entry.
   2240      0    stevel 	 */
   2241      0    stevel 	if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) {
   2242      0    stevel 		if (fin->fin_flx & FI_FRAG) {
   2243      0    stevel 			if (fr_newfrag(fin, pass) == -1) {
   2244   7131  dr146992 				IPF_BUMP(ifs->ifs_frstats[out].fr_bnfr);
   2245      0    stevel 			} else {
   2246   7131  dr146992 				IPF_BUMP(ifs->ifs_frstats[out].fr_nfr);
   2247   7131  dr146992 			}
   2248   7131  dr146992 		} else {
   2249   7131  dr146992 			IPF_BUMP(ifs->ifs_frstats[out].fr_cfr);
   2250      0    stevel 		}
   2251      0    stevel 	}
   2252      0    stevel 
   2253      0    stevel 	/*
   2254      0    stevel 	 * Finally, if we've asked to track state for this packet, set it up.
   2255      0    stevel 	 */
   2256   2393  yz155240 	if ((pass & FR_KEEPSTATE) && !(fin->fin_flx & FI_STATE)) {
   2257      0    stevel 		if (fr_addstate(fin, NULL, 0) != NULL) {
   2258   7131  dr146992 			IPF_BUMP(ifs->ifs_frstats[out].fr_ads);
   2259   7131  dr146992 		} else {
   2260   7131  dr146992 			IPF_BUMP(ifs->ifs_frstats[out].fr_bads);
   2261   2393  yz155240 			if (FR_ISPASS(pass)) {
   2262   2393  yz155240 				pass &= ~FR_CMDMASK;
   2263   2393  yz155240 				pass |= FR_BLOCK;
   2264   2393  yz155240 			}
   2265      0    stevel 		}
   2266      0    stevel 	}
   2267      0    stevel 
   2268      0    stevel 	fr = fin->fin_fr;
   2269      0    stevel 
   2270      0    stevel 	if (passp != NULL)
   2271      0    stevel 		*passp = pass;
   2272      0    stevel 
   2273      0    stevel 	return fr;
   2274      0    stevel }
   2275      0    stevel 
   2276      0    stevel /* ------------------------------------------------------------------------ */
   2277      0    stevel /* Function:    fr_check                                                    */
   2278      0    stevel /* Returns:     int -  0 == packet allowed through,                         */
   2279      0    stevel /*              User space:                                                 */
   2280      0    stevel /*                    -1 == packet blocked                                  */
   2281      0    stevel /*                     1 == packet not matched                              */
   2282   2393  yz155240 /*                    -2 == requires authentication                         */
   2283      0    stevel /*              Kernel:                                                     */
   2284      0    stevel /*                   > 0 == filter error # for packet                       */
   2285      0    stevel /* Parameters: ip(I)   - pointer to start of IPv4/6 packet                  */
   2286      0    stevel /*             hlen(I) - length of header                                   */
   2287      0    stevel /*             ifp(I)  - pointer to interface this packet is on             */
   2288      0    stevel /*             out(I)  - 0 == packet going in, 1 == packet going out        */
   2289      0    stevel /*             mp(IO)  - pointer to caller's buffer pointer that holds this */
   2290      0    stevel /*                       IP packet.                                         */
   2291      0    stevel /* Solaris & HP-UX ONLY :                                                   */
   2292   2393  yz155240 /*             qpi(I)  - pointer to STREAMS queue information for this      */
   2293      0    stevel /*                       interface & direction.                             */
   2294      0    stevel /*                                                                          */
   2295      0    stevel /* fr_check() is the master function for all IPFilter packet processing.    */
   2296      0    stevel /* It orchestrates: Network Address Translation (NAT), checking for packet  */
   2297      0    stevel /* authorisation (or pre-authorisation), presence of related state info.,   */
   2298      0    stevel /* generating log entries, IP packet accounting, routing of packets as      */
   2299      0    stevel /* directed by firewall rules and of course whether or not to allow the     */
   2300      0    stevel /* packet to be further processed by the kernel.                            */
   2301      0    stevel /*                                                                          */
   2302      0    stevel /* For packets blocked, the contents of "mp" will be NULL'd and the buffer  */
   2303      0    stevel /* freed.  Packets passed may be returned with the pointer pointed to by    */
   2304      0    stevel /* by "mp" changed to a new buffer.                                         */
   2305      0    stevel /* ------------------------------------------------------------------------ */
   2306      0    stevel int fr_check(ip, hlen, ifp, out
   2307      0    stevel #if defined(_KERNEL) && defined(MENTAT)
   2308   3448  dh155122 , qif, mp, ifs)
   2309   2393  yz155240 void *qif;
   2310      0    stevel #else
   2311   3448  dh155122 , mp, ifs)
   2312      0    stevel #endif
   2313      0    stevel mb_t **mp;
   2314      0    stevel ip_t *ip;
   2315      0    stevel int hlen;
   2316      0    stevel void *ifp;
   2317      0    stevel int out;
   2318   3448  dh155122 ipf_stack_t *ifs;
   2319      0    stevel {
   2320      0    stevel 	/*
   2321      0    stevel 	 * The above really sucks, but short of writing a diff
   2322      0    stevel 	 */
   2323      0    stevel 	fr_info_t frinfo;
   2324      0    stevel 	fr_info_t *fin = &frinfo;
   2325   3448  dh155122 	u_32_t pass;
   2326      0    stevel 	frentry_t *fr = NULL;
   2327   2393  yz155240 	int v = IP_V(ip);
   2328      0    stevel 	mb_t *mc = NULL;
   2329      0    stevel 	mb_t *m;
   2330    637   ml37995 #ifdef USE_INET6
   2331    637   ml37995 	ip6_t *ip6;
   2332    637   ml37995 #endif
   2333   2393  yz155240 #ifdef	_KERNEL
   2334   2393  yz155240 # ifdef MENTAT
   2335   2393  yz155240 	qpktinfo_t *qpi = qif;
   2336   2393  yz155240 #endif
   2337   2393  yz155240 #endif
   2338   3448  dh155122 
   2339   2393  yz155240 	SPL_INT(s);
   2340   3448  dh155122 	pass = ifs->ifs_fr_pass;
   2341      0    stevel 
   2342      0    stevel 	/*
   2343      0    stevel 	 * The first part of fr_check() deals with making sure that what goes
   2344      0    stevel 	 * into the filtering engine makes some sense.  Information about the
   2345      0    stevel 	 * the packet is distilled, collected into a fr_info_t structure and
   2346      0    stevel 	 * the an attempt to ensure the buffer the packet is in is big enough
   2347      0    stevel 	 * to hold all the required packet headers.
   2348      0    stevel 	 */
   2349      0    stevel #ifdef	_KERNEL
   2350      0    stevel # ifdef MENTAT
   2351   2393  yz155240 	if (!OK_32PTR(ip))
   2352      0    stevel 		return 2;
   2353      0    stevel # endif
   2354   2393  yz155240 
   2355   3448  dh155122 
   2356   3448  dh155122 	if (ifs->ifs_fr_running <= 0) {
   2357      0    stevel 		return 0;
   2358      0    stevel 	}
   2359      0    stevel 
   2360      0    stevel 	bzero((char *)fin, sizeof(*fin));
   2361      0    stevel 
   2362      0    stevel # ifdef MENTAT
   2363   5868  dr146992 	fin->fin_flx = qpi->qpi_flags & (FI_NOCKSUM|FI_MBCAST|FI_MULTICAST|
   2364   5868  dr146992 					 FI_BROADCAST);
   2365   2393  yz155240 	m = qpi->qpi_m;
   2366      0    stevel 	fin->fin_qfm = m;
   2367   2393  yz155240 	fin->fin_qpi = qpi;
   2368      0    stevel # else /* MENTAT */
   2369      0    stevel 
   2370      0    stevel 	m = *mp;
   2371   2393  yz155240 
   2372      0    stevel #  if defined(M_MCAST)
   2373      0    stevel 	if ((m->m_flags & M_MCAST) != 0)
   2374   2393  yz155240 		fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
   2375   2393  yz155240 #  endif
   2376   2393  yz155240 #  if defined(M_MLOOP)
   2377   2393  yz155240 	if ((m->m_flags & M_MLOOP) != 0)
   2378      0    stevel 		fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
   2379      0    stevel #  endif
   2380      0    stevel #  if defined(M_BCAST)
   2381      0    stevel 	if ((m->m_flags & M_BCAST) != 0)
   2382      0    stevel 		fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
   2383      0    stevel #  endif
   2384      0    stevel #  ifdef M_CANFASTFWD
   2385      0    stevel 	/*
   2386      0    stevel 	 * XXX For now, IP Filter and fast-forwarding of cached flows
   2387      0    stevel 	 * XXX are mutually exclusive.  Eventually, IP Filter should
   2388      0    stevel 	 * XXX get a "can-fast-forward" filter rule.
   2389      0    stevel 	 */
   2390      0    stevel 	m->m_flags &= ~M_CANFASTFWD;
   2391      0    stevel #  endif /* M_CANFASTFWD */
   2392      0    stevel #  ifdef CSUM_DELAY_DATA
   2393      0    stevel 	/*
   2394      0    stevel 	 * disable delayed checksums.
   2395      0    stevel 	 */
   2396      0    stevel 	if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
   2397      0    stevel 		in_delayed_cksum(m);
   2398      0    stevel 		m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
   2399      0    stevel 	}
   2400      0    stevel #  endif /* CSUM_DELAY_DATA */
   2401      0    stevel # endif /* MENTAT */
   2402   2393  yz155240 #else
   2403      0    stevel 
   2404      0    stevel 	bzero((char *)fin, sizeof(*fin));
   2405      0    stevel 	m = *mp;
   2406      0    stevel #endif /* _KERNEL */
   2407      0    stevel 
   2408      0    stevel 	fin->fin_v = v;
   2409      0    stevel 	fin->fin_m = m;
   2410   2393  yz155240 	fin->fin_ip = ip;
   2411      0    stevel 	fin->fin_mp = mp;
   2412      0    stevel 	fin->fin_out = out;
   2413      0    stevel 	fin->fin_ifp = ifp;
   2414   2393  yz155240 	fin->fin_error = ENETUNREACH;
   2415   2393  yz155240 	fin->fin_hlen = (u_short)hlen;
   2416      0    stevel 	fin->fin_dp = (char *)ip + hlen;
   2417   2393  yz155240 	fin->fin_ipoff = (char *)ip - MTOD(m, char *);
   2418   3448  dh155122 	fin->fin_ifs = ifs;
   2419   2393  yz155240 
   2420   2393  yz155240 	SPL_NET(s);
   2421   2393  yz155240 
   2422   2393  yz155240 #ifdef	USE_INET6
   2423   2393  yz155240 	if (v == 6) {
   2424   7131  dr146992 		IPF_BUMP(ifs->ifs_frstats[out].fr_ipv6);
   2425   2393  yz155240 		/*
   2426   2393  yz155240 		 * Jumbo grams are quite likely too big for internal buffer
   2427   2393  yz155240 		 * structures to handle comfortably, for now, so just drop
   2428   2393  yz155240 		 * them.
   2429   2393  yz155240 		 */
   2430   2393  yz155240 		ip6 = (ip6_t *)ip;
   2431   2393  yz155240 		fin->fin_plen = ntohs(ip6->ip6_plen);
   2432   2393  yz155240 		if (fin->fin_plen == 0) {
   2433   3448  dh155122 			READ_ENTER(&ifs->ifs_ipf_mutex);
   2434   2393  yz155240 			pass = FR_BLOCK|FR_NOMATCH;
   2435   2393  yz155240 			goto filtered;
   2436   2393  yz155240 		}
   2437   2393  yz155240 		fin->fin_plen += sizeof(ip6_t);
   2438   2393  yz155240 	} else
   2439   2393  yz155240 #endif
   2440   2393  yz155240 	{
   2441   2393  yz155240 #if (OpenBSD >= 200311) && defined(_KERNEL)
   2442   2393  yz155240 		ip->ip_len = ntohs(ip->ip_len);
   2443   2393  yz155240 		ip->ip_off = ntohs(ip->ip_off);
   2444   2393  yz155240 #endif
   2445   2393  yz155240 		fin->fin_plen = ip->ip_len;
   2446   2393  yz155240 	}
   2447   2393  yz155240 
   2448    637   ml37995 	if (fr_makefrip(hlen, ip, fin) == -1) {
   2449   3448  dh155122 		READ_ENTER(&ifs->ifs_ipf_mutex);
   2450    637   ml37995 		pass = FR_BLOCK;
   2451    637   ml37995 		goto filtered;
   2452      0    stevel 	}
   2453      0    stevel 
   2454      0    stevel 	/*
   2455      0    stevel 	 * For at least IPv6 packets, if a m_pullup() fails then this pointer
   2456      0    stevel 	 * becomes NULL and so we have no packet to free.
   2457      0    stevel 	 */
   2458      0    stevel 	if (*fin->fin_mp == NULL)
   2459      0    stevel 		goto finished;
   2460      0    stevel 
   2461      0    stevel 	if (!out) {
   2462      0    stevel 		if (v == 4) {
   2463      0    stevel #ifdef _KERNEL
   2464   3448  dh155122 			if (ifs->ifs_fr_chksrc && !fr_verifysrc(fin)) {
   2465   7131  dr146992 				IPF_BUMP(ifs->ifs_frstats[0].fr_badsrc);
   2466      0    stevel 				fin->fin_flx |= FI_BADSRC;
   2467      0    stevel 			}
   2468      0    stevel #endif
   2469   3448  dh155122 			if (fin->fin_ip->ip_ttl < ifs->ifs_fr_minttl) {
   2470   7131  dr146992 				IPF_BUMP(ifs->ifs_frstats[0].fr_badttl);
   2471      0    stevel 				fin->fin_flx |= FI_LOWTTL;
   2472      0    stevel 			}
   2473      0    stevel 		}
   2474      0    stevel #ifdef USE_INET6
   2475      0    stevel 		else  if (v == 6) {
   2476    637   ml37995 			ip6 = (ip6_t *)ip;
   2477    637   ml37995 #ifdef _KERNEL
   2478   3448  dh155122 			if (ifs->ifs_fr_chksrc && !fr_verifysrc(fin)) {
   2479   7131  dr146992 				IPF_BUMP(ifs->ifs_frstats[0].fr_badsrc);
   2480    637   ml37995 				fin->fin_flx |= FI_BADSRC;
   2481    637   ml37995 			}
   2482    637   ml37995 #endif
   2483   3448  dh155122 			if (ip6->ip6_hlim < ifs->ifs_fr_minttl) {
   2484   7131  dr146992 				IPF_BUMP(ifs->ifs_frstats[0].fr_badttl);
   2485      0    stevel 				fin->fin_flx |= FI_LOWTTL;
   2486      0    stevel 			}
   2487      0    stevel 		}
   2488      0    stevel #endif
   2489      0    stevel 	}
   2490      0    stevel 
   2491      0    stevel 	if (fin->fin_flx & FI_SHORT) {
   2492   7131  dr146992 		IPF_BUMP(ifs->ifs_frstats[out].fr_short);
   2493   3448  dh155122 	}
   2494   3448  dh155122 
   2495   3448  dh155122 	READ_ENTER(&ifs->ifs_ipf_mutex);
   2496      0    stevel 
   2497      0    stevel 	/*
   2498      0    stevel 	 * Check auth now.  This, combined with the check below to see if apass
   2499      0    stevel 	 * is 0 is to ensure that we don't count the packet twice, which can
   2500      0    stevel 	 * otherwise occur when we reprocess it.  As it is, we only count it
   2501      0    stevel 	 * after it has no auth. table matchup.  This also stops NAT from
   2502      0    stevel 	 * occuring until after the packet has been auth'd.
   2503      0    stevel 	 */
   2504      0    stevel 	fr = fr_checkauth(fin, &pass);
   2505   2393  yz155240 	if (!out) {
   2506   7176  yx160601 		switch (fin->fin_v)
   2507   7176  yx160601 		{
   2508   7176  yx160601 		case 4 :
   2509   7176  yx160601 			if (fr_checknatin(fin, &pass) == -1) {
   2510   7176  yx160601 				RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
   2511   7176  yx160601 				goto finished;
   2512   7176  yx160601 			}
   2513   7176  yx160601 			break;
   2514   7176  yx160601 #ifdef	USE_INET6
   2515   7176  yx160601 		case 6 :
   2516   7176  yx160601 			if (fr_checknat6in(fin, &pass) == -1) {
   2517   7176  yx160601 				RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
   2518   7176  yx160601 				goto finished;
   2519   7176  yx160601 			}
   2520   7176  yx160601 			break;
   2521   7176  yx160601 #endif
   2522   7176  yx160601 		default :
   2523   7176  yx160601 			break;
   2524   2393  yz155240 		}
   2525   2393  yz155240 	}
   2526      0    stevel 	if (!out)
   2527      0    stevel 		(void) fr_acctpkt(fin, NULL);
   2528      0    stevel 
   2529      0    stevel 	if (fr == NULL)
   2530      0    stevel 		if ((fin->fin_flx & (FI_FRAG|FI_BAD)) == FI_FRAG)
   2531      0    stevel 			fr = fr_knownfrag(fin, &pass);
   2532      0    stevel 	if (fr == NULL)
   2533      0    stevel 		fr = fr_checkstate(fin, &pass);
   2534      0    stevel 
   2535      0    stevel 	if ((pass & FR_NOMATCH) || (fr == NULL))
   2536      0    stevel 		fr = fr_firewall(fin, &pass);
   2537      0    stevel 
   2538      0    stevel 	fin->fin_fr = fr;
   2539      0    stevel 
   2540      0    stevel 	/*
   2541      0    stevel 	 * Only count/translate packets which will be passed on, out the
   2542      0    stevel 	 * interface.
   2543      0    stevel 	 */
   2544      0    stevel 	if (out && FR_ISPASS(pass)) {
   2545      0    stevel 		(void) fr_acctpkt(fin, NULL);
   2546   2393  yz155240 
   2547   7176  yx160601 		switch (fin->fin_v)
   2548   7176  yx160601 		{
   2549   7176  yx160601 		case 4 :
   2550   7176  yx160601 			if (fr_checknatout(fin, &pass) == -1) {
   2551   7176  yx160601 				RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
   2552   7176  yx160601 				goto finished;
   2553   7176  yx160601 			}
   2554   7176  yx160601 			break;
   2555   7176  yx160601 #ifdef	USE_INET6
   2556   7176  yx160601 		case 6 :
   2557   7176  yx160601 			if (fr_checknat6out(fin, &pass) == -1) {
   2558   7176  yx160601 				RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
   2559   7176  yx160601 				goto finished;
   2560   7176  yx160601 			}
   2561   7176  yx160601 			break;
   2562   7176  yx160601 #endif
   2563   7176  yx160601 		default :
   2564   7176  yx160601 			break;
   2565   7176  yx160601 		}
   2566   7176  yx160601 
   2567   7176  yx160601 		if ((ifs->ifs_fr_update_ipid != 0) && (v == 4)) {
   2568      0    stevel 			if (fr_updateipid(fin) == -1) {
   2569   7131  dr146992 				IPF_BUMP(ifs->ifs_frstats[1].fr_ipud);
   2570      0    stevel 				pass &= ~FR_CMDMASK;
   2571      0    stevel 				pass |= FR_BLOCK;
   2572      0    stevel 			} else {
   2573   7131  dr146992 				IPF_BUMP(ifs->ifs_frstats[0].fr_ipud);
   2574      0    stevel 			}
   2575      0    stevel 		}
   2576      0    stevel 	}
   2577      0    stevel 
   2578      0    stevel #ifdef	IPFILTER_LOG
   2579   3448  dh155122 	if ((ifs->ifs_fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
   2580      0    stevel 		(void) fr_dolog(fin, &pass);
   2581   2393  yz155240 	}
   2582      0    stevel #endif
   2583      0    stevel 
   2584   8624    Darren 	/*
   2585   8624    Darren 	 * The FI_STATE flag is cleared here so that calling fr_checkstate
   2586   8624    Darren 	 * will work when called from inside of fr_fastroute.  Although
   2587   8624    Darren 	 * there is a similar flag, FI_NATED, for NAT, it does have the same
   2588   8624    Darren 	 * impact on code execution.
   2589   8624    Darren 	 */
   2590   8624    Darren 	fin->fin_flx &= ~FI_STATE;
   2591      0    stevel 
   2592      0    stevel 	/*
   2593      0    stevel 	 * Only allow FR_DUP to work if a rule matched - it makes no sense to
   2594      0    stevel 	 * set FR_DUP as a "default" as there are no instructions about where
   2595   2393  yz155240 	 * to send the packet.  Use fin_m here because it may have changed
   2596   2393  yz155240 	 * (without an update of 'm') in prior processing.
   2597      0    stevel 	 */
   2598      0    stevel 	if ((fr != NULL) && (pass & FR_DUP)) {
   2599   2393  yz155240 		mc = M_DUPLICATE(fin->fin_m);
   2600  10838  Alexandr #ifdef _KERNEL
   2601  10838  Alexandr 		mc->b_rptr += fin->fin_ipoff;
   2602  10838  Alexandr #endif
   2603      0    stevel 	}
   2604      0    stevel 
   2605      0    stevel 	if (pass & (FR_RETRST|FR_RETICMP)) {
   2606      0    stevel 		/*
   2607      0    stevel 		 * Should we return an ICMP packet to indicate error
   2608      0    stevel 		 * status passing through the packet filter ?
   2609      0    stevel 		 * WARNING: ICMP error packets AND TCP RST packets should
   2610      0    stevel 		 * ONLY be sent in repsonse to incoming packets.  Sending them
   2611      0    stevel 		 * in response to outbound packets can result in a panic on
   2612      0    stevel 		 * some operating systems.
   2613      0    stevel 		 */
   2614      0    stevel 		if (!out) {
   2615      0    stevel 			if (pass & FR_RETICMP) {
   2616      0    stevel 				int dst;
   2617      0    stevel 
   2618      0    stevel 				if ((pass & FR_RETMASK) == FR_FAKEICMP)
   2619      0    stevel 					dst = 1;
   2620      0    stevel 				else
   2621      0    stevel 					dst = 0;
   2622   9695  Alexandr #if defined(_KERNEL) && (SOLARIS2 >= 10)
   2623   9695  Alexandr 				/*
   2624   9695  Alexandr 				 * Assume it's possible to enter insane rule:
   2625   9695  Alexandr 				 * 	pass return-icmp in proto udp ...
   2626   9695  Alexandr 				 * then we have no other option than to forward
   2627   9695  Alexandr 				 * packet on loopback and give up any attempt
   2628   9695  Alexandr 				 * to create a fake response.
   2629   9695  Alexandr 				 */
   2630   9695  Alexandr 				if (IPF_IS_LOOPBACK(qpi->qpi_flags) &&
   2631   9695  Alexandr 				    FR_ISBLOCK(pass)) {
   2632   9695  Alexandr 
   2633   9695  Alexandr 					if (fr_make_icmp(fin) == 0) {
   2634   9695  Alexandr 						IPF_BUMP(
   2635   9695  Alexandr 						ifs->ifs_frstats[out].fr_ret);
   2636   9695  Alexandr 					}
   2637   9695  Alexandr 					/*
   2638   9695  Alexandr 					 * we drop packet silently in case we
   2639   9695  Alexandr 					 * failed assemble fake response for it
   2640   9695  Alexandr 					 */
   2641   9695  Alexandr 					else if (*mp != NULL) {
   2642   9695  Alexandr 						FREE_MB_T(*mp);
   2643   9695  Alexandr 						m = *mp = NULL;
   2644   9695  Alexandr 					}
   2645   9695  Alexandr 
   2646   9695  Alexandr 					IPF_BUMP(
   2647   9695  Alexandr 					    ifs->ifs_frstats[out].fr_block);
   2648   9695  Alexandr 					RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
   2649   9695  Alexandr 
   2650   9695  Alexandr 					return (0);
   2651   9695  Alexandr 				}
   2652   9695  Alexandr #endif	/* _KERNEL && SOLARIS2 >= 10 */
   2653   9695  Alexandr 
   2654      0    stevel 				(void) fr_send_icmp_err(ICMP_UNREACH, fin, dst);
   2655   9695  Alexandr 				IPF_BUMP(ifs->ifs_frstats[out].fr_ret);
   2656   9695  Alexandr 
   2657      0    stevel 			} else if (((pass & FR_RETMASK) == FR_RETRST) &&
   2658      0    stevel 				   !(fin->fin_flx & FI_SHORT)) {
   2659   9695  Alexandr 
   2660   9695  Alexandr #if defined(_KERNEL) && (SOLARIS2 >= 10)
   2661   9695  Alexandr 				/*
   2662   9695  Alexandr 				 * Assume it's possible to enter insane rule:
   2663   9695  Alexandr 				 * 	pass return-rst in proto tcp ...
   2664   9695  Alexandr 				 * then we have no other option than to forward
   2665   9695  Alexandr 				 * packet on loopback and give up any attempt
   2666   9695  Alexandr 				 * to create a fake response.
   2667   9695  Alexandr 				 */
   2668   9695  Alexandr 				if (IPF_IS_LOOPBACK(qpi->qpi_flags) &&
   2669   9695  Alexandr 				    FR_ISBLOCK(pass)) {
   2670   9695  Alexandr 					if (fr_make_rst(fin) == 0) {
   2671   9695  Alexandr 						IPF_BUMP(
   2672   9695  Alexandr 						ifs->ifs_frstats[out].fr_ret);
   2673   9695  Alexandr 					}
   2674   9695  Alexandr 					else if (mp != NULL) {
   2675   9695  Alexandr 					/*
   2676   9695  Alexandr 					 * we drop packet silently in case we
   2677   9695  Alexandr 					 * failed assemble fake response for it
   2678   9695  Alexandr 					 */
   2679   9695  Alexandr 						FREE_MB_T(*mp);
   2680   9695  Alexandr 						m = *mp = NULL;
   2681   9695  Alexandr 					}
   2682   9695  Alexandr 
   2683   9695  Alexandr 					IPF_BUMP(
   2684   9695  Alexandr 					    ifs->ifs_frstats[out].fr_block);
   2685   9695  Alexandr 					RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
   2686   9695  Alexandr 
   2687   9695  Alexandr 					return (0);
   2688   9695  Alexandr 				 }
   2689   9695  Alexandr #endif /* _KERNEL && _SOLARIS2 >= 10 */
   2690      0    stevel 				if (fr_send_reset(fin) == 0) {
   2691   7131  dr146992 					IPF_BUMP(ifs->ifs_frstats[1].fr_ret);
   2692      0    stevel 				}
   2693      0    stevel 			}
   2694      0    stevel 		} else {
   2695      0    stevel 			if (pass & FR_RETRST)
   2696      0    stevel 				fin->fin_error = ECONNRESET;
   2697      0    stevel 		}
   2698      0    stevel 	}
   2699      0    stevel 
   2700      0    stevel 	/*
   2701      0    stevel 	 * If we didn't drop off the bottom of the list of rules (and thus
   2702      0    stevel 	 * the 'current' rule fr is not NULL), then we may have some extra
   2703      0    stevel 	 * instructions about what to do with a packet.
   2704      0    stevel 	 * Once we're finished return to our caller, freeing the packet if
   2705      0    stevel 	 * we are dropping it (* BSD ONLY *).
   2706   2393  yz155240 	 * Reassign m from fin_m as we may have a new buffer, now.
   2707   2393  yz155240 	 */
   2708      0    stevel filtered:
   2709   2393  yz155240 	m = fin->fin_m;
   2710      0    stevel 
   2711      0    stevel 	if (fr != NULL) {
   2712      0    stevel 		frdest_t *fdp;
   2713      0    stevel 
   2714      0    stevel 		fdp = &fr->fr_tifs[fin->fin_rev];
   2715      0    stevel 
   2716      0    stevel 		if (!out && (pass & FR_FASTROUTE)) {
   2717      0    stevel 			/*
   2718      0    stevel 			 * For fastroute rule, no destioation interface defined
   2719      0    stevel 			 * so pass NULL as the frdest_t parameter
   2720      0    stevel 			 */
   2721      0    stevel 			(void) fr_fastroute(m, mp, fin, NULL);
   2722      0    stevel 			m = *mp = NULL;
   2723      0    stevel 		} else if ((fdp->fd_ifp != NULL) &&
   2724      0    stevel 			   (fdp->fd_ifp != (struct ifnet *)-1)) {
   2725      0    stevel 			/* this is for to rules: */
   2726      0    stevel 			(void) fr_fastroute(m, mp, fin, fdp);
   2727      0    stevel 			m = *mp = NULL;
   2728      0    stevel 		}
   2729      0    stevel 
   2730      0    stevel 		/*
   2731      0    stevel 		 * Generate a duplicated packet.
   2732      0    stevel 		 */
   2733      0    stevel 		if (mc != NULL)
   2734      0    stevel 			(void) fr_fastroute(mc, &mc, fin, &fr->fr_dif);
   2735      0    stevel 	}
   2736   8624    Darren 
   2737   8624    Darren 	if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT))
   2738   8624    Darren 		nat_uncreate(fin);
   2739      0    stevel 
   2740      0    stevel 	/*
   2741      0    stevel 	 * This late because the likes of fr_fastroute() use fin_fr.
   2742      0    stevel 	 */
   2743   3448  dh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
   2744      0    stevel 
   2745   2393  yz155240 finished:
   2746      0    stevel 	if (!FR_ISPASS(pass)) {
   2747   7131  dr146992 		IPF_BUMP(ifs->ifs_frstats[out].fr_block);
   2748   2393  yz155240 		if (*mp != NULL) {
   2749      0    stevel 			FREE_MB_T(*mp);
   2750      0    stevel 			m = *mp = NULL;
   2751      0    stevel 		}
   2752   2393  yz155240 	} else {
   2753   7131  dr146992 		IPF_BUMP(ifs->ifs_frstats[out].fr_pass);
   2754      0    stevel #if defined(_KERNEL) && defined(__sgi)
   2755   2393  yz155240 		if ((fin->fin_hbuf != NULL) &&
   2756   2393  yz155240 		    (mtod(fin->fin_m, struct ip *) != fin->fin_ip)) {
   2757   2393  yz155240 			COPYBACK(m, 0, fin->fin_plen, fin->fin_hbuf);
   2758   2393  yz155240 		}
   2759   2393  yz155240 #endif
   2760   2393  yz155240 	}
   2761   2393  yz155240 
   2762   2393  yz155240 	SPL_X(s);
   2763   2393  yz155240 
   2764      0    stevel #ifdef _KERNEL
   2765   2393  yz155240 # if OpenBSD >= 200311
   2766   2393  yz155240 	if (FR_ISPASS(pass) && (v == 4)) {
   2767   2393  yz155240 		ip = fin->fin_ip;
   2768   2393  yz155240 		ip->ip_len = ntohs(ip->ip_len);
   2769   2393  yz155240 		ip->ip_off = ntohs(ip->ip_off);
   2770   2393  yz155240 	}
   2771   2393  yz155240 # endif
   2772      0    stevel 	return (FR_ISPASS(pass)) ? 0 : fin->fin_error;
   2773      0    stevel #else /* _KERNEL */
   2774   2393  yz155240 	FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass));
   2775      0    stevel 	if ((pass & FR_NOMATCH) != 0)
   2776      0    stevel 		return 1;
   2777      0    stevel 
   2778      0    stevel 	if ((pass & FR_RETMASK) != 0)
   2779      0    stevel 		switch (pass & FR_RETMASK)
   2780      0    stevel 		{
   2781      0    stevel 		case FR_RETRST :
   2782      0    stevel 			return 3;
   2783      0    stevel 		case FR_RETICMP :
   2784      0    stevel 			return 4;
   2785      0    stevel 		case FR_FAKEICMP :
   2786      0    stevel 			return 5;
   2787      0    stevel 		}
   2788      0    stevel 
   2789      0    stevel 	switch (pass & FR_CMDMASK)
   2790      0    stevel 	{
   2791      0    stevel 	case FR_PASS :
   2792      0    stevel 		return 0;
   2793      0    stevel 	case FR_BLOCK :
   2794      0    stevel 		return -1;
   2795      0    stevel 	case FR_AUTH :
   2796      0    stevel 		return -2;
   2797      0    stevel 	case FR_ACCOUNT :
   2798      0    stevel 		return -3;
   2799      0    stevel 	case FR_PREAUTH :
   2800      0    stevel 		return -4;
   2801      0    stevel 	}
   2802      0    stevel 	return 2;
   2803      0    stevel #endif /* _KERNEL */
   2804      0    stevel }
   2805      0    stevel 
   2806      0    stevel 
   2807      0    stevel #ifdef	IPFILTER_LOG
   2808      0    stevel /* ------------------------------------------------------------------------ */
   2809      0    stevel /* Function:    fr_dolog                                                    */
   2810      0    stevel /* Returns:     frentry_t* - returns contents of fin_fr (no change made)    */
   2811      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
   2812      0    stevel /*              passp(IO) - pointer to current/new filter decision (unused) */
   2813      0    stevel /*                                                                          */
   2814      0    stevel /* Checks flags set to see how a packet should be logged, if it is to be    */
   2815      0    stevel /* logged.  Adjust statistics based on its success or not.                  */
   2816      0    stevel /* ------------------------------------------------------------------------ */
   2817      0    stevel frentry_t *fr_dolog(fin, passp)
   2818      0    stevel fr_info_t *fin;
   2819      0    stevel u_32_t *passp;
   2820      0    stevel {
   2821      0    stevel 	u_32_t pass;
   2822      0    stevel 	int out;
   2823   3448  dh155122 	ipf_stack_t *ifs = fin->fin_ifs;
   2824      0    stevel 
   2825      0    stevel 	out = fin->fin_out;
   2826      0    stevel 	pass = *passp;
   2827      0    stevel 
   2828   3448  dh155122 	if ((ifs->ifs_fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
   2829      0    stevel 		pass |= FF_LOGNOMATCH;
   2830   7131  dr146992 		IPF_BUMP(ifs->ifs_frstats[out].fr_npkl);
   2831      0    stevel 		goto logit;
   2832      0    stevel 	} else if (((pass & FR_LOGMASK) == FR_LOGP) ||
   2833   3448  dh155122 	    (FR_ISPASS(pass) && (ifs->ifs_fr_flags & FF_LOGPASS))) {
   2834      0    stevel 		if ((pass & FR_LOGMASK) != FR_LOGP)
   2835      0    stevel 			pass |= FF_LOGPASS;
   2836   7131  dr146992 		IPF_BUMP(ifs->ifs_frstats[out].fr_ppkl);
   2837      0    stevel 		goto logit;
   2838      0    stevel 	} else if (((pass & FR_LOGMASK) == FR_LOGB) ||
   2839   3448  dh155122 		   (FR_ISBLOCK(pass) && (ifs->ifs_fr_flags & FF_LOGBLOCK))) {
   2840      0    stevel 		if ((pass & FR_LOGMASK) != FR_LOGB)
   2841      0    stevel 			pass |= FF_LOGBLOCK;
   2842   7131  dr146992 		IPF_BUMP(ifs->ifs_frstats[out].fr_bpkl);
   2843      0    stevel logit:
   2844      0    stevel 		if (ipflog(fin, pass) == -1) {
   2845   7131  dr146992 			IPF_BUMP(ifs->ifs_frstats[out].fr_skip);
   2846      0    stevel 
   2847      0    stevel 			/*
   2848      0    stevel 			 * If the "or-block" option has been used then
   2849      0    stevel 			 * block the packet if we failed to log it.
   2850      0    stevel 			 */
   2851      0    stevel 			if ((pass & FR_LOGORBLOCK) &&
   2852      0    stevel 			    FR_ISPASS(pass)) {
   2853      0    stevel 				pass &= ~FR_CMDMASK;
   2854      0    stevel 				pass |= FR_BLOCK;
   2855      0    stevel 			}
   2856      0    stevel 		}
   2857      0    stevel 		*passp = pass;
   2858      0    stevel 	}
   2859      0    stevel 
   2860      0    stevel 	return fin->fin_fr;
   2861      0    stevel }
   2862      0    stevel #endif /* IPFILTER_LOG */
   2863      0    stevel 
   2864      0    stevel 
   2865      0    stevel /* ------------------------------------------------------------------------ */
   2866      0    stevel /* Function:    ipf_cksum                                                   */
   2867      0    stevel /* Returns:     u_short - IP header checksum                                */
   2868      0    stevel /* Parameters:  addr(I) - pointer to start of buffer to checksum            */
   2869      0    stevel /*              len(I)  - length of buffer in bytes                         */
   2870      0    stevel /*                                                                          */
   2871      0    stevel /* Calculate the two's complement 16 bit checksum of the buffer passed.     */
   2872      0    stevel /*                                                                          */
   2873      0    stevel /* N.B.: addr should be 16bit aligned.                                      */
   2874      0    stevel /* ------------------------------------------------------------------------ */
   2875      0    stevel u_short ipf_cksum(addr, len)
   2876      0    stevel u_short *addr;
   2877      0    stevel int len;
   2878      0    stevel {
   2879      0    stevel 	u_32_t sum = 0;
   2880      0    stevel 
   2881      0    stevel 	for (sum = 0; len > 1; len -= 2)
   2882      0    stevel 		sum += *addr++;
   2883      0    stevel 
   2884      0    stevel 	/* mop up an odd byte, if necessary */
   2885      0    stevel 	if (len == 1)
   2886      0    stevel 		sum += *(u_char *)addr;
   2887      0    stevel 
   2888      0    stevel 	/*
   2889      0    stevel 	 * add back carry outs from top 16 bits to low 16 bits
   2890      0    stevel 	 */
   2891      0    stevel 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
   2892      0    stevel 	sum += (sum >> 16);			/* add carry */
   2893      0    stevel 	return (u_short)(~sum);
   2894      0    stevel }
   2895      0    stevel 
   2896      0    stevel 
   2897      0    stevel /* ------------------------------------------------------------------------ */
   2898      0    stevel /* Function:    fr_cksum                                                    */
   2899      0    stevel /* Returns:     u_short - layer 4 checksum                                  */
   2900   2393  yz155240 /* Parameters:  m(I  )     - pointer to buffer holding packet               */
   2901   2393  yz155240 /*              ip(I)      - pointer to IP header                           */
   2902   2393  yz155240 /*              l4proto(I) - protocol to caclulate checksum for             */
   2903   2393  yz155240 /*              l4hdr(I)   - pointer to layer 4 header                      */
   2904      0    stevel /*                                                                          */
   2905      0    stevel /* Calculates the TCP checksum for the packet held in "m", using the data   */
   2906      0    stevel /* in the IP header "ip" to seed it.                                        */
   2907      0    stevel /*                                                                          */
   2908      0    stevel /* NB: This function assumes we've pullup'd enough for all of the IP header */
   2909      0    stevel /* and the TCP header.  We also assume that data blocks aren't allocated in */
   2910      0    stevel /* odd sizes.                                                               */
   2911   2393  yz155240 /*                                                                          */
   2912   2393  yz155240 /* Expects ip_len to be in host byte order when called.                     */
   2913      0    stevel /* ------------------------------------------------------------------------ */
   2914      0    stevel u_short fr_cksum(m, ip, l4proto, l4hdr)
   2915      0    stevel mb_t *m;
   2916      0    stevel ip_t *ip;
   2917      0    stevel int l4proto;
   2918      0    stevel void *l4hdr;
   2919      0    stevel {
   2920      0    stevel 	u_short *sp, slen, sumsave, l4hlen, *csump;
   2921      0    stevel 	u_int sum, sum2;
   2922      0    stevel 	int hlen;
   2923      0    stevel #ifdef	USE_INET6
   2924      0    stevel 	ip6_t *ip6;
   2925      0    stevel #endif
   2926      0    stevel 
   2927      0    stevel 	csump = NULL;
   2928      0    stevel 	sumsave = 0;
   2929      0    stevel 	l4hlen = 0;
   2930      0    stevel 	sp = NULL;
   2931      0    stevel 	slen = 0;
   2932      0    stevel 	hlen = 0;
   2933      0    stevel 	sum = 0;
   2934      0    stevel 
   2935      0    stevel 	/*
   2936      0    stevel 	 * Add up IP Header portion
   2937      0    stevel 	 */
   2938      0    stevel #ifdef	USE_INET6
   2939      0    stevel 	if (IP_V(ip) == 4) {
   2940      0    stevel #endif
   2941      0    stevel 		hlen = IP_HL(ip) << 2;
   2942      0    stevel 		slen = ip->ip_len - hlen;
   2943   2393  yz155240 		sum = htons((u_short)l4proto);
   2944      0    stevel 		sum += htons(slen);
   2945      0    stevel 		sp = (u_short *)&ip->ip_src;
   2946      0    stevel 		sum += *sp++;	/* ip_src */
   2947      0    stevel 		sum += *sp++;
   2948      0    stevel 		sum += *sp++;	/* ip_dst */
   2949      0    stevel 		sum += *sp++;
   2950      0    stevel #ifdef	USE_INET6
   2951      0    stevel 	} else if (IP_V(ip) == 6) {
   2952      0    stevel 		ip6 = (ip6_t *)ip;
   2953      0    stevel 		hlen = sizeof(*ip6);
   2954      0    stevel 		slen = ntohs(ip6->ip6_plen);
   2955   2393  yz155240 		sum = htons((u_short)l4proto);
   2956      0    stevel 		sum += htons(slen);
   2957      0    stevel 		sp = (u_short *)&ip6->ip6_src;
   2958      0    stevel 		sum += *sp++;	/* ip6_src */
   2959      0    stevel 		sum += *sp++;
   2960      0    stevel 		sum += *sp++;
   2961      0    stevel 		sum += *sp++;
   2962      0    stevel 		sum += *sp++;
   2963      0    stevel 		sum += *sp++;
   2964      0    stevel 		sum += *sp++;
   2965      0    stevel 		sum += *sp++;
   2966      0    stevel 		sum += *sp++;	/* ip6_dst */
   2967      0    stevel 		sum += *sp++;
   2968      0    stevel 		sum += *sp++;
   2969      0    stevel 		sum += *sp++;
   2970      0    stevel 		sum += *sp++;
   2971      0    stevel 		sum += *sp++;
   2972      0    stevel 		sum += *sp++;
   2973    637   ml37995 		sum += *sp++;
   2974      0    stevel 	}
   2975      0    stevel #endif
   2976      0    stevel 
   2977      0    stevel 	switch (l4proto)
   2978      0    stevel 	{
   2979      0    stevel 	case IPPROTO_UDP :
   2980      0    stevel 		csump = &((udphdr_t *)l4hdr)->uh_sum;
   2981      0    stevel 		l4hlen = sizeof(udphdr_t);
   2982      0    stevel 		break;
   2983      0    stevel 
   2984      0    stevel 	case IPPROTO_TCP :
   2985      0    stevel 		csump = &((tcphdr_t *)l4hdr)->th_sum;
   2986      0    stevel 		l4hlen = sizeof(tcphdr_t);
   2987      0    stevel 		break;
   2988      0    stevel 	case IPPROTO_ICMP :
   2989      0    stevel 		csump = &((icmphdr_t *)l4hdr)->icmp_cksum;
   2990      0    stevel 		l4hlen = 4;
   2991   2393  yz155240 		sum = 0;
   2992      0    stevel 		break;
   2993      0    stevel 	default :
   2994      0    stevel 		break;
   2995      0    stevel 	}
   2996      0    stevel 
   2997      0    stevel 	if (csump != NULL) {
   2998      0    stevel 		sumsave = *csump;
   2999      0    stevel 		*csump = 0;
   3000      0    stevel 	}
   3001      0    stevel 
   3002      0    stevel 	l4hlen = l4hlen;	/* LINT */
   3003      0    stevel 
   3004      0    stevel #ifdef	_KERNEL
   3005      0    stevel # ifdef MENTAT
   3006      0    stevel 	{
   3007      0    stevel 	void *rp = m->b_rptr;
   3008      0    stevel 
   3009      0    stevel 	if ((unsigned char *)ip > m->b_rptr && (unsigned char *)ip < m->b_wptr)
   3010      0    stevel 		m->b_rptr = (u_char *)ip;
   3011      0    stevel 	sum2 = ip_cksum(m, hlen, sum);	/* hlen == offset */
   3012      0    stevel 	m->b_rptr = rp;
   3013      0    stevel 	sum2 = (sum2 & 0xffff) + (sum2 >> 16);
   3014      0    stevel 	sum2 = ~sum2 & 0xffff;
   3015   2393  yz155240 	}
   3016      0    stevel # else /* MENTAT */
   3017      0    stevel #  if defined(BSD) || defined(sun)
   3018      0    stevel #   if BSD >= 199103
   3019      0    stevel 	m->m_data += hlen;
   3020      0    stevel #   else
   3021      0    stevel 	m->m_off += hlen;
   3022      0    stevel #   endif
   3023      0    stevel 	m->m_len -= hlen;
   3024      0    stevel 	sum2 = in_cksum(m, slen);
   3025      0    stevel 	m->m_len += hlen;
   3026      0    stevel #   if BSD >= 199103
   3027      0    stevel 	m->m_data -= hlen;
   3028      0    stevel #   else
   3029      0    stevel 	m->m_off -= hlen;
   3030      0    stevel #   endif
   3031      0    stevel 	/*
   3032      0    stevel 	 * Both sum and sum2 are partial sums, so combine them together.
   3033      0    stevel 	 */
   3034      0    stevel 	sum += ~sum2 & 0xffff;
   3035      0    stevel 	while (sum > 0xffff)
   3036      0    stevel 		sum = (sum & 0xffff) + (sum >> 16);
   3037      0    stevel 	sum2 = ~sum & 0xffff;
   3038      0    stevel #  else /* defined(BSD) || defined(sun) */
   3039      0    stevel {
   3040      0    stevel 	union {
   3041      0    stevel 		u_char	c[2];
   3042      0    stevel 		u_short	s;
   3043      0    stevel 	} bytes;
   3044      0    stevel 	u_short len = ip->ip_len;
   3045      0    stevel #   if defined(__sgi)
   3046      0    stevel 	int add;
   3047      0    stevel #   endif
   3048      0    stevel 
   3049      0    stevel 	/*
   3050      0    stevel 	 * Add up IP Header portion
   3051      0    stevel 	 */
   3052      0    stevel 	if (sp != (u_short *)l4hdr)
   3053      0    stevel 		sp = (u_short *)l4hdr;
   3054      0    stevel 
   3055   2393  yz155240 	switch (l4proto)
   3056      0    stevel 	{
   3057      0    stevel 	case IPPROTO_UDP :
   3058      0    stevel 		sum += *sp++;	/* sport */
   3059      0    stevel 		sum += *sp++;	/* dport */
   3060      0    stevel 		sum += *sp++;	/* udp length */
   3061      0    stevel 		sum += *sp++;	/* checksum */
   3062      0    stevel 		break;
   3063      0    stevel 
   3064      0    stevel 	case IPPROTO_TCP :
   3065      0    stevel 		sum += *sp++;	/* sport */
   3066      0    stevel 		sum += *sp++;	/* dport */
   3067      0    stevel 		sum += *sp++;	/* seq */
   3068      0    stevel 		sum += *sp++;
   3069      0    stevel 		sum += *sp++;	/* ack */
   3070      0    stevel 		sum += *sp++;
   3071      0    stevel 		sum += *sp++;	/* off */
   3072      0    stevel 		sum += *sp++;	/* win */
   3073      0    stevel 		sum += *sp++;	/* checksum */
   3074      0    stevel 		sum += *sp++;	/* urp */
   3075   2393  yz155240 		break;
   3076   2393  yz155240 	case IPPROTO_ICMP :
   3077   2393  yz155240 		sum = *sp++;	/* type/code */
   3078   2393  yz155240 		sum += *sp++;	/* checksum */
   3079      0    stevel 		break;
   3080      0    stevel 	}
   3081      0    stevel 
   3082      0    stevel #   ifdef	__sgi
   3083      0    stevel 	/*
   3084      0    stevel 	 * In case we had to copy the IP & TCP header out of mbufs,
   3085      0    stevel 	 * skip over the mbuf bits which are the header
   3086      0    stevel 	 */
   3087      0    stevel 	if ((caddr_t)ip != mtod(m, caddr_t)) {
   3088      0    stevel 		hlen = (caddr_t)sp - (caddr_t)ip;
   3089      0    stevel 		while (hlen) {
   3090      0    stevel 			add = MIN(hlen, m->m_len);
   3091      0    stevel 			sp = (u_short *)(mtod(m, caddr_t) + add);
   3092      0    stevel 			hlen -= add;
   3093      0    stevel 			if (add == m->m_len) {
   3094      0    stevel 				m = m->m_next;
   3095      0    stevel 				if (!hlen) {
   3096      0    stevel 					if (!m)
   3097      0    stevel 						break;
   3098      0    stevel 					sp = mtod(m, u_short *);
   3099      0    stevel 				}
   3100      0    stevel 				PANIC((!m),("fr_cksum(1): not enough data"));
   3101      0    stevel 			}
   3102      0    stevel 		}
   3103      0    stevel 	}
   3104      0    stevel #   endif
   3105      0    stevel 
   3106   2393  yz155240 	len -= (l4hlen + hlen);
   3107      0    stevel 	if (len <= 0)
   3108      0    stevel 		goto nodata;
   3109      0    stevel 
   3110      0    stevel 	while (len > 1) {
   3111      0    stevel 		if (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len) {
   3112      0    stevel 			m = m->m_next;
   3113      0    stevel 			PANIC((!m),("fr_cksum(2): not enough data"));
   3114      0    stevel 			sp = mtod(m, u_short *);
   3115      0    stevel 		}
   3116      0    stevel 		if (((caddr_t)(sp + 1) - mtod(m, caddr_t)) > m->m_len) {
   3117      0    stevel 			bytes.c[0] = *(u_char *)sp;
   3118      0    stevel 			m = m->m_next;
   3119      0    stevel 			PANIC((!m),("fr_cksum(3): not enough data"));
   3120      0    stevel 			sp = mtod(m, u_short *);
   3121      0    stevel 			bytes.c[1] = *(u_char *)sp;
   3122      0    stevel 			sum += bytes.s;
   3123      0    stevel 			sp = (u_short *)((u_char *)sp + 1);
   3124      0    stevel 		}
   3125      0    stevel 		if ((u_long)sp & 1) {
   3126      0    stevel 			bcopy((char *)sp++, (char *)&bytes.s, sizeof(bytes.s));
   3127      0    stevel 			sum += bytes.s;
   3128      0    stevel 		} else
   3129      0    stevel 			sum += *sp++;
   3130      0    stevel 		len -= 2;
   3131      0    stevel 	}
   3132      0    stevel 
   3133      0    stevel 	if (len != 0)
   3134      0    stevel 		sum += ntohs(*(u_char *)sp << 8);
   3135      0    stevel nodata:
   3136      0    stevel 	while (sum > 0xffff)
   3137      0    stevel 		sum = (sum & 0xffff) + (sum >> 16);
   3138      0    stevel 	sum2 = (u_short)(~sum & 0xffff);
   3139      0    stevel }
   3140      0    stevel #  endif /*  defined(BSD) || defined(sun) */
   3141      0    stevel # endif /* MENTAT */
   3142      0    stevel #else /* _KERNEL */
   3143      0    stevel 	for (; slen > 1; slen -= 2)
   3144      0    stevel 	        sum += *sp++;
   3145      0    stevel 	if (slen)
   3146      0    stevel 		sum += ntohs(*(u_char *)sp << 8);
   3147      0    stevel 	while (sum > 0xffff)
   3148      0    stevel 		sum = (sum & 0xffff) + (sum >> 16);
   3149      0    stevel 	sum2 = (u_short)(~sum & 0xffff);
   3150      0    stevel #endif /* _KERNEL */
   3151      0    stevel 	if (csump != NULL)
   3152      0    stevel 		*csump = sumsave;
   3153      0