The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netpfil/ipfilter/netinet/fil.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $FreeBSD$       */
    2 
    3 /*
    4  * Copyright (C) 2012 by Darren Reed.
    5  *
    6  * See the IPFILTER.LICENCE file for details on licencing.
    7  *
    8  * Copyright 2008 Sun Microsystems.
    9  *
   10  * $Id$
   11  *
   12  */
   13 #if defined(KERNEL) || defined(_KERNEL)
   14 # undef KERNEL
   15 # undef _KERNEL
   16 # define        KERNEL  1
   17 # define        _KERNEL 1
   18 #endif
   19 #include <sys/errno.h>
   20 #include <sys/types.h>
   21 #include <sys/param.h>
   22 #include <sys/time.h>
   23 #if defined(_KERNEL) && defined(__FreeBSD__)
   24 #  if !defined(IPFILTER_LKM)
   25 #   include "opt_inet6.h"
   26 #  endif
   27 # include <sys/filio.h>
   28 #else
   29 # include <sys/ioctl.h>
   30 #endif
   31 #if defined(__SVR4) || defined(sun) /* SOLARIS */
   32 # include <sys/filio.h>
   33 #endif
   34 # include <sys/fcntl.h>
   35 #if defined(_KERNEL)
   36 # include <sys/systm.h>
   37 # include <sys/file.h>
   38 #else
   39 # include <stdio.h>
   40 # include <string.h>
   41 # include <stdlib.h>
   42 # include <stddef.h>
   43 # include <sys/file.h>
   44 # define _KERNEL
   45 # include <sys/uio.h>
   46 # undef _KERNEL
   47 #endif
   48 #if !defined(__SVR4)
   49 # include <sys/mbuf.h>
   50 #else
   51 # include <sys/byteorder.h>
   52 # if (SOLARIS2 < 5) && defined(sun)
   53 #  include <sys/dditypes.h>
   54 # endif
   55 #endif
   56 # include <sys/protosw.h>
   57 #include <sys/socket.h>
   58 #include <net/if.h>
   59 #ifdef sun
   60 # include <net/af.h>
   61 #endif
   62 #include <netinet/in.h>
   63 #include <netinet/in_systm.h>
   64 #include <netinet/ip.h>
   65 #include <netinet/tcp.h>
   66 # include <netinet/udp.h>
   67 # include <netinet/ip_icmp.h>
   68 #include "netinet/ip_compat.h"
   69 #ifdef  USE_INET6
   70 # include <netinet/icmp6.h>
   71 # if !SOLARIS && defined(_KERNEL)
   72 #  include <netinet6/in6_var.h>
   73 # endif
   74 #endif
   75 #include "netinet/ip_fil.h"
   76 #include "netinet/ip_nat.h"
   77 #include "netinet/ip_frag.h"
   78 #include "netinet/ip_state.h"
   79 #include "netinet/ip_proxy.h"
   80 #include "netinet/ip_auth.h"
   81 #ifdef IPFILTER_SCAN
   82 # include "netinet/ip_scan.h"
   83 #endif
   84 #include "netinet/ip_sync.h"
   85 #include "netinet/ip_lookup.h"
   86 #include "netinet/ip_pool.h"
   87 #include "netinet/ip_htable.h"
   88 #ifdef IPFILTER_COMPILED
   89 # include "netinet/ip_rules.h"
   90 #endif
   91 #if defined(IPFILTER_BPF) && defined(_KERNEL)
   92 # include <net/bpf.h>
   93 #endif
   94 #if defined(__FreeBSD__)
   95 # include <sys/malloc.h>
   96 #endif
   97 #include "netinet/ipl.h"
   98 
   99 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
  100 # include <sys/callout.h>
  101 extern struct callout ipf_slowtimer_ch;
  102 #endif
  103 /* END OF INCLUDES */
  104 
  105 #if !defined(lint)
  106 static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed";
  107 static const char rcsid[] = "@(#)$FreeBSD$";
  108 /* static const char rcsid[] = "@(#)$Id: fil.c,v 2.243.2.125 2007/10/10 09:27:20 darrenr Exp $"; */
  109 #endif
  110 
  111 #ifndef _KERNEL
  112 # include "ipf.h"
  113 # include "ipt.h"
  114 extern  int     opts;
  115 extern  int     blockreason;
  116 #endif /* _KERNEL */
  117 
  118 #define FASTROUTE_RECURSION
  119 
  120 #define LBUMP(x)        softc->x++
  121 #define LBUMPD(x, y)    do { softc->x.y++; DT(y); } while (0)
  122 
  123 static  inline int      ipf_check_ipf(fr_info_t *, frentry_t *, int);
  124 static  u_32_t          ipf_checkcipso(fr_info_t *, u_char *, int);
  125 static  u_32_t          ipf_checkripso(u_char *);
  126 static  u_32_t          ipf_decaps(fr_info_t *, u_32_t, int);
  127 #ifdef IPFILTER_LOG
  128 static  frentry_t       *ipf_dolog(fr_info_t *, u_32_t *);
  129 #endif
  130 static  int             ipf_flushlist(ipf_main_softc_t *, int *, frentry_t **);
  131 static  int             ipf_flush_groups(ipf_main_softc_t *, frgroup_t **,
  132                                               int);
  133 static  ipfunc_t        ipf_findfunc(ipfunc_t);
  134 static  void            *ipf_findlookup(ipf_main_softc_t *, int, frentry_t *,
  135                                              i6addr_t *, i6addr_t *);
  136 static  frentry_t       *ipf_firewall(fr_info_t *, u_32_t *);
  137 static  int             ipf_fr_matcharray(fr_info_t *, int *);
  138 static  int             ipf_frruleiter(ipf_main_softc_t *, void *, int,
  139                                             void *);
  140 static  void            ipf_funcfini(ipf_main_softc_t *, frentry_t *);
  141 static  int             ipf_funcinit(ipf_main_softc_t *, frentry_t *);
  142 static  int             ipf_geniter(ipf_main_softc_t *, ipftoken_t *,
  143                                          ipfgeniter_t *);
  144 static  void            ipf_getstat(ipf_main_softc_t *,
  145                                          struct friostat *, int);
  146 static  int             ipf_group_flush(ipf_main_softc_t *, frgroup_t *);
  147 static  void            ipf_group_free(frgroup_t *);
  148 static  int             ipf_grpmapfini(struct ipf_main_softc_s *,
  149                                             frentry_t *);
  150 static  int             ipf_grpmapinit(struct ipf_main_softc_s *,
  151                                             frentry_t *);
  152 static  frentry_t       *ipf_nextrule(ipf_main_softc_t *, int, int,
  153                                            frentry_t *, int);
  154 static  int             ipf_portcheck(frpcmp_t *, u_32_t);
  155 static  inline int      ipf_pr_ah(fr_info_t *);
  156 static  inline void     ipf_pr_esp(fr_info_t *);
  157 static  inline void     ipf_pr_gre(fr_info_t *);
  158 static  inline void     ipf_pr_udp(fr_info_t *);
  159 static  inline void     ipf_pr_tcp(fr_info_t *);
  160 static  inline void     ipf_pr_icmp(fr_info_t *);
  161 static  inline void     ipf_pr_ipv4hdr(fr_info_t *);
  162 static  inline void     ipf_pr_short(fr_info_t *, int);
  163 static  inline int      ipf_pr_tcpcommon(fr_info_t *);
  164 static  inline int      ipf_pr_udpcommon(fr_info_t *);
  165 static  void            ipf_rule_delete(ipf_main_softc_t *, frentry_t *f,
  166                                              int, int);
  167 static  void            ipf_rule_expire_insert(ipf_main_softc_t *,
  168                                                     frentry_t *, int);
  169 static  int             ipf_synclist(ipf_main_softc_t *, frentry_t *,
  170                                           void *);
  171 static  void            ipf_token_flush(ipf_main_softc_t *);
  172 static  void            ipf_token_unlink(ipf_main_softc_t *,
  173                                               ipftoken_t *);
  174 static  ipftuneable_t   *ipf_tune_findbyname(ipftuneable_t *,
  175                                                   const char *);
  176 static  ipftuneable_t   *ipf_tune_findbycookie(ipftuneable_t **, void *,
  177                                                     void **);
  178 static  int             ipf_updateipid(fr_info_t *);
  179 static  int             ipf_settimeout(struct ipf_main_softc_s *,
  180                                             struct ipftuneable *,
  181                                             ipftuneval_t *);
  182 #if !defined(_KERNEL) || SOLARIS
  183 static  int             ppsratecheck(struct timeval *, int *, int);
  184 #endif
  185 
  186 
  187 /*
  188  * bit values for identifying presence of individual IP options
  189  * All of these tables should be ordered by increasing key value on the left
  190  * hand side to allow for binary searching of the array and include a trailer
  191  * with a 0 for the bitmask for linear searches to easily find the end with.
  192  */
  193 static const    struct  optlist ipopts[] = {
  194         { IPOPT_NOP,    0x000001 },
  195         { IPOPT_RR,     0x000002 },
  196         { IPOPT_ZSU,    0x000004 },
  197         { IPOPT_MTUP,   0x000008 },
  198         { IPOPT_MTUR,   0x000010 },
  199         { IPOPT_ENCODE, 0x000020 },
  200         { IPOPT_TS,     0x000040 },
  201         { IPOPT_TR,     0x000080 },
  202         { IPOPT_SECURITY, 0x000100 },
  203         { IPOPT_LSRR,   0x000200 },
  204         { IPOPT_E_SEC,  0x000400 },
  205         { IPOPT_CIPSO,  0x000800 },
  206         { IPOPT_SATID,  0x001000 },
  207         { IPOPT_SSRR,   0x002000 },
  208         { IPOPT_ADDEXT, 0x004000 },
  209         { IPOPT_VISA,   0x008000 },
  210         { IPOPT_IMITD,  0x010000 },
  211         { IPOPT_EIP,    0x020000 },
  212         { IPOPT_FINN,   0x040000 },
  213         { 0,            0x000000 }
  214 };
  215 
  216 #ifdef USE_INET6
  217 static const struct optlist ip6exthdr[] = {
  218         { IPPROTO_HOPOPTS,              0x000001 },
  219         { IPPROTO_IPV6,                 0x000002 },
  220         { IPPROTO_ROUTING,              0x000004 },
  221         { IPPROTO_FRAGMENT,             0x000008 },
  222         { IPPROTO_ESP,                  0x000010 },
  223         { IPPROTO_AH,                   0x000020 },
  224         { IPPROTO_NONE,                 0x000040 },
  225         { IPPROTO_DSTOPTS,              0x000080 },
  226         { IPPROTO_MOBILITY,             0x000100 },
  227         { 0,                            0 }
  228 };
  229 #endif
  230 
  231 /*
  232  * bit values for identifying presence of individual IP security options
  233  */
  234 static const    struct  optlist secopt[] = {
  235         { IPSO_CLASS_RES4,      0x01 },
  236         { IPSO_CLASS_TOPS,      0x02 },
  237         { IPSO_CLASS_SECR,      0x04 },
  238         { IPSO_CLASS_RES3,      0x08 },
  239         { IPSO_CLASS_CONF,      0x10 },
  240         { IPSO_CLASS_UNCL,      0x20 },
  241         { IPSO_CLASS_RES2,      0x40 },
  242         { IPSO_CLASS_RES1,      0x80 }
  243 };
  244 
  245 char    ipfilter_version[] = IPL_VERSION;
  246 
  247 int     ipf_features = 0
  248 #ifdef  IPFILTER_LKM
  249                 | IPF_FEAT_LKM
  250 #endif
  251 #ifdef  IPFILTER_LOG
  252                 | IPF_FEAT_LOG
  253 #endif
  254                 | IPF_FEAT_LOOKUP
  255 #ifdef  IPFILTER_BPF
  256                 | IPF_FEAT_BPF
  257 #endif
  258 #ifdef  IPFILTER_COMPILED
  259                 | IPF_FEAT_COMPILED
  260 #endif
  261 #ifdef  IPFILTER_CKSUM
  262                 | IPF_FEAT_CKSUM
  263 #endif
  264                 | IPF_FEAT_SYNC
  265 #ifdef  IPFILTER_SCAN
  266                 | IPF_FEAT_SCAN
  267 #endif
  268 #ifdef  USE_INET6
  269                 | IPF_FEAT_IPV6
  270 #endif
  271         ;
  272 
  273 
  274 /*
  275  * Table of functions available for use with call rules.
  276  */
  277 static ipfunc_resolve_t ipf_availfuncs[] = {
  278         { "srcgrpmap", ipf_srcgrpmap, ipf_grpmapinit, ipf_grpmapfini },
  279         { "dstgrpmap", ipf_dstgrpmap, ipf_grpmapinit, ipf_grpmapfini },
  280         { "",         NULL,           NULL,           NULL }
  281 };
  282 
  283 static ipftuneable_t ipf_main_tuneables[] = {
  284         { { (void *)offsetof(struct ipf_main_softc_s, ipf_flags) },
  285                 "ipf_flags",            0,      0xffffffff,
  286                 stsizeof(ipf_main_softc_t, ipf_flags),
  287                 0,                      NULL,   NULL },
  288         { { (void *)offsetof(struct ipf_main_softc_s, ipf_active) },
  289                 "active",               0,      0,
  290                 stsizeof(ipf_main_softc_t, ipf_active),
  291                 IPFT_RDONLY,            NULL,   NULL },
  292         { { (void *)offsetof(ipf_main_softc_t, ipf_control_forwarding) },
  293                 "control_forwarding",   0, 1,
  294                 stsizeof(ipf_main_softc_t, ipf_control_forwarding),
  295                 0,                      NULL,   NULL },
  296         { { (void *)offsetof(ipf_main_softc_t, ipf_update_ipid) },
  297                 "update_ipid",          0,      1,
  298                 stsizeof(ipf_main_softc_t, ipf_update_ipid),
  299                 0,                      NULL,   NULL },
  300         { { (void *)offsetof(ipf_main_softc_t, ipf_chksrc) },
  301                 "chksrc",               0,      1,
  302                 stsizeof(ipf_main_softc_t, ipf_chksrc),
  303                 0,                      NULL,   NULL },
  304         { { (void *)offsetof(ipf_main_softc_t, ipf_minttl) },
  305                 "min_ttl",              0,      1,
  306                 stsizeof(ipf_main_softc_t, ipf_minttl),
  307                 0,                      NULL,   NULL },
  308         { { (void *)offsetof(ipf_main_softc_t, ipf_icmpminfragmtu) },
  309                 "icmp_minfragmtu",      0,      1,
  310                 stsizeof(ipf_main_softc_t, ipf_icmpminfragmtu),
  311                 0,                      NULL,   NULL },
  312         { { (void *)offsetof(ipf_main_softc_t, ipf_pass) },
  313                 "default_pass",         0,      0xffffffff,
  314                 stsizeof(ipf_main_softc_t, ipf_pass),
  315                 0,                      NULL,   NULL },
  316         { { (void *)offsetof(ipf_main_softc_t, ipf_tcpidletimeout) },
  317                 "tcp_idle_timeout",     1,      0x7fffffff,
  318                 stsizeof(ipf_main_softc_t, ipf_tcpidletimeout),
  319                 0,                      NULL,   ipf_settimeout },
  320         { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosewait) },
  321                 "tcp_close_wait",       1,      0x7fffffff,
  322                 stsizeof(ipf_main_softc_t, ipf_tcpclosewait),
  323                 0,                      NULL,   ipf_settimeout },
  324         { { (void *)offsetof(ipf_main_softc_t, ipf_tcplastack) },
  325                 "tcp_last_ack",         1,      0x7fffffff,
  326                 stsizeof(ipf_main_softc_t, ipf_tcplastack),
  327                 0,                      NULL,   ipf_settimeout },
  328         { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimeout) },
  329                 "tcp_timeout",          1,      0x7fffffff,
  330                 stsizeof(ipf_main_softc_t, ipf_tcptimeout),
  331                 0,                      NULL,   ipf_settimeout },
  332         { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynsent) },
  333                 "tcp_syn_sent",         1,      0x7fffffff,
  334                 stsizeof(ipf_main_softc_t, ipf_tcpsynsent),
  335                 0,                      NULL,   ipf_settimeout },
  336         { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynrecv) },
  337                 "tcp_syn_received",     1,      0x7fffffff,
  338                 stsizeof(ipf_main_softc_t, ipf_tcpsynrecv),
  339                 0,                      NULL,   ipf_settimeout },
  340         { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosed) },
  341                 "tcp_closed",           1,      0x7fffffff,
  342                 stsizeof(ipf_main_softc_t, ipf_tcpclosed),
  343                 0,                      NULL,   ipf_settimeout },
  344         { { (void *)offsetof(ipf_main_softc_t, ipf_tcphalfclosed) },
  345                 "tcp_half_closed",      1,      0x7fffffff,
  346                 stsizeof(ipf_main_softc_t, ipf_tcphalfclosed),
  347                 0,                      NULL,   ipf_settimeout },
  348         { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimewait) },
  349                 "tcp_time_wait",        1,      0x7fffffff,
  350                 stsizeof(ipf_main_softc_t, ipf_tcptimewait),
  351                 0,                      NULL,   ipf_settimeout },
  352         { { (void *)offsetof(ipf_main_softc_t, ipf_udptimeout) },
  353                 "udp_timeout",          1,      0x7fffffff,
  354                 stsizeof(ipf_main_softc_t, ipf_udptimeout),
  355                 0,                      NULL,   ipf_settimeout },
  356         { { (void *)offsetof(ipf_main_softc_t, ipf_udpacktimeout) },
  357                 "udp_ack_timeout",      1,      0x7fffffff,
  358                 stsizeof(ipf_main_softc_t, ipf_udpacktimeout),
  359                 0,                      NULL,   ipf_settimeout },
  360         { { (void *)offsetof(ipf_main_softc_t, ipf_icmptimeout) },
  361                 "icmp_timeout",         1,      0x7fffffff,
  362                 stsizeof(ipf_main_softc_t, ipf_icmptimeout),
  363                 0,                      NULL,   ipf_settimeout },
  364         { { (void *)offsetof(ipf_main_softc_t, ipf_icmpacktimeout) },
  365                 "icmp_ack_timeout",     1,      0x7fffffff,
  366                 stsizeof(ipf_main_softc_t, ipf_icmpacktimeout),
  367                 0,                      NULL,   ipf_settimeout },
  368         { { (void *)offsetof(ipf_main_softc_t, ipf_iptimeout) },
  369                 "ip_timeout",           1,      0x7fffffff,
  370                 stsizeof(ipf_main_softc_t, ipf_iptimeout),
  371                 0,                      NULL,   ipf_settimeout },
  372 #if defined(INSTANCES) && defined(_KERNEL)
  373         { { (void *)offsetof(ipf_main_softc_t, ipf_get_loopback) },
  374                 "intercept_loopback",   0,      1,
  375                 stsizeof(ipf_main_softc_t, ipf_get_loopback),
  376                 0,                      NULL,   ipf_set_loopback },
  377 #endif
  378         { { 0 },
  379                 NULL,                   0,      0,
  380                 0,
  381                 0,                      NULL,   NULL }
  382 };
  383 
  384 
  385 /*
  386  * The next section of code is a collection of small routines that set
  387  * fields in the fr_info_t structure passed based on properties of the
  388  * current packet.  There are different routines for the same protocol
  389  * for each of IPv4 and IPv6.  Adding a new protocol, for which there
  390  * will "special" inspection for setup, is now more easily done by adding
  391  * a new routine and expanding the ipf_pr_ipinit*() function rather than by
  392  * adding more code to a growing switch statement.
  393  */
  394 #ifdef USE_INET6
  395 static  inline int      ipf_pr_ah6(fr_info_t *);
  396 static  inline void     ipf_pr_esp6(fr_info_t *);
  397 static  inline void     ipf_pr_gre6(fr_info_t *);
  398 static  inline void     ipf_pr_udp6(fr_info_t *);
  399 static  inline void     ipf_pr_tcp6(fr_info_t *);
  400 static  inline void     ipf_pr_icmp6(fr_info_t *);
  401 static  inline void     ipf_pr_ipv6hdr(fr_info_t *);
  402 static  inline void     ipf_pr_short6(fr_info_t *, int);
  403 static  inline int      ipf_pr_hopopts6(fr_info_t *);
  404 static  inline int      ipf_pr_mobility6(fr_info_t *);
  405 static  inline int      ipf_pr_routing6(fr_info_t *);
  406 static  inline int      ipf_pr_dstopts6(fr_info_t *);
  407 static  inline int      ipf_pr_fragment6(fr_info_t *);
  408 static  inline struct ip6_ext *ipf_pr_ipv6exthdr(fr_info_t *, int, int);
  409 
  410 
  411 /* ------------------------------------------------------------------------ */
  412 /* Function:    ipf_pr_short6                                               */
  413 /* Returns:     void                                                        */
  414 /* Parameters:  fin(I)  - pointer to packet information                     */
  415 /*              xmin(I) - minimum header size                               */
  416 /*                                                                          */
  417 /* IPv6 Only                                                                */
  418 /* This is function enforces the 'is a packet too short to be legit' rule   */
  419 /* for IPv6 and marks the packet with FI_SHORT if so.  See function comment */
  420 /* for ipf_pr_short() for more details.                                     */
  421 /* ------------------------------------------------------------------------ */
  422 static inline void
  423 ipf_pr_short6(fr_info_t *fin, int xmin)
  424 {
  425 
  426         if (fin->fin_dlen < xmin)
  427                 fin->fin_flx |= FI_SHORT;
  428 }
  429 
  430 
  431 /* ------------------------------------------------------------------------ */
  432 /* Function:    ipf_pr_ipv6hdr                                              */
  433 /* Returns:     void                                                        */
  434 /* Parameters:  fin(I) - pointer to packet information                      */
  435 /*                                                                          */
  436 /* IPv6 Only                                                                */
  437 /* Copy values from the IPv6 header into the fr_info_t struct and call the  */
  438 /* per-protocol analyzer if it exists.  In validating the packet, a protocol*/
  439 /* analyzer may pullup or free the packet itself so we need to be vigiliant */
  440 /* of that possibility arising.                                             */
  441 /* ------------------------------------------------------------------------ */
  442 static inline void
  443 ipf_pr_ipv6hdr(fr_info_t *fin)
  444 {
  445         ip6_t *ip6 = (ip6_t *)fin->fin_ip;
  446         int p, go = 1, i, hdrcount;
  447         fr_ip_t *fi = &fin->fin_fi;
  448 
  449         fin->fin_off = 0;
  450 
  451         fi->fi_tos = 0;
  452         fi->fi_optmsk = 0;
  453         fi->fi_secmsk = 0;
  454         fi->fi_auth = 0;
  455 
  456         p = ip6->ip6_nxt;
  457         fin->fin_crc = p;
  458         fi->fi_ttl = ip6->ip6_hlim;
  459         fi->fi_src.in6 = ip6->ip6_src;
  460         fin->fin_crc += fi->fi_src.i6[0];
  461         fin->fin_crc += fi->fi_src.i6[1];
  462         fin->fin_crc += fi->fi_src.i6[2];
  463         fin->fin_crc += fi->fi_src.i6[3];
  464         fi->fi_dst.in6 = ip6->ip6_dst;
  465         fin->fin_crc += fi->fi_dst.i6[0];
  466         fin->fin_crc += fi->fi_dst.i6[1];
  467         fin->fin_crc += fi->fi_dst.i6[2];
  468         fin->fin_crc += fi->fi_dst.i6[3];
  469         fin->fin_id = 0;
  470         if (IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6))
  471                 fin->fin_flx |= FI_MULTICAST|FI_MBCAST;
  472 
  473         hdrcount = 0;
  474         while (go && !(fin->fin_flx & FI_SHORT)) {
  475                 switch (p)
  476                 {
  477                 case IPPROTO_UDP :
  478                         ipf_pr_udp6(fin);
  479                         go = 0;
  480                         break;
  481 
  482                 case IPPROTO_TCP :
  483                         ipf_pr_tcp6(fin);
  484                         go = 0;
  485                         break;
  486 
  487                 case IPPROTO_ICMPV6 :
  488                         ipf_pr_icmp6(fin);
  489                         go = 0;
  490                         break;
  491 
  492                 case IPPROTO_GRE :
  493                         ipf_pr_gre6(fin);
  494                         go = 0;
  495                         break;
  496 
  497                 case IPPROTO_HOPOPTS :
  498                         p = ipf_pr_hopopts6(fin);
  499                         break;
  500 
  501                 case IPPROTO_MOBILITY :
  502                         p = ipf_pr_mobility6(fin);
  503                         break;
  504 
  505                 case IPPROTO_DSTOPTS :
  506                         p = ipf_pr_dstopts6(fin);
  507                         break;
  508 
  509                 case IPPROTO_ROUTING :
  510                         p = ipf_pr_routing6(fin);
  511                         break;
  512 
  513                 case IPPROTO_AH :
  514                         p = ipf_pr_ah6(fin);
  515                         break;
  516 
  517                 case IPPROTO_ESP :
  518                         ipf_pr_esp6(fin);
  519                         go = 0;
  520                         break;
  521 
  522                 case IPPROTO_IPV6 :
  523                         for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
  524                                 if (ip6exthdr[i].ol_val == p) {
  525                                         fin->fin_flx |= ip6exthdr[i].ol_bit;
  526                                         break;
  527                                 }
  528                         go = 0;
  529                         break;
  530 
  531                 case IPPROTO_NONE :
  532                         go = 0;
  533                         break;
  534 
  535                 case IPPROTO_FRAGMENT :
  536                         p = ipf_pr_fragment6(fin);
  537                         /*
  538                          * Given that the only fragments we want to let through
  539                          * (where fin_off != 0) are those where the non-first
  540                          * fragments only have data, we can safely stop looking
  541                          * at headers if this is a non-leading fragment.
  542                          */
  543                         if (fin->fin_off != 0)
  544                                 go = 0;
  545                         break;
  546 
  547                 default :
  548                         go = 0;
  549                         break;
  550                 }
  551                 hdrcount++;
  552 
  553                 /*
  554                  * It is important to note that at this point, for the
  555                  * extension headers (go != 0), the entire header may not have
  556                  * been pulled up when the code gets to this point.  This is
  557                  * only done for "go != 0" because the other header handlers
  558                  * will all pullup their complete header.  The other indicator
  559                  * of an incomplete packet is that this was just an extension
  560                  * header.
  561                  */
  562                 if ((go != 0) && (p != IPPROTO_NONE) &&
  563                     (ipf_pr_pullup(fin, 0) == -1)) {
  564                         p = IPPROTO_NONE;
  565                         break;
  566                 }
  567         }
  568 
  569         /*
  570          * Some of the above functions, like ipf_pr_esp6(), can call ipf_pullup
  571          * and destroy whatever packet was here.  The caller of this function
  572          * expects us to return if there is a problem with ipf_pullup.
  573          */
  574         if (fin->fin_m == NULL) {
  575                 ipf_main_softc_t *softc = fin->fin_main_soft;
  576 
  577                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_bad);
  578                 return;
  579         }
  580 
  581         fi->fi_p = p;
  582 
  583         /*
  584          * IPv6 fragment case 1 - see comment for ipf_pr_fragment6().
  585          * "go != 0" implies the above loop hasn't arrived at a layer 4 header.
  586          */
  587         if ((go != 0) && (fin->fin_flx & FI_FRAG) && (fin->fin_off == 0)) {
  588                 ipf_main_softc_t *softc = fin->fin_main_soft;
  589 
  590                 fin->fin_flx |= FI_BAD;
  591                 DT2(ipf_fi_bad_ipv6_frag_1, fr_info_t *, fin, int, go);
  592                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_badfrag);
  593                 LBUMP(ipf_stats[fin->fin_out].fr_v6_bad);
  594         }
  595 }
  596 
  597 
  598 /* ------------------------------------------------------------------------ */
  599 /* Function:    ipf_pr_ipv6exthdr                                           */
  600 /* Returns:     struct ip6_ext * - pointer to the start of the next header  */
  601 /*                                 or NULL if there is a prolblem.          */
  602 /* Parameters:  fin(I)      - pointer to packet information                 */
  603 /*              multiple(I) - flag indicating yes/no if multiple occurances */
  604 /*                            of this extension header are allowed.         */
  605 /*              proto(I)    - protocol number for this extension header     */
  606 /*                                                                          */
  607 /* IPv6 Only                                                                */
  608 /* This function embodies a number of common checks that all IPv6 extension */
  609 /* headers must be subjected to.  For example, making sure the packet is    */
  610 /* big enough for it to be in, checking if it is repeated and setting a     */
  611 /* flag to indicate its presence.                                           */
  612 /* ------------------------------------------------------------------------ */
  613 static inline struct ip6_ext *
  614 ipf_pr_ipv6exthdr(fr_info_t *fin, int multiple, int proto)
  615 {
  616         ipf_main_softc_t *softc = fin->fin_main_soft;
  617         struct ip6_ext *hdr;
  618         u_short shift;
  619         int i;
  620 
  621         fin->fin_flx |= FI_V6EXTHDR;
  622 
  623                                 /* 8 is default length of extension hdr */
  624         if ((fin->fin_dlen - 8) < 0) {
  625                 fin->fin_flx |= FI_SHORT;
  626                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_short);
  627                 return (NULL);
  628         }
  629 
  630         if (ipf_pr_pullup(fin, 8) == -1) {
  631                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_pullup);
  632                 return (NULL);
  633         }
  634 
  635         hdr = fin->fin_dp;
  636         switch (proto)
  637         {
  638         case IPPROTO_FRAGMENT :
  639                 shift = 8;
  640                 break;
  641         default :
  642                 shift = 8 + (hdr->ip6e_len << 3);
  643                 break;
  644         }
  645 
  646         if (shift > fin->fin_dlen) {    /* Nasty extension header length? */
  647                 fin->fin_flx |= FI_BAD;
  648                 DT3(ipf_fi_bad_pr_ipv6exthdr_len, fr_info_t *, fin, u_short, shift, u_short, fin->fin_dlen);
  649                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_hlen);
  650                 return (NULL);
  651         }
  652 
  653         fin->fin_dp = (char *)fin->fin_dp + shift;
  654         fin->fin_dlen -= shift;
  655 
  656         /*
  657          * If we have seen a fragment header, do not set any flags to indicate
  658          * the presence of this extension header as it has no impact on the
  659          * end result until after it has been defragmented.
  660          */
  661         if (fin->fin_flx & FI_FRAG)
  662                 return (hdr);
  663 
  664         for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
  665                 if (ip6exthdr[i].ol_val == proto) {
  666                         /*
  667                          * Most IPv6 extension headers are only allowed once.
  668                          */
  669                         if ((multiple == 0) &&
  670                             ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0)) {
  671                                 fin->fin_flx |= FI_BAD;
  672                                 DT2(ipf_fi_bad_ipv6exthdr_once, fr_info_t *, fin, u_int, (fin->fin_optmsk & ip6exthdr[i].ol_bit));
  673                         } else
  674                                 fin->fin_optmsk |= ip6exthdr[i].ol_bit;
  675                         break;
  676                 }
  677 
  678         return (hdr);
  679 }
  680 
  681 
  682 /* ------------------------------------------------------------------------ */
  683 /* Function:    ipf_pr_hopopts6                                             */
  684 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
  685 /* Parameters:  fin(I) - pointer to packet information                      */
  686 /*                                                                          */
  687 /* IPv6 Only                                                                */
  688 /* This is function checks pending hop by hop options extension header      */
  689 /* ------------------------------------------------------------------------ */
  690 static inline int
  691 ipf_pr_hopopts6(fr_info_t *fin)
  692 {
  693         struct ip6_ext *hdr;
  694 
  695         hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
  696         if (hdr == NULL)
  697                 return (IPPROTO_NONE);
  698         return (hdr->ip6e_nxt);
  699 }
  700 
  701 
  702 /* ------------------------------------------------------------------------ */
  703 /* Function:    ipf_pr_mobility6                                            */
  704 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
  705 /* Parameters:  fin(I) - pointer to packet information                      */
  706 /*                                                                          */
  707 /* IPv6 Only                                                                */
  708 /* This is function checks the IPv6 mobility extension header               */
  709 /* ------------------------------------------------------------------------ */
  710 static inline int
  711 ipf_pr_mobility6(fr_info_t *fin)
  712 {
  713         struct ip6_ext *hdr;
  714 
  715         hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY);
  716         if (hdr == NULL)
  717                 return (IPPROTO_NONE);
  718         return (hdr->ip6e_nxt);
  719 }
  720 
  721 
  722 /* ------------------------------------------------------------------------ */
  723 /* Function:    ipf_pr_routing6                                             */
  724 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
  725 /* Parameters:  fin(I) - pointer to packet information                      */
  726 /*                                                                          */
  727 /* IPv6 Only                                                                */
  728 /* This is function checks pending routing extension header                 */
  729 /* ------------------------------------------------------------------------ */
  730 static inline int
  731 ipf_pr_routing6(fr_info_t *fin)
  732 {
  733         struct ip6_routing *hdr;
  734 
  735         hdr = (struct ip6_routing *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_ROUTING);
  736         if (hdr == NULL)
  737                 return (IPPROTO_NONE);
  738 
  739         switch (hdr->ip6r_type)
  740         {
  741         case 0 :
  742                 /*
  743                  * Nasty extension header length?
  744                  */
  745                 if (((hdr->ip6r_len >> 1) < hdr->ip6r_segleft) ||
  746                     (hdr->ip6r_segleft && (hdr->ip6r_len & 1))) {
  747                         ipf_main_softc_t *softc = fin->fin_main_soft;
  748 
  749                         fin->fin_flx |= FI_BAD;
  750                         DT1(ipf_fi_bad_routing6, fr_info_t *, fin);
  751                         LBUMPD(ipf_stats[fin->fin_out], fr_v6_rh_bad);
  752                         return (IPPROTO_NONE);
  753                 }
  754                 break;
  755 
  756         default :
  757                 break;
  758         }
  759 
  760         return (hdr->ip6r_nxt);
  761 }
  762 
  763 
  764 /* ------------------------------------------------------------------------ */
  765 /* Function:    ipf_pr_fragment6                                            */
  766 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
  767 /* Parameters:  fin(I) - pointer to packet information                      */
  768 /*                                                                          */
  769 /* IPv6 Only                                                                */
  770 /* Examine the IPv6 fragment header and extract fragment offset information.*/
  771 /*                                                                          */
  772 /* Fragments in IPv6 are extraordinarily difficult to deal with - much more */
  773 /* so than in IPv4.  There are 5 cases of fragments with IPv6 that all      */
  774 /* packets with a fragment header can fit into.  They are as follows:       */
  775 /*                                                                          */
  776 /* 1.  [IPv6][0-n EH][FH][0-n EH] (no L4HDR present)                        */
  777 /* 2.  [IPV6][0-n EH][FH][0-n EH][L4HDR part] (short)                       */
  778 /* 3.  [IPV6][0-n EH][FH][L4HDR part][0-n data] (short)                     */
  779 /* 4.  [IPV6][0-n EH][FH][0-n EH][L4HDR][0-n data]                          */
  780 /* 5.  [IPV6][0-n EH][FH][data]                                             */
  781 /*                                                                          */
  782 /* IPV6 = IPv6 header, FH = Fragment Header,                                */
  783 /* 0-n EH = 0 or more extension headers, 0-n data = 0 or more bytes of data */
  784 /*                                                                          */
  785 /* Packets that match 1, 2, 3 will be dropped as the only reasonable        */
  786 /* scenario in which they happen is in extreme circumstances that are most  */
  787 /* likely to be an indication of an attack rather than normal traffic.      */
  788 /* A type 3 packet may be sent by an attacked after a type 4 packet.  There */
  789 /* are two rules that can be used to guard against type 3 packets: L4       */
  790 /* headers must always be in a packet that has the offset field set to 0    */
  791 /* and no packet is allowed to overlay that where offset = 0.               */
  792 /* ------------------------------------------------------------------------ */
  793 static inline int
  794 ipf_pr_fragment6(fr_info_t *fin)
  795 {
  796         ipf_main_softc_t *softc = fin->fin_main_soft;
  797         struct ip6_frag *frag;
  798 
  799         fin->fin_flx |= FI_FRAG;
  800 
  801         frag = (struct ip6_frag *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT);
  802         if (frag == NULL) {
  803                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_frag_bad);
  804                 return (IPPROTO_NONE);
  805         }
  806 
  807         if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0) {
  808                 /*
  809                  * Any fragment that isn't the last fragment must have its
  810                  * length as a multiple of 8.
  811                  */
  812                 if ((fin->fin_plen & 7) != 0) {
  813                         fin->fin_flx |= FI_BAD;
  814                         DT2(ipf_fi_bad_frag_not_8, fr_info_t *, fin, u_int, (fin->fin_plen & 7));
  815                 }
  816         }
  817 
  818         fin->fin_fraghdr = frag;
  819         fin->fin_id = frag->ip6f_ident;
  820         fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK);
  821         if (fin->fin_off != 0)
  822                 fin->fin_flx |= FI_FRAGBODY;
  823 
  824         /*
  825          * Jumbograms aren't handled, so the max. length is 64k
  826          */
  827         if ((fin->fin_off << 3) + fin->fin_dlen > 65535) {
  828                   fin->fin_flx |= FI_BAD;
  829                   DT2(ipf_fi_bad_jumbogram, fr_info_t *, fin, u_int, ((fin->fin_off << 3) + fin->fin_dlen));
  830         }
  831 
  832         /*
  833          * We don't know where the transport layer header (or whatever is next
  834          * is), as it could be behind destination options (amongst others) so
  835         * return the fragment header as the type of packet this is.  Note that
  836          * this effectively disables the fragment cache for > 1 protocol at a
  837          * time.
  838          */
  839         return (frag->ip6f_nxt);
  840 }
  841 
  842 
  843 /* ------------------------------------------------------------------------ */
  844 /* Function:    ipf_pr_dstopts6                                             */
  845 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
  846 /* Parameters:  fin(I) - pointer to packet information                      */
  847 /*                                                                          */
  848 /* IPv6 Only                                                                */
  849 /* This is function checks pending destination options extension header     */
  850 /* ------------------------------------------------------------------------ */
  851 static inline int
  852 ipf_pr_dstopts6(fr_info_t *fin)
  853 {
  854         ipf_main_softc_t *softc = fin->fin_main_soft;
  855         struct ip6_ext *hdr;
  856 
  857         hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_DSTOPTS);
  858         if (hdr == NULL) {
  859                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_dst_bad);
  860                 return (IPPROTO_NONE);
  861         }
  862         return (hdr->ip6e_nxt);
  863 }
  864 
  865 
  866 /* ------------------------------------------------------------------------ */
  867 /* Function:    ipf_pr_icmp6                                                */
  868 /* Returns:     void                                                        */
  869 /* Parameters:  fin(I) - pointer to packet information                      */
  870 /*                                                                          */
  871 /* IPv6 Only                                                                */
  872 /* This routine is mainly concerned with determining the minimum valid size */
  873 /* for an ICMPv6 packet.                                                    */
  874 /* ------------------------------------------------------------------------ */
  875 static inline void
  876 ipf_pr_icmp6(fr_info_t *fin)
  877 {
  878         int minicmpsz = sizeof(struct icmp6_hdr);
  879         struct icmp6_hdr *icmp6;
  880 
  881         if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) {
  882                 ipf_main_softc_t *softc = fin->fin_main_soft;
  883 
  884                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_icmp6_pullup);
  885                 return;
  886         }
  887 
  888         if (fin->fin_dlen > 1) {
  889                 ip6_t *ip6;
  890 
  891                 icmp6 = fin->fin_dp;
  892 
  893                 fin->fin_data[0] = *(u_short *)icmp6;
  894 
  895                 if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0)
  896                         fin->fin_flx |= FI_ICMPQUERY;
  897 
  898                 switch (icmp6->icmp6_type)
  899                 {
  900                 case ICMP6_ECHO_REPLY :
  901                 case ICMP6_ECHO_REQUEST :
  902                         if (fin->fin_dlen >= 6)
  903                                 fin->fin_data[1] = icmp6->icmp6_id;
  904                         minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t);
  905                         break;
  906 
  907                 case ICMP6_DST_UNREACH :
  908                 case ICMP6_PACKET_TOO_BIG :
  909                 case ICMP6_TIME_EXCEEDED :
  910                 case ICMP6_PARAM_PROB :
  911                         fin->fin_flx |= FI_ICMPERR;
  912                         minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t);
  913                         if (fin->fin_plen < ICMP6ERR_IPICMPHLEN)
  914                                 break;
  915 
  916                         if (M_LEN(fin->fin_m) < fin->fin_plen) {
  917                                 if (ipf_coalesce(fin) != 1)
  918                                         return;
  919                         }
  920 
  921                         if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN) == -1)
  922                                 return;
  923 
  924                         /*
  925                          * If the destination of this packet doesn't match the
  926                          * source of the original packet then this packet is
  927                          * not correct.
  928                          */
  929                         icmp6 = fin->fin_dp;
  930                         ip6 = (ip6_t *)((char *)icmp6 + ICMPERR_ICMPHLEN);
  931                         if (IP6_NEQ(&fin->fin_fi.fi_dst,
  932                                     (i6addr_t *)&ip6->ip6_src)) {
  933                                 fin->fin_flx |= FI_BAD;
  934                                 DT1(ipf_fi_bad_icmp6, fr_info_t *, fin);
  935                         }
  936                         break;
  937                 default :
  938                         break;
  939                 }
  940         }
  941 
  942         ipf_pr_short6(fin, minicmpsz);
  943         if ((fin->fin_flx & (FI_SHORT|FI_BAD)) == 0) {
  944                 u_char p = fin->fin_p;
  945 
  946                 fin->fin_p = IPPROTO_ICMPV6;
  947                 ipf_checkv6sum(fin);
  948                 fin->fin_p = p;
  949         }
  950 }
  951 
  952 
  953 /* ------------------------------------------------------------------------ */
  954 /* Function:    ipf_pr_udp6                                                 */
  955 /* Returns:     void                                                        */
  956 /* Parameters:  fin(I) - pointer to packet information                      */
  957 /*                                                                          */
  958 /* IPv6 Only                                                                */
  959 /* Analyse the packet for IPv6/UDP properties.                              */
  960 /* Is not expected to be called for fragmented packets.                     */
  961 /* ------------------------------------------------------------------------ */
  962 static inline void
  963 ipf_pr_udp6(fr_info_t *fin)
  964 {
  965 
  966         if (ipf_pr_udpcommon(fin) == 0) {
  967                 u_char p = fin->fin_p;
  968 
  969                 fin->fin_p = IPPROTO_UDP;
  970                 ipf_checkv6sum(fin);
  971                 fin->fin_p = p;
  972         }
  973 }
  974 
  975 
  976 /* ------------------------------------------------------------------------ */
  977 /* Function:    ipf_pr_tcp6                                                 */
  978 /* Returns:     void                                                        */
  979 /* Parameters:  fin(I) - pointer to packet information                      */
  980 /*                                                                          */
  981 /* IPv6 Only                                                                */
  982 /* Analyse the packet for IPv6/TCP properties.                              */
  983 /* Is not expected to be called for fragmented packets.                     */
  984 /* ------------------------------------------------------------------------ */
  985 static inline void
  986 ipf_pr_tcp6(fr_info_t *fin)
  987 {
  988 
  989         if (ipf_pr_tcpcommon(fin) == 0) {
  990                 u_char p = fin->fin_p;
  991 
  992                 fin->fin_p = IPPROTO_TCP;
  993                 ipf_checkv6sum(fin);
  994                 fin->fin_p = p;
  995         }
  996 }
  997 
  998 
  999 /* ------------------------------------------------------------------------ */
 1000 /* Function:    ipf_pr_esp6                                                 */
 1001 /* Returns:     void                                                        */
 1002 /* Parameters:  fin(I) - pointer to packet information                      */
 1003 /*                                                                          */
 1004 /* IPv6 Only                                                                */
 1005 /* Analyse the packet for ESP properties.                                   */
 1006 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits)  */
 1007 /* even though the newer ESP packets must also have a sequence number that  */
 1008 /* is 32bits as well, it is not possible(?) to determine the version from a */
 1009 /* simple packet header.                                                    */
 1010 /* ------------------------------------------------------------------------ */
 1011 static inline void
 1012 ipf_pr_esp6(fr_info_t *fin)
 1013 {
 1014 
 1015         if ((fin->fin_off == 0) && (ipf_pr_pullup(fin, 8) == -1)) {
 1016                 ipf_main_softc_t *softc = fin->fin_main_soft;
 1017 
 1018                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_esp_pullup);
 1019                 return;
 1020         }
 1021 }
 1022 
 1023 
 1024 /* ------------------------------------------------------------------------ */
 1025 /* Function:    ipf_pr_ah6                                                  */
 1026 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
 1027 /* Parameters:  fin(I) - pointer to packet information                      */
 1028 /*                                                                          */
 1029 /* IPv6 Only                                                                */
 1030 /* Analyse the packet for AH properties.                                    */
 1031 /* The minimum length is taken to be the combination of all fields in the   */
 1032 /* header being present and no authentication data (null algorithm used.)   */
 1033 /* ------------------------------------------------------------------------ */
 1034 static inline int
 1035 ipf_pr_ah6(fr_info_t *fin)
 1036 {
 1037         authhdr_t *ah;
 1038 
 1039         fin->fin_flx |= FI_AH;
 1040 
 1041         ah = (authhdr_t *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
 1042         if (ah == NULL) {
 1043                 ipf_main_softc_t *softc = fin->fin_main_soft;
 1044 
 1045                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ah_bad);
 1046                 return (IPPROTO_NONE);
 1047         }
 1048 
 1049         ipf_pr_short6(fin, sizeof(*ah));
 1050 
 1051         /*
 1052          * No need for another pullup, ipf_pr_ipv6exthdr() will pullup
 1053          * enough data to satisfy ah_next (the very first one.)
 1054          */
 1055         return (ah->ah_next);
 1056 }
 1057 
 1058 
 1059 /* ------------------------------------------------------------------------ */
 1060 /* Function:    ipf_pr_gre6                                                 */
 1061 /* Returns:     void                                                        */
 1062 /* Parameters:  fin(I) - pointer to packet information                      */
 1063 /*                                                                          */
 1064 /* Analyse the packet for GRE properties.                                   */
 1065 /* ------------------------------------------------------------------------ */
 1066 static inline void
 1067 ipf_pr_gre6(fr_info_t *fin)
 1068 {
 1069         grehdr_t *gre;
 1070 
 1071         if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) {
 1072                 ipf_main_softc_t *softc = fin->fin_main_soft;
 1073 
 1074                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_gre_pullup);
 1075                 return;
 1076         }
 1077 
 1078         gre = fin->fin_dp;
 1079         if (GRE_REV(gre->gr_flags) == 1)
 1080                 fin->fin_data[0] = gre->gr_call;
 1081 }
 1082 #endif  /* USE_INET6 */
 1083 
 1084 
 1085 /* ------------------------------------------------------------------------ */
 1086 /* Function:    ipf_pr_pullup                                               */
 1087 /* Returns:     int     - 0 == pullup succeeded, -1 == failure              */
 1088 /* Parameters:  fin(I)  - pointer to packet information                     */
 1089 /*              plen(I) - length (excluding L3 header) to pullup            */
 1090 /*                                                                          */
 1091 /* Short inline function to cut down on code duplication to perform a call  */
 1092 /* to ipf_pullup to ensure there is the required amount of data,            */
 1093 /* consecutively in the packet buffer.                                      */
 1094 /*                                                                          */
 1095 /* This function pulls up 'extra' data at the location of fin_dp.  fin_dp   */
 1096 /* points to the first byte after the complete layer 3 header, which will   */
 1097 /* include all of the known extension headers for IPv6 or options for IPv4. */
 1098 /*                                                                          */
 1099 /* Since fr_pullup() expects the total length of bytes to be pulled up, it  */
 1100 /* is necessary to add those we can already assume to be pulled up (fin_dp  */
 1101 /* - fin_ip) to what is passed through.                                     */
 1102 /* ------------------------------------------------------------------------ */
 1103 int
 1104 ipf_pr_pullup(fr_info_t *fin, int plen)
 1105 {
 1106         ipf_main_softc_t *softc = fin->fin_main_soft;
 1107 
 1108         if (fin->fin_m != NULL) {
 1109                 if (fin->fin_dp != NULL)
 1110                         plen += (char *)fin->fin_dp -
 1111                                 ((char *)fin->fin_ip + fin->fin_hlen);
 1112                 plen += fin->fin_hlen;
 1113                 if (M_LEN(fin->fin_m) < plen + fin->fin_ipoff) {
 1114 #if defined(_KERNEL)
 1115                         if (ipf_pullup(fin->fin_m, fin, plen) == NULL) {
 1116                                 DT(ipf_pullup_fail);
 1117                                 LBUMP(ipf_stats[fin->fin_out].fr_pull[1]);
 1118                                 return (-1);
 1119                         }
 1120                         LBUMP(ipf_stats[fin->fin_out].fr_pull[0]);
 1121 #else
 1122                         LBUMP(ipf_stats[fin->fin_out].fr_pull[1]);
 1123                         /*
 1124                          * Fake ipf_pullup failing
 1125                          */
 1126                         fin->fin_reason = FRB_PULLUP;
 1127                         *fin->fin_mp = NULL;
 1128                         fin->fin_m = NULL;
 1129                         fin->fin_ip = NULL;
 1130                         return (-1);
 1131 #endif
 1132                 }
 1133         }
 1134         return (0);
 1135 }
 1136 
 1137 
 1138 /* ------------------------------------------------------------------------ */
 1139 /* Function:    ipf_pr_short                                                */
 1140 /* Returns:     void                                                        */
 1141 /* Parameters:  fin(I)  - pointer to packet information                     */
 1142 /*              xmin(I) - minimum header size                               */
 1143 /*                                                                          */
 1144 /* Check if a packet is "short" as defined by xmin.  The rule we are        */
 1145 /* applying here is that the packet must not be fragmented within the layer */
 1146 /* 4 header.  That is, it must not be a fragment that has its offset set to */
 1147 /* start within the layer 4 header (hdrmin) or if it is at offset 0, the    */
 1148 /* entire layer 4 header must be present (min).                             */
 1149 /* ------------------------------------------------------------------------ */
 1150 static inline void
 1151 ipf_pr_short(fr_info_t *fin, int xmin)
 1152 {
 1153 
 1154         if (fin->fin_off == 0) {
 1155                 if (fin->fin_dlen < xmin)
 1156                         fin->fin_flx |= FI_SHORT;
 1157         } else if (fin->fin_off < xmin) {
 1158                 fin->fin_flx |= FI_SHORT;
 1159         }
 1160 }
 1161 
 1162 
 1163 /* ------------------------------------------------------------------------ */
 1164 /* Function:    ipf_pr_icmp                                                 */
 1165 /* Returns:     void                                                        */
 1166 /* Parameters:  fin(I) - pointer to packet information                      */
 1167 /*                                                                          */
 1168 /* IPv4 Only                                                                */
 1169 /* Do a sanity check on the packet for ICMP (v4).  In nearly all cases,     */
 1170 /* except extrememly bad packets, both type and code will be present.       */
 1171 /* The expected minimum size of an ICMP packet is very much dependent on    */
 1172 /* the type of it.                                                          */
 1173 /*                                                                          */
 1174 /* XXX - other ICMP sanity checks?                                          */
 1175 /* ------------------------------------------------------------------------ */
 1176 static inline void
 1177 ipf_pr_icmp(fr_info_t *fin)
 1178 {
 1179         ipf_main_softc_t *softc = fin->fin_main_soft;
 1180         int minicmpsz = sizeof(struct icmp);
 1181         icmphdr_t *icmp;
 1182         ip_t *oip;
 1183 
 1184         ipf_pr_short(fin, ICMPERR_ICMPHLEN);
 1185 
 1186         if (fin->fin_off != 0) {
 1187                 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_frag);
 1188                 return;
 1189         }
 1190 
 1191         if (ipf_pr_pullup(fin, ICMPERR_ICMPHLEN) == -1) {
 1192                 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_pullup);
 1193                 return;
 1194         }
 1195 
 1196         icmp = fin->fin_dp;
 1197 
 1198         fin->fin_data[0] = *(u_short *)icmp;
 1199         fin->fin_data[1] = icmp->icmp_id;
 1200 
 1201         switch (icmp->icmp_type)
 1202         {
 1203         case ICMP_ECHOREPLY :
 1204         case ICMP_ECHO :
 1205         /* Router discovery messaes - RFC 1256 */
 1206         case ICMP_ROUTERADVERT :
 1207         case ICMP_ROUTERSOLICIT :
 1208                 fin->fin_flx |= FI_ICMPQUERY;
 1209                 minicmpsz = ICMP_MINLEN;
 1210                 break;
 1211         /*
 1212          * type(1) + code(1) + cksum(2) + id(2) seq(2) +
 1213          * 3 * timestamp(3 * 4)
 1214          */
 1215         case ICMP_TSTAMP :
 1216         case ICMP_TSTAMPREPLY :
 1217                 fin->fin_flx |= FI_ICMPQUERY;
 1218                 minicmpsz = 20;
 1219                 break;
 1220         /*
 1221          * type(1) + code(1) + cksum(2) + id(2) seq(2) +
 1222          * mask(4)
 1223          */
 1224         case ICMP_IREQ :
 1225         case ICMP_IREQREPLY :
 1226         case ICMP_MASKREQ :
 1227         case ICMP_MASKREPLY :
 1228                 fin->fin_flx |= FI_ICMPQUERY;
 1229                 minicmpsz = 12;
 1230                 break;
 1231         /*
 1232          * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+)
 1233          */
 1234         case ICMP_UNREACH :
 1235 #ifdef icmp_nextmtu
 1236                 if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) {
 1237                         if (icmp->icmp_nextmtu < softc->ipf_icmpminfragmtu) {
 1238                                 fin->fin_flx |= FI_BAD;
 1239                                 DT3(ipf_fi_bad_icmp_nextmtu, fr_info_t *, fin, u_int, icmp->icmp_nextmtu, u_int, softc->ipf_icmpminfragmtu);
 1240                         }
 1241                 }
 1242 #endif
 1243                 /* FALLTHROUGH */
 1244         case ICMP_SOURCEQUENCH :
 1245         case ICMP_REDIRECT :
 1246         case ICMP_TIMXCEED :
 1247         case ICMP_PARAMPROB :
 1248                 fin->fin_flx |= FI_ICMPERR;
 1249                 if (ipf_coalesce(fin) != 1) {
 1250                         LBUMPD(ipf_stats[fin->fin_out], fr_icmp_coalesce);
 1251                         return;
 1252                 }
 1253 
 1254                 /*
 1255                  * ICMP error packets should not be generated for IP
 1256                  * packets that are a fragment that isn't the first
 1257                  * fragment.
 1258                  */
 1259                 oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN);
 1260                 if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0) {
 1261                         fin->fin_flx |= FI_BAD;
 1262                         DT2(ipf_fi_bad_icmp_err, fr_info_t, fin, u_int, (ntohs(oip->ip_off) & IP_OFFMASK));
 1263                 }
 1264 
 1265                 /*
 1266                  * If the destination of this packet doesn't match the
 1267                  * source of the original packet then this packet is
 1268                  * not correct.
 1269                  */
 1270                 if (oip->ip_src.s_addr != fin->fin_daddr) {
 1271                         fin->fin_flx |= FI_BAD;
 1272                         DT1(ipf_fi_bad_src_ne_dst, fr_info_t *, fin);
 1273                 }
 1274                 break;
 1275         default :
 1276                 break;
 1277         }
 1278 
 1279         ipf_pr_short(fin, minicmpsz);
 1280 
 1281         ipf_checkv4sum(fin);
 1282 }
 1283 
 1284 
 1285 /* ------------------------------------------------------------------------ */
 1286 /* Function:    ipf_pr_tcpcommon                                            */
 1287 /* Returns:     int    - 0 = header ok, 1 = bad packet, -1 = buffer error   */
 1288 /* Parameters:  fin(I) - pointer to packet information                      */
 1289 /*                                                                          */
 1290 /* TCP header sanity checking.  Look for bad combinations of TCP flags,     */
 1291 /* and make some checks with how they interact with other fields.           */
 1292 /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is     */
 1293 /* valid and mark the packet as bad if not.                                 */
 1294 /* ------------------------------------------------------------------------ */
 1295 static inline int
 1296 ipf_pr_tcpcommon(fr_info_t *fin)
 1297 {
 1298         ipf_main_softc_t *softc = fin->fin_main_soft;
 1299         int flags, tlen;
 1300         tcphdr_t *tcp;
 1301 
 1302         fin->fin_flx |= FI_TCPUDP;
 1303         if (fin->fin_off != 0) {
 1304                 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_frag);
 1305                 return (0);
 1306         }
 1307 
 1308         if (ipf_pr_pullup(fin, sizeof(*tcp)) == -1) {
 1309                 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup);
 1310                 return (-1);
 1311         }
 1312 
 1313         tcp = fin->fin_dp;
 1314         if (fin->fin_dlen > 3) {
 1315                 fin->fin_sport = ntohs(tcp->th_sport);
 1316                 fin->fin_dport = ntohs(tcp->th_dport);
 1317         }
 1318 
 1319         if ((fin->fin_flx & FI_SHORT) != 0) {
 1320                 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_short);
 1321                 return (1);
 1322         }
 1323 
 1324         /*
 1325          * Use of the TCP data offset *must* result in a value that is at
 1326          * least the same size as the TCP header.
 1327          */
 1328         tlen = TCP_OFF(tcp) << 2;
 1329         if (tlen < sizeof(tcphdr_t)) {
 1330                 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_small);
 1331                 fin->fin_flx |= FI_BAD;
 1332                 DT3(ipf_fi_bad_tlen, fr_info_t, fin, u_int, tlen, u_int, sizeof(tcphdr_t));
 1333                 return (1);
 1334         }
 1335 
 1336         flags = tcp->th_flags;
 1337         fin->fin_tcpf = tcp->th_flags;
 1338 
 1339         /*
 1340          * If the urgent flag is set, then the urgent pointer must
 1341          * also be set and vice versa.  Good TCP packets do not have
 1342          * just one of these set.
 1343          */
 1344         if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) {
 1345                 fin->fin_flx |= FI_BAD;
 1346                 DT3(ipf_fi_bad_th_urg, fr_info_t*, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp);
 1347 #if 0
 1348         } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) {
 1349                 /*
 1350                  * Ignore this case (#if 0) as it shows up in "real"
 1351                  * traffic with bogus values in the urgent pointer field.
 1352                  */
 1353                 fin->fin_flx |= FI_BAD;
 1354                 DT3(ipf_fi_bad_th_urg0, fr_info_t *, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp);
 1355 #endif
 1356         } else if (((flags & (TH_SYN|TH_FIN)) != 0) &&
 1357                    ((flags & (TH_RST|TH_ACK)) == TH_RST)) {
 1358                 /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */
 1359                 fin->fin_flx |= FI_BAD;
 1360                 DT1(ipf_fi_bad_th_fin_rst_ack, fr_info_t, fin);
 1361 #if 1
 1362         } else if (((flags & TH_SYN) != 0) &&
 1363                    ((flags & (TH_URG|TH_PUSH)) != 0)) {
 1364                 /*
 1365                  * SYN with URG and PUSH set is not for normal TCP but it is
 1366                  * possible(?) with T/TCP...but who uses T/TCP?
 1367                  */
 1368                 fin->fin_flx |= FI_BAD;
 1369                 DT1(ipf_fi_bad_th_syn_urg_psh, fr_info_t *, fin);
 1370 #endif
 1371         } else if (!(flags & TH_ACK)) {
 1372                 /*
 1373                  * If the ack bit isn't set, then either the SYN or
 1374                  * RST bit must be set.  If the SYN bit is set, then
 1375                  * we expect the ACK field to be 0.  If the ACK is
 1376                  * not set and if URG, PSH or FIN are set, consdier
 1377                  * that to indicate a bad TCP packet.
 1378                  */
 1379                 if ((flags == TH_SYN) && (tcp->th_ack != 0)) {
 1380                         /*
 1381                          * Cisco PIX sets the ACK field to a random value.
 1382                          * In light of this, do not set FI_BAD until a patch
 1383                          * is available from Cisco to ensure that
 1384                          * interoperability between existing systems is
 1385                          * achieved.
 1386                          */
 1387                         /*fin->fin_flx |= FI_BAD*/;
 1388                         /*DT1(ipf_fi_bad_th_syn_ack, fr_info_t *, fin);*/
 1389                 } else if (!(flags & (TH_RST|TH_SYN))) {
 1390                         fin->fin_flx |= FI_BAD;
 1391                         DT1(ipf_fi_bad_th_rst_syn, fr_info_t *, fin);
 1392                 } else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) {
 1393                         fin->fin_flx |= FI_BAD;
 1394                         DT1(ipf_fi_bad_th_urg_push_fin, fr_info_t *, fin);
 1395                 }
 1396         }
 1397         if (fin->fin_flx & FI_BAD) {
 1398                 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_bad_flags);
 1399                 return (1);
 1400         }
 1401 
 1402         /*
 1403          * At this point, it's not exactly clear what is to be gained by
 1404          * marking up which TCP options are and are not present.  The one we
 1405          * are most interested in is the TCP window scale.  This is only in
 1406          * a SYN packet [RFC1323] so we don't need this here...?
 1407          * Now if we were to analyse the header for passive fingerprinting,
 1408          * then that might add some weight to adding this...
 1409          */
 1410         if (tlen == sizeof(tcphdr_t)) {
 1411                 return (0);
 1412         }
 1413 
 1414         if (ipf_pr_pullup(fin, tlen) == -1) {
 1415                 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup);
 1416                 return (-1);
 1417         }
 1418 
 1419 #if 0
 1420         tcp = fin->fin_dp;
 1421         ip = fin->fin_ip;
 1422         s = (u_char *)(tcp + 1);
 1423         off = IP_HL(ip) << 2;
 1424 # ifdef _KERNEL
 1425         if (fin->fin_mp != NULL) {
 1426                 mb_t *m = *fin->fin_mp;
 1427 
 1428                 if (off + tlen > M_LEN(m))
 1429                         return;
 1430         }
 1431 # endif
 1432         for (tlen -= (int)sizeof(*tcp); tlen > 0; ) {
 1433                 opt = *s;
 1434                 if (opt == '\0')
 1435                         break;
 1436                 else if (opt == TCPOPT_NOP)
 1437                         ol = 1;
 1438                 else {
 1439                         if (tlen < 2)
 1440                                 break;
 1441                         ol = (int)*(s + 1);
 1442                         if (ol < 2 || ol > tlen)
 1443                                 break;
 1444                 }
 1445 
 1446                 for (i = 9, mv = 4; mv >= 0; ) {
 1447                         op = ipopts + i;
 1448                         if (opt == (u_char)op->ol_val) {
 1449                                 optmsk |= op->ol_bit;
 1450                                 break;
 1451                         }
 1452                 }
 1453                 tlen -= ol;
 1454                 s += ol;
 1455         }
 1456 #endif /* 0 */
 1457 
 1458         return (0);
 1459 }
 1460 
 1461 
 1462 
 1463 /* ------------------------------------------------------------------------ */
 1464 /* Function:    ipf_pr_udpcommon                                            */
 1465 /* Returns:     int    - 0 = header ok, 1 = bad packet                      */
 1466 /* Parameters:  fin(I) - pointer to packet information                      */
 1467 /*                                                                          */
 1468 /* Extract the UDP source and destination ports, if present.  If compiled   */
 1469 /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid.          */
 1470 /* ------------------------------------------------------------------------ */
 1471 static inline int
 1472 ipf_pr_udpcommon(fr_info_t *fin)
 1473 {
 1474         udphdr_t *udp;
 1475 
 1476         fin->fin_flx |= FI_TCPUDP;
 1477 
 1478         if (!fin->fin_off && (fin->fin_dlen > 3)) {
 1479                 if (ipf_pr_pullup(fin, sizeof(*udp)) == -1) {
 1480                         ipf_main_softc_t *softc = fin->fin_main_soft;
 1481 
 1482                         fin->fin_flx |= FI_SHORT;
 1483                         LBUMPD(ipf_stats[fin->fin_out], fr_udp_pullup);
 1484                         return (1);
 1485                 }
 1486 
 1487                 udp = fin->fin_dp;
 1488 
 1489                 fin->fin_sport = ntohs(udp->uh_sport);
 1490                 fin->fin_dport = ntohs(udp->uh_dport);
 1491         }
 1492 
 1493         return (0);
 1494 }
 1495 
 1496 
 1497 /* ------------------------------------------------------------------------ */
 1498 /* Function:    ipf_pr_tcp                                                  */
 1499 /* Returns:     void                                                        */
 1500 /* Parameters:  fin(I) - pointer to packet information                      */
 1501 /*                                                                          */
 1502 /* IPv4 Only                                                                */
 1503 /* Analyse the packet for IPv4/TCP properties.                              */
 1504 /* ------------------------------------------------------------------------ */
 1505 static inline void
 1506 ipf_pr_tcp(fr_info_t *fin)
 1507 {
 1508 
 1509         ipf_pr_short(fin, sizeof(tcphdr_t));
 1510 
 1511         if (ipf_pr_tcpcommon(fin) == 0)
 1512                 ipf_checkv4sum(fin);
 1513 }
 1514 
 1515 
 1516 /* ------------------------------------------------------------------------ */
 1517 /* Function:    ipf_pr_udp                                                  */
 1518 /* Returns:     void                                                        */
 1519 /* Parameters:  fin(I) - pointer to packet information                      */
 1520 /*                                                                          */
 1521 /* IPv4 Only                                                                */
 1522 /* Analyse the packet for IPv4/UDP properties.                              */
 1523 /* ------------------------------------------------------------------------ */
 1524 static inline void
 1525 ipf_pr_udp(fr_info_t *fin)
 1526 {
 1527 
 1528         ipf_pr_short(fin, sizeof(udphdr_t));
 1529 
 1530         if (ipf_pr_udpcommon(fin) == 0)
 1531                 ipf_checkv4sum(fin);
 1532 }
 1533 
 1534 
 1535 /* ------------------------------------------------------------------------ */
 1536 /* Function:    ipf_pr_esp                                                  */
 1537 /* Returns:     void                                                        */
 1538 /* Parameters:  fin(I) - pointer to packet information                      */
 1539 /*                                                                          */
 1540 /* Analyse the packet for ESP properties.                                   */
 1541 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits)  */
 1542 /* even though the newer ESP packets must also have a sequence number that  */
 1543 /* is 32bits as well, it is not possible(?) to determine the version from a */
 1544 /* simple packet header.                                                    */
 1545 /* ------------------------------------------------------------------------ */
 1546 static inline void
 1547 ipf_pr_esp(fr_info_t *fin)
 1548 {
 1549 
 1550         if (fin->fin_off == 0) {
 1551                 ipf_pr_short(fin, 8);
 1552                 if (ipf_pr_pullup(fin, 8) == -1) {
 1553                         ipf_main_softc_t *softc = fin->fin_main_soft;
 1554 
 1555                         LBUMPD(ipf_stats[fin->fin_out], fr_v4_esp_pullup);
 1556                 }
 1557         }
 1558 }
 1559 
 1560 
 1561 /* ------------------------------------------------------------------------ */
 1562 /* Function:    ipf_pr_ah                                                   */
 1563 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
 1564 /* Parameters:  fin(I) - pointer to packet information                      */
 1565 /*                                                                          */
 1566 /* Analyse the packet for AH properties.                                    */
 1567 /* The minimum length is taken to be the combination of all fields in the   */
 1568 /* header being present and no authentication data (null algorithm used.)   */
 1569 /* ------------------------------------------------------------------------ */
 1570 static inline int
 1571 ipf_pr_ah(fr_info_t *fin)
 1572 {
 1573         ipf_main_softc_t *softc = fin->fin_main_soft;
 1574         authhdr_t *ah;
 1575         int len;
 1576 
 1577         fin->fin_flx |= FI_AH;
 1578         ipf_pr_short(fin, sizeof(*ah));
 1579 
 1580         if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0)) {
 1581                 LBUMPD(ipf_stats[fin->fin_out], fr_v4_ah_bad);
 1582                 return (IPPROTO_NONE);
 1583         }
 1584 
 1585         if (ipf_pr_pullup(fin, sizeof(*ah)) == -1) {
 1586                 DT(fr_v4_ah_pullup_1);
 1587                 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup);
 1588                 return (IPPROTO_NONE);
 1589         }
 1590 
 1591         ah = (authhdr_t *)fin->fin_dp;
 1592 
 1593         len = (ah->ah_plen + 2) << 2;
 1594         ipf_pr_short(fin, len);
 1595         if (ipf_pr_pullup(fin, len) == -1) {
 1596                 DT(fr_v4_ah_pullup_2);
 1597                 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup);
 1598                 return (IPPROTO_NONE);
 1599         }
 1600 
 1601         /*
 1602          * Adjust fin_dp and fin_dlen for skipping over the authentication
 1603          * header.
 1604          */
 1605         fin->fin_dp = (char *)fin->fin_dp + len;
 1606         fin->fin_dlen -= len;
 1607         return (ah->ah_next);
 1608 }
 1609 
 1610 
 1611 /* ------------------------------------------------------------------------ */
 1612 /* Function:    ipf_pr_gre                                                  */
 1613 /* Returns:     void                                                        */
 1614 /* Parameters:  fin(I) - pointer to packet information                      */
 1615 /*                                                                          */
 1616 /* Analyse the packet for GRE properties.                                   */
 1617 /* ------------------------------------------------------------------------ */
 1618 static inline void
 1619 ipf_pr_gre(fr_info_t *fin)
 1620 {
 1621         ipf_main_softc_t *softc = fin->fin_main_soft;
 1622         grehdr_t *gre;
 1623 
 1624         ipf_pr_short(fin, sizeof(grehdr_t));
 1625 
 1626         if (fin->fin_off != 0) {
 1627                 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_frag);
 1628                 return;
 1629         }
 1630 
 1631         if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) {
 1632                 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_pullup);
 1633                 return;
 1634         }
 1635 
 1636         gre = fin->fin_dp;
 1637         if (GRE_REV(gre->gr_flags) == 1)
 1638                 fin->fin_data[0] = gre->gr_call;
 1639 }
 1640 
 1641 
 1642 /* ------------------------------------------------------------------------ */
 1643 /* Function:    ipf_pr_ipv4hdr                                              */
 1644 /* Returns:     void                                                        */
 1645 /* Parameters:  fin(I) - pointer to packet information                      */
 1646 /*                                                                          */
 1647 /* IPv4 Only                                                                */
 1648 /* Analyze the IPv4 header and set fields in the fr_info_t structure.       */
 1649 /* Check all options present and flag their presence if any exist.          */
 1650 /* ------------------------------------------------------------------------ */
 1651 static inline void
 1652 ipf_pr_ipv4hdr(fr_info_t *fin)
 1653 {
 1654         u_short optmsk = 0, secmsk = 0, auth = 0;
 1655         int hlen, ol, mv, p, i;
 1656         const struct optlist *op;
 1657         u_char *s, opt;
 1658         u_short off;
 1659         fr_ip_t *fi;
 1660         ip_t *ip;
 1661 
 1662         fi = &fin->fin_fi;
 1663         hlen = fin->fin_hlen;
 1664 
 1665         ip = fin->fin_ip;
 1666         p = ip->ip_p;
 1667         fi->fi_p = p;
 1668         fin->fin_crc = p;
 1669         fi->fi_tos = ip->ip_tos;
 1670         fin->fin_id = ntohs(ip->ip_id);
 1671         off = ntohs(ip->ip_off);
 1672 
 1673         /* Get both TTL and protocol */
 1674         fi->fi_p = ip->ip_p;
 1675         fi->fi_ttl = ip->ip_ttl;
 1676 
 1677         /* Zero out bits not used in IPv6 address */
 1678         fi->fi_src.i6[1] = 0;
 1679         fi->fi_src.i6[2] = 0;
 1680         fi->fi_src.i6[3] = 0;
 1681         fi->fi_dst.i6[1] = 0;
 1682         fi->fi_dst.i6[2] = 0;
 1683         fi->fi_dst.i6[3] = 0;
 1684 
 1685         fi->fi_saddr = ip->ip_src.s_addr;
 1686         fin->fin_crc += fi->fi_saddr;
 1687         fi->fi_daddr = ip->ip_dst.s_addr;
 1688         fin->fin_crc += fi->fi_daddr;
 1689         if (IN_MULTICAST(ntohl(fi->fi_daddr)))
 1690                 fin->fin_flx |= FI_MULTICAST|FI_MBCAST;
 1691 
 1692         /*
 1693          * set packet attribute flags based on the offset and
 1694          * calculate the byte offset that it represents.
 1695          */
 1696         off &= IP_MF|IP_OFFMASK;
 1697         if (off != 0) {
 1698                 int morefrag = off & IP_MF;
 1699 
 1700                 fi->fi_flx |= FI_FRAG;
 1701                 off &= IP_OFFMASK;
 1702                 if (off == 1 && p == IPPROTO_TCP) {
 1703                         fin->fin_flx |= FI_SHORT;       /* RFC 3128 */
 1704                         DT1(ipf_fi_tcp_frag_off_1, fr_info_t *, fin);
 1705                 }
 1706                 if (off != 0) {
 1707                         fin->fin_flx |= FI_FRAGBODY;
 1708                         off <<= 3;
 1709                         if ((off + fin->fin_dlen > 65535) ||
 1710                             (fin->fin_dlen == 0) ||
 1711                             ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) {
 1712                                 /*
 1713                                  * The length of the packet, starting at its
 1714                                  * offset cannot exceed 65535 (0xffff) as the
 1715                                  * length of an IP packet is only 16 bits.
 1716                                  *
 1717                                  * Any fragment that isn't the last fragment
 1718                                  * must have a length greater than 0 and it
 1719                                  * must be an even multiple of 8.
 1720                                  */
 1721                                 fi->fi_flx |= FI_BAD;
 1722                                 DT1(ipf_fi_bad_fragbody_gt_65535, fr_info_t *, fin);
 1723                         }
 1724                 }
 1725         }
 1726         fin->fin_off = off;
 1727 
 1728         /*
 1729          * Call per-protocol setup and checking
 1730          */
 1731         if (p == IPPROTO_AH) {
 1732                 /*
 1733                  * Treat AH differently because we expect there to be another
 1734                  * layer 4 header after it.
 1735                  */
 1736                 p = ipf_pr_ah(fin);
 1737         }
 1738 
 1739         switch (p)
 1740         {
 1741         case IPPROTO_UDP :
 1742                 ipf_pr_udp(fin);
 1743                 break;
 1744         case IPPROTO_TCP :
 1745                 ipf_pr_tcp(fin);
 1746                 break;
 1747         case IPPROTO_ICMP :
 1748                 ipf_pr_icmp(fin);
 1749                 break;
 1750         case IPPROTO_ESP :
 1751                 ipf_pr_esp(fin);
 1752                 break;
 1753         case IPPROTO_GRE :
 1754                 ipf_pr_gre(fin);
 1755                 break;
 1756         }
 1757 
 1758         ip = fin->fin_ip;
 1759         if (ip == NULL)
 1760                 return;
 1761 
 1762         /*
 1763          * If it is a standard IP header (no options), set the flag fields
 1764          * which relate to options to 0.
 1765          */
 1766         if (hlen == sizeof(*ip)) {
 1767                 fi->fi_optmsk = 0;
 1768                 fi->fi_secmsk = 0;
 1769                 fi->fi_auth = 0;
 1770                 return;
 1771         }
 1772 
 1773         /*
 1774          * So the IP header has some IP options attached.  Walk the entire
 1775          * list of options present with this packet and set flags to indicate
 1776          * which ones are here and which ones are not.  For the somewhat out
 1777          * of date and obscure security classification options, set a flag to
 1778          * represent which classification is present.
 1779          */
 1780         fi->fi_flx |= FI_OPTIONS;
 1781 
 1782         for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) {
 1783                 opt = *s;
 1784                 if (opt == '\0')
 1785                         break;
 1786                 else if (opt == IPOPT_NOP)
 1787                         ol = 1;
 1788                 else {
 1789                         if (hlen < 2)
 1790                                 break;
 1791                         ol = (int)*(s + 1);
 1792                         if (ol < 2 || ol > hlen)
 1793                                 break;
 1794                 }
 1795                 for (i = 9, mv = 4; mv >= 0; ) {
 1796                         op = ipopts + i;
 1797 
 1798                         if ((opt == (u_char)op->ol_val) && (ol > 4)) {
 1799                                 u_32_t doi;
 1800 
 1801                                 switch (opt)
 1802                                 {
 1803                                 case IPOPT_SECURITY :
 1804                                         if (optmsk & op->ol_bit) {
 1805                                                 fin->fin_flx |= FI_BAD;
 1806                                                 DT2(ipf_fi_bad_ipopt_security, fr_info_t *, fin, u_short, (optmsk & op->ol_bit));
 1807                                         } else {
 1808                                                 doi = ipf_checkripso(s);
 1809                                                 secmsk = doi >> 16;
 1810                                                 auth = doi & 0xffff;
 1811                                         }
 1812                                         break;
 1813 
 1814                                 case IPOPT_CIPSO :
 1815 
 1816                                         if (optmsk & op->ol_bit) {
 1817                                                 fin->fin_flx |= FI_BAD;
 1818                                                 DT2(ipf_fi_bad_ipopt_cipso, fr_info_t *, fin, u_short, (optmsk & op->ol_bit));
 1819                                         } else {
 1820                                                 doi = ipf_checkcipso(fin,
 1821                                                                      s, ol);
 1822                                                 secmsk = doi >> 16;
 1823                                                 auth = doi & 0xffff;
 1824                                         }
 1825                                         break;
 1826                                 }
 1827                                 optmsk |= op->ol_bit;
 1828                         }
 1829 
 1830                         if (opt < op->ol_val)
 1831                                 i -= mv;
 1832                         else
 1833                                 i += mv;
 1834                         mv--;
 1835                 }
 1836                 hlen -= ol;
 1837                 s += ol;
 1838         }
 1839 
 1840         /*
 1841          *
 1842          */
 1843         if (auth && !(auth & 0x0100))
 1844                 auth &= 0xff00;
 1845         fi->fi_optmsk = optmsk;
 1846         fi->fi_secmsk = secmsk;
 1847         fi->fi_auth = auth;
 1848 }
 1849 
 1850 
 1851 /* ------------------------------------------------------------------------ */
 1852 /* Function:    ipf_checkripso                                              */
 1853 /* Returns:     void                                                        */
 1854 /* Parameters:  s(I)   - pointer to start of RIPSO option                   */
 1855 /*                                                                          */
 1856 /* ------------------------------------------------------------------------ */
 1857 static u_32_t
 1858 ipf_checkripso(u_char *s)
 1859 {
 1860         const struct optlist *sp;
 1861         u_short secmsk = 0, auth = 0;
 1862         u_char sec;
 1863         int j, m;
 1864 
 1865         sec = *(s + 2); /* classification */
 1866         for (j = 3, m = 2; m >= 0; ) {
 1867                 sp = secopt + j;
 1868                 if (sec == sp->ol_val) {
 1869                         secmsk |= sp->ol_bit;
 1870                         auth = *(s + 3);
 1871                         auth *= 256;
 1872                         auth += *(s + 4);
 1873                         break;
 1874                 }
 1875                 if (sec < sp->ol_val)
 1876                         j -= m;
 1877                 else
 1878                         j += m;
 1879                 m--;
 1880         }
 1881 
 1882         return (secmsk << 16) | auth;
 1883 }
 1884 
 1885 
 1886 /* ------------------------------------------------------------------------ */
 1887 /* Function:    ipf_checkcipso                                              */
 1888 /* Returns:     u_32_t  - 0 = failure, else the doi from the header         */
 1889 /* Parameters:  fin(IO) - pointer to packet information                     */
 1890 /*              s(I)    - pointer to start of CIPSO option                  */
 1891 /*              ol(I)   - length of CIPSO option field                      */
 1892 /*                                                                          */
 1893 /* This function returns the domain of integrity (DOI) field from the CIPSO */
 1894 /* header and returns that whilst also storing the highest sensitivity      */
 1895 /* value found in the fr_info_t structure.                                  */
 1896 /*                                                                          */
 1897 /* No attempt is made to extract the category bitmaps as these are defined  */
 1898 /* by the user (rather than the protocol) and can be rather numerous on the */
 1899 /* end nodes.                                                               */
 1900 /* ------------------------------------------------------------------------ */
 1901 static u_32_t
 1902 ipf_checkcipso(fr_info_t *fin, u_char *s, int ol)
 1903 {
 1904         ipf_main_softc_t *softc = fin->fin_main_soft;
 1905         fr_ip_t *fi;
 1906         u_32_t doi;
 1907         u_char *t, tag, tlen, sensitivity;
 1908         int len;
 1909 
 1910         if (ol < 6 || ol > 40) {
 1911                 LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_bad);
 1912                 fin->fin_flx |= FI_BAD;
 1913                 DT2(ipf_fi_bad_checkcipso_ol, fr_info_t *, fin, u_int, ol);
 1914                 return (0);
 1915         }
 1916 
 1917         fi = &fin->fin_fi;
 1918         fi->fi_sensitivity = 0;
 1919         /*
 1920          * The DOI field MUST be there.
 1921          */
 1922         bcopy(s + 2, &doi, sizeof(doi));
 1923 
 1924         t = (u_char *)s + 6;
 1925         for (len = ol - 6; len >= 2; len -= tlen, t+= tlen) {
 1926                 tag = *t;
 1927                 tlen = *(t + 1);
 1928                 if (tlen > len || tlen < 4 || tlen > 34) {
 1929                         LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_tlen);
 1930                         fin->fin_flx |= FI_BAD;
 1931                         DT2(ipf_fi_bad_checkcipso_tlen, fr_info_t *, fin, u_int, tlen);
 1932                         return (0);
 1933                 }
 1934 
 1935                 sensitivity = 0;
 1936                 /*
 1937                  * Tag numbers 0, 1, 2, 5 are laid out in the CIPSO Internet
 1938                  * draft (16 July 1992) that has expired.
 1939                  */
 1940                 if (tag == 0) {
 1941                         fin->fin_flx |= FI_BAD;
 1942                         DT2(ipf_fi_bad_checkcipso_tag, fr_info_t *, fin, u_int, tag);
 1943                         continue;
 1944                 } else if (tag == 1) {
 1945                         if (*(t + 2) != 0) {
 1946                                 fin->fin_flx |= FI_BAD;
 1947                                 DT2(ipf_fi_bad_checkcipso_tag1_t2, fr_info_t *, fin, u_int, (*t + 2));
 1948                                 continue;
 1949                         }
 1950                         sensitivity = *(t + 3);
 1951                         /* Category bitmap for categories 0-239 */
 1952 
 1953                 } else if (tag == 4) {
 1954                         if (*(t + 2) != 0) {
 1955                                 fin->fin_flx |= FI_BAD;
 1956                                 DT2(ipf_fi_bad_checkcipso_tag4_t2, fr_info_t *, fin, u_int, (*t + 2));
 1957                                 continue;
 1958                         }
 1959                         sensitivity = *(t + 3);
 1960                         /* Enumerated categories, 16bits each, upto 15 */
 1961 
 1962                 } else if (tag == 5) {
 1963                         if (*(t + 2) != 0) {
 1964                                 fin->fin_flx |= FI_BAD;
 1965                                 DT2(ipf_fi_bad_checkcipso_tag5_t2, fr_info_t *, fin, u_int, (*t + 2));
 1966                                 continue;
 1967                         }
 1968                         sensitivity = *(t + 3);
 1969                         /* Range of categories (2*16bits), up to 7 pairs */
 1970 
 1971                 } else if (tag > 127) {
 1972                         /* Custom defined DOI */
 1973                         ;
 1974                 } else {
 1975                         fin->fin_flx |= FI_BAD;
 1976                         DT2(ipf_fi_bad_checkcipso_tag127, fr_info_t *, fin, u_int, tag);
 1977                         continue;
 1978                 }
 1979 
 1980                 if (sensitivity > fi->fi_sensitivity)
 1981                         fi->fi_sensitivity = sensitivity;
 1982         }
 1983 
 1984         return (doi);
 1985 }
 1986 
 1987 
 1988 /* ------------------------------------------------------------------------ */
 1989 /* Function:    ipf_makefrip                                                */
 1990 /* Returns:     int     - 0 == packet ok, -1 == packet freed                */
 1991 /* Parameters:  hlen(I) - length of IP packet header                        */
 1992 /*              ip(I)   - pointer to the IP header                          */
 1993 /*              fin(IO) - pointer to packet information                     */
 1994 /*                                                                          */
 1995 /* Compact the IP header into a structure which contains just the info.     */
 1996 /* which is useful for comparing IP headers with and store this information */
 1997 /* in the fr_info_t structure pointer to by fin.  At present, it is assumed */
 1998 /* this function will be called with either an IPv4 or IPv6 packet.         */
 1999 /* ------------------------------------------------------------------------ */
 2000 int
 2001 ipf_makefrip(int hlen, ip_t *ip, fr_info_t *fin)
 2002 {
 2003         ipf_main_softc_t *softc = fin->fin_main_soft;
 2004         int v;
 2005 
 2006         fin->fin_depth = 0;
 2007         fin->fin_hlen = (u_short)hlen;
 2008         fin->fin_ip = ip;
 2009         fin->fin_rule = 0xffffffff;
 2010         fin->fin_group[0] = -1;
 2011         fin->fin_group[1] = '\0';
 2012         fin->fin_dp = (char *)ip + hlen;
 2013 
 2014         v = fin->fin_v;
 2015         if (v == 4) {
 2016                 fin->fin_plen = ntohs(ip->ip_len);
 2017                 fin->fin_dlen = fin->fin_plen - hlen;
 2018                 ipf_pr_ipv4hdr(fin);
 2019 #ifdef  USE_INET6
 2020         } else if (v == 6) {
 2021                 fin->fin_plen = ntohs(((ip6_t *)ip)->ip6_plen);
 2022                 fin->fin_dlen = fin->fin_plen;
 2023                 fin->fin_plen += hlen;
 2024 
 2025                 ipf_pr_ipv6hdr(fin);
 2026 #endif
 2027         }
 2028         if (fin->fin_ip == NULL) {
 2029                 LBUMP(ipf_stats[fin->fin_out].fr_ip_freed);
 2030                 return (-1);
 2031         }
 2032         return (0);
 2033 }
 2034 
 2035 
 2036 /* ------------------------------------------------------------------------ */
 2037 /* Function:    ipf_portcheck                                               */
 2038 /* Returns:     int - 1 == port matched, 0 == port match failed             */
 2039 /* Parameters:  frp(I) - pointer to port check `expression'                 */
 2040 /*              pop(I) - port number to evaluate                            */
 2041 /*                                                                          */
 2042 /* Perform a comparison of a port number against some other(s), using a     */
 2043 /* structure with compare information stored in it.                         */
 2044 /* ------------------------------------------------------------------------ */
 2045 static inline int
 2046 ipf_portcheck(frpcmp_t *frp, u_32_t pop)
 2047 {
 2048         int err = 1;
 2049         u_32_t po;
 2050 
 2051         po = frp->frp_port;
 2052 
 2053         /*
 2054          * Do opposite test to that required and continue if that succeeds.
 2055          */
 2056         switch (frp->frp_cmp)
 2057         {
 2058         case FR_EQUAL :
 2059                 if (pop != po) /* EQUAL */
 2060                         err = 0;
 2061                 break;
 2062         case FR_NEQUAL :
 2063                 if (pop == po) /* NOTEQUAL */
 2064                         err = 0;
 2065                 break;
 2066         case FR_LESST :
 2067                 if (pop >= po) /* LESSTHAN */
 2068                         err = 0;
 2069                 break;
 2070         case FR_GREATERT :
 2071                 if (pop <= po) /* GREATERTHAN */
 2072                         err = 0;
 2073                 break;
 2074         case FR_LESSTE :
 2075                 if (pop > po) /* LT or EQ */
 2076                         err = 0;
 2077                 break;
 2078         case FR_GREATERTE :
 2079                 if (pop < po) /* GT or EQ */
 2080                         err = 0;
 2081                 break;
 2082         case FR_OUTRANGE :
 2083                 if (pop >= po && pop <= frp->frp_top) /* Out of range */
 2084                         err = 0;
 2085                 break;
 2086         case FR_INRANGE :
 2087                 if (pop <= po || pop >= frp->frp_top) /* In range */
 2088                         err = 0;
 2089                 break;
 2090         case FR_INCRANGE :
 2091                 if (pop < po || pop > frp->frp_top) /* Inclusive range */
 2092                         err = 0;
 2093                 break;
 2094         default :
 2095                 break;
 2096         }
 2097         return (err);
 2098 }
 2099 
 2100 
 2101 /* ------------------------------------------------------------------------ */
 2102 /* Function:    ipf_tcpudpchk                                               */
 2103 /* Returns:     int - 1 == protocol matched, 0 == check failed              */
 2104 /* Parameters:  fda(I) - pointer to packet information                      */
 2105 /*              ft(I)  - pointer to structure with comparison data          */
 2106 /*                                                                          */
 2107 /* Compares the current pcket (assuming it is TCP/UDP) information with a   */
 2108 /* structure containing information that we want to match against.          */
 2109 /* ------------------------------------------------------------------------ */
 2110 int
 2111 ipf_tcpudpchk(fr_ip_t *fi, frtuc_t *ft)
 2112 {
 2113         int err = 1;
 2114 
 2115         /*
 2116          * Both ports should *always* be in the first fragment.
 2117          * So far, I cannot find any cases where they can not be.
 2118          *
 2119          * compare destination ports
 2120          */
 2121         if (ft->ftu_dcmp)
 2122                 err = ipf_portcheck(&ft->ftu_dst, fi->fi_ports[1]);
 2123 
 2124         /*
 2125          * compare source ports
 2126          */
 2127         if (err && ft->ftu_scmp)
 2128                 err = ipf_portcheck(&ft->ftu_src, fi->fi_ports[0]);
 2129 
 2130         /*
 2131          * If we don't have all the TCP/UDP header, then how can we
 2132          * expect to do any sort of match on it ?  If we were looking for
 2133          * TCP flags, then NO match.  If not, then match (which should
 2134          * satisfy the "short" class too).
 2135          */
 2136         if (err && (fi->fi_p == IPPROTO_TCP)) {
 2137                 if (fi->fi_flx & FI_SHORT)
 2138                         return (!(ft->ftu_tcpf | ft->ftu_tcpfm));
 2139                 /*
 2140                  * Match the flags ?  If not, abort this match.
 2141                  */
 2142                 if (ft->ftu_tcpfm &&
 2143                     ft->ftu_tcpf != (fi->fi_tcpf & ft->ftu_tcpfm)) {
 2144                         FR_DEBUG(("f. %#x & %#x != %#x\n", fi->fi_tcpf,
 2145                                  ft->ftu_tcpfm, ft->ftu_tcpf));
 2146                         err = 0;
 2147                 }
 2148         }
 2149         return (err);
 2150 }
 2151 
 2152 
 2153 /* ------------------------------------------------------------------------ */
 2154 /* Function:    ipf_check_ipf                                               */
 2155 /* Returns:     int - 0 == match, else no match                             */
 2156 /* Parameters:  fin(I)     - pointer to packet information                  */
 2157 /*              fr(I)      - pointer to filter rule                         */
 2158 /*              portcmp(I) - flag indicating whether to attempt matching on */
 2159 /*                           TCP/UDP port data.                             */
 2160 /*                                                                          */
 2161 /* Check to see if a packet matches an IPFilter rule.  Checks of addresses, */
 2162 /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */
 2163 /* this function.                                                           */
 2164 /* ------------------------------------------------------------------------ */
 2165 static inline int
 2166 ipf_check_ipf(fr_info_t *fin, frentry_t *fr, int portcmp)
 2167 {
 2168         u_32_t  *ld, *lm, *lip;
 2169         fripf_t *fri;
 2170         fr_ip_t *fi;
 2171         int i;
 2172 
 2173         fi = &fin->fin_fi;
 2174         fri = fr->fr_ipf;
 2175         lip = (u_32_t *)fi;
 2176         lm = (u_32_t *)&fri->fri_mip;
 2177         ld = (u_32_t *)&fri->fri_ip;
 2178 
 2179         /*
 2180          * first 32 bits to check coversion:
 2181          * IP version, TOS, TTL, protocol
 2182          */
 2183         i = ((*lip & *lm) != *ld);
 2184         FR_DEBUG(("0. %#08x & %#08x != %#08x\n",
 2185                    ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 2186         if (i)
 2187                 return (1);
 2188 
 2189         /*
 2190          * Next 32 bits is a constructed bitmask indicating which IP options
 2191          * are present (if any) in this packet.
 2192          */
 2193         lip++, lm++, ld++;
 2194         i = ((*lip & *lm) != *ld);
 2195         FR_DEBUG(("1. %#08x & %#08x != %#08x\n",
 2196                    ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 2197         if (i != 0)
 2198                 return (1);
 2199 
 2200         lip++, lm++, ld++;
 2201         /*
 2202          * Unrolled loops (4 each, for 32 bits) for address checks.
 2203          */
 2204         /*
 2205          * Check the source address.
 2206          */
 2207         if (fr->fr_satype == FRI_LOOKUP) {
 2208                 i = (*fr->fr_srcfunc)(fin->fin_main_soft, fr->fr_srcptr,
 2209                                       fi->fi_v, lip, fin->fin_plen);
 2210                 if (i == -1)
 2211                         return (1);
 2212                 lip += 3;
 2213                 lm += 3;
 2214                 ld += 3;
 2215         } else {
 2216                 i = ((*lip & *lm) != *ld);
 2217                 FR_DEBUG(("2a. %#08x & %#08x != %#08x\n",
 2218                            ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 2219                 if (fi->fi_v == 6) {
 2220                         lip++, lm++, ld++;
 2221                         i |= ((*lip & *lm) != *ld);
 2222                         FR_DEBUG(("2b. %#08x & %#08x != %#08x\n",
 2223                                    ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 2224                         lip++, lm++, ld++;
 2225                         i |= ((*lip & *lm) != *ld);
 2226                         FR_DEBUG(("2c. %#08x & %#08x != %#08x\n",
 2227                                    ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 2228                         lip++, lm++, ld++;
 2229                         i |= ((*lip & *lm) != *ld);
 2230                         FR_DEBUG(("2d. %#08x & %#08x != %#08x\n",
 2231                                    ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 2232                 } else {
 2233                         lip += 3;
 2234                         lm += 3;
 2235                         ld += 3;
 2236                 }
 2237         }
 2238         i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6;
 2239         if (i != 0)
 2240                 return (1);
 2241 
 2242         /*
 2243          * Check the destination address.
 2244          */
 2245         lip++, lm++, ld++;
 2246         if (fr->fr_datype == FRI_LOOKUP) {
 2247                 i = (*fr->fr_dstfunc)(fin->fin_main_soft, fr->fr_dstptr,
 2248                                       fi->fi_v, lip, fin->fin_plen);
 2249                 if (i == -1)
 2250                         return (1);
 2251                 lip += 3;
 2252                 lm += 3;
 2253                 ld += 3;
 2254         } else {
 2255                 i = ((*lip & *lm) != *ld);
 2256                 FR_DEBUG(("3a. %#08x & %#08x != %#08x\n",
 2257                            ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 2258                 if (fi->fi_v == 6) {
 2259                         lip++, lm++, ld++;
 2260                         i |= ((*lip & *lm) != *ld);
 2261                         FR_DEBUG(("3b. %#08x & %#08x != %#08x\n",
 2262                                    ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 2263                         lip++, lm++, ld++;
 2264                         i |= ((*lip & *lm) != *ld);
 2265                         FR_DEBUG(("3c. %#08x & %#08x != %#08x\n",
 2266                                    ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 2267                         lip++, lm++, ld++;
 2268                         i |= ((*lip & *lm) != *ld);
 2269                         FR_DEBUG(("3d. %#08x & %#08x != %#08x\n",
 2270                                    ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 2271                 } else {
 2272                         lip += 3;
 2273                         lm += 3;
 2274                         ld += 3;
 2275                 }
 2276         }
 2277         i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7;
 2278         if (i != 0)
 2279                 return (1);
 2280         /*
 2281          * IP addresses matched.  The next 32bits contains:
 2282          * mast of old IP header security & authentication bits.
 2283          */
 2284         lip++, lm++, ld++;
 2285         i = (*ld - (*lip & *lm));
 2286         FR_DEBUG(("4. %#08x & %#08x != %#08x\n", *lip, *lm, *ld));
 2287 
 2288         /*
 2289          * Next we have 32 bits of packet flags.
 2290          */
 2291         lip++, lm++, ld++;
 2292         i |= (*ld - (*lip & *lm));
 2293         FR_DEBUG(("5. %#08x & %#08x != %#08x\n", *lip, *lm, *ld));
 2294 
 2295         if (i == 0) {
 2296                 /*
 2297                  * If a fragment, then only the first has what we're
 2298                  * looking for here...
 2299                  */
 2300                 if (portcmp) {
 2301                         if (!ipf_tcpudpchk(&fin->fin_fi, &fr->fr_tuc))
 2302                                 i = 1;
 2303                 } else {
 2304                         if (fr->fr_dcmp || fr->fr_scmp ||
 2305                             fr->fr_tcpf || fr->fr_tcpfm)
 2306                                 i = 1;
 2307                         if (fr->fr_icmpm || fr->fr_icmp) {
 2308                                 if (((fi->fi_p != IPPROTO_ICMP) &&
 2309                                      (fi->fi_p != IPPROTO_ICMPV6)) ||
 2310                                     fin->fin_off || (fin->fin_dlen < 2))
 2311                                         i = 1;
 2312                                 else if ((fin->fin_data[0] & fr->fr_icmpm) !=
 2313                                          fr->fr_icmp) {
 2314                                         FR_DEBUG(("i. %#x & %#x != %#x\n",
 2315                                                  fin->fin_data[0],
 2316                                                  fr->fr_icmpm, fr->fr_icmp));
 2317                                         i = 1;
 2318                                 }
 2319                         }
 2320                 }
 2321         }
 2322         return (i);
 2323 }
 2324 
 2325 
 2326 /* ------------------------------------------------------------------------ */
 2327 /* Function:    ipf_scanlist                                                */
 2328 /* Returns:     int - result flags of scanning filter list                  */
 2329 /* Parameters:  fin(I) - pointer to packet information                      */
 2330 /*              pass(I) - default result to return for filtering            */
 2331 /*                                                                          */
 2332 /* Check the input/output list of rules for a match to the current packet.  */
 2333 /* If a match is found, the value of fr_flags from the rule becomes the     */
 2334 /* return value and fin->fin_fr points to the matched rule.                 */
 2335 /*                                                                          */
 2336 /* This function may be called recursively upto 16 times (limit inbuilt.)   */
 2337 /* When unwinding, it should finish up with fin_depth as 0.                 */
 2338 /*                                                                          */
 2339 /* Could be per interface, but this gets real nasty when you don't have,    */
 2340 /* or can't easily change, the kernel source code to .                      */
 2341 /* ------------------------------------------------------------------------ */
 2342 int
 2343 ipf_scanlist(fr_info_t *fin, u_32_t pass)
 2344 {
 2345         ipf_main_softc_t *softc = fin->fin_main_soft;
 2346         int rulen, portcmp, off, skip;
 2347         struct frentry *fr, *fnext;
 2348         u_32_t passt, passo;
 2349 
 2350         /*
 2351          * Do not allow nesting deeper than 16 levels.
 2352          */
 2353         if (fin->fin_depth >= 16)
 2354                 return (pass);
 2355 
 2356         fr = fin->fin_fr;
 2357 
 2358         /*
 2359         * If there are no rules in this list, return now.
 2360          */
 2361         if (fr == NULL)
 2362                 return (pass);
 2363 
 2364         skip = 0;
 2365         portcmp = 0;
 2366         fin->fin_depth++;
 2367         fin->fin_fr = NULL;
 2368         off = fin->fin_off;
 2369 
 2370         if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off)
 2371                 portcmp = 1;
 2372 
 2373         for (rulen = 0; fr; fr = fnext, rulen++) {
 2374                 fnext = fr->fr_next;
 2375                 if (skip != 0) {
 2376                         FR_VERBOSE(("SKIP %d (%#x)\n", skip, fr->fr_flags));
 2377                         skip--;
 2378                         continue;
 2379                 }
 2380 
 2381                 /*
 2382                  * In all checks below, a null (zero) value in the
 2383                  * filter struture is taken to mean a wildcard.
 2384                  *
 2385                  * check that we are working for the right interface
 2386                  */
 2387 #ifdef  _KERNEL
 2388                 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
 2389                         continue;
 2390 #else
 2391                 if (opts & (OPT_VERBOSE|OPT_DEBUG))
 2392                         printf("\n");
 2393                 FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' :
 2394                                   FR_ISPASS(pass) ? 'p' :
 2395                                   FR_ISACCOUNT(pass) ? 'A' :
 2396                                   FR_ISAUTH(pass) ? 'a' :
 2397                                   (pass & FR_NOMATCH) ? 'n' :'b'));
 2398                 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
 2399                         continue;
 2400                 FR_VERBOSE((":i"));
 2401 #endif
 2402 
 2403                 switch (fr->fr_type)
 2404                 {
 2405                 case FR_T_IPF :
 2406                 case FR_T_IPF_BUILTIN :
 2407                         if (ipf_check_ipf(fin, fr, portcmp))
 2408                                 continue;
 2409                         break;
 2410 #if defined(IPFILTER_BPF)
 2411                 case FR_T_BPFOPC :
 2412                 case FR_T_BPFOPC_BUILTIN :
 2413                     {
 2414                         u_char *mc;
 2415                         int wlen;
 2416 
 2417                         if (*fin->fin_mp == NULL)
 2418                                 continue;
 2419                         if (fin->fin_family != fr->fr_family)
 2420                                 continue;
 2421                         mc = (u_char *)fin->fin_m;
 2422                         wlen = fin->fin_dlen + fin->fin_hlen;
 2423                         if (!bpf_filter(fr->fr_data, mc, wlen, 0))
 2424                                 continue;
 2425                         break;
 2426                     }
 2427 #endif
 2428                 case FR_T_CALLFUNC_BUILTIN :
 2429                     {
 2430                         frentry_t *f;
 2431 
 2432                         f = (*fr->fr_func)(fin, &pass);
 2433                         if (f != NULL)
 2434                                 fr = f;
 2435                         else
 2436                                 continue;
 2437                         break;
 2438                     }
 2439 
 2440                 case FR_T_IPFEXPR :
 2441                 case FR_T_IPFEXPR_BUILTIN :
 2442                         if (fin->fin_family != fr->fr_family)
 2443                                 continue;
 2444                         if (ipf_fr_matcharray(fin, fr->fr_data) == 0)
 2445                                 continue;
 2446                         break;
 2447 
 2448                 default :
 2449                         break;
 2450                 }
 2451 
 2452                 if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) {
 2453                         if (fin->fin_nattag == NULL)
 2454                                 continue;
 2455                         if (ipf_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0)
 2456                                 continue;
 2457                 }
 2458                 FR_VERBOSE(("=%d/%d.%d *", fr->fr_grhead, fr->fr_group, rulen));
 2459 
 2460                 passt = fr->fr_flags;
 2461 
 2462                 /*
 2463                  * If the rule is a "call now" rule, then call the function
 2464                  * in the rule, if it exists and use the results from that.
 2465                  * If the function pointer is bad, just make like we ignore
 2466                  * it, except for increasing the hit counter.
 2467                  */
 2468                 if ((passt & FR_CALLNOW) != 0) {
 2469                         frentry_t *frs;
 2470 
 2471                         ATOMIC_INC64(fr->fr_hits);
 2472                         if ((fr->fr_func == NULL) ||
 2473                             (fr->fr_func == (ipfunc_t)-1))
 2474                                 continue;
 2475 
 2476                         frs = fin->fin_fr;
 2477                         fin->fin_fr = fr;
 2478                         fr = (*fr->fr_func)(fin, &passt);
 2479                         if (fr == NULL) {
 2480                                 fin->fin_fr = frs;
 2481                                 continue;
 2482                         }
 2483                         passt = fr->fr_flags;
 2484                 }
 2485                 fin->fin_fr = fr;
 2486 
 2487 #ifdef  IPFILTER_LOG
 2488                 /*
 2489                  * Just log this packet...
 2490                  */
 2491                 if ((passt & FR_LOGMASK) == FR_LOG) {
 2492                         if (ipf_log_pkt(fin, passt) == -1) {
 2493                                 if (passt & FR_LOGORBLOCK) {
 2494                                         DT(frb_logfail);
 2495                                         passt &= ~FR_CMDMASK;
 2496                                         passt |= FR_BLOCK|FR_QUICK;
 2497                                         fin->fin_reason = FRB_LOGFAIL;
 2498                                 }
 2499                         }
 2500                 }
 2501 #endif /* IPFILTER_LOG */
 2502 
 2503                 MUTEX_ENTER(&fr->fr_lock);
 2504                 fr->fr_bytes += (U_QUAD_T)fin->fin_plen;
 2505                 fr->fr_hits++;
 2506                 MUTEX_EXIT(&fr->fr_lock);
 2507                 fin->fin_rule = rulen;
 2508 
 2509                 passo = pass;
 2510                 if (FR_ISSKIP(passt)) {
 2511                         skip = fr->fr_arg;
 2512                         continue;
 2513                 } else if (((passt & FR_LOGMASK) != FR_LOG) &&
 2514                            ((passt & FR_LOGMASK) != FR_DECAPSULATE)) {
 2515                         pass = passt;
 2516                 }
 2517 
 2518                 if (passt & (FR_RETICMP|FR_FAKEICMP))
 2519                         fin->fin_icode = fr->fr_icode;
 2520 
 2521                 if (fr->fr_group != -1) {
 2522                         (void) strncpy(fin->fin_group,
 2523                                        FR_NAME(fr, fr_group),
 2524                                        strlen(FR_NAME(fr, fr_group)));
 2525                 } else {
 2526                         fin->fin_group[0] = '\0';
 2527                 }
 2528 
 2529                 FR_DEBUG(("pass %#x/%#x/%x\n", passo, pass, passt));
 2530 
 2531                 if (fr->fr_grphead != NULL) {
 2532                         fin->fin_fr = fr->fr_grphead->fg_start;
 2533                         FR_VERBOSE(("group %s\n", FR_NAME(fr, fr_grhead)));
 2534 
 2535                         if (FR_ISDECAPS(passt))
 2536                                 passt = ipf_decaps(fin, pass, fr->fr_icode);
 2537                         else
 2538                                 passt = ipf_scanlist(fin, pass);
 2539 
 2540                         if (fin->fin_fr == NULL) {
 2541                                 fin->fin_rule = rulen;
 2542                                 if (fr->fr_group != -1)
 2543                                         (void) strncpy(fin->fin_group,
 2544                                                        fr->fr_names +
 2545                                                        fr->fr_group,
 2546                                                        strlen(fr->fr_names +
 2547                                                               fr->fr_group));
 2548                                 fin->fin_fr = fr;
 2549                                 passt = pass;
 2550                         }
 2551                         pass = passt;
 2552                 }
 2553 
 2554                 if (pass & FR_QUICK) {
 2555                         /*
 2556                          * Finally, if we've asked to track state for this
 2557                          * packet, set it up.  Add state for "quick" rules
 2558                          * here so that if the action fails we can consider
 2559                          * the rule to "not match" and keep on processing
 2560                          * filter rules.
 2561                          */
 2562                         if ((pass & FR_KEEPSTATE) && !FR_ISAUTH(pass) &&
 2563                             !(fin->fin_flx & FI_STATE)) {
 2564                                 int out = fin->fin_out;
 2565 
 2566                                 fin->fin_fr = fr;
 2567                                 if (ipf_state_add(softc, fin, NULL, 0) == 0) {
 2568                                         LBUMPD(ipf_stats[out], fr_ads);
 2569                                 } else {
 2570                                         LBUMPD(ipf_stats[out], fr_bads);
 2571                                         pass = passo;
 2572                                         continue;
 2573                                 }
 2574                         }
 2575                         break;
 2576                 }
 2577         }
 2578         fin->fin_depth--;
 2579         return (pass);
 2580 }
 2581 
 2582 
 2583 /* ------------------------------------------------------------------------ */
 2584 /* Function:    ipf_acctpkt                                                 */
 2585 /* Returns:     frentry_t* - always returns NULL                            */
 2586 /* Parameters:  fin(I) - pointer to packet information                      */
 2587 /*              passp(IO) - pointer to current/new filter decision (unused) */
 2588 /*                                                                          */
 2589 /* Checks a packet against accounting rules, if there are any for the given */
 2590 /* IP protocol version.                                                     */
 2591 /*                                                                          */
 2592 /* N.B.: this function returns NULL to match the prototype used by other    */
 2593 /* functions called from the IPFilter "mainline" in ipf_check().            */
 2594 /* ------------------------------------------------------------------------ */
 2595 frentry_t *
 2596 ipf_acctpkt(fr_info_t *fin, u_32_t *passp)
 2597 {
 2598         ipf_main_softc_t *softc = fin->fin_main_soft;
 2599         char group[FR_GROUPLEN];
 2600         frentry_t *fr, *frsave;
 2601         u_32_t pass, rulen;
 2602 
 2603         passp = passp;
 2604         fr = softc->ipf_acct[fin->fin_out][softc->ipf_active];
 2605 
 2606         if (fr != NULL) {
 2607                 frsave = fin->fin_fr;
 2608                 bcopy(fin->fin_group, group, FR_GROUPLEN);
 2609                 rulen = fin->fin_rule;
 2610                 fin->fin_fr = fr;
 2611                 pass = ipf_scanlist(fin, FR_NOMATCH);
 2612                 if (FR_ISACCOUNT(pass)) {
 2613                         LBUMPD(ipf_stats[0], fr_acct);
 2614                 }
 2615                 fin->fin_fr = frsave;
 2616                 bcopy(group, fin->fin_group, FR_GROUPLEN);
 2617                 fin->fin_rule = rulen;
 2618         }
 2619         return (NULL);
 2620 }
 2621 
 2622 
 2623 /* ------------------------------------------------------------------------ */
 2624 /* Function:    ipf_firewall                                                */
 2625 /* Returns:     frentry_t* - returns pointer to matched rule, if no matches */
 2626 /*                           were found, returns NULL.                      */
 2627 /* Parameters:  fin(I) - pointer to packet information                      */
 2628 /*              passp(IO) - pointer to current/new filter decision (unused) */
 2629 /*                                                                          */
 2630 /* Applies an appropriate set of firewall rules to the packet, to see if    */
 2631 /* there are any matches.  The first check is to see if a match can be seen */
 2632 /* in the cache.  If not, then search an appropriate list of rules.  Once a */
 2633 /* matching rule is found, take any appropriate actions as defined by the   */
 2634 /* rule - except logging.                                                   */
 2635 /* ------------------------------------------------------------------------ */
 2636 static frentry_t *
 2637 ipf_firewall(fr_info_t *fin, u_32_t *passp)
 2638 {
 2639         ipf_main_softc_t *softc = fin->fin_main_soft;
 2640         frentry_t *fr;
 2641         u_32_t pass;
 2642         int out;
 2643 
 2644         out = fin->fin_out;
 2645         pass = *passp;
 2646 
 2647         /*
 2648          * This rule cache will only affect packets that are not being
 2649          * statefully filtered.
 2650          */
 2651         fin->fin_fr = softc->ipf_rules[out][softc->ipf_active];
 2652         if (fin->fin_fr != NULL)
 2653                 pass = ipf_scanlist(fin, softc->ipf_pass);
 2654 
 2655         if ((pass & FR_NOMATCH)) {
 2656                 LBUMPD(ipf_stats[out], fr_nom);
 2657         }
 2658         fr = fin->fin_fr;
 2659 
 2660         /*
 2661          * Apply packets per second rate-limiting to a rule as required.
 2662          */
 2663         if ((fr != NULL) && (fr->fr_pps != 0) &&
 2664             !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) {
 2665                 DT2(frb_ppsrate, fr_info_t *, fin, frentry_t *, fr);
 2666                 pass &= ~(FR_CMDMASK|FR_RETICMP|FR_RETRST);
 2667                 pass |= FR_BLOCK;
 2668                 LBUMPD(ipf_stats[out], fr_ppshit);
 2669                 fin->fin_reason = FRB_PPSRATE;
 2670         }
 2671 
 2672         /*
 2673          * If we fail to add a packet to the authorization queue, then we
 2674          * drop the packet later.  However, if it was added then pretend
 2675          * we've dropped it already.
 2676          */
 2677         if (FR_ISAUTH(pass)) {
 2678                 if (ipf_auth_new(fin->fin_m, fin) != 0) {
 2679                         DT1(frb_authnew, fr_info_t *, fin);
 2680                         fin->fin_m = *fin->fin_mp = NULL;
 2681                         fin->fin_reason = FRB_AUTHNEW;
 2682                         fin->fin_error = 0;
 2683                 } else {
 2684                         IPFERROR(1);
 2685                         fin->fin_error = ENOSPC;
 2686                 }
 2687         }
 2688 
 2689         if ((fr != NULL) && (fr->fr_func != NULL) &&
 2690             (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW))
 2691                 (void) (*fr->fr_func)(fin, &pass);
 2692 
 2693         /*
 2694          * If a rule is a pre-auth rule, check again in the list of rules
 2695          * loaded for authenticated use.  It does not particulary matter
 2696          * if this search fails because a "preauth" result, from a rule,
 2697          * is treated as "not a pass", hence the packet is blocked.
 2698          */
 2699         if (FR_ISPREAUTH(pass)) {
 2700                 pass = ipf_auth_pre_scanlist(softc, fin, pass);
 2701         }
 2702 
 2703         /*
 2704          * If the rule has "keep frag" and the packet is actually a fragment,
 2705          * then create a fragment state entry.
 2706          */
 2707         if (pass & FR_KEEPFRAG) {
 2708                 if (fin->fin_flx & FI_FRAG) {
 2709                         if (ipf_frag_new(softc, fin, pass) == -1) {
 2710                                 LBUMP(ipf_stats[out].fr_bnfr);
 2711                         } else {
 2712                                 LBUMP(ipf_stats[out].fr_nfr);
 2713                         }
 2714                 } else {
 2715                         LBUMP(ipf_stats[out].fr_cfr);
 2716                 }
 2717         }
 2718 
 2719         fr = fin->fin_fr;
 2720         *passp = pass;
 2721 
 2722         return (fr);
 2723 }
 2724 
 2725 
 2726 /* ------------------------------------------------------------------------ */
 2727 /* Function:    ipf_check                                                   */
 2728 /* Returns:     int -  0 == packet allowed through,                         */
 2729 /*              User space:                                                 */
 2730 /*                    -1 == packet blocked                                  */
 2731 /*                     1 == packet not matched                              */
 2732 /*                    -2 == requires authentication                         */
 2733 /*              Kernel:                                                     */
 2734 /*                   > 0 == filter error # for packet                       */
 2735 /* Parameters: ctx(I)  - pointer to the instance context                    */
 2736 /*             ip(I)   - pointer to start of IPv4/6 packet                  */
 2737 /*             hlen(I) - length of header                                   */
 2738 /*             ifp(I)  - pointer to interface this packet is on             */
 2739 /*             out(I)  - 0 == packet going in, 1 == packet going out        */
 2740 /*             mp(IO)  - pointer to caller's buffer pointer that holds this */
 2741 /*                       IP packet.                                         */
 2742 /* Solaris:                                                                 */
 2743 /*             qpi(I)  - pointer to STREAMS queue information for this      */
 2744 /*                       interface & direction.                             */
 2745 /*                                                                          */
 2746 /* ipf_check() is the master function for all IPFilter packet processing.   */
 2747 /* It orchestrates: Network Address Translation (NAT), checking for packet  */
 2748 /* authorisation (or pre-authorisation), presence of related state info.,   */
 2749 /* generating log entries, IP packet accounting, routing of packets as      */
 2750 /* directed by firewall rules and of course whether or not to allow the     */
 2751 /* packet to be further processed by the kernel.                            */
 2752 /*                                                                          */
 2753 /* For packets blocked, the contents of "mp" will be NULL'd and the buffer  */
 2754 /* freed.  Packets passed may be returned with the pointer pointed to by    */
 2755 /* by "mp" changed to a new buffer.                                         */
 2756 /* ------------------------------------------------------------------------ */
 2757 int
 2758 ipf_check(void *ctx, ip_t *ip, int hlen, struct ifnet *ifp, int out
 2759 #if defined(_KERNEL) && SOLARIS
 2760         , void* qif, mb_t **mp)
 2761 #else
 2762         , mb_t **mp)
 2763 #endif
 2764 {
 2765         /*
 2766          * The above really sucks, but short of writing a diff
 2767          */
 2768         ipf_main_softc_t *softc = ctx;
 2769         fr_info_t frinfo;
 2770         fr_info_t *fin = &frinfo;
 2771         u_32_t pass = softc->ipf_pass;
 2772         frentry_t *fr = NULL;
 2773         int v = IP_V(ip);
 2774         mb_t *mc = NULL;
 2775         mb_t *m;
 2776         /*
 2777          * The first part of ipf_check() deals with making sure that what goes
 2778          * into the filtering engine makes some sense.  Information about the
 2779          * the packet is distilled, collected into a fr_info_t structure and
 2780          * the an attempt to ensure the buffer the packet is in is big enough
 2781          * to hold all the required packet headers.
 2782          */
 2783 #ifdef  _KERNEL
 2784 # if SOLARIS
 2785         qpktinfo_t *qpi = qif;
 2786 
 2787 #  ifdef __sparc
 2788         if ((u_int)ip & 0x3)
 2789                 return (2);
 2790 #  endif
 2791 # else
 2792         SPL_INT(s);
 2793 # endif
 2794 
 2795         if (softc->ipf_running <= 0) {
 2796                 return (0);
 2797         }
 2798 
 2799         bzero((char *)fin, sizeof(*fin));
 2800 
 2801 # if SOLARIS
 2802         if (qpi->qpi_flags & QF_BROADCAST)
 2803                 fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
 2804         if (qpi->qpi_flags & QF_MULTICAST)
 2805                 fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
 2806         m = qpi->qpi_m;
 2807         fin->fin_qfm = m;
 2808         fin->fin_qpi = qpi;
 2809 # else /* SOLARIS */
 2810 
 2811         m = *mp;
 2812 
 2813 #  if defined(M_MCAST)
 2814         if ((m->m_flags & M_MCAST) != 0)
 2815                 fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
 2816 #  endif
 2817 #  if defined(M_MLOOP)
 2818         if ((m->m_flags & M_MLOOP) != 0)
 2819                 fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
 2820 #  endif
 2821 #  if defined(M_BCAST)
 2822         if ((m->m_flags & M_BCAST) != 0)
 2823                 fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
 2824 #  endif
 2825 #  ifdef M_CANFASTFWD
 2826         /*
 2827          * XXX For now, IP Filter and fast-forwarding of cached flows
 2828          * XXX are mutually exclusive.  Eventually, IP Filter should
 2829          * XXX get a "can-fast-forward" filter rule.
 2830          */
 2831         m->m_flags &= ~M_CANFASTFWD;
 2832 #  endif /* M_CANFASTFWD */
 2833 #  if defined(CSUM_DELAY_DATA) && !defined(__FreeBSD__)
 2834         /*
 2835          * disable delayed checksums.
 2836          */
 2837         if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
 2838                 in_delayed_cksum(m);
 2839                 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
 2840         }
 2841 #  endif /* CSUM_DELAY_DATA */
 2842 # endif /* SOLARIS */
 2843 #else
 2844         bzero((char *)fin, sizeof(*fin));
 2845         m = *mp;
 2846 # if defined(M_MCAST)
 2847         if ((m->m_flags & M_MCAST) != 0)
 2848                 fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
 2849 # endif
 2850 # if defined(M_MLOOP)
 2851         if ((m->m_flags & M_MLOOP) != 0)
 2852                 fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
 2853 # endif
 2854 # if defined(M_BCAST)
 2855         if ((m->m_flags & M_BCAST) != 0)
 2856                 fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
 2857 # endif
 2858 #endif /* _KERNEL */
 2859 
 2860         fin->fin_v = v;
 2861         fin->fin_m = m;
 2862         fin->fin_ip = ip;
 2863         fin->fin_mp = mp;
 2864         fin->fin_out = out;
 2865         fin->fin_ifp = ifp;
 2866         fin->fin_error = ENETUNREACH;
 2867         fin->fin_hlen = (u_short)hlen;
 2868         fin->fin_dp = (char *)ip + hlen;
 2869         fin->fin_main_soft = softc;
 2870 
 2871         fin->fin_ipoff = (char *)ip - MTOD(m, char *);
 2872 
 2873         SPL_NET(s);
 2874 
 2875 #ifdef  USE_INET6
 2876         if (v == 6) {
 2877                 LBUMP(ipf_stats[out].fr_ipv6);
 2878                 /*
 2879                  * Jumbo grams are quite likely too big for internal buffer
 2880                  * structures to handle comfortably, for now, so just drop
 2881                  * them.
 2882                  */
 2883                 if (((ip6_t *)ip)->ip6_plen == 0) {
 2884                         DT1(frb_jumbo, ip6_t *, (ip6_t *)ip);
 2885                         pass = FR_BLOCK|FR_NOMATCH;
 2886                         fin->fin_reason = FRB_JUMBO;
 2887                         goto finished;
 2888                 }
 2889                 fin->fin_family = AF_INET6;
 2890         } else
 2891 #endif
 2892         {
 2893                 fin->fin_family = AF_INET;
 2894         }
 2895 
 2896         if (ipf_makefrip(hlen, ip, fin) == -1) {
 2897                 DT1(frb_makefrip, fr_info_t *, fin);
 2898                 pass = FR_BLOCK|FR_NOMATCH;
 2899                 fin->fin_reason = FRB_MAKEFRIP;
 2900                 goto finished;
 2901         }
 2902 
 2903         /*
 2904          * For at least IPv6 packets, if a m_pullup() fails then this pointer
 2905          * becomes NULL and so we have no packet to free.
 2906          */
 2907         if (*fin->fin_mp == NULL)
 2908                 goto finished;
 2909 
 2910         if (!out) {
 2911                 if (v == 4) {
 2912                         if (softc->ipf_chksrc && !ipf_verifysrc(fin)) {
 2913                                 LBUMPD(ipf_stats[0], fr_v4_badsrc);
 2914                                 fin->fin_flx |= FI_BADSRC;
 2915                         }
 2916                         if (fin->fin_ip->ip_ttl < softc->ipf_minttl) {
 2917                                 LBUMPD(ipf_stats[0], fr_v4_badttl);
 2918                                 fin->fin_flx |= FI_LOWTTL;
 2919                         }
 2920                 }
 2921 #ifdef USE_INET6
 2922                 else  if (v == 6) {
 2923                         if (((ip6_t *)ip)->ip6_hlim < softc->ipf_minttl) {
 2924                                 LBUMPD(ipf_stats[0], fr_v6_badttl);
 2925                                 fin->fin_flx |= FI_LOWTTL;
 2926                         }
 2927                 }
 2928 #endif
 2929         }
 2930 
 2931         if (fin->fin_flx & FI_SHORT) {
 2932                 LBUMPD(ipf_stats[out], fr_short);
 2933         }
 2934 
 2935         READ_ENTER(&softc->ipf_mutex);
 2936 
 2937         if (!out) {
 2938                 switch (fin->fin_v)
 2939                 {
 2940                 case 4 :
 2941                         if (ipf_nat_checkin(fin, &pass) == -1) {
 2942                                 goto filterdone;
 2943                         }
 2944                         break;
 2945 #ifdef USE_INET6
 2946                 case 6 :
 2947                         if (ipf_nat6_checkin(fin, &pass) == -1) {
 2948                                 goto filterdone;
 2949                         }
 2950                         break;
 2951 #endif
 2952                 default :
 2953                         break;
 2954                 }
 2955         }
 2956         /*
 2957          * Check auth now.
 2958          * If a packet is found in the auth table, then skip checking
 2959          * the access lists for permission but we do need to consider
 2960          * the result as if it were from the ACL's.  In addition, being
 2961          * found in the auth table means it has been seen before, so do
 2962          * not pass it through accounting (again), lest it be counted twice.
 2963          */
 2964         fr = ipf_auth_check(fin, &pass);
 2965         if (!out && (fr == NULL))
 2966                 (void) ipf_acctpkt(fin, NULL);
 2967 
 2968         if (fr == NULL) {
 2969                 if ((fin->fin_flx & FI_FRAG) != 0)
 2970                         fr = ipf_frag_known(fin, &pass);
 2971 
 2972                 if (fr == NULL)
 2973                         fr = ipf_state_check(fin, &pass);
 2974         }
 2975 
 2976         if ((pass & FR_NOMATCH) || (fr == NULL))
 2977                 fr = ipf_firewall(fin, &pass);
 2978 
 2979         /*
 2980          * If we've asked to track state for this packet, set it up.
 2981          * Here rather than ipf_firewall because ipf_checkauth may decide
 2982         * to return a packet for "keep state"
 2983          */
 2984         if ((pass & FR_KEEPSTATE) && (fin->fin_m != NULL) &&
 2985             !(fin->fin_flx & FI_STATE)) {
 2986                 if (ipf_state_add(softc, fin, NULL, 0) == 0) {
 2987                         LBUMP(ipf_stats[out].fr_ads);
 2988                 } else {
 2989                         LBUMP(ipf_stats[out].fr_bads);
 2990                         if (FR_ISPASS(pass)) {
 2991                                 DT(frb_stateadd);
 2992                                 pass &= ~FR_CMDMASK;
 2993                                 pass |= FR_BLOCK;
 2994                                 fin->fin_reason = FRB_STATEADD;
 2995                         }
 2996                 }
 2997         }
 2998 
 2999         fin->fin_fr = fr;
 3000         if ((fr != NULL) && !(fin->fin_flx & FI_STATE)) {
 3001                 fin->fin_dif = &fr->fr_dif;
 3002                 fin->fin_tif = &fr->fr_tifs[fin->fin_rev];
 3003         }
 3004 
 3005         /*
 3006          * Only count/translate packets which will be passed on, out the
 3007          * interface.
 3008          */
 3009         if (out && FR_ISPASS(pass)) {
 3010                 (void) ipf_acctpkt(fin, NULL);
 3011 
 3012                 switch (fin->fin_v)
 3013                 {
 3014                 case 4 :
 3015                         if (ipf_nat_checkout(fin, &pass) == -1) {
 3016                                 ;
 3017                         } else if ((softc->ipf_update_ipid != 0) && (v == 4)) {
 3018                                 if (ipf_updateipid(fin) == -1) {
 3019                                         DT(frb_updateipid);
 3020                                         LBUMP(ipf_stats[1].fr_ipud);
 3021                                         pass &= ~FR_CMDMASK;
 3022                                         pass |= FR_BLOCK;
 3023                                         fin->fin_reason = FRB_UPDATEIPID;
 3024                                 } else {
 3025                                         LBUMP(ipf_stats[0].fr_ipud);
 3026                                 }
 3027                         }
 3028                         break;
 3029 #ifdef USE_INET6
 3030                 case 6 :
 3031                         (void) ipf_nat6_checkout(fin, &pass);
 3032                         break;
 3033 #endif
 3034                 default :
 3035                         break;
 3036                 }
 3037         }
 3038 
 3039 filterdone:
 3040 #ifdef  IPFILTER_LOG
 3041         if ((softc->ipf_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
 3042                 (void) ipf_dolog(fin, &pass);
 3043         }
 3044 #endif
 3045 
 3046         /*
 3047          * The FI_STATE flag is cleared here so that calling ipf_state_check
 3048          * will work when called from inside of fr_fastroute.  Although
 3049          * there is a similar flag, FI_NATED, for NAT, it does have the same
 3050          * impact on code execution.
 3051          */
 3052         fin->fin_flx &= ~FI_STATE;
 3053 
 3054 #if defined(FASTROUTE_RECURSION)
 3055         /*
 3056          * Up the reference on fr_lock and exit ipf_mutex. The generation of
 3057          * a packet below can sometimes cause a recursive call into IPFilter.
 3058          * On those platforms where that does happen, we need to hang onto
 3059          * the filter rule just in case someone decides to remove or flush it
 3060          * in the meantime.
 3061          */
 3062         if (fr != NULL) {
 3063                 MUTEX_ENTER(&fr->fr_lock);
 3064                 fr->fr_ref++;
 3065                 MUTEX_EXIT(&fr->fr_lock);
 3066         }
 3067 
 3068         RWLOCK_EXIT(&softc->ipf_mutex);
 3069 #endif
 3070 
 3071         if ((pass & FR_RETMASK) != 0) {
 3072                 /*
 3073                 * Should we return an ICMP packet to indicate error
 3074                  * status passing through the packet filter ?
 3075                  * WARNING: ICMP error packets AND TCP RST packets should
 3076                  * ONLY be sent in repsonse to incoming packets.  Sending
 3077                  * them in response to outbound packets can result in a
 3078                  * panic on some operating systems.
 3079                  */
 3080                 if (!out) {
 3081                         if (pass & FR_RETICMP) {
 3082                                 int dst;
 3083 
 3084                                 if ((pass & FR_RETMASK) == FR_FAKEICMP)
 3085                                         dst = 1;
 3086                                 else
 3087                                         dst = 0;
 3088                                 (void) ipf_send_icmp_err(ICMP_UNREACH, fin,
 3089                                                          dst);
 3090                                 LBUMP(ipf_stats[0].fr_ret);
 3091                         } else if (((pass & FR_RETMASK) == FR_RETRST) &&
 3092                                    !(fin->fin_flx & FI_SHORT)) {
 3093                                 if (((fin->fin_flx & FI_OOW) != 0) ||
 3094                                     (ipf_send_reset(fin) == 0)) {
 3095                                         LBUMP(ipf_stats[1].fr_ret);
 3096                                 }
 3097                         }
 3098 
 3099                         /*
 3100                          * When using return-* with auth rules, the auth code
 3101                          * takes over disposing of this packet.
 3102                          */
 3103                         if (FR_ISAUTH(pass) && (fin->fin_m != NULL)) {
 3104                                 DT1(frb_authcapture, fr_info_t *, fin);
 3105                                 fin->fin_m = *fin->fin_mp = NULL;
 3106                                 fin->fin_reason = FRB_AUTHCAPTURE;
 3107                                 m = NULL;
 3108                         }
 3109                 } else {
 3110                         if (pass & FR_RETRST) {
 3111                                 fin->fin_error = ECONNRESET;
 3112                         }
 3113                 }
 3114         }
 3115 
 3116         /*
 3117          * After the above so that ICMP unreachables and TCP RSTs get
 3118          * created properly.
 3119          */
 3120         if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT))
 3121                 ipf_nat_uncreate(fin);
 3122 
 3123         /*
 3124          * If we didn't drop off the bottom of the list of rules (and thus
 3125          * the 'current' rule fr is not NULL), then we may have some extra
 3126          * instructions about what to do with a packet.
 3127         * Once we're finished return to our caller, freeing the packet if
 3128          * we are dropping it.
 3129          */
 3130         if (fr != NULL) {
 3131                 frdest_t *fdp;
 3132 
 3133                 /*
 3134                  * Generate a duplicated packet first because ipf_fastroute
 3135                  * can lead to fin_m being free'd... not good.
 3136                  */
 3137                 fdp = fin->fin_dif;
 3138                 if ((fdp != NULL) && (fdp->fd_ptr != NULL) &&
 3139                     (fdp->fd_ptr != (void *)-1)) {
 3140                         mc = M_COPY(fin->fin_m);
 3141                         if (mc != NULL)
 3142                                 ipf_fastroute(mc, &mc, fin, fdp);
 3143                 }
 3144 
 3145                 fdp = fin->fin_tif;
 3146                 if (!out && (pass & FR_FASTROUTE)) {
 3147                         /*
 3148                          * For fastroute rule, no destination interface defined
 3149                          * so pass NULL as the frdest_t parameter
 3150                          */
 3151                         (void) ipf_fastroute(fin->fin_m, mp, fin, NULL);
 3152                         m = *mp = NULL;
 3153                 } else if ((fdp != NULL) && (fdp->fd_ptr != NULL) &&
 3154                            (fdp->fd_ptr != (struct ifnet *)-1)) {
 3155                         /* this is for to rules: */
 3156                         ipf_fastroute(fin->fin_m, mp, fin, fdp);
 3157                         m = *mp = NULL;
 3158                 }
 3159 
 3160 #if defined(FASTROUTE_RECURSION)
 3161                 (void) ipf_derefrule(softc, &fr);
 3162 #endif
 3163         }
 3164 #if !defined(FASTROUTE_RECURSION)
 3165         RWLOCK_EXIT(&softc->ipf_mutex);
 3166 #endif
 3167 
 3168 finished:
 3169         if (!FR_ISPASS(pass)) {
 3170                 LBUMP(ipf_stats[out].fr_block);
 3171                 if (*mp != NULL) {
 3172 #ifdef _KERNEL
 3173                         FREE_MB_T(*mp);
 3174 #endif
 3175                         m = *mp = NULL;
 3176                 }
 3177         } else {
 3178                 LBUMP(ipf_stats[out].fr_pass);
 3179         }
 3180 
 3181         SPL_X(s);
 3182 
 3183 #ifdef _KERNEL
 3184         if (FR_ISPASS(pass))
 3185                 return (0);
 3186         LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]);
 3187         return (fin->fin_error);
 3188 #else /* _KERNEL */
 3189         if (*mp != NULL)
 3190                 (*mp)->mb_ifp = fin->fin_ifp;
 3191         blockreason = fin->fin_reason;
 3192         FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass));
 3193         /*if ((pass & FR_CMDMASK) == (softc->ipf_pass & FR_CMDMASK))*/
 3194                 if ((pass & FR_NOMATCH) != 0)
 3195                         return (1);
 3196 
 3197         if ((pass & FR_RETMASK) != 0)
 3198                 switch (pass & FR_RETMASK)
 3199                 {
 3200                 case FR_RETRST :
 3201                         return (3);
 3202                 case FR_RETICMP :
 3203                         return (4);
 3204                 case FR_FAKEICMP :
 3205                         return (5);
 3206                 }
 3207 
 3208         switch (pass & FR_CMDMASK)
 3209         {
 3210         case FR_PASS :
 3211                 return (0);
 3212         case FR_BLOCK :
 3213                 return (-1);
 3214         case FR_AUTH :
 3215                 return (-2);
 3216         case FR_ACCOUNT :
 3217                 return (-3);
 3218         case FR_PREAUTH :
 3219                 return (-4);
 3220         }
 3221         return (2);
 3222 #endif /* _KERNEL */
 3223 }
 3224 
 3225 
 3226 #ifdef  IPFILTER_LOG
 3227 /* ------------------------------------------------------------------------ */
 3228 /* Function:    ipf_dolog                                                   */
 3229 /* Returns:     frentry_t* - returns contents of fin_fr (no change made)    */
 3230 /* Parameters:  fin(I) - pointer to packet information                      */
 3231 /*              passp(IO) - pointer to current/new filter decision (unused) */
 3232 /*                                                                          */
 3233 /* Checks flags set to see how a packet should be logged, if it is to be    */
 3234 /* logged.  Adjust statistics based on its success or not.                  */
 3235 /* ------------------------------------------------------------------------ */
 3236 frentry_t *
 3237 ipf_dolog(fr_info_t *fin, u_32_t *passp)
 3238 {
 3239         ipf_main_softc_t *softc = fin->fin_main_soft;
 3240         u_32_t pass;
 3241         int out;
 3242 
 3243         out = fin->fin_out;
 3244         pass = *passp;
 3245 
 3246         if ((softc->ipf_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
 3247                 pass |= FF_LOGNOMATCH;
 3248                 LBUMPD(ipf_stats[out], fr_npkl);
 3249                 goto logit;
 3250 
 3251         } else if (((pass & FR_LOGMASK) == FR_LOGP) ||
 3252             (FR_ISPASS(pass) && (softc->ipf_flags & FF_LOGPASS))) {
 3253                 if ((pass & FR_LOGMASK) != FR_LOGP)
 3254                         pass |= FF_LOGPASS;
 3255                 LBUMPD(ipf_stats[out], fr_ppkl);
 3256                 goto logit;
 3257 
 3258         } else if (((pass & FR_LOGMASK) == FR_LOGB) ||
 3259                    (FR_ISBLOCK(pass) && (softc->ipf_flags & FF_LOGBLOCK))) {
 3260                 if ((pass & FR_LOGMASK) != FR_LOGB)
 3261                         pass |= FF_LOGBLOCK;
 3262                 LBUMPD(ipf_stats[out], fr_bpkl);
 3263 
 3264 logit:
 3265                 if (ipf_log_pkt(fin, pass) == -1) {
 3266                         /*
 3267                          * If the "or-block" option has been used then
 3268                          * block the packet if we failed to log it.
 3269                          */
 3270                         if ((pass & FR_LOGORBLOCK) && FR_ISPASS(pass)) {
 3271                                 DT1(frb_logfail2, u_int, pass);
 3272                                 pass &= ~FR_CMDMASK;
 3273                                 pass |= FR_BLOCK;
 3274                                 fin->fin_reason = FRB_LOGFAIL2;
 3275                         }
 3276                 }
 3277                 *passp = pass;
 3278         }
 3279 
 3280         return (fin->fin_fr);
 3281 }
 3282 #endif /* IPFILTER_LOG */
 3283 
 3284 
 3285 /* ------------------------------------------------------------------------ */
 3286 /* Function:    ipf_cksum                                                   */
 3287 /* Returns:     u_short - IP header checksum                                */
 3288 /* Parameters:  addr(I) - pointer to start of buffer to checksum            */
 3289 /*              len(I)  - length of buffer in bytes                         */
 3290 /*                                                                          */
 3291 /* Calculate the two's complement 16 bit checksum of the buffer passed.     */
 3292 /*                                                                          */
 3293 /* N.B.: addr should be 16bit aligned.                                      */
 3294 /* ------------------------------------------------------------------------ */
 3295 u_short
 3296 ipf_cksum(u_short *addr, int len)
 3297 {
 3298         u_32_t sum = 0;
 3299 
 3300         for (sum = 0; len > 1; len -= 2)
 3301                 sum += *addr++;
 3302 
 3303         /* mop up an odd byte, if necessary */
 3304         if (len == 1)
 3305                 sum += *(u_char *)addr;
 3306 
 3307         /*
 3308          * add back carry outs from top 16 bits to low 16 bits
 3309          */
 3310         sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
 3311         sum += (sum >> 16);                     /* add carry */
 3312         return (u_short)(~sum);
 3313 }
 3314 
 3315 
 3316 /* ------------------------------------------------------------------------ */
 3317 /* Function:    fr_cksum                                                    */
 3318 /* Returns:     u_short - layer 4 checksum                                  */
 3319 /* Parameters:  fin(I)     - pointer to packet information                  */
 3320 /*              ip(I)      - pointer to IP header                           */
 3321 /*              l4proto(I) - protocol to caclulate checksum for             */
 3322 /*              l4hdr(I)   - pointer to layer 4 header                      */
 3323 /*                                                                          */
 3324 /* Calculates the TCP checksum for the packet held in "m", using the data   */
 3325 /* in the IP header "ip" to seed it.                                        */
 3326 /*                                                                          */
 3327 /* NB: This function assumes we've pullup'd enough for all of the IP header */
 3328 /* and the TCP header.  We also assume that data blocks aren't allocated in */
 3329 /* odd sizes.                                                               */
 3330 /*                                                                          */
 3331 /* Expects ip_len and ip_off to be in network byte order when called.       */
 3332 /* ------------------------------------------------------------------------ */
 3333 u_short
 3334 fr_cksum(fr_info_t *fin, ip_t *ip, int l4proto, void *l4hdr)
 3335 {
 3336         u_short *sp, slen, sumsave, *csump;
 3337         u_int sum, sum2;
 3338         int hlen;
 3339         int off;
 3340 #ifdef  USE_INET6
 3341         ip6_t *ip6;
 3342 #endif
 3343 
 3344         csump = NULL;
 3345         sumsave = 0;
 3346         sp = NULL;
 3347         slen = 0;
 3348         hlen = 0;
 3349         sum = 0;
 3350 
 3351         sum = htons((u_short)l4proto);
 3352         /*
 3353          * Add up IP Header portion
 3354          */
 3355 #ifdef  USE_INET6
 3356         if (IP_V(ip) == 4) {
 3357 #endif
 3358                 hlen = IP_HL(ip) << 2;
 3359                 off = hlen;
 3360                 sp = (u_short *)&ip->ip_src;
 3361                 sum += *sp++;   /* ip_src */
 3362                 sum += *sp++;
 3363                 sum += *sp++;   /* ip_dst */
 3364                 sum += *sp++;
 3365                 slen = fin->fin_plen - off;
 3366                 sum += htons(slen);
 3367 #ifdef  USE_INET6
 3368         } else if (IP_V(ip) == 6) {
 3369                 mb_t *m;
 3370 
 3371                 m = fin->fin_m;
 3372                 ip6 = (ip6_t *)ip;
 3373                 off = ((caddr_t)ip6 - m->m_data) + sizeof(struct ip6_hdr);
 3374                 int len = ntohs(ip6->ip6_plen) - (off - sizeof(*ip6));
 3375                 return (ipf_pcksum6(m, ip6, off, len));
 3376         } else {
 3377                 return (0xffff);
 3378         }
 3379 #endif
 3380 
 3381         switch (l4proto)
 3382         {
 3383         case IPPROTO_UDP :
 3384                 csump = &((udphdr_t *)l4hdr)->uh_sum;
 3385                 break;
 3386 
 3387         case IPPROTO_TCP :
 3388                 csump = &((tcphdr_t *)l4hdr)->th_sum;
 3389                 break;
 3390         case IPPROTO_ICMP :
 3391                 csump = &((icmphdr_t *)l4hdr)->icmp_cksum;
 3392                 sum = 0;        /* Pseudo-checksum is not included */
 3393                 break;
 3394 #ifdef USE_INET6
 3395         case IPPROTO_ICMPV6 :
 3396                 csump = &((struct icmp6_hdr *)l4hdr)->icmp6_cksum;
 3397                 break;
 3398 #endif
 3399         default :
 3400                 break;
 3401         }
 3402 
 3403         if (csump != NULL) {
 3404                 sumsave = *csump;
 3405                 *csump = 0;
 3406         }
 3407 
 3408         sum2 = ipf_pcksum(fin, off, sum);
 3409         if (csump != NULL)
 3410                 *csump = sumsave;
 3411         return (sum2);
 3412 }
 3413 
 3414 
 3415 /* ------------------------------------------------------------------------ */
 3416 /* Function:    ipf_findgroup                                               */
 3417 /* Returns:     frgroup_t * - NULL = group not found, else pointer to group */
 3418 /* Parameters:  softc(I) - pointer to soft context main structure           */
 3419 /*              group(I) - group name to search for                         */
 3420 /*              unit(I)  - device to which this group belongs               */
 3421 /*              set(I)   - which set of rules (inactive/inactive) this is   */
 3422 /*              fgpp(O)  - pointer to place to store pointer to the pointer */
 3423 /*                         to where to add the next (last) group or where   */
 3424 /*                         to delete group from.                            */
 3425 /*                                                                          */
 3426 /* Search amongst the defined groups for a particular group number.         */
 3427 /* ------------------------------------------------------------------------ */
 3428 frgroup_t *
 3429 ipf_findgroup(ipf_main_softc_t *softc, char *group, minor_t unit, int set,
 3430         frgroup_t ***fgpp)
 3431 {
 3432         frgroup_t *fg, **fgp;
 3433 
 3434         /*
 3435          * Which list of groups to search in is dependent on which list of
 3436          * rules are being operated on.
 3437          */
 3438         fgp = &softc->ipf_groups[unit][set];
 3439 
 3440         while ((fg = *fgp) != NULL) {
 3441                 if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0)
 3442                         break;
 3443                 else
 3444                         fgp = &fg->fg_next;
 3445         }
 3446         if (fgpp != NULL)
 3447                 *fgpp = fgp;
 3448         return (fg);
 3449 }
 3450 
 3451 
 3452 /* ------------------------------------------------------------------------ */
 3453 /* Function:    ipf_group_add                                               */
 3454 /* Returns:     frgroup_t * - NULL == did not create group,                 */
 3455 /*                            != NULL == pointer to the group               */
 3456 /* Parameters:  softc(I) - pointer to soft context main structure           */
 3457 /*              num(I)   - group number to add                              */
 3458 /*              head(I)  - rule pointer that is using this as the head      */
 3459 /*              flags(I) - rule flags which describe the type of rule it is */
 3460 /*              unit(I)  - device to which this group will belong to        */
 3461 /*              set(I)   - which set of rules (inactive/inactive) this is   */
 3462 /* Write Locks: ipf_mutex                                                   */
 3463 /*                                                                          */
 3464 /* Add a new group head, or if it already exists, increase the reference    */
 3465 /* count to it.                                                             */
 3466 /* ------------------------------------------------------------------------ */
 3467 frgroup_t *
 3468 ipf_group_add(ipf_main_softc_t *softc, char *group, void *head, u_32_t flags,
 3469         minor_t unit, int set)
 3470 {
 3471         frgroup_t *fg, **fgp;
 3472         u_32_t gflags;
 3473 
 3474         if (group == NULL)
 3475                 return (NULL);
 3476 
 3477         if (unit == IPL_LOGIPF && *group == '\0')
 3478                 return (NULL);
 3479 
 3480         fgp = NULL;
 3481         gflags = flags & FR_INOUT;
 3482 
 3483         fg = ipf_findgroup(softc, group, unit, set, &fgp);
 3484         if (fg != NULL) {
 3485                 if (fg->fg_head == NULL && head != NULL)
 3486                         fg->fg_head = head;
 3487                 if (fg->fg_flags == 0)
 3488                         fg->fg_flags = gflags;
 3489                 else if (gflags != fg->fg_flags)
 3490                         return (NULL);
 3491                 fg->fg_ref++;
 3492                 return (fg);
 3493         }
 3494 
 3495         KMALLOC(fg, frgroup_t *);
 3496         if (fg != NULL) {
 3497                 fg->fg_head = head;
 3498                 fg->fg_start = NULL;
 3499                 fg->fg_next = *fgp;
 3500                 bcopy(group, fg->fg_name, strlen(group) + 1);
 3501                 fg->fg_flags = gflags;
 3502                 fg->fg_ref = 1;
 3503                 fg->fg_set = &softc->ipf_groups[unit][set];
 3504                 *fgp = fg;
 3505         }
 3506         return (fg);
 3507 }
 3508 
 3509 
 3510 /* ------------------------------------------------------------------------ */
 3511 /* Function:    ipf_group_del                                               */
 3512 /* Returns:     int      - number of rules deleted                          */
 3513 /* Parameters:  softc(I) - pointer to soft context main structure           */
 3514 /*              group(I) - group name to delete                             */
 3515 /*              fr(I)    - filter rule from which group is referenced       */
 3516 /* Write Locks: ipf_mutex                                                   */
 3517 /*                                                                          */
 3518 /* This function is called whenever a reference to a group is to be dropped */
 3519 /* and thus its reference count needs to be lowered and the group free'd if */
 3520 /* the reference count reaches zero. Passing in fr is really for the sole   */
 3521 /* purpose of knowing when the head rule is being deleted.                  */
 3522 /* ------------------------------------------------------------------------ */
 3523 void
 3524 ipf_group_del(ipf_main_softc_t *softc, frgroup_t *group, frentry_t *fr)
 3525 {
 3526 
 3527         if (group->fg_head == fr)
 3528                 group->fg_head = NULL;
 3529 
 3530         group->fg_ref--;
 3531         if ((group->fg_ref == 0) && (group->fg_start == NULL))
 3532                 ipf_group_free(group);
 3533 }
 3534 
 3535 
 3536 /* ------------------------------------------------------------------------ */
 3537 /* Function:    ipf_group_free                                              */
 3538 /* Returns:     Nil                                                         */
 3539 /* Parameters:  group(I) - pointer to filter rule group                     */
 3540 /*                                                                          */
 3541 /* Remove the group from the list of groups and free it.                    */
 3542 /* ------------------------------------------------------------------------ */
 3543 static void
 3544 ipf_group_free(frgroup_t *group)
 3545 {
 3546         frgroup_t **gp;
 3547 
 3548         for (gp = group->fg_set; *gp != NULL; gp = &(*gp)->fg_next) {
 3549                 if (*gp == group) {
 3550                         *gp = group->fg_next;
 3551                         break;
 3552                 }
 3553         }
 3554         KFREE(group);
 3555 }
 3556 
 3557 
 3558 /* ------------------------------------------------------------------------ */
 3559 /* Function:    ipf_group_flush                                             */
 3560 /* Returns:     int      - number of rules flush from group                 */
 3561 /* Parameters:  softc(I) - pointer to soft context main structure           */
 3562 /* Parameters:  group(I) - pointer to filter rule group                     */
 3563 /*                                                                          */
 3564 /* Remove all of the rules that currently are listed under the given group. */
 3565 /* ------------------------------------------------------------------------ */
 3566 static int
 3567 ipf_group_flush(ipf_main_softc_t *softc, frgroup_t *group)
 3568 {
 3569         int gone = 0;
 3570 
 3571         (void) ipf_flushlist(softc, &gone, &group->fg_start);
 3572 
 3573         return (gone);
 3574 }
 3575 
 3576 
 3577 /* ------------------------------------------------------------------------ */
 3578 /* Function:    ipf_getrulen                                                */
 3579 /* Returns:     frentry_t * - NULL == not found, else pointer to rule n     */
 3580 /* Parameters:  softc(I) - pointer to soft context main structure           */
 3581 /* Parameters:  unit(I)  - device for which to count the rule's number      */
 3582 /*              flags(I) - which set of rules to find the rule in           */
 3583 /*              group(I) - group name                                       */
 3584 /*              n(I)     - rule number to find                              */
 3585 /*                                                                          */
 3586 /* Find rule # n in group # g and return a pointer to it.  Return NULl if   */
 3587 /* group # g doesn't exist or there are less than n rules in the group.     */
 3588 /* ------------------------------------------------------------------------ */
 3589 frentry_t *
 3590 ipf_getrulen(ipf_main_softc_t *softc, int unit, char *group, u_32_t n)
 3591 {
 3592         frentry_t *fr;
 3593         frgroup_t *fg;
 3594 
 3595         fg = ipf_findgroup(softc, group, unit, softc->ipf_active, NULL);
 3596         if (fg == NULL)
 3597                 return (NULL);
 3598         for (fr = fg->fg_start; fr && n; fr = fr->fr_next, n--)
 3599                 ;
 3600         if (n != 0)
 3601                 return (NULL);
 3602         return (fr);
 3603 }
 3604 
 3605 
 3606 /* ------------------------------------------------------------------------ */
 3607 /* Function:    ipf_flushlist                                               */
 3608 /* Returns:     int - >= 0 - number of flushed rules                        */
 3609 /* Parameters:  softc(I)   - pointer to soft context main structure         */
 3610 /*              nfreedp(O) - pointer to int where flush count is stored     */
 3611 /*              listp(I)   - pointer to list to flush pointer               */
 3612 /* Write Locks: ipf_mutex                                                   */
 3613 /*                                                                          */
 3614 /* Recursively flush rules from the list, descending groups as they are     */
 3615 /* encountered.  if a rule is the head of a group and it has lost all its   */
 3616 /* group members, then also delete the group reference.  nfreedp is needed  */
 3617 /* to store the accumulating count of rules removed, whereas the returned   */
 3618 /* value is just the number removed from the current list.  The latter is   */
 3619 /* needed to correctly adjust reference counts on rules that define groups. */
 3620 /*                                                                          */
 3621 /* NOTE: Rules not loaded from user space cannot be flushed.                */
 3622 /* ------------------------------------------------------------------------ */
 3623 static int
 3624 ipf_flushlist(ipf_main_softc_t *softc, int *nfreedp, frentry_t **listp)
 3625 {
 3626         int freed = 0;
 3627         frentry_t *fp;
 3628 
 3629         while ((fp = *listp) != NULL) {
 3630                 if ((fp->fr_type & FR_T_BUILTIN) ||
 3631                     !(fp->fr_flags & FR_COPIED)) {
 3632                         listp = &fp->fr_next;
 3633                         continue;
 3634                 }
 3635                 *listp = fp->fr_next;
 3636                 if (fp->fr_next != NULL)
 3637                         fp->fr_next->fr_pnext = fp->fr_pnext;
 3638                 fp->fr_pnext = NULL;
 3639 
 3640                 if (fp->fr_grphead != NULL) {
 3641                         freed += ipf_group_flush(softc, fp->fr_grphead);
 3642                         fp->fr_names[fp->fr_grhead] = '\0';
 3643                 }
 3644 
 3645                 if (fp->fr_icmpgrp != NULL) {
 3646                         freed += ipf_group_flush(softc, fp->fr_icmpgrp);
 3647                         fp->fr_names[fp->fr_icmphead] = '\0';
 3648                 }
 3649 
 3650                 if (fp->fr_srctrack.ht_max_nodes)
 3651                         ipf_rb_ht_flush(&fp->fr_srctrack);
 3652 
 3653                 fp->fr_next = NULL;
 3654 
 3655                 ASSERT(fp->fr_ref > 0);
 3656                 if (ipf_derefrule(softc, &fp) == 0)
 3657                         freed++;
 3658         }
 3659         *nfreedp += freed;
 3660         return (freed);
 3661 }
 3662 
 3663 
 3664 /* ------------------------------------------------------------------------ */
 3665 /* Function:    ipf_flush                                                   */
 3666 /* Returns:     int - >= 0 - number of flushed rules                        */
 3667 /* Parameters:  softc(I) - pointer to soft context main structure           */
 3668 /*              unit(I)  - device for which to flush rules                  */
 3669 /*              flags(I) - which set of rules to flush                      */
 3670 /*                                                                          */
 3671 /* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */
 3672 /* and IPv6) as defined by the value of flags.                              */
 3673 /* ------------------------------------------------------------------------ */
 3674 int
 3675 ipf_flush(ipf_main_softc_t *softc, minor_t unit, int flags)
 3676 {
 3677         int flushed = 0, set;
 3678 
 3679         WRITE_ENTER(&softc->ipf_mutex);
 3680 
 3681         set = softc->ipf_active;
 3682         if ((flags & FR_INACTIVE) == FR_INACTIVE)
 3683                 set = 1 - set;
 3684 
 3685         if (flags & FR_OUTQUE) {
 3686                 ipf_flushlist(softc, &flushed, &softc->ipf_rules[1][set]);
 3687                 ipf_flushlist(softc, &flushed, &softc->ipf_acct[1][set]);
 3688         }
 3689         if (flags & FR_INQUE) {
 3690                 ipf_flushlist(softc, &flushed, &softc->ipf_rules[0][set]);
 3691                 ipf_flushlist(softc, &flushed, &softc->ipf_acct[0][set]);
 3692         }
 3693 
 3694         flushed += ipf_flush_groups(softc, &softc->ipf_groups[unit][set],
 3695                                     flags & (FR_INQUE|FR_OUTQUE));
 3696 
 3697         RWLOCK_EXIT(&softc->ipf_mutex);
 3698 
 3699         if (unit == IPL_LOGIPF) {
 3700                 int tmp;
 3701 
 3702                 tmp = ipf_flush(softc, IPL_LOGCOUNT, flags);
 3703                 if (tmp >= 0)
 3704                         flushed += tmp;
 3705         }
 3706         return (flushed);
 3707 }
 3708 
 3709 
 3710 /* ------------------------------------------------------------------------ */
 3711 /* Function:    ipf_flush_groups                                            */
 3712 /* Returns:     int - >= 0 - number of flushed rules                        */
 3713 /* Parameters:  softc(I)  - soft context pointerto work with                */
 3714 /*              grhead(I) - pointer to the start of the group list to flush */
 3715 /*              flags(I)  - which set of rules to flush                     */
 3716 /*                                                                          */
 3717 /* Walk through all of the groups under the given group head and remove all */
 3718 /* of those that match the flags passed in. The for loop here is bit more   */
 3719 /* complicated than usual because the removal of a rule with ipf_derefrule  */
 3720 /* may end up removing not only the structure pointed to by "fg" but also   */
 3721 /* what is fg_next and fg_next after that. So if a filter rule is actually  */
 3722 /* removed from the group then it is necessary to start again.              */
 3723 /* ------------------------------------------------------------------------ */
 3724 static int
 3725 ipf_flush_groups(ipf_main_softc_t *softc, frgroup_t **grhead, int flags)
 3726 {
 3727         frentry_t *fr, **frp;
 3728         frgroup_t *fg, **fgp;
 3729         int flushed = 0;
 3730         int removed = 0;
 3731 
 3732         for (fgp = grhead; (fg = *fgp) != NULL; ) {
 3733                 while ((fg != NULL) && ((fg->fg_flags & flags) == 0))
 3734                         fg = fg->fg_next;
 3735                 if (fg == NULL)
 3736                         break;
 3737                 removed = 0;
 3738                 frp = &fg->fg_start;
 3739                 while ((removed == 0) && ((fr = *frp) != NULL)) {
 3740                         if ((fr->fr_flags & flags) == 0) {
 3741                                 frp = &fr->fr_next;
 3742                         } else {
 3743                                 if (fr->fr_next != NULL)
 3744                                         fr->fr_next->fr_pnext = fr->fr_pnext;
 3745                                 *frp = fr->fr_next;
 3746                                 fr->fr_pnext = NULL;
 3747                                 fr->fr_next = NULL;
 3748                                 (void) ipf_derefrule(softc, &fr);
 3749                                 flushed++;
 3750                                 removed++;
 3751                         }
 3752                 }
 3753                 if (removed == 0)
 3754                         fgp = &fg->fg_next;
 3755         }
 3756         return (flushed);
 3757 }
 3758 
 3759 
 3760 /* ------------------------------------------------------------------------ */
 3761 /* Function:    memstr                                                      */
 3762 /* Returns:     char *  - NULL if failed, != NULL pointer to matching bytes */
 3763 /* Parameters:  src(I)  - pointer to byte sequence to match                 */
 3764 /*              dst(I)  - pointer to byte sequence to search                */
 3765 /*              slen(I) - match length                                      */
 3766 /*              dlen(I) - length available to search in                     */
 3767 /*                                                                          */
 3768 /* Search dst for a sequence of bytes matching those at src and extend for  */
 3769 /* slen bytes.                                                              */
 3770 /* ------------------------------------------------------------------------ */
 3771 char *
 3772 memstr(const char *src, char *dst, size_t slen, size_t dlen)
 3773 {
 3774         char *s = NULL;
 3775 
 3776         while (dlen >= slen) {
 3777                 if (bcmp(src, dst, slen) == 0) {
 3778                         s = dst;
 3779                         break;
 3780                 }
 3781                 dst++;
 3782                 dlen--;
 3783         }
 3784         return (s);
 3785 }
 3786 /* ------------------------------------------------------------------------ */
 3787 /* Function:    ipf_fixskip                                                 */
 3788 /* Returns:     Nil                                                         */
 3789 /* Parameters:  listp(IO)    - pointer to start of list with skip rule      */
 3790 /*              rp(I)        - rule added/removed with skip in it.          */
 3791 /*              addremove(I) - adjustment (-1/+1) to make to skip count,    */
 3792 /*                             depending on whether a rule was just added   */
 3793 /*                             or removed.                                  */
 3794 /*                                                                          */
 3795 /* Adjust all the rules in a list which would have skip'd past the position */
 3796 /* where we are inserting to skip to the right place given the change.      */
 3797 /* ------------------------------------------------------------------------ */
 3798 void
 3799 ipf_fixskip(frentry_t **listp, frentry_t *rp, int addremove)
 3800 {
 3801         int rules, rn;
 3802         frentry_t *fp;
 3803 
 3804         rules = 0;
 3805         for (fp = *listp; (fp != NULL) && (fp != rp); fp = fp->fr_next)
 3806                 rules++;
 3807 
 3808         if (fp == NULL)
 3809                 return;
 3810 
 3811         for (rn = 0, fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++)
 3812                 if (FR_ISSKIP(fp->fr_flags) && (rn + fp->fr_arg >= rules))
 3813                         fp->fr_arg += addremove;
 3814 }
 3815 
 3816 
 3817 #ifdef  _KERNEL
 3818 /* ------------------------------------------------------------------------ */
 3819 /* Function:    count4bits                                                  */
 3820 /* Returns:     int - >= 0 - number of consecutive bits in input            */
 3821 /* Parameters:  ip(I) - 32bit IP address                                    */
 3822 /*                                                                          */
 3823 /* IPv4 ONLY                                                                */
 3824 /* count consecutive 1's in bit mask.  If the mask generated by counting    */
 3825 /* consecutive 1's is different to that passed, return -1, else return #    */
 3826 /* of bits.                                                                 */
 3827 /* ------------------------------------------------------------------------ */
 3828 int
 3829 count4bits(u_32_t ip)
 3830 {
 3831         u_32_t  ipn;
 3832         int     cnt = 0, i, j;
 3833 
 3834         ip = ipn = ntohl(ip);
 3835         for (i = 32; i; i--, ipn *= 2)
 3836                 if (ipn & 0x80000000)
 3837                         cnt++;
 3838                 else
 3839                         break;
 3840         ipn = 0;
 3841         for (i = 32, j = cnt; i; i--, j--) {
 3842                 ipn *= 2;
 3843                 if (j > 0)
 3844                         ipn++;
 3845         }
 3846         if (ipn == ip)
 3847                 return (cnt);
 3848         return (-1);
 3849 }
 3850 
 3851 
 3852 /* ------------------------------------------------------------------------ */
 3853 /* Function:    count6bits                                                  */
 3854 /* Returns:     int - >= 0 - number of consecutive bits in input            */
 3855 /* Parameters:  msk(I) - pointer to start of IPv6 bitmask                   */
 3856 /*                                                                          */
 3857 /* IPv6 ONLY                                                                */
 3858 /* count consecutive 1's in bit mask.                                       */
 3859 /* ------------------------------------------------------------------------ */
 3860 # ifdef USE_INET6
 3861 int
 3862 count6bits(u_32_t *msk)
 3863 {
 3864         int i = 0, k;
 3865         u_32_t j;
 3866 
 3867         for (k = 3; k >= 0; k--)
 3868                 if (msk[k] == 0xffffffff)
 3869                         i += 32;
 3870                 else {
 3871                         for (j = msk[k]; j; j <<= 1)
 3872                                 if (j & 0x80000000)
 3873                                         i++;
 3874                 }
 3875         return (i);
 3876 }
 3877 # endif
 3878 #endif /* _KERNEL */
 3879 
 3880 
 3881 /* ------------------------------------------------------------------------ */
 3882 /* Function:    ipf_synclist                                                */
 3883 /* Returns:     int    - 0 = no failures, else indication of first failure  */
 3884 /* Parameters:  fr(I)  - start of filter list to sync interface names for   */
 3885 /*              ifp(I) - interface pointer for limiting sync lookups        */
 3886 /* Write Locks: ipf_mutex                                                   */
 3887 /*                                                                          */
 3888 /* Walk through a list of filter rules and resolve any interface names into */
 3889 /* pointers.  Where dynamic addresses are used, also update the IP address  */
 3890 /* used in the rule.  The interface pointer is used to limit the lookups to */
 3891 /* a specific set of matching names if it is non-NULL.                      */
 3892 /* Errors can occur when resolving the destination name of to/dup-to fields */
 3893 /* when the name points to a pool and that pool doest not exist. If this    */
 3894 /* does happen then it is necessary to check if there are any lookup refs   */
 3895 /* that need to be dropped before returning with an error.                  */
 3896 /* ------------------------------------------------------------------------ */
 3897 static int
 3898 ipf_synclist(ipf_main_softc_t *softc, frentry_t *fr, void *ifp)
 3899 {
 3900         frentry_t *frt, *start = fr;
 3901         frdest_t *fdp;
 3902         char *name;
 3903         int error;
 3904         void *ifa;
 3905         int v, i;
 3906 
 3907         error = 0;
 3908 
 3909         for (; fr; fr = fr->fr_next) {
 3910                 if (fr->fr_family == AF_INET)
 3911                         v = 4;
 3912                 else if (fr->fr_family == AF_INET6)
 3913                         v = 6;
 3914                 else
 3915                         v = 0;
 3916 
 3917                 /*
 3918                  * Lookup all the interface names that are part of the rule.
 3919                  */
 3920                 for (i = 0; i < FR_NUM(fr->fr_ifas); i++) {
 3921                         if ((ifp != NULL) && (fr->fr_ifas[i] != ifp))
 3922                                 continue;
 3923                         if (fr->fr_ifnames[i] == -1)
 3924                                 continue;
 3925                         name = FR_NAME(fr, fr_ifnames[i]);
 3926                         fr->fr_ifas[i] = ipf_resolvenic(softc, name, v);
 3927                 }
 3928 
 3929                 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) {
 3930                         if (fr->fr_satype != FRI_NORMAL &&
 3931                             fr->fr_satype != FRI_LOOKUP) {
 3932                                 ifa = ipf_resolvenic(softc, fr->fr_names +
 3933                                                      fr->fr_sifpidx, v);
 3934                                 ipf_ifpaddr(softc, v, fr->fr_satype, ifa,
 3935                                             &fr->fr_src6, &fr->fr_smsk6);
 3936                         }
 3937                         if (fr->fr_datype != FRI_NORMAL &&
 3938                             fr->fr_datype != FRI_LOOKUP) {
 3939                                 ifa = ipf_resolvenic(softc, fr->fr_names +
 3940                                                      fr->fr_sifpidx, v);
 3941                                 ipf_ifpaddr(softc, v, fr->fr_datype, ifa,
 3942                                             &fr->fr_dst6, &fr->fr_dmsk6);
 3943                         }
 3944                 }
 3945 
 3946                 fdp = &fr->fr_tifs[0];
 3947                 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
 3948                         error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
 3949                         if (error != 0)
 3950                                 goto unwind;
 3951                 }
 3952 
 3953                 fdp = &fr->fr_tifs[1];
 3954                 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
 3955                         error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
 3956                         if (error != 0)
 3957                                 goto unwind;
 3958                 }
 3959 
 3960                 fdp = &fr->fr_dif;
 3961                 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
 3962                         error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
 3963                         if (error != 0)
 3964                                 goto unwind;
 3965                 }
 3966 
 3967                 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
 3968                     (fr->fr_satype == FRI_LOOKUP) && (fr->fr_srcptr == NULL)) {
 3969                         fr->fr_srcptr = ipf_lookup_res_num(softc,
 3970                                                            fr->fr_srctype,
 3971                                                            IPL_LOGIPF,
 3972                                                            fr->fr_srcnum,
 3973                                                            &fr->fr_srcfunc);
 3974                 }
 3975                 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
 3976                     (fr->fr_datype == FRI_LOOKUP) && (fr->fr_dstptr == NULL)) {
 3977                         fr->fr_dstptr = ipf_lookup_res_num(softc,
 3978                                                            fr->fr_dsttype,
 3979                                                            IPL_LOGIPF,
 3980                                                            fr->fr_dstnum,
 3981                                                            &fr->fr_dstfunc);
 3982                 }
 3983         }
 3984         return (0);
 3985 
 3986 unwind:
 3987         for (frt = start; frt != fr; fr = fr->fr_next) {
 3988                 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
 3989                     (frt->fr_satype == FRI_LOOKUP) && (frt->fr_srcptr != NULL))
 3990                                 ipf_lookup_deref(softc, frt->fr_srctype,
 3991                                                  frt->fr_srcptr);
 3992                 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
 3993                     (frt->fr_datype == FRI_LOOKUP) && (frt->fr_dstptr != NULL))
 3994                                 ipf_lookup_deref(softc, frt->fr_dsttype,
 3995                                                  frt->fr_dstptr);
 3996         }
 3997         return (error);
 3998 }
 3999 
 4000 
 4001 /* ------------------------------------------------------------------------ */
 4002 /* Function:    ipf_sync                                                    */
 4003 /* Returns:     void                                                        */
 4004 /* Parameters:  Nil                                                         */
 4005 /*                                                                          */
 4006 /* ipf_sync() is called when we suspect that the interface list or          */
 4007 /* information about interfaces (like IP#) has changed.  Go through all     */
 4008 /* filter rules, NAT entries and the state table and check if anything      */
 4009 /* needs to be changed/updated.                                             */
 4010 /* ------------------------------------------------------------------------ */
 4011 int
 4012 ipf_sync(ipf_main_softc_t *softc, void *ifp)
 4013 {
 4014         int i;
 4015 
 4016 #if !SOLARIS
 4017         ipf_nat_sync(softc, ifp);
 4018         ipf_state_sync(softc, ifp);
 4019         ipf_lookup_sync(softc, ifp);
 4020 #endif
 4021 
 4022         WRITE_ENTER(&softc->ipf_mutex);
 4023         (void) ipf_synclist(softc, softc->ipf_acct[0][softc->ipf_active], ifp);
 4024         (void) ipf_synclist(softc, softc->ipf_acct[1][softc->ipf_active], ifp);
 4025         (void) ipf_synclist(softc, softc->ipf_rules[0][softc->ipf_active], ifp);
 4026         (void) ipf_synclist(softc, softc->ipf_rules[1][softc->ipf_active], ifp);
 4027 
 4028         for (i = 0; i < IPL_LOGSIZE; i++) {
 4029                 frgroup_t *g;
 4030 
 4031                 for (g = softc->ipf_groups[i][0]; g != NULL; g = g->fg_next)
 4032                         (void) ipf_synclist(softc, g->fg_start, ifp);
 4033                 for (g = softc->ipf_groups[i][1]; g != NULL; g = g->fg_next)
 4034                         (void) ipf_synclist(softc, g->fg_start, ifp);
 4035         }
 4036         RWLOCK_EXIT(&softc->ipf_mutex);
 4037 
 4038         return (0);
 4039 }
 4040 
 4041 
 4042 /*
 4043  * In the functions below, bcopy() is called because the pointer being
 4044  * copied _from_ in this instance is a pointer to a char buf (which could
 4045  * end up being unaligned) and on the kernel's local stack.
 4046  */
 4047 /* ------------------------------------------------------------------------ */
 4048 /* Function:    copyinptr                                                   */
 4049 /* Returns:     int - 0 = success, else failure                             */
 4050 /* Parameters:  src(I)  - pointer to the source address                     */
 4051 /*              dst(I)  - destination address                               */
 4052 /*              size(I) - number of bytes to copy                           */
 4053 /*                                                                          */
 4054 /* Copy a block of data in from user space, given a pointer to the pointer  */
 4055 /* to start copying from (src) and a pointer to where to store it (dst).    */
 4056 /* NB: src - pointer to user space pointer, dst - kernel space pointer      */
 4057 /* ------------------------------------------------------------------------ */
 4058 int
 4059 copyinptr(ipf_main_softc_t *softc, void *src, void *dst, size_t size)
 4060 {
 4061         caddr_t ca;
 4062         int error;
 4063 
 4064 #if SOLARIS
 4065         error = COPYIN(src, &ca, sizeof(ca));
 4066         if (error != 0)
 4067                 return (error);
 4068 #else
 4069         bcopy(src, (caddr_t)&ca, sizeof(ca));
 4070 #endif
 4071         error = COPYIN(ca, dst, size);
 4072         if (error != 0) {
 4073                 IPFERROR(3);
 4074                 error = EFAULT;
 4075         }
 4076         return (error);
 4077 }
 4078 
 4079 
 4080 /* ------------------------------------------------------------------------ */
 4081 /* Function:    copyoutptr                                                  */
 4082 /* Returns:     int - 0 = success, else failure                             */
 4083 /* Parameters:  src(I)  - pointer to the source address                     */
 4084 /*              dst(I)  - destination address                               */
 4085 /*              size(I) - number of bytes to copy                           */
 4086 /*                                                                          */
 4087 /* Copy a block of data out to user space, given a pointer to the pointer   */
 4088 /* to start copying from (src) and a pointer to where to store it (dst).    */
 4089 /* NB: src - kernel space pointer, dst - pointer to user space pointer.     */
 4090 /* ------------------------------------------------------------------------ */
 4091 int
 4092 copyoutptr(ipf_main_softc_t *softc, void *src, void *dst, size_t size)
 4093 {
 4094         caddr_t ca;
 4095         int error;
 4096 
 4097         bcopy(dst, (caddr_t)&ca, sizeof(ca));
 4098         error = COPYOUT(src, ca, size);
 4099         if (error != 0) {
 4100                 IPFERROR(4);
 4101                 error = EFAULT;
 4102         }
 4103         return (error);
 4104 }
 4105 
 4106 
 4107 /* ------------------------------------------------------------------------ */
 4108 /* Function:    ipf_lock                                                    */
 4109 /* Returns:     int      - 0 = success, else error                          */
 4110 /* Parameters:  data(I)  - pointer to lock value to set                     */
 4111 /*              lockp(O) - pointer to location to store old lock value      */
 4112 /*                                                                          */
 4113 /* Get the new value for the lock integer, set it and return the old value  */
 4114 /* in *lockp.                                                               */
 4115 /* ------------------------------------------------------------------------ */
 4116 int
 4117 ipf_lock(caddr_t data, int *lockp)
 4118 {
 4119         int arg, err;
 4120 
 4121         err = BCOPYIN(data, &arg, sizeof(arg));
 4122         if (err != 0)
 4123                 return (EFAULT);
 4124         err = BCOPYOUT(lockp, data, sizeof(*lockp));
 4125         if (err != 0)
 4126                 return (EFAULT);
 4127         *lockp = arg;
 4128         return (0);
 4129 }
 4130 
 4131 
 4132 /* ------------------------------------------------------------------------ */
 4133 /* Function:    ipf_getstat                                                 */
 4134 /* Returns:     Nil                                                         */
 4135 /* Parameters:  softc(I) - pointer to soft context main structure           */
 4136 /*              fiop(I)  - pointer to ipfilter stats structure              */
 4137 /*              rev(I)   - version claim by program doing ioctl             */
 4138 /*                                                                          */
 4139 /* Stores a copy of current pointers, counters, etc, in the friostat        */
 4140 /* structure.                                                               */
 4141 /* If IPFILTER_COMPAT is compiled, we pretend to be whatever version the    */
 4142 /* program is looking for. This ensure that validation of the version it    */
 4143 /* expects will always succeed. Thus kernels with IPFILTER_COMPAT will      */
 4144 /* allow older binaries to work but kernels without it will not.            */
 4145 /* ------------------------------------------------------------------------ */
 4146 /*ARGSUSED*/
 4147 static void
 4148 ipf_getstat(ipf_main_softc_t *softc, friostat_t *fiop, int rev)
 4149 {
 4150         int i;
 4151 
 4152         bcopy((char *)softc->ipf_stats, (char *)fiop->f_st,
 4153               sizeof(ipf_statistics_t) * 2);
 4154         fiop->f_locks[IPL_LOGSTATE] = -1;
 4155         fiop->f_locks[IPL_LOGNAT] = -1;
 4156         fiop->f_locks[IPL_LOGIPF] = -1;
 4157         fiop->f_locks[IPL_LOGAUTH] = -1;
 4158 
 4159         fiop->f_ipf[0][0] = softc->ipf_rules[0][0];
 4160         fiop->f_acct[0][0] = softc->ipf_acct[0][0];
 4161         fiop->f_ipf[0][1] = softc->ipf_rules[0][1];
 4162         fiop->f_acct[0][1] = softc->ipf_acct[0][1];
 4163         fiop->f_ipf[1][0] = softc->ipf_rules[1][0];
 4164         fiop->f_acct[1][0] = softc->ipf_acct[1][0];
 4165         fiop->f_ipf[1][1] = softc->ipf_rules[1][1];
 4166         fiop->f_acct[1][1] = softc->ipf_acct[1][1];
 4167 
 4168         fiop->f_ticks = softc->ipf_ticks;
 4169         fiop->f_active = softc->ipf_active;
 4170         fiop->f_froute[0] = softc->ipf_frouteok[0];
 4171         fiop->f_froute[1] = softc->ipf_frouteok[1];
 4172         fiop->f_rb_no_mem = softc->ipf_rb_no_mem;
 4173         fiop->f_rb_node_max = softc->ipf_rb_node_max;
 4174 
 4175         fiop->f_running = softc->ipf_running;
 4176         for (i = 0; i < IPL_LOGSIZE; i++) {
 4177                 fiop->f_groups[i][0] = softc->ipf_groups[i][0];
 4178                 fiop->f_groups[i][1] = softc->ipf_groups[i][1];
 4179         }
 4180 #ifdef  IPFILTER_LOG
 4181         fiop->f_log_ok = ipf_log_logok(softc, IPL_LOGIPF);
 4182         fiop->f_log_fail = ipf_log_failures(softc, IPL_LOGIPF);
 4183         fiop->f_logging = 1;
 4184 #else
 4185         fiop->f_log_ok = 0;
 4186         fiop->f_log_fail = 0;
 4187         fiop->f_logging = 0;
 4188 #endif
 4189         fiop->f_defpass = softc->ipf_pass;
 4190         fiop->f_features = ipf_features;
 4191 
 4192 #ifdef IPFILTER_COMPAT
 4193         snprintf(fiop->f_version, sizeof(friostat.f_version), "IP Filter: v%d.%d.%d",
 4194                 (rev / 1000000) % 100,
 4195                 (rev / 10000) % 100,
 4196                 (rev / 100) % 100);
 4197 #else
 4198         rev = rev;
 4199         (void) strncpy(fiop->f_version, ipfilter_version,
 4200                        sizeof(fiop->f_version));
 4201 #endif
 4202 }
 4203 
 4204 
 4205 #ifdef  USE_INET6
 4206 int icmptoicmp6types[ICMP_MAXTYPE+1] = {
 4207         ICMP6_ECHO_REPLY,       /* 0: ICMP_ECHOREPLY */
 4208         -1,                     /* 1: UNUSED */
 4209         -1,                     /* 2: UNUSED */
 4210         ICMP6_DST_UNREACH,      /* 3: ICMP_UNREACH */
 4211         -1,                     /* 4: ICMP_SOURCEQUENCH */
 4212         ND_REDIRECT,            /* 5: ICMP_REDIRECT */
 4213         -1,                     /* 6: UNUSED */
 4214         -1,                     /* 7: UNUSED */
 4215         ICMP6_ECHO_REQUEST,     /* 8: ICMP_ECHO */
 4216         -1,                     /* 9: UNUSED */
 4217         -1,                     /* 10: UNUSED */
 4218         ICMP6_TIME_EXCEEDED,    /* 11: ICMP_TIMXCEED */
 4219         ICMP6_PARAM_PROB,       /* 12: ICMP_PARAMPROB */
 4220         -1,                     /* 13: ICMP_TSTAMP */
 4221         -1,                     /* 14: ICMP_TSTAMPREPLY */
 4222         -1,                     /* 15: ICMP_IREQ */
 4223         -1,                     /* 16: ICMP_IREQREPLY */
 4224         -1,                     /* 17: ICMP_MASKREQ */
 4225         -1,                     /* 18: ICMP_MASKREPLY */
 4226 };
 4227 
 4228 
 4229 int     icmptoicmp6unreach[ICMP_MAX_UNREACH] = {
 4230         ICMP6_DST_UNREACH_ADDR,         /* 0: ICMP_UNREACH_NET */
 4231         ICMP6_DST_UNREACH_ADDR,         /* 1: ICMP_UNREACH_HOST */
 4232         -1,                             /* 2: ICMP_UNREACH_PROTOCOL */
 4233         ICMP6_DST_UNREACH_NOPORT,       /* 3: ICMP_UNREACH_PORT */
 4234         -1,                             /* 4: ICMP_UNREACH_NEEDFRAG */
 4235         ICMP6_DST_UNREACH_NOTNEIGHBOR,  /* 5: ICMP_UNREACH_SRCFAIL */
 4236         ICMP6_DST_UNREACH_ADDR,         /* 6: ICMP_UNREACH_NET_UNKNOWN */
 4237         ICMP6_DST_UNREACH_ADDR,         /* 7: ICMP_UNREACH_HOST_UNKNOWN */
 4238         -1,                             /* 8: ICMP_UNREACH_ISOLATED */
 4239         ICMP6_DST_UNREACH_ADMIN,        /* 9: ICMP_UNREACH_NET_PROHIB */
 4240         ICMP6_DST_UNREACH_ADMIN,        /* 10: ICMP_UNREACH_HOST_PROHIB */
 4241         -1,                             /* 11: ICMP_UNREACH_TOSNET */
 4242         -1,                             /* 12: ICMP_UNREACH_TOSHOST */
 4243         ICMP6_DST_UNREACH_ADMIN,        /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */
 4244 };
 4245 int     icmpreplytype6[ICMP6_MAXTYPE + 1];
 4246 #endif
 4247 
 4248 int     icmpreplytype4[ICMP_MAXTYPE + 1];
 4249 
 4250 
 4251 /* ------------------------------------------------------------------------ */
 4252 /* Function:    ipf_matchicmpqueryreply                                     */
 4253 /* Returns:     int - 1 if "icmp" is a valid reply to "ic" else 0.          */
 4254 /* Parameters:  v(I)    - IP protocol version (4 or 6)                      */
 4255 /*              ic(I)   - ICMP information                                  */
 4256 /*              icmp(I) - ICMP packet header                                */
 4257 /*              rev(I)  - direction (0 = forward/1 = reverse) of packet     */
 4258 /*                                                                          */
 4259 /* Check if the ICMP packet defined by the header pointed to by icmp is a   */
 4260 /* reply to one as described by what's in ic.  If it is a match, return 1,  */
 4261 /* else return 0 for no match.                                              */
 4262 /* ------------------------------------------------------------------------ */
 4263 int
 4264 ipf_matchicmpqueryreply(int v, icmpinfo_t *ic, icmphdr_t *icmp, int rev)
 4265 {
 4266         int ictype;
 4267 
 4268         ictype = ic->ici_type;
 4269 
 4270         if (v == 4) {
 4271                 /*
 4272                  * If we matched its type on the way in, then when going out
 4273                  * it will still be the same type.
 4274                  */
 4275                 if ((!rev && (icmp->icmp_type == ictype)) ||
 4276                     (rev && (icmpreplytype4[ictype] == icmp->icmp_type))) {
 4277                         if (icmp->icmp_type != ICMP_ECHOREPLY)
 4278                                 return (1);
 4279                         if (icmp->icmp_id == ic->ici_id)
 4280                                 return (1);
 4281                 }
 4282         }
 4283 #ifdef  USE_INET6
 4284         else if (v == 6) {
 4285                 if ((!rev && (icmp->icmp_type == ictype)) ||
 4286                     (rev && (icmpreplytype6[ictype] == icmp->icmp_type))) {
 4287                         if (icmp->icmp_type != ICMP6_ECHO_REPLY)
 4288                                 return (1);
 4289                         if (icmp->icmp_id == ic->ici_id)
 4290                                 return (1);
 4291                 }
 4292         }
 4293 #endif
 4294         return (0);
 4295 }
 4296 
 4297 
 4298 /*
 4299  * IFNAMES are located in the variable length field starting at
 4300  * frentry.fr_names. As pointers within the struct cannot be passed
 4301  * to the kernel from ipf(8), an offset is used. An offset of -1 means it
 4302  * is unused (invalid). If it is used (valid) it is an offset to the
 4303  * character string of an interface name or a comment. The following
 4304  * macros will assist those who follow to understand the code.
 4305  */
 4306 #define IPF_IFNAME_VALID(_a)    (_a != -1)
 4307 #define IPF_IFNAME_INVALID(_a)  (_a == -1)
 4308 #define IPF_IFNAMES_DIFFERENT(_a)       \
 4309         !((IPF_IFNAME_INVALID(fr1->_a) &&       \
 4310         IPF_IFNAME_INVALID(fr2->_a)) || \
 4311         (IPF_IFNAME_VALID(fr1->_a) &&   \
 4312         IPF_IFNAME_VALID(fr2->_a) &&    \
 4313         !strcmp(FR_NAME(fr1, _a), FR_NAME(fr2, _a))))
 4314 #define IPF_FRDEST_DIFFERENT(_a)        \
 4315         (memcmp(&fr1->_a.fd_addr, &fr2->_a.fd_addr,     \
 4316         offsetof(frdest_t, fd_name) - offsetof(frdest_t, fd_addr)) ||   \
 4317         IPF_IFNAMES_DIFFERENT(_a.fd_name))
 4318 
 4319 
 4320 /* ------------------------------------------------------------------------ */
 4321 /* Function:    ipf_rule_compare                                            */
 4322 /* Parameters:  fr1(I) - first rule structure to compare                    */
 4323 /*              fr2(I) - second rule structure to compare                   */
 4324 /* Returns:     int    - 0 == rules are the same, else mismatch             */
 4325 /*                                                                          */
 4326 /* Compare two rules and return 0 if they match or a number indicating      */
 4327 /* which of the individual checks failed.                                   */
 4328 /* ------------------------------------------------------------------------ */
 4329 static int
 4330 ipf_rule_compare(frentry_t *fr1, frentry_t *fr2)
 4331 {
 4332         int i;
 4333 
 4334         if (fr1->fr_cksum != fr2->fr_cksum)
 4335                 return (1);
 4336         if (fr1->fr_size != fr2->fr_size)
 4337                 return (2);
 4338         if (fr1->fr_dsize != fr2->fr_dsize)
 4339                 return (3);
 4340         if (bcmp((char *)&fr1->fr_func, (char *)&fr2->fr_func, FR_CMPSIZ)
 4341             != 0)
 4342                 return (4);
 4343         /*
 4344          * XXX: There is still a bug here as different rules with the
 4345          *      the same interfaces but in a different order will compare
 4346          *      differently. But since multiple interfaces in a rule doesn't
 4347          *      work anyway a simple straightforward compare is performed
 4348          *      here. Ultimately frentry_t creation will need to be
 4349          *      revisited in ipf_y.y. While the other issue, recognition
 4350          *      of only the first interface in a list of interfaces will
 4351          *      need to be separately addressed along with why only four.
 4352          */
 4353         for (i = 0; i < FR_NUM(fr1->fr_ifnames); i++) {
 4354                 /*
 4355                  * XXX: It's either the same index or uninitialized.
 4356                  *      We assume this because multiple interfaces
 4357                  *      referenced by the same rule doesn't work anyway.
 4358                  */
 4359                 if (IPF_IFNAMES_DIFFERENT(fr_ifnames[i]))
 4360                         return (5);
 4361         }
 4362 
 4363         if (IPF_FRDEST_DIFFERENT(fr_tif))
 4364                 return (6);
 4365         if (IPF_FRDEST_DIFFERENT(fr_rif))
 4366                 return (7);
 4367         if (IPF_FRDEST_DIFFERENT(fr_dif))
 4368                 return (8);
 4369         if (!fr1->fr_data && !fr2->fr_data)
 4370                 return (0);     /* move along, nothing to see here */
 4371         if (fr1->fr_data && fr2->fr_data) {
 4372                 if (bcmp(fr1->fr_caddr, fr2->fr_caddr, fr1->fr_dsize) == 0)
 4373                         return (0);     /* same */
 4374         }
 4375         return (9);
 4376 }
 4377 
 4378 
 4379 /* ------------------------------------------------------------------------ */
 4380 /* Function:    frrequest                                                   */
 4381 /* Returns:     int - 0 == success, > 0 == errno value                      */
 4382 /* Parameters:  unit(I)     - device for which this is for                  */
 4383 /*              req(I)      - ioctl command (SIOC*)                         */
 4384 /*              data(I)     - pointr to ioctl data                          */
 4385 /*              set(I)      - 1 or 0 (filter set)                           */
 4386 /*              makecopy(I) - flag indicating whether data points to a rule */
 4387 /*                            in kernel space & hence doesn't need copying. */
 4388 /*                                                                          */
 4389 /* This function handles all the requests which operate on the list of      */
 4390 /* filter rules.  This includes adding, deleting, insertion.  It is also    */
 4391 /* responsible for creating groups when a "head" rule is loaded.  Interface */
 4392 /* names are resolved here and other sanity checks are made on the content  */
 4393 /* of the rule structure being loaded.  If a rule has user defined timeouts */
 4394 /* then make sure they are created and initialised before exiting.          */
 4395 /* ------------------------------------------------------------------------ */
 4396 int
 4397 frrequest(ipf_main_softc_t *softc, int unit, ioctlcmd_t req, caddr_t data,
 4398         int set, int makecopy)
 4399 {
 4400         int error = 0, in, family, need_free = 0;
 4401         enum {  OP_ADD,         /* add rule */
 4402                 OP_REM,         /* remove rule */
 4403                 OP_ZERO         /* zero statistics and counters */ }
 4404                 addrem = OP_ADD;
 4405         frentry_t frd, *fp, *f, **fprev, **ftail;
 4406         void *ptr, *uptr, *cptr;
 4407         u_int *p, *pp;
 4408         frgroup_t *fg;
 4409         char *group;
 4410 
 4411         ptr = NULL;
 4412         cptr = NULL;
 4413         fg = NULL;
 4414         fp = &frd;
 4415         if (makecopy != 0) {
 4416                 bzero(fp, sizeof(frd));
 4417                 error = ipf_inobj(softc, data, NULL, fp, IPFOBJ_FRENTRY);
 4418                 if (error) {
 4419                         return (error);
 4420                 }
 4421                 if ((fp->fr_type & FR_T_BUILTIN) != 0) {
 4422                         IPFERROR(6);
 4423                         return (EINVAL);
 4424                 }
 4425                 KMALLOCS(f, frentry_t *, fp->fr_size);
 4426                 if (f == NULL) {
 4427                         IPFERROR(131);
 4428                         return (ENOMEM);
 4429                 }
 4430                 bzero(f, fp->fr_size);
 4431                 error = ipf_inobjsz(softc, data, f, IPFOBJ_FRENTRY,
 4432                                     fp->fr_size);
 4433                 if (error) {
 4434                         KFREES(f, fp->fr_size);
 4435                         return (error);
 4436                 }
 4437 
 4438                 fp = f;
 4439                 f = NULL;
 4440                 fp->fr_next = NULL;
 4441                 fp->fr_dnext = NULL;
 4442                 fp->fr_pnext = NULL;
 4443                 fp->fr_pdnext = NULL;
 4444                 fp->fr_grp = NULL;
 4445                 fp->fr_grphead = NULL;
 4446                 fp->fr_icmpgrp = NULL;
 4447                 fp->fr_isc = (void *)-1;
 4448                 fp->fr_ptr = NULL;
 4449                 fp->fr_ref = 0;
 4450                 fp->fr_flags |= FR_COPIED;
 4451         } else {
 4452                 fp = (frentry_t *)data;
 4453                 if ((fp->fr_type & FR_T_BUILTIN) == 0) {
 4454                         IPFERROR(7);
 4455                         return (EINVAL);
 4456                 }
 4457                 fp->fr_flags &= ~FR_COPIED;
 4458         }
 4459 
 4460         if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) ||
 4461             ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) {
 4462                 IPFERROR(8);
 4463                 error = EINVAL;
 4464                 goto donenolock;
 4465         }
 4466 
 4467         family = fp->fr_family;
 4468         uptr = fp->fr_data;
 4469 
 4470         if (req == (ioctlcmd_t)SIOCINAFR || req == (ioctlcmd_t)SIOCINIFR ||
 4471             req == (ioctlcmd_t)SIOCADAFR || req == (ioctlcmd_t)SIOCADIFR)
 4472                 addrem = OP_ADD;        /* Add rule */
 4473         else if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR)
 4474                 addrem = OP_REM;                /* Remove rule */
 4475         else if (req == (ioctlcmd_t)SIOCZRLST)
 4476                 addrem = OP_ZERO;       /* Zero statistics and counters */
 4477         else {
 4478                 IPFERROR(9);
 4479                 error = EINVAL;
 4480                 goto donenolock;
 4481         }
 4482 
 4483         /*
 4484          * Only filter rules for IPv4 or IPv6 are accepted.
 4485          */
 4486         if (family == AF_INET) {
 4487                 /*EMPTY*/;
 4488 #ifdef  USE_INET6
 4489         } else if (family == AF_INET6) {
 4490                 /*EMPTY*/;
 4491 #endif
 4492         } else if (family != 0) {
 4493                 IPFERROR(10);
 4494                 error = EINVAL;
 4495                 goto donenolock;
 4496         }
 4497 
 4498         /*
 4499          * If the rule is being loaded from user space, i.e. we had to copy it
 4500          * into kernel space, then do not trust the function pointer in the
 4501          * rule.
 4502          */
 4503         if ((makecopy == 1) && (fp->fr_func != NULL)) {
 4504                 if (ipf_findfunc(fp->fr_func) == NULL) {
 4505                         IPFERROR(11);
 4506                         error = ESRCH;
 4507                         goto donenolock;
 4508                 }
 4509 
 4510                 if (addrem == OP_ADD) {
 4511                         error = ipf_funcinit(softc, fp);
 4512                         if (error != 0)
 4513                                 goto donenolock;
 4514                 }
 4515         }
 4516         if ((fp->fr_flags & FR_CALLNOW) &&
 4517             ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) {
 4518                 IPFERROR(142);
 4519                 error = ESRCH;
 4520                 goto donenolock;
 4521         }
 4522         if (((fp->fr_flags & FR_CMDMASK) == FR_CALL) &&
 4523             ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) {
 4524                 IPFERROR(143);
 4525                 error = ESRCH;
 4526                 goto donenolock;
 4527         }
 4528 
 4529         ptr = NULL;
 4530         cptr = NULL;
 4531 
 4532         if (FR_ISACCOUNT(fp->fr_flags))
 4533                 unit = IPL_LOGCOUNT;
 4534 
 4535         /*
 4536          * Check that each group name in the rule has a start index that
 4537          * is valid.
 4538          */
 4539         if (fp->fr_icmphead != -1) {
 4540                 if ((fp->fr_icmphead < 0) ||
 4541                     (fp->fr_icmphead >= fp->fr_namelen)) {
 4542                         IPFERROR(136);
 4543                         error = EINVAL;
 4544                         goto donenolock;
 4545                 }
 4546                 if (!strcmp(FR_NAME(fp, fr_icmphead), ""))
 4547                         fp->fr_names[fp->fr_icmphead] = '\0';
 4548         }
 4549 
 4550         if (fp->fr_grhead != -1) {
 4551                 if ((fp->fr_grhead < 0) ||
 4552                     (fp->fr_grhead >= fp->fr_namelen)) {
 4553                         IPFERROR(137);
 4554                         error = EINVAL;
 4555                         goto donenolock;
 4556                 }
 4557                 if (!strcmp(FR_NAME(fp, fr_grhead), ""))
 4558                         fp->fr_names[fp->fr_grhead] = '\0';
 4559         }
 4560 
 4561         if (fp->fr_group != -1) {
 4562                 if ((fp->fr_group < 0) ||
 4563                     (fp->fr_group >= fp->fr_namelen)) {
 4564                         IPFERROR(138);
 4565                         error = EINVAL;
 4566                         goto donenolock;
 4567                 }
 4568                 if ((req != (int)SIOCZRLST) && (fp->fr_group != -1)) {
 4569                         /*
 4570                          * Allow loading rules that are in groups to cause
 4571                          * them to be created if they don't already exit.
 4572                          */
 4573                         group = FR_NAME(fp, fr_group);
 4574                         if (addrem == OP_ADD) {
 4575                                 fg = ipf_group_add(softc, group, NULL,
 4576                                                    fp->fr_flags, unit, set);
 4577                                 fp->fr_grp = fg;
 4578                         } else {
 4579                                 fg = ipf_findgroup(softc, group, unit,
 4580                                                    set, NULL);
 4581                                 if (fg == NULL) {
 4582                                         IPFERROR(12);
 4583                                         error = ESRCH;
 4584                                         goto donenolock;
 4585                                 }
 4586                         }
 4587 
 4588                         if (fg->fg_flags == 0) {
 4589                                 fg->fg_flags = fp->fr_flags & FR_INOUT;
 4590                         } else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) {
 4591                                 IPFERROR(13);
 4592                                 error = ESRCH;
 4593                                 goto donenolock;
 4594                         }
 4595                 }
 4596         } else {
 4597                 /*
 4598                  * If a rule is going to be part of a group then it does
 4599                  * not matter whether it is an in or out rule, but if it
 4600                  * isn't in a group, then it does...
 4601                  */
 4602                 if ((fp->fr_flags & (FR_INQUE|FR_OUTQUE)) == 0) {
 4603                         IPFERROR(14);
 4604                         error = EINVAL;
 4605                         goto donenolock;
 4606                 }
 4607         }
 4608         in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
 4609 
 4610         /*
 4611          * Work out which rule list this change is being applied to.
 4612          */
 4613         ftail = NULL;
 4614         fprev = NULL;
 4615         if (unit == IPL_LOGAUTH) {
 4616                 if ((fp->fr_tifs[0].fd_ptr != NULL) ||
 4617                     (fp->fr_tifs[1].fd_ptr != NULL) ||
 4618                     (fp->fr_dif.fd_ptr != NULL) ||
 4619                     (fp->fr_flags & FR_FASTROUTE)) {
 4620                         softc->ipf_interror = 145;
 4621                         error = EINVAL;
 4622                         goto donenolock;
 4623                 }
 4624                 fprev = ipf_auth_rulehead(softc);
 4625         } else {
 4626                 if (FR_ISACCOUNT(fp->fr_flags))
 4627                         fprev = &softc->ipf_acct[in][set];
 4628                 else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0)
 4629                         fprev = &softc->ipf_rules[in][set];
 4630         }
 4631         if (fprev == NULL) {
 4632                 IPFERROR(15);
 4633                 error = ESRCH;
 4634                 goto donenolock;
 4635         }
 4636 
 4637         if (fg != NULL)
 4638                 fprev = &fg->fg_start;
 4639 
 4640         /*
 4641          * Copy in extra data for the rule.
 4642          */
 4643         if (fp->fr_dsize != 0) {
 4644                 if (makecopy != 0) {
 4645                         KMALLOCS(ptr, void *, fp->fr_dsize);
 4646                         if (ptr == NULL) {
 4647                                 IPFERROR(16);
 4648                                 error = ENOMEM;
 4649                                 goto donenolock;
 4650                         }
 4651 
 4652                         /*
 4653                          * The bcopy case is for when the data is appended
 4654                          * to the rule by ipf_in_compat().
 4655                          */
 4656                         if (uptr >= (void *)fp &&
 4657                             uptr < (void *)((char *)fp + fp->fr_size)) {
 4658                                 bcopy(uptr, ptr, fp->fr_dsize);
 4659                                 error = 0;
 4660                         } else {
 4661                                 error = COPYIN(uptr, ptr, fp->fr_dsize);
 4662                                 if (error != 0) {
 4663                                         IPFERROR(17);
 4664                                         error = EFAULT;
 4665                                         goto donenolock;
 4666                                 }
 4667                         }
 4668                 } else {
 4669                         ptr = uptr;
 4670                 }
 4671                 fp->fr_data = ptr;
 4672         } else {
 4673                 fp->fr_data = NULL;
 4674         }
 4675 
 4676         /*
 4677          * Perform per-rule type sanity checks of their members.
 4678          * All code after this needs to be aware that allocated memory
 4679          * may need to be free'd before exiting.
 4680          */
 4681         switch (fp->fr_type & ~FR_T_BUILTIN)
 4682         {
 4683 #if defined(IPFILTER_BPF)
 4684         case FR_T_BPFOPC :
 4685                 if (fp->fr_dsize == 0) {
 4686                         IPFERROR(19);
 4687                         error = EINVAL;
 4688                         break;
 4689                 }
 4690                 if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) {
 4691                         IPFERROR(20);
 4692                         error = EINVAL;
 4693                         break;
 4694                 }
 4695                 break;
 4696 #endif
 4697         case FR_T_IPF :
 4698                 /*
 4699                  * Preparation for error case at the bottom of this function.
 4700                  */
 4701                 if (fp->fr_datype == FRI_LOOKUP)
 4702                         fp->fr_dstptr = NULL;
 4703                 if (fp->fr_satype == FRI_LOOKUP)
 4704                         fp->fr_srcptr = NULL;
 4705 
 4706                 if (fp->fr_dsize != sizeof(fripf_t)) {
 4707                         IPFERROR(21);
 4708                         error = EINVAL;
 4709                         break;
 4710                 }
 4711 
 4712                 /*
 4713                  * Allowing a rule with both "keep state" and "with oow" is
 4714                  * pointless because adding a state entry to the table will
 4715                  * fail with the out of window (oow) flag set.
 4716                  */
 4717                 if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) {
 4718                         IPFERROR(22);
 4719                         error = EINVAL;
 4720                         break;
 4721                 }
 4722 
 4723                 switch (fp->fr_satype)
 4724                 {
 4725                 case FRI_BROADCAST :
 4726                 case FRI_DYNAMIC :
 4727                 case FRI_NETWORK :
 4728                 case FRI_NETMASKED :
 4729                 case FRI_PEERADDR :
 4730                         if (fp->fr_sifpidx < 0) {
 4731                                 IPFERROR(23);
 4732                                 error = EINVAL;
 4733                         }
 4734                         break;
 4735                 case FRI_LOOKUP :
 4736                         fp->fr_srcptr = ipf_findlookup(softc, unit, fp,
 4737                                                        &fp->fr_src6,
 4738                                                        &fp->fr_smsk6);
 4739                         if (fp->fr_srcfunc == NULL) {
 4740                                 IPFERROR(132);
 4741                                 error = ESRCH;
 4742                                 break;
 4743                         }
 4744                         break;
 4745                 case FRI_NORMAL :
 4746                         break;
 4747                 default :
 4748                         IPFERROR(133);
 4749                         error = EINVAL;
 4750                         break;
 4751                 }
 4752                 if (error != 0)
 4753                         break;
 4754 
 4755                 switch (fp->fr_datype)
 4756                 {
 4757                 case FRI_BROADCAST :
 4758                 case FRI_DYNAMIC :
 4759                 case FRI_NETWORK :
 4760                 case FRI_NETMASKED :
 4761                 case FRI_PEERADDR :
 4762                         if (fp->fr_difpidx < 0) {
 4763                                 IPFERROR(24);
 4764                                 error = EINVAL;
 4765                         }
 4766                         break;
 4767                 case FRI_LOOKUP :
 4768                         fp->fr_dstptr = ipf_findlookup(softc, unit, fp,
 4769                                                        &fp->fr_dst6,
 4770                                                        &fp->fr_dmsk6);
 4771                         if (fp->fr_dstfunc == NULL) {
 4772                                 IPFERROR(134);
 4773                                 error = ESRCH;
 4774                         }
 4775                         break;
 4776                 case FRI_NORMAL :
 4777                         break;
 4778                 default :
 4779                         IPFERROR(135);
 4780                         error = EINVAL;
 4781                 }
 4782                 break;
 4783 
 4784         case FR_T_NONE :
 4785         case FR_T_CALLFUNC :
 4786         case FR_T_COMPIPF :
 4787                 break;
 4788 
 4789         case FR_T_IPFEXPR :
 4790                 if (ipf_matcharray_verify(fp->fr_data, fp->fr_dsize) == -1) {
 4791                         IPFERROR(25);
 4792                         error = EINVAL;
 4793                 }
 4794                 break;
 4795 
 4796         default :
 4797                 IPFERROR(26);
 4798                 error = EINVAL;
 4799                 break;
 4800         }
 4801         if (error != 0)
 4802                 goto donenolock;
 4803 
 4804         if (fp->fr_tif.fd_name != -1) {
 4805                 if ((fp->fr_tif.fd_name < 0) ||
 4806                     (fp->fr_tif.fd_name >= fp->fr_namelen)) {
 4807                         IPFERROR(139);
 4808                         error = EINVAL;
 4809                         goto donenolock;
 4810                 }
 4811         }
 4812 
 4813         if (fp->fr_dif.fd_name != -1) {
 4814                 if ((fp->fr_dif.fd_name < 0) ||
 4815                     (fp->fr_dif.fd_name >= fp->fr_namelen)) {
 4816                         IPFERROR(140);
 4817                         error = EINVAL;
 4818                         goto donenolock;
 4819                 }
 4820         }
 4821 
 4822         if (fp->fr_rif.fd_name != -1) {
 4823                 if ((fp->fr_rif.fd_name < 0) ||
 4824                     (fp->fr_rif.fd_name >= fp->fr_namelen)) {
 4825                         IPFERROR(141);
 4826                         error = EINVAL;
 4827                         goto donenolock;
 4828                 }
 4829         }
 4830 
 4831         /*
 4832          * Lookup all the interface names that are part of the rule.
 4833          */
 4834         error = ipf_synclist(softc, fp, NULL);
 4835         if (error != 0)
 4836                 goto donenolock;
 4837         fp->fr_statecnt = 0;
 4838         if (fp->fr_srctrack.ht_max_nodes != 0)
 4839                 ipf_rb_ht_init(&fp->fr_srctrack);
 4840 
 4841         /*
 4842          * Look for an existing matching filter rule, but don't include the
 4843          * next or interface pointer in the comparison (fr_next, fr_ifa).
 4844          * This elminates rules which are indentical being loaded.  Checksum
 4845          * the constant part of the filter rule to make comparisons quicker
 4846          * (this meaning no pointers are included).
 4847          */
 4848         pp = (u_int *)(fp->fr_caddr + fp->fr_dsize);
 4849         for (fp->fr_cksum = 0, p = (u_int *)fp->fr_data; p < pp; p++)
 4850                 fp->fr_cksum += *p;
 4851 
 4852         WRITE_ENTER(&softc->ipf_mutex);
 4853 
 4854         /*
 4855          * Now that the filter rule lists are locked, we can walk the
 4856          * chain of them without fear.
 4857          */
 4858         ftail = fprev;
 4859         for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) {
 4860                 if (fp->fr_collect <= f->fr_collect) {
 4861                         ftail = fprev;
 4862                         f = NULL;
 4863                         break;
 4864                 }
 4865                 fprev = ftail;
 4866         }
 4867 
 4868         for (; (f = *ftail) != NULL; ftail = &f->fr_next) {
 4869                 if (ipf_rule_compare(fp, f) == 0)
 4870                         break;
 4871         }
 4872 
 4873         /*
 4874          * If zero'ing statistics, copy current to caller and zero.
 4875          */
 4876         if (addrem == OP_ZERO) {
 4877                 if (f == NULL) {
 4878                         IPFERROR(27);
 4879                         error = ESRCH;
 4880                 } else {
 4881                         /*
 4882                          * Copy and reduce lock because of impending copyout.
 4883                          * Well we should, but if we do then the atomicity of
 4884                          * this call and the correctness of fr_hits and
 4885                          * fr_bytes cannot be guaranteed.  As it is, this code
 4886                          * only resets them to 0 if they are successfully
 4887                          * copied out into user space.
 4888                          */
 4889                         bcopy((char *)f, (char *)fp, f->fr_size);
 4890                         /* MUTEX_DOWNGRADE(&softc->ipf_mutex); */
 4891 
 4892                         /*
 4893                          * When we copy this rule back out, set the data
 4894                          * pointer to be what it was in user space.
 4895                          */
 4896                         fp->fr_data = uptr;
 4897                         error = ipf_outobj(softc, data, fp, IPFOBJ_FRENTRY);
 4898 
 4899                         if (error == 0) {
 4900                                 if ((f->fr_dsize != 0) && (uptr != NULL)) {
 4901                                         error = COPYOUT(f->fr_data, uptr,
 4902                                                         f->fr_dsize);
 4903                                         if (error == 0) {
 4904                                                 f->fr_hits = 0;
 4905                                                 f->fr_bytes = 0;
 4906                                         } else {
 4907                                                 IPFERROR(28);
 4908                                                 error = EFAULT;
 4909                                         }
 4910                                 }
 4911                         }
 4912                 }
 4913 
 4914                 if (makecopy != 0) {
 4915                         if (ptr != NULL) {
 4916                                 KFREES(ptr, fp->fr_dsize);
 4917                         }
 4918                         KFREES(fp, fp->fr_size);
 4919                 }
 4920                 RWLOCK_EXIT(&softc->ipf_mutex);
 4921                 return (error);
 4922         }
 4923 
 4924         if (f == NULL) {
 4925                 /*
 4926                  * At the end of this, ftail must point to the place where the
 4927                  * new rule is to be saved/inserted/added.
 4928                  * For SIOCAD*FR, this should be the last rule in the group of
 4929                  * rules that have equal fr_collect fields.
 4930                  * For SIOCIN*FR, ...
 4931                  */
 4932                 if (req == (ioctlcmd_t)SIOCADAFR ||
 4933                     req == (ioctlcmd_t)SIOCADIFR) {
 4934 
 4935                         for (ftail = fprev; (f = *ftail) != NULL; ) {
 4936                                 if (f->fr_collect > fp->fr_collect)
 4937                                         break;
 4938                                 ftail = &f->fr_next;
 4939                                 fprev = ftail;
 4940                         }
 4941                         ftail = fprev;
 4942                         f = NULL;
 4943                         ptr = NULL;
 4944                 } else if (req == (ioctlcmd_t)SIOCINAFR ||
 4945                            req == (ioctlcmd_t)SIOCINIFR) {
 4946                         while ((f = *fprev) != NULL) {
 4947                                 if (f->fr_collect >= fp->fr_collect)
 4948                                         break;
 4949                                 fprev = &f->fr_next;
 4950                         }
 4951                         ftail = fprev;
 4952                         if (fp->fr_hits != 0) {
 4953                                 while (fp->fr_hits && (f = *ftail)) {
 4954                                         if (f->fr_collect != fp->fr_collect)
 4955                                                 break;
 4956                                         fprev = ftail;
 4957                                         ftail = &f->fr_next;
 4958                                         fp->fr_hits--;
 4959                                 }
 4960                         }
 4961                         f = NULL;
 4962                         ptr = NULL;
 4963                 }
 4964         }
 4965 
 4966         /*
 4967          * Request to remove a rule.
 4968          */
 4969         if (addrem == OP_REM) {
 4970                 if (f == NULL) {
 4971                         IPFERROR(29);
 4972                         error = ESRCH;
 4973                 } else {
 4974                         /*
 4975                          * Do not allow activity from user space to interfere
 4976                          * with rules not loaded that way.
 4977                          */
 4978                         if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) {
 4979                                 IPFERROR(30);
 4980                                 error = EPERM;
 4981                                 goto done;
 4982                         }
 4983 
 4984                         /*
 4985                          * Return EBUSY if the rule is being reference by
 4986                          * something else (eg state information.)
 4987                          */
 4988                         if (f->fr_ref > 1) {
 4989                                 IPFERROR(31);
 4990                                 error = EBUSY;
 4991                                 goto done;
 4992                         }
 4993 #ifdef  IPFILTER_SCAN
 4994                         if (f->fr_isctag != -1 &&
 4995                             (f->fr_isc != (struct ipscan *)-1))
 4996                                 ipf_scan_detachfr(f);
 4997 #endif
 4998 
 4999                         if (unit == IPL_LOGAUTH) {
 5000                                 error = ipf_auth_precmd(softc, req, f, ftail);
 5001                                 goto done;
 5002                         }
 5003 
 5004                         ipf_rule_delete(softc, f, unit, set);
 5005 
 5006                         need_free = makecopy;
 5007                 }
 5008         } else {
 5009                 /*
 5010                  * Not removing, so we must be adding/inserting a rule.
 5011                  */
 5012                 if (f != NULL) {
 5013                         IPFERROR(32);
 5014                         error = EEXIST;
 5015                         goto done;
 5016                 }
 5017                 if (unit == IPL_LOGAUTH) {
 5018                         error = ipf_auth_precmd(softc, req, fp, ftail);
 5019                         goto done;
 5020                 }
 5021 
 5022                 MUTEX_NUKE(&fp->fr_lock);
 5023                 MUTEX_INIT(&fp->fr_lock, "filter rule lock");
 5024                 if (fp->fr_die != 0)
 5025                         ipf_rule_expire_insert(softc, fp, set);
 5026 
 5027                 fp->fr_hits = 0;
 5028                 if (makecopy != 0)
 5029                         fp->fr_ref = 1;
 5030                 fp->fr_pnext = ftail;
 5031                 fp->fr_next = *ftail;
 5032                 if (fp->fr_next != NULL)
 5033                         fp->fr_next->fr_pnext = &fp->fr_next;
 5034                 *ftail = fp;
 5035                 ipf_fixskip(ftail, fp, 1);
 5036 
 5037                 fp->fr_icmpgrp = NULL;
 5038                 if (fp->fr_icmphead != -1) {
 5039                         group = FR_NAME(fp, fr_icmphead);
 5040                         fg = ipf_group_add(softc, group, fp, 0, unit, set);
 5041                         fp->fr_icmpgrp = fg;
 5042                 }
 5043 
 5044                 fp->fr_grphead = NULL;
 5045                 if (fp->fr_grhead != -1) {
 5046                         group = FR_NAME(fp, fr_grhead);
 5047                         fg = ipf_group_add(softc, group, fp, fp->fr_flags,
 5048                                            unit, set);
 5049                         fp->fr_grphead = fg;
 5050                 }
 5051         }
 5052 done:
 5053         RWLOCK_EXIT(&softc->ipf_mutex);
 5054 donenolock:
 5055         if (need_free || (error != 0)) {
 5056                 if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) {
 5057                         if ((fp->fr_satype == FRI_LOOKUP) &&
 5058                             (fp->fr_srcptr != NULL))
 5059                                 ipf_lookup_deref(softc, fp->fr_srctype,
 5060                                                  fp->fr_srcptr);
 5061                         if ((fp->fr_datype == FRI_LOOKUP) &&
 5062                             (fp->fr_dstptr != NULL))
 5063                                 ipf_lookup_deref(softc, fp->fr_dsttype,
 5064                                                  fp->fr_dstptr);
 5065                 }
 5066                 if (fp->fr_grp != NULL) {
 5067                         WRITE_ENTER(&softc->ipf_mutex);
 5068                         ipf_group_del(softc, fp->fr_grp, fp);
 5069                         RWLOCK_EXIT(&softc->ipf_mutex);
 5070                 }
 5071                 if ((ptr != NULL) && (makecopy != 0)) {
 5072                         KFREES(ptr, fp->fr_dsize);
 5073                 }
 5074                 KFREES(fp, fp->fr_size);
 5075         }
 5076         return (error);
 5077 }
 5078 
 5079 
 5080 /* ------------------------------------------------------------------------ */
 5081 /* Function:   ipf_rule_delete                                              */
 5082 /* Returns:    Nil                                                          */
 5083 /* Parameters: softc(I) - pointer to soft context main structure            */
 5084 /*             f(I)     - pointer to the rule being deleted                 */
 5085 /*             ftail(I) - pointer to the pointer to f                       */
 5086 /*             unit(I)  - device for which this is for                      */
 5087 /*             set(I)   - 1 or 0 (filter set)                               */
 5088 /*                                                                          */
 5089 /* This function attempts to do what it can to delete a filter rule: remove */
 5090 /* it from any linked lists and remove any groups it is responsible for.    */
 5091 /* But in the end, removing a rule can only drop the reference count - we   */
 5092 /* must use that as the guide for whether or not it can be freed.           */
 5093 /* ------------------------------------------------------------------------ */
 5094 static void
 5095 ipf_rule_delete(ipf_main_softc_t *softc, frentry_t *f, int unit, int set)
 5096 {
 5097 
 5098         /*
 5099          * If fr_pdnext is set, then the rule is on the expire list, so
 5100          * remove it from there.
 5101          */
 5102         if (f->fr_pdnext != NULL) {
 5103                 *f->fr_pdnext = f->fr_dnext;
 5104                 if (f->fr_dnext != NULL)
 5105                         f->fr_dnext->fr_pdnext = f->fr_pdnext;
 5106                 f->fr_pdnext = NULL;
 5107                 f->fr_dnext = NULL;
 5108         }
 5109 
 5110         ipf_fixskip(f->fr_pnext, f, -1);
 5111         if (f->fr_pnext != NULL)
 5112                 *f->fr_pnext = f->fr_next;
 5113         if (f->fr_next != NULL)
 5114                 f->fr_next->fr_pnext = f->fr_pnext;
 5115         f->fr_pnext = NULL;
 5116         f->fr_next = NULL;
 5117 
 5118         (void) ipf_derefrule(softc, &f);
 5119 }
 5120 
 5121 /* ------------------------------------------------------------------------ */
 5122 /* Function:   ipf_rule_expire_insert                                       */
 5123 /* Returns:    Nil                                                          */
 5124 /* Parameters: softc(I) - pointer to soft context main structure            */
 5125 /*             f(I)     - pointer to rule to be added to expire list        */
 5126 /*             set(I)   - 1 or 0 (filter set)                               */
 5127 /*                                                                          */
 5128 /* If the new rule has a given expiration time, insert it into the list of  */
 5129 /* expiring rules with the ones to be removed first added to the front of   */
 5130 /* the list. The insertion is O(n) but it is kept sorted for quick scans at */
 5131 /* expiration interval checks.                                              */
 5132 /* ------------------------------------------------------------------------ */
 5133 static void
 5134 ipf_rule_expire_insert(ipf_main_softc_t *softc, frentry_t *f, int set)
 5135 {
 5136         frentry_t *fr;
 5137 
 5138         /*
 5139          */
 5140 
 5141         f->fr_die = softc->ipf_ticks + IPF_TTLVAL(f->fr_die);
 5142         for (fr = softc->ipf_rule_explist[set]; fr != NULL;
 5143              fr = fr->fr_dnext) {
 5144                 if (f->fr_die < fr->fr_die)
 5145                         break;
 5146                 if (fr->fr_dnext == NULL) {
 5147                         /*
 5148                          * We've got to the last rule and everything
 5149                          * wanted to be expired before this new node,
 5150                          * so we have to tack it on the end...
 5151                          */
 5152                         fr->fr_dnext = f;
 5153                         f->fr_pdnext = &fr->fr_dnext;
 5154                         fr = NULL;
 5155                         break;
 5156                 }
 5157         }
 5158 
 5159         if (softc->ipf_rule_explist[set] == NULL) {
 5160                 softc->ipf_rule_explist[set] = f;
 5161                 f->fr_pdnext = &softc->ipf_rule_explist[set];
 5162         } else if (fr != NULL) {
 5163                 f->fr_dnext = fr;
 5164                 f->fr_pdnext = fr->fr_pdnext;
 5165                 fr->fr_pdnext = &f->fr_dnext;
 5166         }
 5167 }
 5168 
 5169 
 5170 /* ------------------------------------------------------------------------ */
 5171 /* Function:   ipf_findlookup                                               */
 5172 /* Returns:    NULL = failure, else success                                 */
 5173 /* Parameters: softc(I) - pointer to soft context main structure            */
 5174 /*             unit(I)  - ipf device we want to find match for              */
 5175 /*             fp(I)    - rule for which lookup is for                      */
 5176 /*             addrp(I) - pointer to lookup information in address struct   */
 5177 /*             maskp(O) - pointer to lookup information for storage         */
 5178 /*                                                                          */
 5179 /* When using pools and hash tables to store addresses for matching in      */
 5180 /* rules, it is necessary to resolve both the object referred to by the     */
 5181 /* name or address (and return that pointer) and also provide the means by  */
 5182 /* which to determine if an address belongs to that object to make the      */
 5183 /* packet matching quicker.                                                 */
 5184 /* ------------------------------------------------------------------------ */
 5185 static void *
 5186 ipf_findlookup(ipf_main_softc_t *softc, int unit, frentry_t *fr,
 5187         i6addr_t *addrp, i6addr_t *maskp)
 5188 {
 5189         void *ptr = NULL;
 5190 
 5191         switch (addrp->iplookupsubtype)
 5192         {
 5193         case 0 :
 5194                 ptr = ipf_lookup_res_num(softc, unit, addrp->iplookuptype,
 5195                                          addrp->iplookupnum,
 5196                                          &maskp->iplookupfunc);
 5197                 break;
 5198         case 1 :
 5199                 if (addrp->iplookupname < 0)
 5200                         break;
 5201                 if (addrp->iplookupname >= fr->fr_namelen)
 5202                         break;
 5203                 ptr = ipf_lookup_res_name(softc, unit, addrp->iplookuptype,
 5204                                           fr->fr_names + addrp->iplookupname,
 5205                                           &maskp->iplookupfunc);
 5206                 break;
 5207         default :
 5208                 break;
 5209         }
 5210 
 5211         return (ptr);
 5212 }
 5213 
 5214 
 5215 /* ------------------------------------------------------------------------ */
 5216 /* Function:    ipf_funcinit                                                */
 5217 /* Returns:     int - 0 == success, else ESRCH: cannot resolve rule details */
 5218 /* Parameters:  softc(I) - pointer to soft context main structure           */
 5219 /*              fr(I)    - pointer to filter rule                           */
 5220 /*                                                                          */
 5221 /* If a rule is a call rule, then check if the function it points to needs  */
 5222 /* an init function to be called now the rule has been loaded.              */
 5223 /* ------------------------------------------------------------------------ */
 5224 static int
 5225 ipf_funcinit(ipf_main_softc_t *softc, frentry_t *fr)
 5226 {
 5227         ipfunc_resolve_t *ft;
 5228         int err;
 5229 
 5230         IPFERROR(34);
 5231         err = ESRCH;
 5232 
 5233         for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
 5234                 if (ft->ipfu_addr == fr->fr_func) {
 5235                         err = 0;
 5236                         if (ft->ipfu_init != NULL)
 5237                                 err = (*ft->ipfu_init)(softc, fr);
 5238                         break;
 5239                 }
 5240         return (err);
 5241 }
 5242 
 5243 
 5244 /* ------------------------------------------------------------------------ */
 5245 /* Function:    ipf_funcfini                                                */
 5246 /* Returns:     Nil                                                         */
 5247 /* Parameters:  softc(I) - pointer to soft context main structure           */
 5248 /*              fr(I)    - pointer to filter rule                           */
 5249 /*                                                                          */
 5250 /* For a given filter rule, call the matching "fini" function if the rule   */
 5251 /* is using a known function that would have resulted in the "init" being   */
 5252 /* called for ealier.                                                       */
 5253 /* ------------------------------------------------------------------------ */
 5254 static void
 5255 ipf_funcfini(ipf_main_softc_t *softc, frentry_t *fr)
 5256 {
 5257         ipfunc_resolve_t *ft;
 5258 
 5259         for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
 5260                 if (ft->ipfu_addr == fr->fr_func) {
 5261                         if (ft->ipfu_fini != NULL)
 5262                                 (void) (*ft->ipfu_fini)(softc, fr);
 5263                         break;
 5264                 }
 5265 }
 5266 
 5267 
 5268 /* ------------------------------------------------------------------------ */
 5269 /* Function:    ipf_findfunc                                                */
 5270 /* Returns:     ipfunc_t - pointer to function if found, else NULL          */
 5271 /* Parameters:  funcptr(I) - function pointer to lookup                     */
 5272 /*                                                                          */
 5273 /* Look for a function in the table of known functions.                     */
 5274 /* ------------------------------------------------------------------------ */
 5275 static ipfunc_t
 5276 ipf_findfunc(ipfunc_t funcptr)
 5277 {
 5278         ipfunc_resolve_t *ft;
 5279 
 5280         for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
 5281                 if (ft->ipfu_addr == funcptr)
 5282                         return (funcptr);
 5283         return (NULL);
 5284 }
 5285 
 5286 
 5287 /* ------------------------------------------------------------------------ */
 5288 /* Function:    ipf_resolvefunc                                             */
 5289 /* Returns:     int - 0 == success, else error                              */
 5290 /* Parameters:  data(IO) - ioctl data pointer to ipfunc_resolve_t struct    */
 5291 /*                                                                          */
 5292 /* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */
 5293 /* This will either be the function name (if the pointer is set) or the     */
 5294 /* function pointer if the name is set.  When found, fill in the other one  */
 5295 /* so that the entire, complete, structure can be copied back to user space.*/
 5296 /* ------------------------------------------------------------------------ */
 5297 int
 5298 ipf_resolvefunc(ipf_main_softc_t *softc, void *data)
 5299 {
 5300         ipfunc_resolve_t res, *ft;
 5301         int error;
 5302 
 5303         error = BCOPYIN(data, &res, sizeof(res));
 5304         if (error != 0) {
 5305                 IPFERROR(123);
 5306                 return (EFAULT);
 5307         }
 5308 
 5309         if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') {
 5310                 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
 5311                         if (strncmp(res.ipfu_name, ft->ipfu_name,
 5312                                     sizeof(res.ipfu_name)) == 0) {
 5313                                 res.ipfu_addr = ft->ipfu_addr;
 5314                                 res.ipfu_init = ft->ipfu_init;
 5315                                 if (COPYOUT(&res, data, sizeof(res)) != 0) {
 5316                                         IPFERROR(35);
 5317                                         return (EFAULT);
 5318                                 }
 5319                                 return (0);
 5320                         }
 5321         }
 5322         if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') {
 5323                 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
 5324                         if (ft->ipfu_addr == res.ipfu_addr) {
 5325                                 (void) strncpy(res.ipfu_name, ft->ipfu_name,
 5326                                                sizeof(res.ipfu_name));
 5327                                 res.ipfu_init = ft->ipfu_init;
 5328                                 if (COPYOUT(&res, data, sizeof(res)) != 0) {
 5329                                         IPFERROR(36);
 5330                                         return (EFAULT);
 5331                                 }
 5332                                 return (0);
 5333                         }
 5334         }
 5335         IPFERROR(37);
 5336         return (ESRCH);
 5337 }
 5338 
 5339 
 5340 #if !defined(_KERNEL) || SOLARIS
 5341 /*
 5342  * From: NetBSD
 5343  * ppsratecheck(): packets (or events) per second limitation.
 5344  */
 5345 int
 5346 ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps)
 5347         /* maxpps: maximum pps allowed */
 5348 {
 5349         struct timeval tv, delta;
 5350         int rv;
 5351 
 5352         GETKTIME(&tv);
 5353 
 5354         delta.tv_sec = tv.tv_sec - lasttime->tv_sec;
 5355         delta.tv_usec = tv.tv_usec - lasttime->tv_usec;
 5356         if (delta.tv_usec < 0) {
 5357                 delta.tv_sec--;
 5358                 delta.tv_usec += 1000000;
 5359         }
 5360 
 5361         /*
 5362          * check for 0,0 is so that the message will be seen at least once.
 5363          * if more than one second have passed since the last update of
 5364          * lasttime, reset the counter.
 5365          *
 5366          * we do increment *curpps even in *curpps < maxpps case, as some may
 5367          * try to use *curpps for stat purposes as well.
 5368          */
 5369         if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) ||
 5370             delta.tv_sec >= 1) {
 5371                 *lasttime = tv;
 5372                 *curpps = 0;
 5373                 rv = 1;
 5374         } else if (maxpps < 0)
 5375                 rv = 1;
 5376         else if (*curpps < maxpps)
 5377                 rv = 1;
 5378         else
 5379                 rv = 0;
 5380         *curpps = *curpps + 1;
 5381 
 5382         return (rv);
 5383 }
 5384 #endif
 5385 
 5386 
 5387 /* ------------------------------------------------------------------------ */
 5388 /* Function:    ipf_derefrule                                               */
 5389 /* Returns:     int   - 0 == rule freed up, else rule not freed             */
 5390 /* Parameters:  fr(I) - pointer to filter rule                              */
 5391 /*                                                                          */
 5392 /* Decrement the reference counter to a rule by one.  If it reaches zero,   */
 5393 /* free it and any associated storage space being used by it.               */
 5394 /* ------------------------------------------------------------------------ */
 5395 int
 5396 ipf_derefrule(ipf_main_softc_t *softc, frentry_t **frp)
 5397 {
 5398         frentry_t *fr;
 5399         frdest_t *fdp;
 5400 
 5401         fr = *frp;
 5402         *frp = NULL;
 5403 
 5404         MUTEX_ENTER(&fr->fr_lock);
 5405         fr->fr_ref--;
 5406         if (fr->fr_ref == 0) {
 5407                 MUTEX_EXIT(&fr->fr_lock);
 5408                 MUTEX_DESTROY(&fr->fr_lock);
 5409 
 5410                 ipf_funcfini(softc, fr);
 5411 
 5412                 fdp = &fr->fr_tif;
 5413                 if (fdp->fd_type == FRD_DSTLIST)
 5414                         ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
 5415 
 5416                 fdp = &fr->fr_rif;
 5417                 if (fdp->fd_type == FRD_DSTLIST)
 5418                         ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
 5419 
 5420                 fdp = &fr->fr_dif;
 5421                 if (fdp->fd_type == FRD_DSTLIST)
 5422                         ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
 5423 
 5424                 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
 5425                     fr->fr_satype == FRI_LOOKUP)
 5426                         ipf_lookup_deref(softc, fr->fr_srctype, fr->fr_srcptr);
 5427                 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
 5428                     fr->fr_datype == FRI_LOOKUP)
 5429                         ipf_lookup_deref(softc, fr->fr_dsttype, fr->fr_dstptr);
 5430 
 5431                 if (fr->fr_grp != NULL)
 5432                         ipf_group_del(softc, fr->fr_grp, fr);
 5433 
 5434                 if (fr->fr_grphead != NULL)
 5435                         ipf_group_del(softc, fr->fr_grphead, fr);
 5436 
 5437                 if (fr->fr_icmpgrp != NULL)
 5438                         ipf_group_del(softc, fr->fr_icmpgrp, fr);
 5439 
 5440                 if ((fr->fr_flags & FR_COPIED) != 0) {
 5441                         if (fr->fr_dsize) {
 5442                                 KFREES(fr->fr_data, fr->fr_dsize);
 5443                         }
 5444                         KFREES(fr, fr->fr_size);
 5445                         return (0);
 5446                 }
 5447                 return (1);
 5448         } else {
 5449                 MUTEX_EXIT(&fr->fr_lock);
 5450         }
 5451         return (-1);
 5452 }
 5453 
 5454 
 5455 /* ------------------------------------------------------------------------ */
 5456 /* Function:    ipf_grpmapinit                                              */
 5457 /* Returns:     int - 0 == success, else ESRCH because table entry not found*/
 5458 /* Parameters:  fr(I) - pointer to rule to find hash table for              */
 5459 /*                                                                          */
 5460 /* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr.  */
 5461 /* fr_ptr is later used by ipf_srcgrpmap and ipf_dstgrpmap.                 */
 5462 /* ------------------------------------------------------------------------ */
 5463 static int
 5464 ipf_grpmapinit(ipf_main_softc_t *softc, frentry_t *fr)
 5465 {
 5466         char name[FR_GROUPLEN];
 5467         iphtable_t *iph;
 5468 
 5469         (void) snprintf(name, sizeof(name), "%d", fr->fr_arg);
 5470         iph = ipf_lookup_find_htable(softc, IPL_LOGIPF, name);
 5471         if (iph == NULL) {
 5472                 IPFERROR(38);
 5473                 return (ESRCH);
 5474         }
 5475         if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) {
 5476                 IPFERROR(39);
 5477                 return (ESRCH);
 5478         }
 5479         iph->iph_ref++;
 5480         fr->fr_ptr = iph;
 5481         return (0);
 5482 }
 5483 
 5484 
 5485 /* ------------------------------------------------------------------------ */
 5486 /* Function:    ipf_grpmapfini                                              */
 5487 /* Returns:     int - 0 == success, else ESRCH because table entry not found*/
 5488 /* Parameters:  softc(I) - pointer to soft context main structure           */
 5489 /*              fr(I)    - pointer to rule to release hash table for        */
 5490 /*                                                                          */
 5491 /* For rules that have had ipf_grpmapinit called, ipf_lookup_deref needs to */
 5492 /* be called to undo what ipf_grpmapinit caused to be done.                 */
 5493 /* ------------------------------------------------------------------------ */
 5494 static int
 5495 ipf_grpmapfini(ipf_main_softc_t *softc, frentry_t *fr)
 5496 {
 5497         iphtable_t *iph;
 5498         iph = fr->fr_ptr;
 5499         if (iph != NULL)
 5500                 ipf_lookup_deref(softc, IPLT_HASH, iph);
 5501         return (0);
 5502 }
 5503 
 5504 
 5505 /* ------------------------------------------------------------------------ */
 5506 /* Function:    ipf_srcgrpmap                                               */
 5507 /* Returns:     frentry_t * - pointer to "new last matching" rule or NULL   */
 5508 /* Parameters:  fin(I)    - pointer to packet information                   */
 5509 /*              passp(IO) - pointer to current/new filter decision (unused) */
 5510 /*                                                                          */
 5511 /* Look for a rule group head in a hash table, using the source address as  */
 5512 /* the key, and descend into that group and continue matching rules against */
 5513 /* the packet.                                                              */
 5514 /* ------------------------------------------------------------------------ */
 5515 frentry_t *
 5516 ipf_srcgrpmap(fr_info_t *fin, u_32_t *passp)
 5517 {
 5518         frgroup_t *fg;
 5519         void *rval;
 5520 
 5521         rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr,
 5522                                  &fin->fin_src);
 5523         if (rval == NULL)
 5524                 return (NULL);
 5525 
 5526         fg = rval;
 5527         fin->fin_fr = fg->fg_start;
 5528         (void) ipf_scanlist(fin, *passp);
 5529         return (fin->fin_fr);
 5530 }
 5531 
 5532 
 5533 /* ------------------------------------------------------------------------ */
 5534 /* Function:    ipf_dstgrpmap                                               */
 5535 /* Returns:     frentry_t * - pointer to "new last matching" rule or NULL   */
 5536 /* Parameters:  fin(I)    - pointer to packet information                   */
 5537 /*              passp(IO) - pointer to current/new filter decision (unused) */
 5538 /*                                                                          */
 5539 /* Look for a rule group head in a hash table, using the destination        */
 5540 /* address as the key, and descend into that group and continue matching    */
 5541 /* rules against  the packet.                                               */
 5542 /* ------------------------------------------------------------------------ */
 5543 frentry_t *
 5544 ipf_dstgrpmap(fr_info_t *fin, u_32_t *passp)
 5545 {
 5546         frgroup_t *fg;
 5547         void *rval;
 5548 
 5549         rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr,
 5550                                  &fin->fin_dst);
 5551         if (rval == NULL)
 5552                 return (NULL);
 5553 
 5554         fg = rval;
 5555         fin->fin_fr = fg->fg_start;
 5556         (void) ipf_scanlist(fin, *passp);
 5557         return (fin->fin_fr);
 5558 }
 5559 
 5560 /*
 5561  * Queue functions
 5562  * ===============
 5563  * These functions manage objects on queues for efficient timeouts.  There
 5564  * are a number of system defined queues as well as user defined timeouts.
 5565  * It is expected that a lock is held in the domain in which the queue
 5566  * belongs (i.e. either state or NAT) when calling any of these functions
 5567  * that prevents ipf_freetimeoutqueue() from being called at the same time
 5568  * as any other.
 5569  */
 5570 
 5571 
 5572 /* ------------------------------------------------------------------------ */
 5573 /* Function:    ipf_addtimeoutqueue                                         */
 5574 /* Returns:     struct ifqtq * - NULL if malloc fails, else pointer to      */
 5575 /*                               timeout queue with given interval.         */
 5576 /* Parameters:  parent(I)  - pointer to pointer to parent node of this list */
 5577 /*                           of interface queues.                           */
 5578 /*              seconds(I) - timeout value in seconds for this queue.       */
 5579 /*                                                                          */
 5580 /* This routine first looks for a timeout queue that matches the interval   */
 5581 /* being requested.  If it finds one, increments the reference counter and  */
 5582 /* returns a pointer to it.  If none are found, it allocates a new one and  */
 5583 /* inserts it at the top of the list.                                       */
 5584 /*                                                                          */
 5585 /* Locking.                                                                 */
 5586 /* It is assumed that the caller of this function has an appropriate lock   */
 5587 /* held (exclusively) in the domain that encompases 'parent'.               */
 5588 /* ------------------------------------------------------------------------ */
 5589 ipftq_t *
 5590 ipf_addtimeoutqueue(ipf_main_softc_t *softc, ipftq_t **parent, u_int seconds)
 5591 {
 5592         ipftq_t *ifq;
 5593         u_int period;
 5594 
 5595         period = seconds * IPF_HZ_DIVIDE;
 5596 
 5597         MUTEX_ENTER(&softc->ipf_timeoutlock);
 5598         for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) {
 5599                 if (ifq->ifq_ttl == period) {
 5600                         /*
 5601                          * Reset the delete flag, if set, so the structure
 5602                          * gets reused rather than freed and reallocated.
 5603                          */
 5604                         MUTEX_ENTER(&ifq->ifq_lock);
 5605                         ifq->ifq_flags &= ~IFQF_DELETE;
 5606                         ifq->ifq_ref++;
 5607                         MUTEX_EXIT(&ifq->ifq_lock);
 5608                         MUTEX_EXIT(&softc->ipf_timeoutlock);
 5609 
 5610                         return (ifq);
 5611                 }
 5612         }
 5613 
 5614         KMALLOC(ifq, ipftq_t *);
 5615         if (ifq != NULL) {
 5616                 MUTEX_NUKE(&ifq->ifq_lock);
 5617                 IPFTQ_INIT(ifq, period, "ipftq mutex");
 5618                 ifq->ifq_next = *parent;
 5619                 ifq->ifq_pnext = parent;
 5620                 ifq->ifq_flags = IFQF_USER;
 5621                 ifq->ifq_ref++;
 5622                 *parent = ifq;
 5623                 softc->ipf_userifqs++;
 5624         }
 5625         MUTEX_EXIT(&softc->ipf_timeoutlock);
 5626         return (ifq);
 5627 }
 5628 
 5629 
 5630 /* ------------------------------------------------------------------------ */
 5631 /* Function:    ipf_deletetimeoutqueue                                      */
 5632 /* Returns:     int    - new reference count value of the timeout queue     */
 5633 /* Parameters:  ifq(I) - timeout queue which is losing a reference.         */
 5634 /* Locks:       ifq->ifq_lock                                               */
 5635 /*                                                                          */
 5636 /* This routine must be called when we're discarding a pointer to a timeout */
 5637 /* queue object, taking care of the reference counter.                      */
 5638 /*                                                                          */
 5639 /* Now that this just sets a DELETE flag, it requires the expire code to    */
 5640 /* check the list of user defined timeout queues and call the free function */
 5641 /* below (currently commented out) to stop memory leaking.  It is done this */
 5642 /* way because the locking may not be sufficient to safely do a free when   */
 5643 /* this function is called.                                                 */
 5644 /* ------------------------------------------------------------------------ */
 5645 int
 5646 ipf_deletetimeoutqueue(ipftq_t *ifq)
 5647 {
 5648 
 5649         ifq->ifq_ref--;
 5650         if ((ifq->ifq_ref == 0) && ((ifq->ifq_flags & IFQF_USER) != 0)) {
 5651                 ifq->ifq_flags |= IFQF_DELETE;
 5652         }
 5653 
 5654         return (ifq->ifq_ref);
 5655 }
 5656 
 5657 
 5658 /* ------------------------------------------------------------------------ */
 5659 /* Function:    ipf_freetimeoutqueue                                        */
 5660 /* Parameters:  ifq(I) - timeout queue which is losing a reference.         */
 5661 /* Returns:     Nil                                                         */
 5662 /*                                                                          */
 5663 /* Locking:                                                                 */
 5664 /* It is assumed that the caller of this function has an appropriate lock   */
 5665 /* held (exclusively) in the domain that encompases the callers "domain".   */
 5666 /* The ifq_lock for this structure should not be held.                      */
 5667 /*                                                                          */
 5668 /* Remove a user defined timeout queue from the list of queues it is in and */
 5669 /* tidy up after this is done.                                              */
 5670 /* ------------------------------------------------------------------------ */
 5671 void
 5672 ipf_freetimeoutqueue(ipf_main_softc_t *softc, ipftq_t *ifq)
 5673 {
 5674 
 5675         if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) ||
 5676             ((ifq->ifq_flags & IFQF_USER) == 0)) {
 5677                 printf("ipf_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n",
 5678                        (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl,
 5679                        ifq->ifq_ref);
 5680                 return;
 5681         }
 5682 
 5683         /*
 5684          * Remove from its position in the list.
 5685          */
 5686         *ifq->ifq_pnext = ifq->ifq_next;
 5687         if (ifq->ifq_next != NULL)
 5688                 ifq->ifq_next->ifq_pnext = ifq->ifq_pnext;
 5689         ifq->ifq_next = NULL;
 5690         ifq->ifq_pnext = NULL;
 5691 
 5692         MUTEX_DESTROY(&ifq->ifq_lock);
 5693         ATOMIC_DEC(softc->ipf_userifqs);
 5694         KFREE(ifq);
 5695 }
 5696 
 5697 
 5698 /* ------------------------------------------------------------------------ */
 5699 /* Function:    ipf_deletequeueentry                                        */
 5700 /* Returns:     Nil                                                         */
 5701 /* Parameters:  tqe(I) - timeout queue entry to delete                      */
 5702 /*                                                                          */
 5703 /* Remove a tail queue entry from its queue and make it an orphan.          */
 5704 /* ipf_deletetimeoutqueue is called to make sure the reference count on the */
 5705 /* queue is correct.  We can't, however, call ipf_freetimeoutqueue because  */
 5706 /* the correct lock(s) may not be held that would make it safe to do so.    */
 5707 /* ------------------------------------------------------------------------ */
 5708 void
 5709 ipf_deletequeueentry(ipftqent_t *tqe)
 5710 {
 5711         ipftq_t *ifq;
 5712 
 5713         ifq = tqe->tqe_ifq;
 5714 
 5715         MUTEX_ENTER(&ifq->ifq_lock);
 5716 
 5717         if (tqe->tqe_pnext != NULL) {
 5718                 *tqe->tqe_pnext = tqe->tqe_next;
 5719                 if (tqe->tqe_next != NULL)
 5720                         tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
 5721                 else    /* we must be the tail anyway */
 5722                         ifq->ifq_tail = tqe->tqe_pnext;
 5723 
 5724                 tqe->tqe_pnext = NULL;
 5725                 tqe->tqe_ifq = NULL;
 5726         }
 5727 
 5728         (void) ipf_deletetimeoutqueue(ifq);
 5729         ASSERT(ifq->ifq_ref > 0);
 5730 
 5731         MUTEX_EXIT(&ifq->ifq_lock);
 5732 }
 5733 
 5734 
 5735 /* ------------------------------------------------------------------------ */
 5736 /* Function:    ipf_queuefront                                              */
 5737 /* Returns:     Nil                                                         */
 5738 /* Parameters:  tqe(I) - pointer to timeout queue entry                     */
 5739 /*                                                                          */
 5740 /* Move a queue entry to the front of the queue, if it isn't already there. */
 5741 /* ------------------------------------------------------------------------ */
 5742 void
 5743 ipf_queuefront(ipftqent_t *tqe)
 5744 {
 5745         ipftq_t *ifq;
 5746 
 5747         ifq = tqe->tqe_ifq;
 5748         if (ifq == NULL)
 5749                 return;
 5750 
 5751         MUTEX_ENTER(&ifq->ifq_lock);
 5752         if (ifq->ifq_head != tqe) {
 5753                 *tqe->tqe_pnext = tqe->tqe_next;
 5754                 if (tqe->tqe_next)
 5755                         tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
 5756                 else
 5757                         ifq->ifq_tail = tqe->tqe_pnext;
 5758 
 5759                 tqe->tqe_next = ifq->ifq_head;
 5760                 ifq->ifq_head->tqe_pnext = &tqe->tqe_next;
 5761                 ifq->ifq_head = tqe;
 5762                 tqe->tqe_pnext = &ifq->ifq_head;
 5763         }
 5764         MUTEX_EXIT(&ifq->ifq_lock);
 5765 }
 5766 
 5767 
 5768 /* ------------------------------------------------------------------------ */
 5769 /* Function:    ipf_queueback                                               */
 5770 /* Returns:     Nil                                                         */
 5771 /* Parameters:  ticks(I) - ipf tick time to use with this call              */
 5772 /*              tqe(I)   - pointer to timeout queue entry                   */
 5773 /*                                                                          */
 5774 /* Move a queue entry to the back of the queue, if it isn't already there.  */
 5775 /* We use use ticks to calculate the expiration and mark for when we last   */
 5776 /* touched the structure.                                                   */
 5777 /* ------------------------------------------------------------------------ */
 5778 void
 5779 ipf_queueback(u_long ticks, ipftqent_t *tqe)
 5780 {
 5781         ipftq_t *ifq;
 5782 
 5783         ifq = tqe->tqe_ifq;
 5784         if (ifq == NULL)
 5785                 return;
 5786         tqe->tqe_die = ticks + ifq->ifq_ttl;
 5787         tqe->tqe_touched = ticks;
 5788 
 5789         MUTEX_ENTER(&ifq->ifq_lock);
 5790         if (tqe->tqe_next != NULL) {            /* at the end already ? */
 5791                 /*
 5792                  * Remove from list
 5793                  */
 5794                 *tqe->tqe_pnext = tqe->tqe_next;
 5795                 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
 5796 
 5797                 /*
 5798                  * Make it the last entry.
 5799                  */
 5800                 tqe->tqe_next = NULL;
 5801                 tqe->tqe_pnext = ifq->ifq_tail;
 5802                 *ifq->ifq_tail = tqe;
 5803                 ifq->ifq_tail = &tqe->tqe_next;
 5804         }
 5805         MUTEX_EXIT(&ifq->ifq_lock);
 5806 }
 5807 
 5808 
 5809 /* ------------------------------------------------------------------------ */
 5810 /* Function:    ipf_queueappend                                             */
 5811 /* Returns:     Nil                                                         */
 5812 /* Parameters:  ticks(I)  - ipf tick time to use with this call             */
 5813 /*              tqe(I)    - pointer to timeout queue entry                  */
 5814 /*              ifq(I)    - pointer to timeout queue                        */
 5815 /*              parent(I) - owing object pointer                            */
 5816 /*                                                                          */
 5817 /* Add a new item to this queue and put it on the very end.                 */
 5818 /* We use use ticks to calculate the expiration and mark for when we last   */
 5819 /* touched the structure.                                                   */
 5820 /* ------------------------------------------------------------------------ */
 5821 void
 5822 ipf_queueappend(u_long ticks, ipftqent_t *tqe, ipftq_t *ifq, void *parent)
 5823 {
 5824 
 5825         MUTEX_ENTER(&ifq->ifq_lock);
 5826         tqe->tqe_parent = parent;
 5827         tqe->tqe_pnext = ifq->ifq_tail;
 5828         *ifq->ifq_tail = tqe;
 5829         ifq->ifq_tail = &tqe->tqe_next;
 5830         tqe->tqe_next = NULL;
 5831         tqe->tqe_ifq = ifq;
 5832         tqe->tqe_die = ticks + ifq->ifq_ttl;
 5833         tqe->tqe_touched = ticks;
 5834         ifq->ifq_ref++;
 5835         MUTEX_EXIT(&ifq->ifq_lock);
 5836 }
 5837 
 5838 
 5839 /* ------------------------------------------------------------------------ */
 5840 /* Function:    ipf_movequeue                                               */
 5841 /* Returns:     Nil                                                         */
 5842 /* Parameters:  tq(I)   - pointer to timeout queue information              */
 5843 /*              oifp(I) - old timeout queue entry was on                    */
 5844 /*              nifp(I) - new timeout queue to put entry on                 */
 5845 /*                                                                          */
 5846 /* Move a queue entry from one timeout queue to another timeout queue.      */
 5847 /* If it notices that the current entry is already last and does not need   */
 5848 /* to move queue, the return.                                               */
 5849 /* ------------------------------------------------------------------------ */
 5850 void
 5851 ipf_movequeue(u_long ticks, ipftqent_t *tqe, ipftq_t *oifq, ipftq_t *nifq)
 5852 {
 5853 
 5854         /*
 5855          * If the queue hasn't changed and we last touched this entry at the
 5856          * same ipf time, then we're not going to achieve anything by either
 5857          * changing the ttl or moving it on the queue.
 5858          */
 5859         if (oifq == nifq && tqe->tqe_touched == ticks)
 5860                 return;
 5861 
 5862         /*
 5863          * For any of this to be outside the lock, there is a risk that two
 5864          * packets entering simultaneously, with one changing to a different
 5865          * queue and one not, could end up with things in a bizarre state.
 5866          */
 5867         MUTEX_ENTER(&oifq->ifq_lock);
 5868 
 5869         tqe->tqe_touched = ticks;
 5870         tqe->tqe_die = ticks + nifq->ifq_ttl;
 5871         /*
 5872          * Is the operation here going to be a no-op ?
 5873          */
 5874         if (oifq == nifq) {
 5875                 if ((tqe->tqe_next == NULL) ||
 5876                     (tqe->tqe_next->tqe_die == tqe->tqe_die)) {
 5877                         MUTEX_EXIT(&oifq->ifq_lock);
 5878                         return;
 5879                 }
 5880         }
 5881 
 5882         /*
 5883          * Remove from the old queue
 5884          */
 5885         *tqe->tqe_pnext = tqe->tqe_next;
 5886         if (tqe->tqe_next)
 5887                 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
 5888         else
 5889                 oifq->ifq_tail = tqe->tqe_pnext;
 5890         tqe->tqe_next = NULL;
 5891 
 5892         /*
 5893          * If we're moving from one queue to another, release the
 5894          * lock on the old queue and get a lock on the new queue.
 5895          * For user defined queues, if we're moving off it, call
 5896          * delete in case it can now be freed.
 5897          */
 5898         if (oifq != nifq) {
 5899                 tqe->tqe_ifq = NULL;
 5900 
 5901                 (void) ipf_deletetimeoutqueue(oifq);
 5902 
 5903                 MUTEX_EXIT(&oifq->ifq_lock);
 5904 
 5905                 MUTEX_ENTER(&nifq->ifq_lock);
 5906 
 5907                 tqe->tqe_ifq = nifq;
 5908                 nifq->ifq_ref++;
 5909         }
 5910 
 5911         /*
 5912          * Add to the bottom of the new queue
 5913          */
 5914         tqe->tqe_pnext = nifq->ifq_tail;
 5915         *nifq->ifq_tail = tqe;
 5916         nifq->ifq_tail = &tqe->tqe_next;
 5917         MUTEX_EXIT(&nifq->ifq_lock);
 5918 }
 5919 
 5920 
 5921 /* ------------------------------------------------------------------------ */
 5922 /* Function:    ipf_updateipid                                              */
 5923 /* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
 5924 /* Parameters:  fin(I) - pointer to packet information                      */
 5925 /*                                                                          */
 5926 /* When we are doing NAT, change the IP of every packet to represent a      */
 5927 /* single sequence of packets coming from the host, hiding any host         */
 5928 /* specific sequencing that might otherwise be revealed.  If the packet is  */
 5929 /* a fragment, then store the 'new' IPid in the fragment cache and look up  */
 5930 /* the fragment cache for non-leading fragments.  If a non-leading fragment */
 5931 /* has no match in the cache, return an error.                              */
 5932 /* ------------------------------------------------------------------------ */
 5933 static int
 5934 ipf_updateipid(fr_info_t *fin)
 5935 {
 5936         u_short id, ido, sums;
 5937         u_32_t sumd, sum;
 5938         ip_t *ip;
 5939 
 5940         ip = fin->fin_ip;
 5941         ido = ntohs(ip->ip_id);
 5942         if (fin->fin_off != 0) {
 5943                 sum = ipf_frag_ipidknown(fin);
 5944                 if (sum == 0xffffffff)
 5945                         return (-1);
 5946                 sum &= 0xffff;
 5947                 id = (u_short)sum;
 5948                 ip->ip_id = htons(id);
 5949         } else {
 5950                 ip_fillid(ip);
 5951                 id = ntohs(ip->ip_id);
 5952                 if ((fin->fin_flx & FI_FRAG) != 0)
 5953                         (void) ipf_frag_ipidnew(fin, (u_32_t)id);
 5954         }
 5955 
 5956         if (id == ido)
 5957                 return (0);
 5958         CALC_SUMD(ido, id, sumd);       /* DESTRUCTIVE MACRO! id,ido change */
 5959         sum = (~ntohs(ip->ip_sum)) & 0xffff;
 5960         sum += sumd;
 5961         sum = (sum >> 16) + (sum & 0xffff);
 5962         sum = (sum >> 16) + (sum & 0xffff);
 5963         sums = ~(u_short)sum;
 5964         ip->ip_sum = htons(sums);
 5965         return (0);
 5966 }
 5967 
 5968 
 5969 #ifdef  NEED_FRGETIFNAME
 5970 /* ------------------------------------------------------------------------ */
 5971 /* Function:    ipf_getifname                                               */
 5972 /* Returns:     char *    - pointer to interface name                       */
 5973 /* Parameters:  ifp(I)    - pointer to network interface                    */
 5974 /*              buffer(O) - pointer to where to store interface name        */
 5975 /*                                                                          */
 5976 /* Constructs an interface name in the buffer passed.  The buffer passed is */
 5977 /* expected to be at least LIFNAMSIZ in bytes big.  If buffer is passed in  */
 5978 /* as a NULL pointer then return a pointer to a static array.               */
 5979 /* ------------------------------------------------------------------------ */
 5980 char *
 5981 ipf_getifname(struct ifnet *ifp, char *buffer)
 5982 {
 5983         static char namebuf[LIFNAMSIZ];
 5984 # if SOLARIS || defined(__FreeBSD__)
 5985         int unit, space;
 5986         char temp[20];
 5987         char *s;
 5988 # endif
 5989 
 5990         if (buffer == NULL)
 5991                 buffer = namebuf;
 5992         (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ);
 5993         buffer[LIFNAMSIZ - 1] = '\0';
 5994 # if SOLARIS || defined(__FreeBSD__)
 5995         for (s = buffer; *s; s++)
 5996                 ;
 5997         unit = ifp->if_unit;
 5998         space = LIFNAMSIZ - (s - buffer);
 5999         if ((space > 0) && (unit >= 0)) {
 6000                 (void) snprintf(temp, sizeof(name), "%d", unit);
 6001                 (void) strncpy(s, temp, space);
 6002         }
 6003 # endif
 6004         return (buffer);
 6005 }
 6006 #endif
 6007 
 6008 
 6009 /* ------------------------------------------------------------------------ */
 6010 /* Function:    ipf_ioctlswitch                                             */
 6011 /* Returns:     int     - -1 continue processing, else ioctl return value   */
 6012 /* Parameters:  unit(I) - device unit opened                                */
 6013 /*              data(I) - pointer to ioctl data                             */
 6014 /*              cmd(I)  - ioctl command                                     */
 6015 /*              mode(I) - mode value                                        */
 6016 /*              uid(I)  - uid making the ioctl call                         */
 6017 /*              ctx(I)  - pointer to context data                           */
 6018 /*                                                                          */
 6019 /* Based on the value of unit, call the appropriate ioctl handler or return */
 6020 /* EIO if ipfilter is not running.   Also checks if write perms are req'd   */
 6021 /* for the device in order to execute the ioctl.  A special case is made    */
 6022 /* SIOCIPFINTERROR so that the same code isn't required in every handler.   */
 6023 /* The context data pointer is passed through as this is used as the key    */
 6024 /* for locating a matching token for continued access for walking lists,    */
 6025 /* etc.                                                                     */
 6026 /* ------------------------------------------------------------------------ */
 6027 int
 6028 ipf_ioctlswitch(ipf_main_softc_t *softc, int unit, void *data, ioctlcmd_t cmd,
 6029         int mode, int uid, void *ctx)
 6030 {
 6031         int error = 0;
 6032 
 6033         switch (cmd)
 6034         {
 6035         case SIOCIPFINTERROR :
 6036                 error = BCOPYOUT(&softc->ipf_interror, data,
 6037                                  sizeof(softc->ipf_interror));
 6038                 if (error != 0) {
 6039                         IPFERROR(40);
 6040                         error = EFAULT;
 6041                 }
 6042                 return (error);
 6043         default :
 6044                 break;
 6045         }
 6046 
 6047         switch (unit)
 6048         {
 6049         case IPL_LOGIPF :
 6050                 error = ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx);
 6051                 break;
 6052         case IPL_LOGNAT :
 6053                 if (softc->ipf_running > 0) {
 6054                         error = ipf_nat_ioctl(softc, data, cmd, mode,
 6055                                               uid, ctx);
 6056                 } else {
 6057                         IPFERROR(42);
 6058                         error = EIO;
 6059                 }
 6060                 break;
 6061         case IPL_LOGSTATE :
 6062                 if (softc->ipf_running > 0) {
 6063                         error = ipf_state_ioctl(softc, data, cmd, mode,
 6064                                                 uid, ctx);
 6065                 } else {
 6066                         IPFERROR(43);
 6067                         error = EIO;
 6068                 }
 6069                 break;
 6070         case IPL_LOGAUTH :
 6071                 if (softc->ipf_running > 0) {
 6072                         error = ipf_auth_ioctl(softc, data, cmd, mode,
 6073                                                uid, ctx);
 6074                 } else {
 6075                         IPFERROR(44);
 6076                         error = EIO;
 6077                 }
 6078                 break;
 6079         case IPL_LOGSYNC :
 6080                 if (softc->ipf_running > 0) {
 6081                         error = ipf_sync_ioctl(softc, data, cmd, mode,
 6082                                                uid, ctx);
 6083                 } else {
 6084                         error = EIO;
 6085                         IPFERROR(45);
 6086                 }
 6087                 break;
 6088         case IPL_LOGSCAN :
 6089 #ifdef IPFILTER_SCAN
 6090                 if (softc->ipf_running > 0)
 6091                         error = ipf_scan_ioctl(softc, data, cmd, mode,
 6092                                                uid, ctx);
 6093                 else
 6094 #endif
 6095                 {
 6096                         error = EIO;
 6097                         IPFERROR(46);
 6098                 }
 6099                 break;
 6100         case IPL_LOGLOOKUP :
 6101                 if (softc->ipf_running > 0) {
 6102                         error = ipf_lookup_ioctl(softc, data, cmd, mode,
 6103                                                  uid, ctx);
 6104                 } else {
 6105                         error = EIO;
 6106                         IPFERROR(47);
 6107                 }
 6108                 break;
 6109         default :
 6110                 IPFERROR(48);
 6111                 error = EIO;
 6112                 break;
 6113         }
 6114 
 6115         return (error);
 6116 }
 6117 
 6118 
 6119 /*
 6120  * This array defines the expected size of objects coming into the kernel
 6121  * for the various recognised object types. The first column is flags (see
 6122  * below), 2nd column is current size, 3rd column is the version number of
 6123  * when the current size became current.
 6124  * Flags:
 6125  * 1 = minimum size, not absolute size
 6126  */
 6127 static const int        ipf_objbytes[IPFOBJ_COUNT][3] = {
 6128         { 1,    sizeof(struct frentry),         5010000 },      /* 0 */
 6129         { 1,    sizeof(struct friostat),        5010000 },
 6130         { 0,    sizeof(struct fr_info),         5010000 },
 6131         { 0,    sizeof(struct ipf_authstat),    4010100 },
 6132         { 0,    sizeof(struct ipfrstat),        5010000 },
 6133         { 1,    sizeof(struct ipnat),           5010000 },      /* 5 */
 6134         { 0,    sizeof(struct natstat),         5010000 },
 6135         { 0,    sizeof(struct ipstate_save),    5010000 },
 6136         { 1,    sizeof(struct nat_save),        5010000 },
 6137         { 0,    sizeof(struct natlookup),       5010000 },
 6138         { 1,    sizeof(struct ipstate),         5010000 },      /* 10 */
 6139         { 0,    sizeof(struct ips_stat),        5010000 },
 6140         { 0,    sizeof(struct frauth),          5010000 },
 6141         { 0,    sizeof(struct ipftune),         4010100 },
 6142         { 0,    sizeof(struct nat),             5010000 },
 6143         { 0,    sizeof(struct ipfruleiter),     4011400 },      /* 15 */
 6144         { 0,    sizeof(struct ipfgeniter),      4011400 },
 6145         { 0,    sizeof(struct ipftable),        4011400 },
 6146         { 0,    sizeof(struct ipflookupiter),   4011400 },
 6147         { 0,    sizeof(struct ipftq) * IPF_TCP_NSTATES },
 6148         { 1,    0,                              0       }, /* IPFEXPR */
 6149         { 0,    0,                              0       }, /* PROXYCTL */
 6150         { 0,    sizeof (struct fripf),          5010000 }
 6151 };
 6152 
 6153 
 6154 /* ------------------------------------------------------------------------ */
 6155 /* Function:    ipf_inobj                                                   */
 6156 /* Returns:     int     - 0 = success, else failure                         */
 6157 /* Parameters:  softc(I) - soft context pointerto work with                 */
 6158 /*              data(I)  - pointer to ioctl data                            */
 6159 /*              objp(O)  - where to store ipfobj structure                  */
 6160 /*              ptr(I)   - pointer to data to copy out                      */
 6161 /*              type(I)  - type of structure being moved                    */
 6162 /*                                                                          */
 6163 /* Copy in the contents of what the ipfobj_t points to.  In future, we      */
 6164 /* add things to check for version numbers, sizes, etc, to make it backward */
 6165 /* compatible at the ABI for user land.                                     */
 6166 /* If objp is not NULL then we assume that the caller wants to see what is  */
 6167 /* in the ipfobj_t structure being copied in. As an example, this can tell  */
 6168 /* the caller what version of ipfilter the ioctl program was written to.    */
 6169 /* ------------------------------------------------------------------------ */
 6170 int
 6171 ipf_inobj(ipf_main_softc_t *softc, void *data, ipfobj_t *objp, void *ptr,
 6172         int type)
 6173 {
 6174         ipfobj_t obj;
 6175         int error;
 6176         int size;
 6177 
 6178         if ((type < 0) || (type >= IPFOBJ_COUNT)) {
 6179                 IPFERROR(49);
 6180                 return (EINVAL);
 6181         }
 6182 
 6183         if (objp == NULL)
 6184                 objp = &obj;
 6185         error = BCOPYIN(data, objp, sizeof(*objp));
 6186         if (error != 0) {
 6187                 IPFERROR(124);
 6188                 return (EFAULT);
 6189         }
 6190 
 6191         if (objp->ipfo_type != type) {
 6192                 IPFERROR(50);
 6193                 return (EINVAL);
 6194         }
 6195 
 6196         if (objp->ipfo_rev >= ipf_objbytes[type][2]) {
 6197                 if ((ipf_objbytes[type][0] & 1) != 0) {
 6198                         if (objp->ipfo_size < ipf_objbytes[type][1]) {
 6199                                 IPFERROR(51);
 6200                                 return (EINVAL);
 6201                         }
 6202                         size =  ipf_objbytes[type][1];
 6203                 } else if (objp->ipfo_size == ipf_objbytes[type][1]) {
 6204                         size =  objp->ipfo_size;
 6205                 } else {
 6206                         IPFERROR(52);
 6207                         return (EINVAL);
 6208                 }
 6209                 error = COPYIN(objp->ipfo_ptr, ptr, size);
 6210                 if (error != 0) {
 6211                         IPFERROR(55);
 6212                         error = EFAULT;
 6213                 }
 6214         } else {
 6215 #ifdef  IPFILTER_COMPAT
 6216                 error = ipf_in_compat(softc, objp, ptr, 0);
 6217 #else
 6218                 IPFERROR(54);
 6219                 error = EINVAL;
 6220 #endif
 6221         }
 6222         return (error);
 6223 }
 6224 
 6225 
 6226 /* ------------------------------------------------------------------------ */
 6227 /* Function:    ipf_inobjsz                                                 */
 6228 /* Returns:     int     - 0 = success, else failure                         */
 6229 /* Parameters:  softc(I) - soft context pointerto work with                 */
 6230 /*              data(I)  - pointer to ioctl data                            */
 6231 /*              ptr(I)   - pointer to store real data in                    */
 6232 /*              type(I)  - type of structure being moved                    */
 6233 /*              sz(I)    - size of data to copy                             */
 6234 /*                                                                          */
 6235 /* As per ipf_inobj, except the size of the object to copy in is passed in  */
 6236 /* but it must not be smaller than the size defined for the type and the    */
 6237 /* type must allow for varied sized objects.  The extra requirement here is */
 6238 /* that sz must match the size of the object being passed in - this is not  */
 6239 /* not possible nor required in ipf_inobj().                                */
 6240 /* ------------------------------------------------------------------------ */
 6241 int
 6242 ipf_inobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz)
 6243 {
 6244         ipfobj_t obj;
 6245         int error;
 6246 
 6247         if ((type < 0) || (type >= IPFOBJ_COUNT)) {
 6248                 IPFERROR(56);
 6249                 return (EINVAL);
 6250         }
 6251 
 6252         error = BCOPYIN(data, &obj, sizeof(obj));
 6253         if (error != 0) {
 6254                 IPFERROR(125);
 6255                 return (EFAULT);
 6256         }
 6257 
 6258         if (obj.ipfo_type != type) {
 6259                 IPFERROR(58);
 6260                 return (EINVAL);
 6261         }
 6262 
 6263         if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
 6264                 if (((ipf_objbytes[type][0] & 1) == 0) ||
 6265                     (sz < ipf_objbytes[type][1])) {
 6266                         IPFERROR(57);
 6267                         return (EINVAL);
 6268                 }
 6269                 error = COPYIN(obj.ipfo_ptr, ptr, sz);
 6270                 if (error != 0) {
 6271                         IPFERROR(61);
 6272                         error = EFAULT;
 6273                 }
 6274         } else {
 6275 #ifdef  IPFILTER_COMPAT
 6276                 error = ipf_in_compat(softc, &obj, ptr, sz);
 6277 #else
 6278                 IPFERROR(60);
 6279                 error = EINVAL;
 6280 #endif
 6281         }
 6282         return (error);
 6283 }
 6284 
 6285 
 6286 /* ------------------------------------------------------------------------ */
 6287 /* Function:    ipf_outobjsz                                                */
 6288 /* Returns:     int     - 0 = success, else failure                         */
 6289 /* Parameters:  data(I) - pointer to ioctl data                             */
 6290 /*              ptr(I)  - pointer to store real data in                     */
 6291 /*              type(I) - type of structure being moved                     */
 6292 /*              sz(I)   - size of data to copy                              */
 6293 /*                                                                          */
 6294 /* As per ipf_outobj, except the size of the object to copy out is passed in*/
 6295 /* but it must not be smaller than the size defined for the type and the    */
 6296 /* type must allow for varied sized objects.  The extra requirement here is */
 6297 /* that sz must match the size of the object being passed in - this is not  */
 6298 /* not possible nor required in ipf_outobj().                               */
 6299 /* ------------------------------------------------------------------------ */
 6300 int
 6301 ipf_outobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz)
 6302 {
 6303         ipfobj_t obj;
 6304         int error;
 6305 
 6306         if ((type < 0) || (type >= IPFOBJ_COUNT)) {
 6307                 IPFERROR(62);
 6308                 return (EINVAL);
 6309         }
 6310 
 6311         error = BCOPYIN(data, &obj, sizeof(obj));
 6312         if (error != 0) {
 6313                 IPFERROR(127);
 6314                 return (EFAULT);
 6315         }
 6316 
 6317         if (obj.ipfo_type != type) {
 6318                 IPFERROR(63);
 6319                 return (EINVAL);
 6320         }
 6321 
 6322         if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
 6323                 if (((ipf_objbytes[type][0] & 1) == 0) ||
 6324                     (sz < ipf_objbytes[type][1])) {
 6325                         IPFERROR(146);
 6326                         return (EINVAL);
 6327                 }
 6328                 error = COPYOUT(ptr, obj.ipfo_ptr, sz);
 6329                 if (error != 0) {
 6330                         IPFERROR(66);
 6331                         error = EFAULT;
 6332                 }
 6333         } else {
 6334 #ifdef  IPFILTER_COMPAT
 6335                 error = ipf_out_compat(softc, &obj, ptr);
 6336 #else
 6337                 IPFERROR(65);
 6338                 error = EINVAL;
 6339 #endif
 6340         }
 6341         return (error);
 6342 }
 6343 
 6344 
 6345 /* ------------------------------------------------------------------------ */
 6346 /* Function:    ipf_outobj                                                  */
 6347 /* Returns:     int     - 0 = success, else failure                         */
 6348 /* Parameters:  data(I) - pointer to ioctl data                             */
 6349 /*              ptr(I)  - pointer to store real data in                     */
 6350 /*              type(I) - type of structure being moved                     */
 6351 /*                                                                          */
 6352 /* Copy out the contents of what ptr is to where ipfobj points to.  In      */
 6353 /* future, we add things to check for version numbers, sizes, etc, to make  */
 6354 /* it backward  compatible at the ABI for user land.                        */
 6355 /* ------------------------------------------------------------------------ */
 6356 int
 6357 ipf_outobj(ipf_main_softc_t *softc, void *data, void *ptr, int type)
 6358 {
 6359         ipfobj_t obj;
 6360         int error;
 6361 
 6362         if ((type < 0) || (type >= IPFOBJ_COUNT)) {
 6363                 IPFERROR(67);
 6364                 return (EINVAL);
 6365         }
 6366 
 6367         error = BCOPYIN(data, &obj, sizeof(obj));
 6368         if (error != 0) {
 6369                 IPFERROR(126);
 6370                 return (EFAULT);
 6371         }
 6372 
 6373         if (obj.ipfo_type != type) {
 6374                 IPFERROR(68);
 6375                 return (EINVAL);
 6376         }
 6377 
 6378         if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
 6379                 if ((ipf_objbytes[type][0] & 1) != 0) {
 6380                         if (obj.ipfo_size < ipf_objbytes[type][1]) {
 6381                                 IPFERROR(69);
 6382                                 return (EINVAL);
 6383                         }
 6384                 } else if (obj.ipfo_size != ipf_objbytes[type][1]) {
 6385                         IPFERROR(70);
 6386                         return (EINVAL);
 6387                 }
 6388 
 6389                 error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size);
 6390                 if (error != 0) {
 6391                         IPFERROR(73);
 6392                         error = EFAULT;
 6393                 }
 6394         } else {
 6395 #ifdef  IPFILTER_COMPAT
 6396                 error = ipf_out_compat(softc, &obj, ptr);
 6397 #else
 6398                 IPFERROR(72);
 6399                 error = EINVAL;
 6400 #endif
 6401         }
 6402         return (error);
 6403 }
 6404 
 6405 
 6406 /* ------------------------------------------------------------------------ */
 6407 /* Function:    ipf_outobjk                                                 */
 6408 /* Returns:     int     - 0 = success, else failure                         */
 6409 /* Parameters:  obj(I)  - pointer to data description structure             */
 6410 /*              ptr(I)  - pointer to kernel data to copy out                */
 6411 /*                                                                          */
 6412 /* In the above functions, the ipfobj_t structure is copied into the kernel,*/
 6413 /* telling ipfilter how to copy out data. In this instance, the ipfobj_t is */
 6414 /* already populated with information and now we just need to use it.       */
 6415 /* There is no need for this function to have a "type" parameter as there   */
 6416 /* is no point in validating information that comes from the kernel with    */
 6417 /* itself.                                                                  */
 6418 /* ------------------------------------------------------------------------ */
 6419 int
 6420 ipf_outobjk(ipf_main_softc_t *softc, ipfobj_t *obj, void *ptr)
 6421 {
 6422         int type = obj->ipfo_type;
 6423         int error;
 6424 
 6425         if ((type < 0) || (type >= IPFOBJ_COUNT)) {
 6426                 IPFERROR(147);
 6427                 return (EINVAL);
 6428         }
 6429 
 6430         if (obj->ipfo_rev >= ipf_objbytes[type][2]) {
 6431                 if ((ipf_objbytes[type][0] & 1) != 0) {
 6432                         if (obj->ipfo_size < ipf_objbytes[type][1]) {
 6433                                 IPFERROR(148);
 6434                                 return (EINVAL);
 6435                         }
 6436 
 6437                 } else if (obj->ipfo_size != ipf_objbytes[type][1]) {
 6438                         IPFERROR(149);
 6439                         return (EINVAL);
 6440                 }
 6441 
 6442                 error = COPYOUT(ptr, obj->ipfo_ptr, obj->ipfo_size);
 6443                 if (error != 0) {
 6444                         IPFERROR(150);
 6445                         error = EFAULT;
 6446                 }
 6447         } else {
 6448 #ifdef  IPFILTER_COMPAT
 6449                 error = ipf_out_compat(softc, obj, ptr);
 6450 #else
 6451                 IPFERROR(151);
 6452                 error = EINVAL;
 6453 #endif
 6454         }
 6455         return (error);
 6456 }
 6457 
 6458 
 6459 /* ------------------------------------------------------------------------ */
 6460 /* Function:    ipf_checkl4sum                                              */
 6461 /* Returns:     int     - 0 = good, -1 = bad, 1 = cannot check              */
 6462 /* Parameters:  fin(I) - pointer to packet information                      */
 6463 /*                                                                          */
 6464 /* If possible, calculate the layer 4 checksum for the packet.  If this is  */
 6465 /* not possible, return without indicating a failure or success but in a    */
 6466 /* way that is ditinguishable. This function should only be called by the   */
 6467 /* ipf_checkv6sum() for each platform.                                      */
 6468 /* ------------------------------------------------------------------------ */
 6469 inline int
 6470 ipf_checkl4sum(fr_info_t *fin)
 6471 {
 6472         u_short sum, hdrsum, *csump;
 6473         udphdr_t *udp;
 6474         int dosum;
 6475 
 6476         /*
 6477          * If the TCP packet isn't a fragment, isn't too short and otherwise
 6478          * isn't already considered "bad", then validate the checksum.  If
 6479          * this check fails then considered the packet to be "bad".
 6480          */
 6481         if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0)
 6482                 return (1);
 6483 
 6484         DT2(l4sumo, int, fin->fin_out, int, (int)fin->fin_p);
 6485         if (fin->fin_out == 1) {
 6486                 fin->fin_cksum = FI_CK_SUMOK;
 6487                 return (0);
 6488         }
 6489 
 6490         csump = NULL;
 6491         hdrsum = 0;
 6492         dosum = 0;
 6493         sum = 0;
 6494 
 6495         switch (fin->fin_p)
 6496         {
 6497         case IPPROTO_TCP :
 6498                 csump = &((tcphdr_t *)fin->fin_dp)->th_sum;
 6499                 dosum = 1;
 6500                 break;
 6501 
 6502         case IPPROTO_UDP :
 6503                 udp = fin->fin_dp;
 6504                 if (udp->uh_sum != 0) {
 6505                         csump = &udp->uh_sum;
 6506                         dosum = 1;
 6507                 }
 6508                 break;
 6509 
 6510 #ifdef USE_INET6
 6511         case IPPROTO_ICMPV6 :
 6512                 csump = &((struct icmp6_hdr *)fin->fin_dp)->icmp6_cksum;
 6513                 dosum = 1;
 6514                 break;
 6515 #endif
 6516 
 6517         case IPPROTO_ICMP :
 6518                 csump = &((struct icmp *)fin->fin_dp)->icmp_cksum;
 6519                 dosum = 1;
 6520                 break;
 6521 
 6522         default :
 6523                 return (1);
 6524                 /*NOTREACHED*/
 6525         }
 6526 
 6527         if (csump != NULL) {
 6528                 hdrsum = *csump;
 6529                 if (fin->fin_p == IPPROTO_UDP && hdrsum == 0xffff)
 6530                         hdrsum = 0x0000;
 6531         }
 6532 
 6533         if (dosum) {
 6534                 sum = fr_cksum(fin, fin->fin_ip, fin->fin_p, fin->fin_dp);
 6535         }
 6536 #if !defined(_KERNEL)
 6537         if (sum == hdrsum) {
 6538                 FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum));
 6539         } else {
 6540                 FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum));
 6541         }
 6542 #endif
 6543         DT3(l4sums, u_short, hdrsum, u_short, sum, fr_info_t *, fin);
 6544 #ifdef USE_INET6
 6545         if (hdrsum == sum || (sum == 0 && IP_V(fin->fin_ip) == 6)) {
 6546 #else
 6547         if (hdrsum == sum) {
 6548 #endif
 6549                 fin->fin_cksum = FI_CK_SUMOK;
 6550                 return (0);
 6551         }
 6552         fin->fin_cksum = FI_CK_BAD;
 6553         return (-1);
 6554 }
 6555 
 6556 
 6557 /* ------------------------------------------------------------------------ */
 6558 /* Function:    ipf_ifpfillv4addr                                           */
 6559 /* Returns:     int     - 0 = address update, -1 = address not updated      */
 6560 /* Parameters:  atype(I)   - type of network address update to perform      */
 6561 /*              sin(I)     - pointer to source of address information       */
 6562 /*              mask(I)    - pointer to source of netmask information       */
 6563 /*              inp(I)     - pointer to destination address store           */
 6564 /*              inpmask(I) - pointer to destination netmask store           */
 6565 /*                                                                          */
 6566 /* Given a type of network address update (atype) to perform, copy          */
 6567 /* information from sin/mask into inp/inpmask.  If ipnmask is NULL then no  */
 6568 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in  */
 6569 /* which case the operation fails.  For all values of atype other than      */
 6570 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s  */
 6571 /* value.                                                                   */
 6572 /* ------------------------------------------------------------------------ */
 6573 int
 6574 ipf_ifpfillv4addr(int atype, struct sockaddr_in *sin, struct sockaddr_in *mask,
 6575         struct in_addr *inp, struct in_addr *inpmask)
 6576 {
 6577         if (inpmask != NULL && atype != FRI_NETMASKED)
 6578                 inpmask->s_addr = 0xffffffff;
 6579 
 6580         if (atype == FRI_NETWORK || atype == FRI_NETMASKED) {
 6581                 if (atype == FRI_NETMASKED) {
 6582                         if (inpmask == NULL)
 6583                                 return (-1);
 6584                         inpmask->s_addr = mask->sin_addr.s_addr;
 6585                 }
 6586                 inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr;
 6587         } else {
 6588                 inp->s_addr = sin->sin_addr.s_addr;
 6589         }
 6590         return (0);
 6591 }
 6592 
 6593 
 6594 #ifdef  USE_INET6
 6595 /* ------------------------------------------------------------------------ */
 6596 /* Function:    ipf_ifpfillv6addr                                           */
 6597 /* Returns:     int     - 0 = address update, -1 = address not updated      */
 6598 /* Parameters:  atype(I)   - type of network address update to perform      */
 6599 /*              sin(I)     - pointer to source of address information       */
 6600 /*              mask(I)    - pointer to source of netmask information       */
 6601 /*              inp(I)     - pointer to destination address store           */
 6602 /*              inpmask(I) - pointer to destination netmask store           */
 6603 /*                                                                          */
 6604 /* Given a type of network address update (atype) to perform, copy          */
 6605 /* information from sin/mask into inp/inpmask.  If ipnmask is NULL then no  */
 6606 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in  */
 6607 /* which case the operation fails.  For all values of atype other than      */
 6608 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s  */
 6609 /* value.                                                                   */
 6610 /* ------------------------------------------------------------------------ */
 6611 int
 6612 ipf_ifpfillv6addr(int atype, struct sockaddr_in6 *sin,
 6613         struct sockaddr_in6 *mask, i6addr_t *inp, i6addr_t *inpmask)
 6614 {
 6615         i6addr_t *src, *and;
 6616 
 6617         src = (i6addr_t *)&sin->sin6_addr;
 6618         and = (i6addr_t *)&mask->sin6_addr;
 6619 
 6620         if (inpmask != NULL && atype != FRI_NETMASKED) {
 6621                 inpmask->i6[0] = 0xffffffff;
 6622                 inpmask->i6[1] = 0xffffffff;
 6623                 inpmask->i6[2] = 0xffffffff;
 6624                 inpmask->i6[3] = 0xffffffff;
 6625         }
 6626 
 6627         if (atype == FRI_NETWORK || atype == FRI_NETMASKED) {
 6628                 if (atype == FRI_NETMASKED) {
 6629                         if (inpmask == NULL)
 6630                                 return (-1);
 6631                         inpmask->i6[0] = and->i6[0];
 6632                         inpmask->i6[1] = and->i6[1];
 6633                         inpmask->i6[2] = and->i6[2];
 6634                         inpmask->i6[3] = and->i6[3];
 6635                 }
 6636 
 6637                 inp->i6[0] = src->i6[0] & and->i6[0];
 6638                 inp->i6[1] = src->i6[1] & and->i6[1];
 6639                 inp->i6[2] = src->i6[2] & and->i6[2];
 6640                 inp->i6[3] = src->i6[3] & and->i6[3];
 6641         } else {
 6642                 inp->i6[0] = src->i6[0];
 6643                 inp->i6[1] = src->i6[1];
 6644                 inp->i6[2] = src->i6[2];
 6645                 inp->i6[3] = src->i6[3];
 6646         }
 6647         return (0);
 6648 }
 6649 #endif
 6650 
 6651 
 6652 /* ------------------------------------------------------------------------ */
 6653 /* Function:    ipf_matchtag                                                */
 6654 /* Returns:     0 == mismatch, 1 == match.                                  */
 6655 /* Parameters:  tag1(I) - pointer to first tag to compare                   */
 6656 /*              tag2(I) - pointer to second tag to compare                  */
 6657 /*                                                                          */
 6658 /* Returns true (non-zero) or false(0) if the two tag structures can be     */
 6659 /* considered to be a match or not match, respectively.  The tag is 16      */
 6660 /* bytes long (16 characters) but that is overlayed with 4 32bit ints so    */
 6661 /* compare the ints instead, for speed. tag1 is the master of the           */
 6662 /* comparison.  This function should only be called with both tag1 and tag2 */
 6663 /* as non-NULL pointers.                                                    */
 6664 /* ------------------------------------------------------------------------ */
 6665 int
 6666 ipf_matchtag(ipftag_t *tag1, ipftag_t *tag2)
 6667 {
 6668         if (tag1 == tag2)
 6669                 return (1);
 6670 
 6671         if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0))
 6672                 return (1);
 6673 
 6674         if ((tag1->ipt_num[0] == tag2->ipt_num[0]) &&
 6675             (tag1->ipt_num[1] == tag2->ipt_num[1]) &&
 6676             (tag1->ipt_num[2] == tag2->ipt_num[2]) &&
 6677             (tag1->ipt_num[3] == tag2->ipt_num[3]))
 6678                 return (1);
 6679         return (0);
 6680 }
 6681 
 6682 
 6683 /* ------------------------------------------------------------------------ */
 6684 /* Function:    ipf_coalesce                                                */
 6685 /* Returns:     1 == success, -1 == failure, 0 == no change                 */
 6686 /* Parameters:  fin(I) - pointer to packet information                      */
 6687 /*                                                                          */
 6688 /* Attempt to get all of the packet data into a single, contiguous buffer.  */
 6689 /* If this call returns a failure then the buffers have also been freed.    */
 6690 /* ------------------------------------------------------------------------ */
 6691 int
 6692 ipf_coalesce(fr_info_t *fin)
 6693 {
 6694 
 6695         if ((fin->fin_flx & FI_COALESCE) != 0)
 6696                 return (1);
 6697 
 6698         /*
 6699          * If the mbuf pointers indicate that there is no mbuf to work with,
 6700         * return but do not indicate success or failure.
 6701          */
 6702         if (fin->fin_m == NULL || fin->fin_mp == NULL)
 6703                 return (0);
 6704 
 6705 #if defined(_KERNEL)
 6706         if (ipf_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) {
 6707                 ipf_main_softc_t *softc = fin->fin_main_soft;
 6708 
 6709                 DT1(frb_coalesce, fr_info_t *, fin);
 6710                 LBUMP(ipf_stats[fin->fin_out].fr_badcoalesces);
 6711 # if SOLARIS
 6712                 FREE_MB_T(*fin->fin_mp);
 6713 # endif
 6714                 fin->fin_reason = FRB_COALESCE;
 6715                 *fin->fin_mp = NULL;
 6716                 fin->fin_m = NULL;
 6717                 return (-1);
 6718         }
 6719 #else
 6720         fin = fin;      /* LINT */
 6721 #endif
 6722         return (1);
 6723 }
 6724 
 6725 
 6726 /*
 6727  * The following table lists all of the tunable variables that can be
 6728  * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXt.  The format of each row
 6729  * in the table below is as follows:
 6730  *
 6731  * pointer to value, name of value, minimum, maximum, size of the value's
 6732  *     container, value attribute flags
 6733  *
 6734  * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED
 6735  * means the value can only be written to when IPFilter is loaded but disabled.
 6736  * The obvious implication is if neither of these are set then the value can be
 6737  * changed at any time without harm.
 6738  */
 6739 
 6740 
 6741 /* ------------------------------------------------------------------------ */
 6742 /* Function:    ipf_tune_findbycookie                                       */
 6743 /* Returns:     NULL = search failed, else pointer to tune struct           */
 6744 /* Parameters:  cookie(I) - cookie value to search for amongst tuneables    */
 6745 /*              next(O)   - pointer to place to store the cookie for the    */
 6746 /*                          "next" tuneable, if it is desired.              */
 6747 /*                                                                          */
 6748 /* This function is used to walk through all of the existing tunables with  */
 6749 /* successive calls.  It searches the known tunables for the one which has  */
 6750 /* a matching value for "cookie" - ie its address.  When returning a match, */
 6751 /* the next one to be found may be returned inside next.                    */
 6752 /* ------------------------------------------------------------------------ */
 6753 static ipftuneable_t *
 6754 ipf_tune_findbycookie(ipftuneable_t **ptop, void *cookie, void **next)
 6755 {
 6756         ipftuneable_t *ta, **tap;
 6757 
 6758         for (ta = *ptop; ta->ipft_name != NULL; ta++)
 6759                 if (ta == cookie) {
 6760                         if (next != NULL) {
 6761                                 /*
 6762                                  * If the next entry in the array has a name
 6763                                 * present, then return a pointer to it for
 6764                                 * where to go next, else return a pointer to
 6765                                  * the dynaminc list as a key to search there
 6766                                  * next.  This facilitates a weak linking of
 6767                                  * the two "lists" together.
 6768                                  */
 6769                                 if ((ta + 1)->ipft_name != NULL)
 6770                                         *next = ta + 1;
 6771                                 else
 6772                                         *next = ptop;
 6773                         }
 6774                         return (ta);
 6775                 }
 6776 
 6777         for (tap = ptop; (ta = *tap) != NULL; tap = &ta->ipft_next)
 6778                 if (tap == cookie) {
 6779                         if (next != NULL)
 6780                                 *next = &ta->ipft_next;
 6781                         return (ta);
 6782                 }
 6783 
 6784         if (next != NULL)
 6785                 *next = NULL;
 6786         return (NULL);
 6787 }
 6788 
 6789 
 6790 /* ------------------------------------------------------------------------ */
 6791 /* Function:    ipf_tune_findbyname                                         */
 6792 /* Returns:     NULL = search failed, else pointer to tune struct           */
 6793 /* Parameters:  name(I) - name of the tuneable entry to find.               */
 6794 /*                                                                          */
 6795 /* Search the static array of tuneables and the list of dynamic tuneables   */
 6796 /* for an entry with a matching name.  If we can find one, return a pointer */
 6797 /* to the matching structure.                                               */
 6798 /* ------------------------------------------------------------------------ */
 6799 static ipftuneable_t *
 6800 ipf_tune_findbyname(ipftuneable_t *top, const char *name)
 6801 {
 6802         ipftuneable_t *ta;
 6803 
 6804         for (ta = top; ta != NULL; ta = ta->ipft_next)
 6805                 if (!strcmp(ta->ipft_name, name)) {
 6806                         return (ta);
 6807                 }
 6808 
 6809         return (NULL);
 6810 }
 6811 
 6812 
 6813 /* ------------------------------------------------------------------------ */
 6814 /* Function:    ipf_tune_add_array                                          */
 6815 /* Returns:     int - 0 == success, else failure                            */
 6816 /* Parameters:  newtune - pointer to new tune array to add to tuneables     */
 6817 /*                                                                          */
 6818 /* Appends tune structures from the array passed in (newtune) to the end of */
 6819 /* the current list of "dynamic" tuneable parameters.                       */
 6820 /* If any entry to be added is already present (by name) then the operation */
 6821 /* is aborted - entries that have been added are removed before returning.  */
 6822 /* An entry with no name (NULL) is used as the indication that the end of   */
 6823 /* the array has been reached.                                              */
 6824 /* ------------------------------------------------------------------------ */
 6825 int
 6826 ipf_tune_add_array(ipf_main_softc_t *softc, ipftuneable_t *newtune)
 6827 {
 6828         ipftuneable_t *nt, *dt;
 6829         int error = 0;
 6830 
 6831         for (nt = newtune; nt->ipft_name != NULL; nt++) {
 6832                 error = ipf_tune_add(softc, nt);
 6833                 if (error != 0) {
 6834                         for (dt = newtune; dt != nt; dt++) {
 6835                                 (void) ipf_tune_del(softc, dt);
 6836                         }
 6837                 }
 6838         }
 6839 
 6840         return (error);
 6841 }
 6842 
 6843 
 6844 /* ------------------------------------------------------------------------ */
 6845 /* Function:    ipf_tune_array_link                                         */
 6846 /* Returns:     0 == success, -1 == failure                                 */
 6847 /* Parameters:  softc(I) - soft context pointerto work with                 */
 6848 /*              array(I) - pointer to an array of tuneables                 */
 6849 /*                                                                          */
 6850 /* Given an array of tunables (array), append them to the current list of   */
 6851 /* tuneables for this context (softc->ipf_tuners.) To properly prepare the  */
 6852 /* the array for being appended to the list, initialise all of the next     */
 6853 /* pointers so we don't need to walk parts of it with ++ and others with    */
 6854 /* next. The array is expected to have an entry with a NULL name as the     */
 6855 /* terminator. Trying to add an array with no non-NULL names will return as */
 6856 /* a failure.                                                               */
 6857 /* ------------------------------------------------------------------------ */
 6858 int
 6859 ipf_tune_array_link(ipf_main_softc_t *softc, ipftuneable_t *array)
 6860 {
 6861         ipftuneable_t *t, **p;
 6862 
 6863         t = array;
 6864         if (t->ipft_name == NULL)
 6865                 return (-1);
 6866 
 6867         for (; t[1].ipft_name != NULL; t++)
 6868                 t[0].ipft_next = &t[1];
 6869         t->ipft_next = NULL;
 6870 
 6871         /*
 6872          * Since a pointer to the last entry isn't kept, we need to find it
 6873          * each time we want to add new variables to the list.
 6874          */
 6875         for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next)
 6876                 if (t->ipft_name == NULL)
 6877                         break;
 6878         *p = array;
 6879 
 6880         return (0);
 6881 }
 6882 
 6883 
 6884 /* ------------------------------------------------------------------------ */
 6885 /* Function:    ipf_tune_array_unlink                                       */
 6886 /* Returns:     0 == success, -1 == failure                                 */
 6887 /* Parameters:  softc(I) - soft context pointerto work with                 */
 6888 /*              array(I) - pointer to an array of tuneables                 */
 6889 /*                                                                          */
 6890 /* ------------------------------------------------------------------------ */
 6891 int
 6892 ipf_tune_array_unlink(ipf_main_softc_t *softc, ipftuneable_t *array)
 6893 {
 6894         ipftuneable_t *t, **p;
 6895 
 6896         for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next)
 6897                 if (t == array)
 6898                         break;
 6899         if (t == NULL)
 6900                 return (-1);
 6901 
 6902         for (; t[1].ipft_name != NULL; t++)
 6903                 ;
 6904 
 6905         *p = t->ipft_next;
 6906 
 6907         return (0);
 6908 }
 6909 
 6910 
 6911 /* ------------------------------------------------------------------------ */
 6912 /* Function:   ipf_tune_array_copy                                          */
 6913 /* Returns:    NULL = failure, else pointer to new array                    */
 6914 /* Parameters: base(I)     - pointer to structure base                      */
 6915 /*             size(I)     - size of the array at template                  */
 6916 /*             template(I) - original array to copy                         */
 6917 /*                                                                          */
 6918 /* Allocate memory for a new set of tuneable values and copy everything     */
 6919 /* from template into the new region of memory.  The new region is full of  */
 6920 /* uninitialised pointers (ipft_next) so set them up.  Now, ipftp_offset... */
 6921 /*                                                                          */
 6922 /* NOTE: the following assumes that sizeof(long) == sizeof(void *)          */
 6923 /* In the array template, ipftp_offset is the offset (in bytes) of the      */
 6924 /* location of the tuneable value inside the structure pointed to by base.  */
 6925 /* As ipftp_offset is a union over the pointers to the tuneable values, if  */
 6926 /* we add base to the copy's ipftp_offset, copy ends up with a pointer in   */
 6927 /* ipftp_void that points to the stored value.                              */
 6928 /* ------------------------------------------------------------------------ */
 6929 ipftuneable_t *
 6930 ipf_tune_array_copy(void *base, size_t size, ipftuneable_t *template)
 6931 {
 6932         ipftuneable_t *copy;
 6933         int i;
 6934 
 6935 
 6936         KMALLOCS(copy, ipftuneable_t *, size);
 6937         if (copy == NULL) {
 6938                 return (NULL);
 6939         }
 6940         bcopy(template, copy, size);
 6941 
 6942         for (i = 0; copy[i].ipft_name; i++) {
 6943                 copy[i].ipft_una.ipftp_offset += (u_long)base;
 6944                 copy[i].ipft_next = copy + i + 1;
 6945         }
 6946 
 6947         return (copy);
 6948 }
 6949 
 6950 
 6951 /* ------------------------------------------------------------------------ */
 6952 /* Function:    ipf_tune_add                                                */
 6953 /* Returns:     int - 0 == success, else failure                            */
 6954 /* Parameters:  newtune - pointer to new tune entry to add to tuneables     */
 6955 /*                                                                          */
 6956 /* Appends tune structures from the array passed in (newtune) to the end of */
 6957 /* the current list of "dynamic" tuneable parameters.  Once added, the      */
 6958 /* owner of the object is not expected to ever change "ipft_next".          */
 6959 /* ------------------------------------------------------------------------ */
 6960 int
 6961 ipf_tune_add(ipf_main_softc_t *softc, ipftuneable_t *newtune)
 6962 {
 6963         ipftuneable_t *ta, **tap;
 6964 
 6965         ta = ipf_tune_findbyname(softc->ipf_tuners, newtune->ipft_name);
 6966         if (ta != NULL) {
 6967                 IPFERROR(74);
 6968                 return (EEXIST);
 6969         }
 6970 
 6971         for (tap = &softc->ipf_tuners; *tap != NULL; tap = &(*tap)->ipft_next)
 6972                 ;
 6973 
 6974         newtune->ipft_next = NULL;
 6975         *tap = newtune;
 6976         return (0);
 6977 }
 6978 
 6979 
 6980 /* ------------------------------------------------------------------------ */
 6981 /* Function:    ipf_tune_del                                                */
 6982 /* Returns:     int - 0 == success, else failure                            */
 6983 /* Parameters:  oldtune - pointer to tune entry to remove from the list of  */
 6984 /*                        current dynamic tuneables                         */
 6985 /*                                                                          */
 6986 /* Search for the tune structure, by pointer, in the list of those that are */
 6987 /* dynamically added at run time.  If found, adjust the list so that this   */
 6988 /* structure is no longer part of it.                                       */
 6989 /* ------------------------------------------------------------------------ */
 6990 int
 6991 ipf_tune_del(ipf_main_softc_t *softc, ipftuneable_t *oldtune)
 6992 {
 6993         ipftuneable_t *ta, **tap;
 6994         int error = 0;
 6995 
 6996         for (tap = &softc->ipf_tuners; (ta = *tap) != NULL;
 6997              tap = &ta->ipft_next) {
 6998                 if (ta == oldtune) {
 6999                         *tap = oldtune->ipft_next;
 7000                         oldtune->ipft_next = NULL;
 7001                         break;
 7002                 }
 7003         }
 7004 
 7005         if (ta == NULL) {
 7006                 error = ESRCH;
 7007                 IPFERROR(75);
 7008         }
 7009         return (error);
 7010 }
 7011 
 7012 
 7013 /* ------------------------------------------------------------------------ */
 7014 /* Function:    ipf_tune_del_array                                          */
 7015 /* Returns:     int - 0 == success, else failure                            */
 7016 /* Parameters:  oldtune - pointer to tuneables array                        */
 7017 /*                                                                          */
 7018 /* Remove each tuneable entry in the array from the list of "dynamic"       */
 7019 /* tunables.  If one entry should fail to be found, an error will be        */
 7020 /* returned and no further ones removed.                                    */
 7021 /* An entry with a NULL name is used as the indicator of the last entry in  */
 7022 /* the array.                                                               */
 7023 /* ------------------------------------------------------------------------ */
 7024 int
 7025 ipf_tune_del_array(ipf_main_softc_t *softc, ipftuneable_t *oldtune)
 7026 {
 7027         ipftuneable_t *ot;
 7028         int error = 0;
 7029 
 7030         for (ot = oldtune; ot->ipft_name != NULL; ot++) {
 7031                 error = ipf_tune_del(softc, ot);
 7032                 if (error != 0)
 7033                         break;
 7034         }
 7035 
 7036         return (error);
 7037 
 7038 }
 7039 
 7040 
 7041 /* ------------------------------------------------------------------------ */
 7042 /* Function:    ipf_tune                                                    */
 7043 /* Returns:     int - 0 == success, else failure                            */
 7044 /* Parameters:  cmd(I)  - ioctl command number                              */
 7045 /*              data(I) - pointer to ioctl data structure                   */
 7046 /*                                                                          */
 7047 /* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET.  These  */
 7048 /* three ioctls provide the means to access and control global variables    */
 7049 /* within IPFilter, allowing (for example) timeouts and table sizes to be   */
 7050 /* changed without rebooting, reloading or recompiling.  The initialisation */
 7051 /* and 'destruction' routines of the various components of ipfilter are all */
 7052 /* each responsible for handling their own values being too big.            */
 7053 /* ------------------------------------------------------------------------ */
 7054 int
 7055 ipf_ipftune(ipf_main_softc_t *softc, ioctlcmd_t cmd, void *data)
 7056 {
 7057         ipftuneable_t *ta;
 7058         ipftune_t tu;
 7059         void *cookie;
 7060         int error;
 7061 
 7062         error = ipf_inobj(softc, data, NULL, &tu, IPFOBJ_TUNEABLE);
 7063         if (error != 0)
 7064                 return (error);
 7065 
 7066         tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0';
 7067         cookie = tu.ipft_cookie;
 7068         ta = NULL;
 7069 
 7070         switch (cmd)
 7071         {
 7072         case SIOCIPFGETNEXT :
 7073                 /*
 7074                  * If cookie is non-NULL, assume it to be a pointer to the last
 7075                 * entry we looked at, so find it (if possible) and return a
 7076                  * pointer to the next one after it.  The last entry in the
 7077                  * the table is a NULL entry, so when we get to it, set cookie
 7078                 * to NULL and return that, indicating end of list, erstwhile
 7079                  * if we come in with cookie set to NULL, we are starting anew
 7080                  * at the front of the list.
 7081                  */
 7082                 if (cookie != NULL) {
 7083                         ta = ipf_tune_findbycookie(&softc->ipf_tuners,
 7084                                                    cookie, &tu.ipft_cookie);
 7085                 } else {
 7086                         ta = softc->ipf_tuners;
 7087                         tu.ipft_cookie = ta + 1;
 7088                 }
 7089                 if (ta != NULL) {
 7090                         /*
 7091                          * Entry found, but does the data pointed to by that
 7092                          * row fit in what we can return?
 7093                          */
 7094                         if (ta->ipft_sz > sizeof(tu.ipft_un)) {
 7095                                 IPFERROR(76);
 7096                                 return (EINVAL);
 7097                         }
 7098 
 7099                         tu.ipft_vlong = 0;
 7100                         if (ta->ipft_sz == sizeof(u_long))
 7101                                 tu.ipft_vlong = *ta->ipft_plong;
 7102                         else if (ta->ipft_sz == sizeof(u_int))
 7103                                 tu.ipft_vint = *ta->ipft_pint;
 7104                         else if (ta->ipft_sz == sizeof(u_short))
 7105                                 tu.ipft_vshort = *ta->ipft_pshort;
 7106                         else if (ta->ipft_sz == sizeof(u_char))
 7107                                 tu.ipft_vchar = *ta->ipft_pchar;
 7108 
 7109                         tu.ipft_sz = ta->ipft_sz;
 7110                         tu.ipft_min = ta->ipft_min;
 7111                         tu.ipft_max = ta->ipft_max;
 7112                         tu.ipft_flags = ta->ipft_flags;
 7113                         bcopy(ta->ipft_name, tu.ipft_name,
 7114                               MIN(sizeof(tu.ipft_name),
 7115                                   strlen(ta->ipft_name) + 1));
 7116                 }
 7117                 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
 7118                 break;
 7119 
 7120         case SIOCIPFGET :
 7121         case SIOCIPFSET :
 7122                 /*
 7123                  * Search by name or by cookie value for a particular entry
 7124                  * in the tuning parameter table.
 7125                  */
 7126                 IPFERROR(77);
 7127                 error = ESRCH;
 7128                 if (cookie != NULL) {
 7129                         ta = ipf_tune_findbycookie(&softc->ipf_tuners,
 7130                                                    cookie, NULL);
 7131                         if (ta != NULL)
 7132                                 error = 0;
 7133                 } else if (tu.ipft_name[0] != '\0') {
 7134                         ta = ipf_tune_findbyname(softc->ipf_tuners,
 7135                                                  tu.ipft_name);
 7136                         if (ta != NULL)
 7137                                 error = 0;
 7138                 }
 7139                 if (error != 0)
 7140                         break;
 7141 
 7142                 if (cmd == (ioctlcmd_t)SIOCIPFGET) {
 7143                         /*
 7144                          * Fetch the tuning parameters for a particular value
 7145                          */
 7146                         tu.ipft_vlong = 0;
 7147                         if (ta->ipft_sz == sizeof(u_long))
 7148                                 tu.ipft_vlong = *ta->ipft_plong;
 7149                         else if (ta->ipft_sz == sizeof(u_int))
 7150                                 tu.ipft_vint = *ta->ipft_pint;
 7151                         else if (ta->ipft_sz == sizeof(u_short))
 7152                                 tu.ipft_vshort = *ta->ipft_pshort;
 7153                         else if (ta->ipft_sz == sizeof(u_char))
 7154                                 tu.ipft_vchar = *ta->ipft_pchar;
 7155                         tu.ipft_cookie = ta;
 7156                         tu.ipft_sz = ta->ipft_sz;
 7157                         tu.ipft_min = ta->ipft_min;
 7158                         tu.ipft_max = ta->ipft_max;
 7159                         tu.ipft_flags = ta->ipft_flags;
 7160                         error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
 7161 
 7162                 } else if (cmd == (ioctlcmd_t)SIOCIPFSET) {
 7163                         /*
 7164                          * Set an internal parameter.  The hard part here is
 7165                          * getting the new value safely and correctly out of
 7166                          * the kernel (given we only know its size, not type.)
 7167                          */
 7168                         u_long in;
 7169 
 7170                         if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) &&
 7171                             (softc->ipf_running > 0)) {
 7172                                 IPFERROR(78);
 7173                                 error = EBUSY;
 7174                                 break;
 7175                         }
 7176 
 7177                         in = tu.ipft_vlong;
 7178                         if (in < ta->ipft_min || in > ta->ipft_max) {
 7179                                 IPFERROR(79);
 7180                                 error = EINVAL;
 7181                                 break;
 7182                         }
 7183 
 7184                         if (ta->ipft_func != NULL) {
 7185                                 SPL_INT(s);
 7186 
 7187                                 SPL_NET(s);
 7188                                 error = (*ta->ipft_func)(softc, ta,
 7189                                                          &tu.ipft_un);
 7190                                 SPL_X(s);
 7191 
 7192                         } else if (ta->ipft_sz == sizeof(u_long)) {
 7193                                 tu.ipft_vlong = *ta->ipft_plong;
 7194                                 *ta->ipft_plong = in;
 7195 
 7196                         } else if (ta->ipft_sz == sizeof(u_int)) {
 7197                                 tu.ipft_vint = *ta->ipft_pint;
 7198                                 *ta->ipft_pint = (u_int)(in & 0xffffffff);
 7199 
 7200                         } else if (ta->ipft_sz == sizeof(u_short)) {
 7201                                 tu.ipft_vshort = *ta->ipft_pshort;
 7202                                 *ta->ipft_pshort = (u_short)(in & 0xffff);
 7203 
 7204                         } else if (ta->ipft_sz == sizeof(u_char)) {
 7205                                 tu.ipft_vchar = *ta->ipft_pchar;
 7206                                 *ta->ipft_pchar = (u_char)(in & 0xff);
 7207                         }
 7208                         error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
 7209                 }
 7210                 break;
 7211 
 7212         default :
 7213                 IPFERROR(80);
 7214                 error = EINVAL;
 7215                 break;
 7216         }
 7217 
 7218         return (error);
 7219 }
 7220 
 7221 
 7222 /* ------------------------------------------------------------------------ */
 7223 /* Function:    ipf_zerostats                                               */
 7224 /* Returns:     int - 0 = success, else failure                             */
 7225 /* Parameters:  data(O) - pointer to pointer for copying data back to       */
 7226 /*                                                                          */
 7227 /* Copies the current statistics out to userspace and then zero's the       */
 7228 /* current ones in the kernel. The lock is only held across the bzero() as  */
 7229 /* the copyout may result in paging (ie network activity.)                  */
 7230 /* ------------------------------------------------------------------------ */
 7231 int
 7232 ipf_zerostats(ipf_main_softc_t *softc, caddr_t data)
 7233 {
 7234         friostat_t fio;
 7235         ipfobj_t obj;
 7236         int error;
 7237 
 7238         error = ipf_inobj(softc, data, &obj, &fio, IPFOBJ_IPFSTAT);
 7239         if (error != 0)
 7240                 return (error);
 7241         ipf_getstat(softc, &fio, obj.ipfo_rev);
 7242         error = ipf_outobj(softc, data, &fio, IPFOBJ_IPFSTAT);
 7243         if (error != 0)
 7244                 return (error);
 7245 
 7246         WRITE_ENTER(&softc->ipf_mutex);
 7247         bzero(&softc->ipf_stats, sizeof(softc->ipf_stats));
 7248         RWLOCK_EXIT(&softc->ipf_mutex);
 7249 
 7250         return (0);
 7251 }
 7252 
 7253 
 7254 /* ------------------------------------------------------------------------ */
 7255 /* Function:    ipf_resolvedest                                             */
 7256 /* Returns:     Nil                                                         */
 7257 /* Parameters:  softc(I) - pointer to soft context main structure           */
 7258 /*              base(I)  - where strings are stored                         */
 7259 /*              fdp(IO)  - pointer to destination information to resolve    */
 7260 /*              v(I)     - IP protocol version to match                     */
 7261 /*                                                                          */
 7262 /* Looks up an interface name in the frdest structure pointed to by fdp and */
 7263 /* if a matching name can be found for the particular IP protocol version   */
 7264 /* then store the interface pointer in the frdest struct.  If no match is   */
 7265 /* found, then set the interface pointer to be -1 as NULL is considered to  */
 7266 /* indicate there is no information at all in the structure.                */
 7267 /* ------------------------------------------------------------------------ */
 7268 int
 7269 ipf_resolvedest(ipf_main_softc_t *softc, char *base, frdest_t *fdp, int v)
 7270 {
 7271         int errval = 0;
 7272         void *ifp;
 7273 
 7274         ifp = NULL;
 7275 
 7276         if (fdp->fd_name != -1) {
 7277                 if (fdp->fd_type == FRD_DSTLIST) {
 7278                         ifp = ipf_lookup_res_name(softc, IPL_LOGIPF,
 7279                                                   IPLT_DSTLIST,
 7280                                                   base + fdp->fd_name,
 7281                                                   NULL);
 7282                         if (ifp == NULL) {
 7283                                 IPFERROR(144);
 7284                                 errval = ESRCH;
 7285                         }
 7286                 } else {
 7287                         ifp = GETIFP(base + fdp->fd_name, v);
 7288                         if (ifp == NULL)
 7289                                 ifp = (void *)-1;
 7290                 }
 7291         }
 7292         fdp->fd_ptr = ifp;
 7293 
 7294         return (errval);
 7295 }
 7296 
 7297 
 7298 /* ------------------------------------------------------------------------ */
 7299 /* Function:    ipf_resolvenic                                              */
 7300 /* Returns:     void* - NULL = wildcard name, -1 = failed to find NIC, else */
 7301 /*                      pointer to interface structure for NIC              */
 7302 /* Parameters:  softc(I)- pointer to soft context main structure            */
 7303 /*              name(I) - complete interface name                           */
 7304 /*              v(I)    - IP protocol version                               */
 7305 /*                                                                          */
 7306 /* Look for a network interface structure that firstly has a matching name  */
 7307 /* to that passed in and that is also being used for that IP protocol       */
 7308 /* version (necessary on some platforms where there are separate listings   */
 7309 /* for both IPv4 and IPv6 on the same physical NIC.                         */
 7310 /* ------------------------------------------------------------------------ */
 7311 void *
 7312 ipf_resolvenic(ipf_main_softc_t *softc, char *name, int v)
 7313 {
 7314         void *nic;
 7315 
 7316         softc = softc;  /* gcc -Wextra */
 7317         if (name[0] == '\0')
 7318                 return (NULL);
 7319 
 7320         if ((name[1] == '\0') && ((name[0] == '-') || (name[0] == '*'))) {
 7321                 return (NULL);
 7322         }
 7323 
 7324         nic = GETIFP(name, v);
 7325         if (nic == NULL)
 7326                 nic = (void *)-1;
 7327         return (nic);
 7328 }
 7329 
 7330 
 7331 /* ------------------------------------------------------------------------ */
 7332 /* Function:    ipf_token_expire                                            */
 7333 /* Returns:     None.                                                       */
 7334 /* Parameters:  softc(I) - pointer to soft context main structure           */
 7335 /*                                                                          */
 7336 /* This function is run every ipf tick to see if there are any tokens that  */
 7337 /* have been held for too long and need to be freed up.                     */
 7338 /* ------------------------------------------------------------------------ */
 7339 void
 7340 ipf_token_expire(ipf_main_softc_t *softc)
 7341 {
 7342         ipftoken_t *it;
 7343 
 7344         WRITE_ENTER(&softc->ipf_tokens);
 7345         while ((it = softc->ipf_token_head) != NULL) {
 7346                 if (it->ipt_die > softc->ipf_ticks)
 7347                         break;
 7348 
 7349                 ipf_token_deref(softc, it);
 7350         }
 7351         RWLOCK_EXIT(&softc->ipf_tokens);
 7352 }
 7353 
 7354 
 7355 /* ------------------------------------------------------------------------ */
 7356 /* Function:    ipf_token_flush                                             */
 7357 /* Returns:     None.                                                       */
 7358 /* Parameters:  softc(I) - pointer to soft context main structure           */
 7359 /*                                                                          */
 7360 /* Loop through all of the existing tokens and call deref to see if they    */
 7361 /* can be freed. Normally a function like this might just loop on           */
 7362 /* ipf_token_head but there is a chance that a token might have a ref count */
 7363 /* of greater than one and in that case the reference would drop twice      */
 7364 /* by code that is only entitled to drop it once.                           */
 7365 /* ------------------------------------------------------------------------ */
 7366 static void
 7367 ipf_token_flush(ipf_main_softc_t *softc)
 7368 {
 7369         ipftoken_t *it, *next;
 7370 
 7371         WRITE_ENTER(&softc->ipf_tokens);
 7372         for (it = softc->ipf_token_head; it != NULL; it = next) {
 7373                 next = it->ipt_next;
 7374                 (void) ipf_token_deref(softc, it);
 7375         }
 7376         RWLOCK_EXIT(&softc->ipf_tokens);
 7377 }
 7378 
 7379 
 7380 /* ------------------------------------------------------------------------ */
 7381 /* Function:    ipf_token_del                                               */
 7382 /* Returns:     int     - 0 = success, else error                           */
 7383 /* Parameters:  softc(I)- pointer to soft context main structure            */
 7384 /*              type(I) - the token type to match                           */
 7385 /*              uid(I)  - uid owning the token                              */
 7386 /*              ptr(I)  - context pointer for the token                     */
 7387 /*                                                                          */
 7388 /* This function looks for a token in the current list that matches up      */
 7389 /* the fields (type, uid, ptr).  If none is found, ESRCH is returned, else  */
 7390 /* call ipf_token_dewref() to remove it from the list. In the event that    */
 7391 /* the token has a reference held elsewhere, setting ipt_complete to 2      */
 7392 /* enables debugging to distinguish between the two paths that ultimately   */
 7393 /* lead to a token to be deleted.                                           */
 7394 /* ------------------------------------------------------------------------ */
 7395 int
 7396 ipf_token_del(ipf_main_softc_t *softc, int type, int uid, void *ptr)
 7397 {
 7398         ipftoken_t *it;
 7399         int error;
 7400 
 7401         IPFERROR(82);
 7402         error = ESRCH;
 7403 
 7404         WRITE_ENTER(&softc->ipf_tokens);
 7405         for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) {
 7406                 if (ptr == it->ipt_ctx && type == it->ipt_type &&
 7407                     uid == it->ipt_uid) {
 7408                         it->ipt_complete = 2;
 7409                         ipf_token_deref(softc, it);
 7410                         error = 0;
 7411                         break;
 7412                 }
 7413         }
 7414         RWLOCK_EXIT(&softc->ipf_tokens);
 7415 
 7416         return (error);
 7417 }
 7418 
 7419 
 7420 /* ------------------------------------------------------------------------ */
 7421 /* Function:    ipf_token_mark_complete                                     */
 7422 /* Returns:     None.                                                       */
 7423 /* Parameters:  token(I) - pointer to token structure                       */
 7424 /*                                                                          */
 7425 /* Mark a token as being ineligable for being found with ipf_token_find.    */
 7426 /* ------------------------------------------------------------------------ */
 7427 void
 7428 ipf_token_mark_complete(ipftoken_t *token)
 7429 {
 7430         if (token->ipt_complete == 0)
 7431                 token->ipt_complete = 1;
 7432 }
 7433 
 7434 
 7435 /* ------------------------------------------------------------------------ */
 7436 /* Function:    ipf_token_find                                               */
 7437 /* Returns:     ipftoken_t * - NULL if no memory, else pointer to token     */
 7438 /* Parameters:  softc(I)- pointer to soft context main structure            */
 7439 /*              type(I) - the token type to match                           */
 7440 /*              uid(I)  - uid owning the token                              */
 7441 /*              ptr(I)  - context pointer for the token                     */
 7442 /*                                                                          */
 7443 /* This function looks for a live token in the list of current tokens that  */
 7444 /* matches the tuple (type, uid, ptr).  If one cannot be found then one is  */
 7445 /* allocated.  If one is found then it is moved to the top of the list of   */
 7446 /* currently active tokens.                                                 */
 7447 /* ------------------------------------------------------------------------ */
 7448 ipftoken_t *
 7449 ipf_token_find(ipf_main_softc_t *softc, int type, int uid, void *ptr)
 7450 {
 7451         ipftoken_t *it, *new;
 7452 
 7453         KMALLOC(new, ipftoken_t *);
 7454         if (new != NULL)
 7455                 bzero((char *)new, sizeof(*new));
 7456 
 7457         WRITE_ENTER(&softc->ipf_tokens);
 7458         for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) {
 7459                 if ((ptr == it->ipt_ctx) && (type == it->ipt_type) &&
 7460                     (uid == it->ipt_uid) && (it->ipt_complete < 2))
 7461                         break;
 7462         }
 7463 
 7464         if (it == NULL) {
 7465                 it = new;
 7466                 new = NULL;
 7467                 if (it == NULL) {
 7468                         RWLOCK_EXIT(&softc->ipf_tokens);
 7469                         return (NULL);
 7470                 }
 7471                 it->ipt_ctx = ptr;
 7472                 it->ipt_uid = uid;
 7473                 it->ipt_type = type;
 7474                 it->ipt_ref = 1;
 7475         } else {
 7476                 if (new != NULL) {
 7477                         KFREE(new);
 7478                         new = NULL;
 7479                 }
 7480 
 7481                 if (it->ipt_complete > 0)
 7482                         it = NULL;
 7483                 else
 7484                         ipf_token_unlink(softc, it);
 7485         }
 7486 
 7487         if (it != NULL) {
 7488                 it->ipt_pnext = softc->ipf_token_tail;
 7489                 *softc->ipf_token_tail = it;
 7490                 softc->ipf_token_tail = &it->ipt_next;
 7491                 it->ipt_next = NULL;
 7492                 it->ipt_ref++;
 7493 
 7494                 it->ipt_die = softc->ipf_ticks + 20;
 7495         }
 7496 
 7497         RWLOCK_EXIT(&softc->ipf_tokens);
 7498 
 7499         return (it);
 7500 }
 7501 
 7502 
 7503 /* ------------------------------------------------------------------------ */
 7504 /* Function:    ipf_token_unlink                                            */
 7505 /* Returns:     None.                                                       */
 7506 /* Parameters:  softc(I) - pointer to soft context main structure           */
 7507 /*              token(I) - pointer to token structure                       */
 7508 /* Write Locks: ipf_tokens                                                  */
 7509 /*                                                                          */
 7510 /* This function unlinks a token structure from the linked list of tokens   */
 7511 /* that "own" it.  The head pointer never needs to be explicitly adjusted   */
 7512 /* but the tail does due to the linked list implementation.                 */
 7513 /* ------------------------------------------------------------------------ */
 7514 static void
 7515 ipf_token_unlink(ipf_main_softc_t *softc, ipftoken_t *token)
 7516 {
 7517 
 7518         if (softc->ipf_token_tail == &token->ipt_next)
 7519                 softc->ipf_token_tail = token->ipt_pnext;
 7520 
 7521         *token->ipt_pnext = token->ipt_next;
 7522         if (token->ipt_next != NULL)
 7523                 token->ipt_next->ipt_pnext = token->ipt_pnext;
 7524         token->ipt_next = NULL;
 7525         token->ipt_pnext = NULL;
 7526 }
 7527 
 7528 
 7529 /* ------------------------------------------------------------------------ */
 7530 /* Function:    ipf_token_deref                                             */
 7531 /* Returns:     int      - 0 == token freed, else reference count           */
 7532 /* Parameters:  softc(I) - pointer to soft context main structure           */
 7533 /*              token(I) - pointer to token structure                       */
 7534 /* Write Locks: ipf_tokens                                                  */
 7535 /*                                                                          */
 7536 /* Drop the reference count on the token structure and if it drops to zero, */
 7537 /* call the dereference function for the token type because it is then      */
 7538 /* possible to free the token data structure.                               */
 7539 /* ------------------------------------------------------------------------ */
 7540 int
 7541 ipf_token_deref(ipf_main_softc_t *softc, ipftoken_t *token)
 7542 {
 7543         void *data, **datap;
 7544 
 7545         ASSERT(token->ipt_ref > 0);
 7546         token->ipt_ref--;
 7547         if (token->ipt_ref > 0)
 7548                 return (token->ipt_ref);
 7549 
 7550         data = token->ipt_data;
 7551         datap = &data;
 7552 
 7553         if ((data != NULL) && (data != (void *)-1)) {
 7554                 switch (token->ipt_type)
 7555                 {
 7556                 case IPFGENITER_IPF :
 7557                         (void) ipf_derefrule(softc, (frentry_t **)datap);
 7558                         break;
 7559                 case IPFGENITER_IPNAT :
 7560                         WRITE_ENTER(&softc->ipf_nat);
 7561                         ipf_nat_rule_deref(softc, (ipnat_t **)datap);
 7562                         RWLOCK_EXIT(&softc->ipf_nat);
 7563                         break;
 7564                 case IPFGENITER_NAT :
 7565                         ipf_nat_deref(softc, (nat_t **)datap);
 7566                         break;
 7567                 case IPFGENITER_STATE :
 7568                         ipf_state_deref(softc, (ipstate_t **)datap);
 7569                         break;
 7570                 case IPFGENITER_FRAG :
 7571                         ipf_frag_pkt_deref(softc, (ipfr_t **)datap);
 7572                         break;
 7573                 case IPFGENITER_NATFRAG :
 7574                         ipf_frag_nat_deref(softc, (ipfr_t **)datap);
 7575                         break;
 7576                 case IPFGENITER_HOSTMAP :
 7577                         WRITE_ENTER(&softc->ipf_nat);
 7578                         ipf_nat_hostmapdel(softc, (hostmap_t **)datap);
 7579                         RWLOCK_EXIT(&softc->ipf_nat);
 7580                         break;
 7581                 default :
 7582                         ipf_lookup_iterderef(softc, token->ipt_type, data);
 7583                         break;
 7584                 }
 7585         }
 7586 
 7587         ipf_token_unlink(softc, token);
 7588         KFREE(token);
 7589         return (0);
 7590 }
 7591 
 7592 
 7593 /* ------------------------------------------------------------------------ */
 7594 /* Function:    ipf_nextrule                                                */
 7595 /* Returns:     frentry_t * - NULL == no more rules, else pointer to next   */
 7596 /* Parameters:  softc(I)    - pointer to soft context main structure        */
 7597 /*              fr(I)       - pointer to filter rule                        */
 7598 /*              out(I)      - 1 == out rules, 0 == input rules              */
 7599 /*                                                                          */
 7600 /* Starting with "fr", find the next rule to visit. This includes visiting  */
 7601 /* the list of rule groups if either fr is NULL (empty list) or it is the   */
 7602 /* last rule in the list. When walking rule lists, it is either input or    */
 7603 /* output rules that are returned, never both.                              */
 7604 /* ------------------------------------------------------------------------ */
 7605 static frentry_t *
 7606 ipf_nextrule(ipf_main_softc_t *softc, int active, int unit, frentry_t *fr,
 7607         int out)
 7608 {
 7609         frentry_t *next;
 7610         frgroup_t *fg;
 7611 
 7612         if (fr != NULL && fr->fr_group != -1) {
 7613                 fg = ipf_findgroup(softc, fr->fr_names + fr->fr_group,
 7614                                    unit, active, NULL);
 7615                 if (fg != NULL)
 7616                         fg = fg->fg_next;
 7617         } else {
 7618                 fg = softc->ipf_groups[unit][active];
 7619         }
 7620 
 7621         while (fg != NULL) {
 7622                 next = fg->fg_start;
 7623                 while (next != NULL) {
 7624                         if (out) {
 7625                                 if (next->fr_flags & FR_OUTQUE)
 7626                                         return (next);
 7627                         } else if (next->fr_flags & FR_INQUE) {
 7628                                 return (next);
 7629                         }
 7630                         next = next->fr_next;
 7631                 }
 7632                 if (next == NULL)
 7633                         fg = fg->fg_next;
 7634         }
 7635 
 7636         return (NULL);
 7637 }
 7638 
 7639 /* ------------------------------------------------------------------------ */
 7640 /* Function:    ipf_getnextrule                                             */
 7641 /* Returns:     int - 0 = success, else error                               */
 7642 /* Parameters:  softc(I)- pointer to soft context main structure            */
 7643 /*              t(I)   - pointer to destination information to resolve      */
 7644 /*              ptr(I) - pointer to ipfobj_t to copyin from user space      */
 7645 /*                                                                          */
 7646 /* This function's first job is to bring in the ipfruleiter_t structure via */
 7647 /* the ipfobj_t structure to determine what should be the next rule to      */
 7648 /* return. Once the ipfruleiter_t has been brought in, it then tries to     */
 7649 /* find the 'next rule'.  This may include searching rule group lists or    */
 7650 /* just be as simple as looking at the 'next' field in the rule structure.  */
 7651 /* When we have found the rule to return, increase its reference count and  */
 7652 /* if we used an existing rule to get here, decrease its reference count.   */
 7653 /* ------------------------------------------------------------------------ */
 7654 int
 7655 ipf_getnextrule(ipf_main_softc_t *softc, ipftoken_t *t, void *ptr)
 7656 {
 7657         frentry_t *fr, *next, zero;
 7658         ipfruleiter_t it;
 7659         int error, out;
 7660         frgroup_t *fg;
 7661         ipfobj_t obj;
 7662         int predict;
 7663         char *dst;
 7664         int unit;
 7665 
 7666         if (t == NULL || ptr == NULL) {
 7667                 IPFERROR(84);
 7668                 return (EFAULT);
 7669         }
 7670 
 7671         error = ipf_inobj(softc, ptr, &obj, &it, IPFOBJ_IPFITER);
 7672         if (error != 0)
 7673                 return (error);
 7674 
 7675         if ((it.iri_inout < 0) || (it.iri_inout > 3)) {
 7676                 IPFERROR(85);
 7677                 return (EINVAL);
 7678         }
 7679         if ((it.iri_active != 0) && (it.iri_active != 1)) {
 7680                 IPFERROR(86);
 7681                 return (EINVAL);
 7682         }
 7683         if (it.iri_nrules == 0) {
 7684                 IPFERROR(87);
 7685                 return (ENOSPC);
 7686         }
 7687         if (it.iri_rule == NULL) {
 7688                 IPFERROR(88);
 7689                 return (EFAULT);
 7690         }
 7691 
 7692         fg = NULL;
 7693         fr = t->ipt_data;
 7694         if ((it.iri_inout & F_OUT) != 0)
 7695                 out = 1;
 7696         else
 7697                 out = 0;
 7698         if ((it.iri_inout & F_ACIN) != 0)
 7699                 unit = IPL_LOGCOUNT;
 7700         else
 7701                 unit = IPL_LOGIPF;
 7702 
 7703         READ_ENTER(&softc->ipf_mutex);
 7704         if (fr == NULL) {
 7705                 if (*it.iri_group == '\0') {
 7706                         if (unit == IPL_LOGCOUNT) {
 7707                                 next = softc->ipf_acct[out][it.iri_active];
 7708                         } else {
 7709                                 next = softc->ipf_rules[out][it.iri_active];
 7710                         }
 7711                         if (next == NULL)
 7712                                 next = ipf_nextrule(softc, it.iri_active,
 7713                                                     unit, NULL, out);
 7714                 } else {
 7715                         fg = ipf_findgroup(softc, it.iri_group, unit,
 7716                                            it.iri_active, NULL);
 7717                         if (fg != NULL)
 7718                                 next = fg->fg_start;
 7719                         else
 7720                                 next = NULL;
 7721                 }
 7722         } else {
 7723                 next = fr->fr_next;
 7724                 if (next == NULL)
 7725                         next = ipf_nextrule(softc, it.iri_active, unit,
 7726                                             fr, out);
 7727         }
 7728 
 7729         if (next != NULL && next->fr_next != NULL)
 7730                 predict = 1;
 7731         else if (ipf_nextrule(softc, it.iri_active, unit, next, out) != NULL)
 7732                 predict = 1;
 7733         else
 7734                 predict = 0;
 7735 
 7736         if (fr != NULL)
 7737                 (void) ipf_derefrule(softc, &fr);
 7738 
 7739         obj.ipfo_type = IPFOBJ_FRENTRY;
 7740         dst = (char *)it.iri_rule;
 7741 
 7742         if (next != NULL) {
 7743                 obj.ipfo_size = next->fr_size;
 7744                 MUTEX_ENTER(&next->fr_lock);
 7745                 next->fr_ref++;
 7746                 MUTEX_EXIT(&next->fr_lock);
 7747                 t->ipt_data = next;
 7748         } else {
 7749                 obj.ipfo_size = sizeof(frentry_t);
 7750                 bzero(&zero, sizeof(zero));
 7751                 next = &zero;
 7752                 t->ipt_data = NULL;
 7753         }
 7754         it.iri_rule = predict ? next : NULL;
 7755         if (predict == 0)
 7756                 ipf_token_mark_complete(t);
 7757 
 7758         RWLOCK_EXIT(&softc->ipf_mutex);
 7759 
 7760         obj.ipfo_ptr = dst;
 7761         error = ipf_outobjk(softc, &obj, next);
 7762         if (error == 0 && t->ipt_data != NULL) {
 7763                 dst += obj.ipfo_size;
 7764                 if (next->fr_data != NULL) {
 7765                         ipfobj_t dobj;
 7766 
 7767                         if (next->fr_type == FR_T_IPFEXPR)
 7768                                 dobj.ipfo_type = IPFOBJ_IPFEXPR;
 7769                         else
 7770                                 dobj.ipfo_type = IPFOBJ_FRIPF;
 7771                         dobj.ipfo_size = next->fr_dsize;
 7772                         dobj.ipfo_rev = obj.ipfo_rev;
 7773                         dobj.ipfo_ptr = dst;
 7774                         error = ipf_outobjk(softc, &dobj, next->fr_data);
 7775                 }
 7776         }
 7777 
 7778         if ((fr != NULL) && (next == &zero))
 7779                 (void) ipf_derefrule(softc, &fr);
 7780 
 7781         return (error);
 7782 }
 7783 
 7784 
 7785 /* ------------------------------------------------------------------------ */
 7786 /* Function:    ipf_frruleiter                                              */
 7787 /* Returns:     int - 0 = success, else error                               */
 7788 /* Parameters:  softc(I)- pointer to soft context main structure            */
 7789 /*              data(I) - the token type to match                           */
 7790 /*              uid(I)  - uid owning the token                              */
 7791 /*              ptr(I)  - context pointer for the token                     */
 7792 /*                                                                          */
 7793 /* This function serves as a stepping stone between ipf_ipf_ioctl and       */
 7794 /* ipf_getnextrule.  It's role is to find the right token in the kernel for */
 7795 /* the process doing the ioctl and use that to ask for the next rule.       */
 7796 /* ------------------------------------------------------------------------ */
 7797 static int
 7798 ipf_frruleiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx)
 7799 {
 7800         ipftoken_t *token;
 7801         ipfruleiter_t it;
 7802         ipfobj_t obj;
 7803         int error;
 7804 
 7805         token = ipf_token_find(softc, IPFGENITER_IPF, uid, ctx);
 7806         if (token != NULL) {
 7807                 error = ipf_getnextrule(softc, token, data);
 7808                 WRITE_ENTER(&softc->ipf_tokens);
 7809                 ipf_token_deref(softc, token);
 7810                 RWLOCK_EXIT(&softc->ipf_tokens);
 7811         } else {
 7812                 error = ipf_inobj(softc, data, &obj, &it, IPFOBJ_IPFITER);
 7813                 if (error != 0)
 7814                         return (error);
 7815                 it.iri_rule = NULL;
 7816                 error = ipf_outobj(softc, data, &it, IPFOBJ_IPFITER);
 7817         }
 7818 
 7819         return (error);
 7820 }
 7821 
 7822 
 7823 /* ------------------------------------------------------------------------ */
 7824 /* Function:    ipf_geniter                                                 */
 7825 /* Returns:     int - 0 = success, else error                               */
 7826 /* Parameters:  softc(I) - pointer to soft context main structure           */
 7827 /*              token(I) - pointer to ipftoken_t structure                  */
 7828 /*              itp(I)   - pointer to iterator data                         */
 7829 /*                                                                          */
 7830 /* Decide which iterator function to call using information passed through  */
 7831 /* the ipfgeniter_t structure at itp.                                       */
 7832 /* ------------------------------------------------------------------------ */
 7833 static int
 7834 ipf_geniter(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp)
 7835 {
 7836         int error;
 7837 
 7838         switch (itp->igi_type)
 7839         {
 7840         case IPFGENITER_FRAG :
 7841                 error = ipf_frag_pkt_next(softc, token, itp);
 7842                 break;
 7843         default :
 7844                 IPFERROR(92);
 7845                 error = EINVAL;
 7846                 break;
 7847         }
 7848 
 7849         return (error);
 7850 }
 7851 
 7852 
 7853 /* ------------------------------------------------------------------------ */
 7854 /* Function:    ipf_genericiter                                             */
 7855 /* Returns:     int - 0 = success, else error                               */
 7856 /* Parameters:  softc(I)- pointer to soft context main structure            */
 7857 /*              data(I) - the token type to match                           */
 7858 /*              uid(I)  - uid owning the token                              */
 7859 /*              ptr(I)  - context pointer for the token                     */
 7860 /*                                                                          */
 7861 /* Handle the SIOCGENITER ioctl for the ipfilter device. The primary role   */
 7862 /* ------------------------------------------------------------------------ */
 7863 int
 7864 ipf_genericiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx)
 7865 {
 7866         ipftoken_t *token;
 7867         ipfgeniter_t iter;
 7868         int error;
 7869 
 7870         error = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_GENITER);
 7871         if (error != 0)
 7872                 return (error);
 7873 
 7874         token = ipf_token_find(softc, iter.igi_type, uid, ctx);
 7875         if (token != NULL) {
 7876                 token->ipt_subtype = iter.igi_type;
 7877                 error = ipf_geniter(softc, token, &iter);
 7878                 WRITE_ENTER(&softc->ipf_tokens);
 7879                 ipf_token_deref(softc, token);
 7880                 RWLOCK_EXIT(&softc->ipf_tokens);
 7881         } else {
 7882                 IPFERROR(93);
 7883                 error = 0;
 7884         }
 7885 
 7886         return (error);
 7887 }
 7888 
 7889 
 7890 /* ------------------------------------------------------------------------ */
 7891 /* Function:    ipf_ipf_ioctl                                               */
 7892 /* Returns:     int - 0 = success, else error                               */
 7893 /* Parameters:  softc(I)- pointer to soft context main structure           */
 7894 /*              data(I) - the token type to match                           */
 7895 /*              cmd(I)  - the ioctl command number                          */
 7896 /*              mode(I) - mode flags for the ioctl                          */
 7897 /*              uid(I)  - uid owning the token                              */
 7898 /*              ptr(I)  - context pointer for the token                     */
 7899 /*                                                                          */
 7900 /* This function handles all of the ioctl command that are actually isssued */
 7901 /* to the /dev/ipl device.                                                  */
 7902 /* ------------------------------------------------------------------------ */
 7903 int
 7904 ipf_ipf_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd, int mode,
 7905         int uid, void *ctx)
 7906 {
 7907         friostat_t fio;
 7908         int error, tmp;
 7909         ipfobj_t obj;
 7910         SPL_INT(s);
 7911 
 7912         switch (cmd)
 7913         {
 7914         case SIOCFRENB :
 7915                 if (!(mode & FWRITE)) {
 7916                         IPFERROR(94);
 7917                         error = EPERM;
 7918                 } else {
 7919                         error = BCOPYIN(data, &tmp, sizeof(tmp));
 7920                         if (error != 0) {
 7921                                 IPFERROR(95);
 7922                                 error = EFAULT;
 7923                                 break;
 7924                         }
 7925 
 7926                         WRITE_ENTER(&softc->ipf_global);
 7927                         if (tmp) {
 7928                                 if (softc->ipf_running > 0)
 7929                                         error = 0;
 7930                                 else
 7931                                         error = ipfattach(softc);
 7932                                 if (error == 0)
 7933                                         softc->ipf_running = 1;
 7934                                 else
 7935                                         (void) ipfdetach(softc);
 7936                         } else {
 7937                                 if (softc->ipf_running == 1)
 7938                                         error = ipfdetach(softc);
 7939                                 else
 7940                                         error = 0;
 7941                                 if (error == 0)
 7942                                         softc->ipf_running = -1;
 7943                         }
 7944                         RWLOCK_EXIT(&softc->ipf_global);
 7945                 }
 7946                 break;
 7947 
 7948         case SIOCIPFSET :
 7949                 if (!(mode & FWRITE)) {
 7950                         IPFERROR(96);
 7951                         error = EPERM;
 7952                         break;
 7953                 }
 7954                 /* FALLTHRU */
 7955         case SIOCIPFGETNEXT :
 7956         case SIOCIPFGET :
 7957                 error = ipf_ipftune(softc, cmd, (void *)data);
 7958                 break;
 7959 
 7960         case SIOCSETFF :
 7961                 if (!(mode & FWRITE)) {
 7962                         IPFERROR(97);
 7963                         error = EPERM;
 7964                 } else {
 7965                         error = BCOPYIN(data, &softc->ipf_flags,
 7966                                         sizeof(softc->ipf_flags));
 7967                         if (error != 0) {
 7968                                 IPFERROR(98);
 7969                                 error = EFAULT;
 7970                         }
 7971                 }
 7972                 break;
 7973 
 7974         case SIOCGETFF :
 7975                 error = BCOPYOUT(&softc->ipf_flags, data,
 7976                                  sizeof(softc->ipf_flags));
 7977                 if (error != 0) {
 7978                         IPFERROR(99);
 7979                         error = EFAULT;
 7980                 }
 7981                 break;
 7982 
 7983         case SIOCFUNCL :
 7984                 error = ipf_resolvefunc(softc, (void *)data);
 7985                 break;
 7986 
 7987         case SIOCINAFR :
 7988         case SIOCRMAFR :
 7989         case SIOCADAFR :
 7990         case SIOCZRLST :
 7991                 if (!(mode & FWRITE)) {
 7992                         IPFERROR(100);
 7993                         error = EPERM;
 7994                 } else {
 7995                         error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data,
 7996                                           softc->ipf_active, 1);
 7997                 }
 7998                 break;
 7999 
 8000         case SIOCINIFR :
 8001         case SIOCRMIFR :
 8002         case SIOCADIFR :
 8003                 if (!(mode & FWRITE)) {
 8004                         IPFERROR(101);
 8005                         error = EPERM;
 8006                 } else {
 8007                         error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data,
 8008                                           1 - softc->ipf_active, 1);
 8009                 }
 8010                 break;
 8011 
 8012         case SIOCSWAPA :
 8013                 if (!(mode & FWRITE)) {
 8014                         IPFERROR(102);
 8015                         error = EPERM;
 8016                 } else {
 8017                         WRITE_ENTER(&softc->ipf_mutex);
 8018                         error = BCOPYOUT(&softc->ipf_active, data,
 8019                                          sizeof(softc->ipf_active));
 8020                         if (error != 0) {
 8021                                 IPFERROR(103);
 8022                                 error = EFAULT;
 8023                         } else {
 8024                                 softc->ipf_active = 1 - softc->ipf_active;
 8025                         }
 8026                         RWLOCK_EXIT(&softc->ipf_mutex);
 8027                 }
 8028                 break;
 8029 
 8030         case SIOCGETFS :
 8031                 error = ipf_inobj(softc, (void *)data, &obj, &fio,
 8032                                   IPFOBJ_IPFSTAT);
 8033                 if (error != 0)
 8034                         break;
 8035                 ipf_getstat(softc, &fio, obj.ipfo_rev);
 8036                 error = ipf_outobj(softc, (void *)data, &fio, IPFOBJ_IPFSTAT);
 8037                 break;
 8038 
 8039         case SIOCFRZST :
 8040                 if (!(mode & FWRITE)) {
 8041                         IPFERROR(104);
 8042                         error = EPERM;
 8043                 } else
 8044                         error = ipf_zerostats(softc, (caddr_t)data);
 8045                 break;
 8046 
 8047         case SIOCIPFFL :
 8048                 if (!(mode & FWRITE)) {
 8049                         IPFERROR(105);
 8050                         error = EPERM;
 8051                 } else {
 8052                         error = BCOPYIN(data, &tmp, sizeof(tmp));
 8053                         if (!error) {
 8054                                 tmp = ipf_flush(softc, IPL_LOGIPF, tmp);
 8055                                 error = BCOPYOUT(&tmp, data, sizeof(tmp));
 8056                                 if (error != 0) {
 8057                                         IPFERROR(106);
 8058                                         error = EFAULT;
 8059                                 }
 8060                         } else {
 8061                                 IPFERROR(107);
 8062                                 error = EFAULT;
 8063                         }
 8064                 }
 8065                 break;
 8066 
 8067 #ifdef USE_INET6
 8068         case SIOCIPFL6 :
 8069                 if (!(mode & FWRITE)) {
 8070                         IPFERROR(108);
 8071                         error = EPERM;
 8072                 } else {
 8073                         error = BCOPYIN(data, &tmp, sizeof(tmp));
 8074                         if (!error) {
 8075                                 tmp = ipf_flush(softc, IPL_LOGIPF, tmp);
 8076                                 error = BCOPYOUT(&tmp, data, sizeof(tmp));
 8077                                 if (error != 0) {
 8078                                         IPFERROR(109);
 8079                                         error = EFAULT;
 8080                                 }
 8081                         } else {
 8082                                 IPFERROR(110);
 8083                                 error = EFAULT;
 8084                         }
 8085                 }
 8086                 break;
 8087 #endif
 8088 
 8089         case SIOCSTLCK :
 8090                 if (!(mode & FWRITE)) {
 8091                         IPFERROR(122);
 8092                         error = EPERM;
 8093                 } else {
 8094                         error = BCOPYIN(data, &tmp, sizeof(tmp));
 8095                         if (error == 0) {
 8096                                 ipf_state_setlock(softc->ipf_state_soft, tmp);
 8097                                 ipf_nat_setlock(softc->ipf_nat_soft, tmp);
 8098                                 ipf_frag_setlock(softc->ipf_frag_soft, tmp);
 8099                                 ipf_auth_setlock(softc->ipf_auth_soft, tmp);
 8100                         } else {
 8101                                 IPFERROR(111);
 8102                                 error = EFAULT;
 8103                         }
 8104                 }
 8105                 break;
 8106 
 8107 #ifdef  IPFILTER_LOG
 8108         case SIOCIPFFB :
 8109                 if (!(mode & FWRITE)) {
 8110                         IPFERROR(112);
 8111                         error = EPERM;
 8112                 } else {
 8113                         tmp = ipf_log_clear(softc, IPL_LOGIPF);
 8114                         error = BCOPYOUT(&tmp, data, sizeof(tmp));
 8115                         if (error) {
 8116                                 IPFERROR(113);
 8117                                 error = EFAULT;
 8118                         }
 8119                 }
 8120                 break;
 8121 #endif /* IPFILTER_LOG */
 8122 
 8123         case SIOCFRSYN :
 8124                 if (!(mode & FWRITE)) {
 8125                         IPFERROR(114);
 8126                         error = EPERM;
 8127                 } else {
 8128                         WRITE_ENTER(&softc->ipf_global);
 8129 #if (SOLARIS && defined(_KERNEL)) && !defined(INSTANCES)
 8130                         error = ipfsync();
 8131 #else
 8132                         ipf_sync(softc, NULL);
 8133                         error = 0;
 8134 #endif
 8135                         RWLOCK_EXIT(&softc->ipf_global);
 8136 
 8137                 }
 8138                 break;
 8139 
 8140         case SIOCGFRST :
 8141                 error = ipf_outobj(softc, (void *)data,
 8142                                    ipf_frag_stats(softc->ipf_frag_soft),
 8143                                    IPFOBJ_FRAGSTAT);
 8144                 break;
 8145 
 8146 #ifdef  IPFILTER_LOG
 8147         case FIONREAD :
 8148                 tmp = ipf_log_bytesused(softc, IPL_LOGIPF);
 8149                 error = BCOPYOUT(&tmp, data, sizeof(tmp));
 8150                 break;
 8151 #endif
 8152 
 8153         case SIOCIPFITER :
 8154                 SPL_SCHED(s);
 8155                 error = ipf_frruleiter(softc, data, uid, ctx);
 8156                 SPL_X(s);
 8157                 break;
 8158 
 8159         case SIOCGENITER :
 8160                 SPL_SCHED(s);
 8161                 error = ipf_genericiter(softc, data, uid, ctx);
 8162                 SPL_X(s);
 8163                 break;
 8164 
 8165         case SIOCIPFDELTOK :
 8166                 error = BCOPYIN(data, &tmp, sizeof(tmp));
 8167                 if (error == 0) {
 8168                         SPL_SCHED(s);
 8169                         error = ipf_token_del(softc, tmp, uid, ctx);
 8170                         SPL_X(s);
 8171                 }
 8172                 break;
 8173 
 8174         default :
 8175                 IPFERROR(115);
 8176                 error = EINVAL;
 8177                 break;
 8178         }
 8179 
 8180         return (error);
 8181 }
 8182 
 8183 
 8184 /* ------------------------------------------------------------------------ */
 8185 /* Function:    ipf_decaps                                                  */
 8186 /* Returns:     int        - -1 == decapsulation failed, else bit mask of   */
 8187 /*                           flags indicating packet filtering decision.    */
 8188 /* Parameters:  fin(I)     - pointer to packet information                  */
 8189 /*              pass(I)    - IP protocol version to match                   */
 8190 /*              l5proto(I) - layer 5 protocol to decode UDP data as.        */
 8191 /*                                                                          */
 8192 /* This function is called for packets that are wrapt up in other packets,  */
 8193 /* for example, an IP packet that is the entire data segment for another IP */
 8194 /* packet.  If the basic constraints for this are satisfied, change the     */
 8195 /* buffer to point to the start of the inner packet and start processing    */
 8196 /* rules belonging to the head group this rule specifies.                   */
 8197 /* ------------------------------------------------------------------------ */
 8198 u_32_t
 8199 ipf_decaps(fr_info_t *fin, u_32_t pass, int l5proto)
 8200 {
 8201         fr_info_t fin2, *fino = NULL;
 8202         int elen, hlen, nh;
 8203         grehdr_t gre;
 8204         ip_t *ip;
 8205         mb_t *m;
 8206 
 8207         if ((fin->fin_flx & FI_COALESCE) == 0)
 8208                 if (ipf_coalesce(fin) == -1)
 8209                         goto cantdecaps;
 8210 
 8211         m = fin->fin_m;
 8212         hlen = fin->fin_hlen;
 8213 
 8214         switch (fin->fin_p)
 8215         {
 8216         case IPPROTO_UDP :
 8217                 /*
 8218                  * In this case, the specific protocol being decapsulated
 8219                  * inside UDP frames comes from the rule.
 8220                  */
 8221                 nh = fin->fin_fr->fr_icode;
 8222                 break;
 8223 
 8224         case IPPROTO_GRE :      /* 47 */
 8225                 bcopy(fin->fin_dp, (char *)&gre, sizeof(gre));
 8226                 hlen += sizeof(grehdr_t);
 8227                 if (gre.gr_R|gre.gr_s)
 8228                         goto cantdecaps;
 8229                 if (gre.gr_C)
 8230                         hlen += 4;
 8231                 if (gre.gr_K)
 8232                         hlen += 4;
 8233                 if (gre.gr_S)
 8234                         hlen += 4;
 8235 
 8236                 nh = IPPROTO_IP;
 8237 
 8238                 /*
 8239                  * If the routing options flag is set, validate that it is
 8240                  * there and bounce over it.
 8241                  */
 8242 #if 0
 8243                 /* This is really heavy weight and lots of room for error, */
 8244                 /* so for now, put it off and get the simple stuff right.  */
 8245                 if (gre.gr_R) {
 8246                         u_char off, len, *s;
 8247                         u_short af;
 8248                         int end;
 8249 
 8250                         end = 0;
 8251                         s = fin->fin_dp;
 8252                         s += hlen;
 8253                         aplen = fin->fin_plen - hlen;
 8254                         while (aplen > 3) {
 8255                                 af = (s[0] << 8) | s[1];
 8256                                 off = s[2];
 8257                                 len = s[3];
 8258                                 aplen -= 4;
 8259                                 s += 4;
 8260                                 if (af == 0 && len == 0) {
 8261                                         end = 1;
 8262                                         break;
 8263                                 }
 8264                                 if (aplen < len)
 8265                                         break;
 8266                                 s += len;
 8267                                 aplen -= len;
 8268                         }
 8269                         if (end != 1)
 8270                                 goto cantdecaps;
 8271                         hlen = s - (u_char *)fin->fin_dp;
 8272                 }
 8273 #endif
 8274                 break;
 8275 
 8276 #ifdef IPPROTO_IPIP
 8277         case IPPROTO_IPIP :     /* 4 */
 8278 #endif
 8279                 nh = IPPROTO_IP;
 8280                 break;
 8281 
 8282         default :       /* Includes ESP, AH is special for IPv4 */
 8283                 goto cantdecaps;
 8284         }
 8285 
 8286         switch (nh)
 8287         {
 8288         case IPPROTO_IP :
 8289         case IPPROTO_IPV6 :
 8290                 break;
 8291         default :
 8292                 goto cantdecaps;
 8293         }
 8294 
 8295         bcopy((char *)fin, (char *)&fin2, sizeof(fin2));
 8296         fino = fin;
 8297         fin = &fin2;
 8298         elen = hlen;
 8299 #if SOLARIS && defined(_KERNEL)
 8300         m->b_rptr += elen;
 8301 #else
 8302         m->m_data += elen;
 8303         m->m_len -= elen;
 8304 #endif
 8305         fin->fin_plen -= elen;
 8306 
 8307         ip = (ip_t *)((char *)fin->fin_ip + elen);
 8308 
 8309         /*
 8310          * Make sure we have at least enough data for the network layer
 8311          * header.
 8312          */
 8313         if (IP_V(ip) == 4)
 8314                 hlen = IP_HL(ip) << 2;
 8315 #ifdef USE_INET6
 8316         else if (IP_V(ip) == 6)
 8317                 hlen = sizeof(ip6_t);
 8318 #endif
 8319         else
 8320                 goto cantdecaps2;
 8321 
 8322         if (fin->fin_plen < hlen)
 8323                 goto cantdecaps2;
 8324 
 8325         fin->fin_dp = (char *)ip + hlen;
 8326 
 8327         if (IP_V(ip) == 4) {
 8328                 /*
 8329                  * Perform IPv4 header checksum validation.
 8330                  */
 8331                 if (ipf_cksum((u_short *)ip, hlen))
 8332                         goto cantdecaps2;
 8333         }
 8334 
 8335         if (ipf_makefrip(hlen, ip, fin) == -1) {
 8336 cantdecaps2:
 8337                 if (m != NULL) {
 8338 #if SOLARIS && defined(_KERNEL)
 8339                         m->b_rptr -= elen;
 8340 #else
 8341                         m->m_data -= elen;
 8342                         m->m_len += elen;
 8343 #endif
 8344                 }
 8345 cantdecaps:
 8346                 DT1(frb_decapfrip, fr_info_t *, fin);
 8347                 pass &= ~FR_CMDMASK;
 8348                 pass |= FR_BLOCK|FR_QUICK;
 8349                 fin->fin_reason = FRB_DECAPFRIP;
 8350                 return (-1);
 8351         }
 8352 
 8353         pass = ipf_scanlist(fin, pass);
 8354 
 8355         /*
 8356          * Copy the packet filter "result" fields out of the fr_info_t struct
 8357          * that is local to the decapsulation processing and back into the
 8358          * one we were called with.
 8359          */
 8360         fino->fin_flx = fin->fin_flx;
 8361         fino->fin_rev = fin->fin_rev;
 8362         fino->fin_icode = fin->fin_icode;
 8363         fino->fin_rule = fin->fin_rule;
 8364         (void) strncpy(fino->fin_group, fin->fin_group, FR_GROUPLEN);
 8365         fino->fin_fr = fin->fin_fr;
 8366         fino->fin_error = fin->fin_error;
 8367         fino->fin_mp = fin->fin_mp;
 8368         fino->fin_m = fin->fin_m;
 8369         m = fin->fin_m;
 8370         if (m != NULL) {
 8371 #if SOLARIS && defined(_KERNEL)
 8372                 m->b_rptr -= elen;
 8373 #else
 8374                 m->m_data -= elen;
 8375                 m->m_len += elen;
 8376 #endif
 8377         }
 8378         return (pass);
 8379 }
 8380 
 8381 
 8382 /* ------------------------------------------------------------------------ */
 8383 /* Function:    ipf_matcharray_load                                         */
 8384 /* Returns:     int         - 0 = success, else error                       */
 8385 /* Parameters:  softc(I)    - pointer to soft context main structure        */
 8386 /*              data(I)     - pointer to ioctl data                         */
 8387 /*              objp(I)     - ipfobj_t structure to load data into          */
 8388 /*              arrayptr(I) - pointer to location to store array pointer    */
 8389 /*                                                                          */
 8390 /* This function loads in a mathing array through the ipfobj_t struct that  */
 8391 /* describes it.  Sanity checking and array size limitations are enforced   */
 8392 /* in this function to prevent userspace from trying to load in something   */
 8393 /* that is insanely big.  Once the size of the array is known, the memory   */
 8394 /* required is malloc'd and returned through changing *arrayptr.  The       */
 8395 /* contents of the array are verified before returning.  Only in the event  */
 8396 /* of a successful call is the caller required to free up the malloc area.  */
 8397 /* ------------------------------------------------------------------------ */
 8398 int
 8399 ipf_matcharray_load(ipf_main_softc_t *softc, caddr_t data, ipfobj_t *objp,
 8400         int **arrayptr)
 8401 {
 8402         int arraysize, *array, error;
 8403 
 8404         *arrayptr = NULL;
 8405 
 8406         error = BCOPYIN(data, objp, sizeof(*objp));
 8407         if (error != 0) {
 8408                 IPFERROR(116);
 8409                 return (EFAULT);
 8410         }
 8411 
 8412         if (objp->ipfo_type != IPFOBJ_IPFEXPR) {
 8413                 IPFERROR(117);
 8414                 return (EINVAL);
 8415         }
 8416 
 8417         if (((objp->ipfo_size & 3) != 0) || (objp->ipfo_size == 0) ||
 8418             (objp->ipfo_size > 1024)) {
 8419                 IPFERROR(118);
 8420                 return (EINVAL);
 8421         }
 8422 
 8423         arraysize = objp->ipfo_size * sizeof(*array);
 8424         KMALLOCS(array, int *, arraysize);
 8425         if (array == NULL) {
 8426                 IPFERROR(119);
 8427                 return (ENOMEM);
 8428         }
 8429 
 8430         error = COPYIN(objp->ipfo_ptr, array, arraysize);
 8431         if (error != 0) {
 8432                 KFREES(array, arraysize);
 8433                 IPFERROR(120);
 8434                 return (EFAULT);
 8435         }
 8436 
 8437         if (ipf_matcharray_verify(array, arraysize) != 0) {
 8438                 KFREES(array, arraysize);
 8439                 IPFERROR(121);
 8440                 return (EINVAL);
 8441         }
 8442 
 8443         *arrayptr = array;
 8444         return (0);
 8445 }
 8446 
 8447 
 8448 /* ------------------------------------------------------------------------ */
 8449 /* Function:    ipf_matcharray_verify                                       */
 8450 /* Returns:     Nil                                                         */
 8451 /* Parameters:  array(I)     - pointer to matching array                    */
 8452 /*              arraysize(I) - number of elements in the array              */
 8453 /*                                                                          */
 8454 /* Verify the contents of a matching array by stepping through each element */
 8455 /* in it.  The actual commands in the array are not verified for            */
 8456 /* correctness, only that all of the sizes are correctly within limits.     */
 8457 /* ------------------------------------------------------------------------ */
 8458 int
 8459 ipf_matcharray_verify(int *array, int arraysize)
 8460 {
 8461         int i, nelem, maxidx;
 8462         ipfexp_t *e;
 8463 
 8464         nelem = arraysize / sizeof(*array);
 8465 
 8466         /*
 8467          * Currently, it makes no sense to have an array less than 6
 8468          * elements long - the initial size at the from, a single operation
 8469          * (minimum 4 in length) and a trailer, for a total of 6.
 8470          */
 8471         if ((array[0] < 6) || (arraysize < 24) || (arraysize > 4096)) {
 8472                 return (-1);
 8473         }
 8474 
 8475         /*
 8476          * Verify the size of data pointed to by array with how long
 8477          * the array claims to be itself.
 8478          */
 8479         if (array[0] * sizeof(*array) != arraysize) {
 8480                 return (-1);
 8481         }
 8482 
 8483         maxidx = nelem - 1;
 8484         /*
 8485          * The last opcode in this array should be an IPF_EXP_END.
 8486          */
 8487         if (array[maxidx] != IPF_EXP_END) {
 8488                 return (-1);
 8489         }
 8490 
 8491         for (i = 1; i < maxidx; ) {
 8492                 e = (ipfexp_t *)(array + i);
 8493 
 8494                 /*
 8495                  * The length of the bits to check must be at least 1
 8496                  * (or else there is nothing to comapre with!) and it
 8497                  * cannot exceed the length of the data present.
 8498                  */
 8499                 if ((e->ipfe_size < 1 ) ||
 8500                     (e->ipfe_size + i > maxidx)) {
 8501                         return (-1);
 8502                 }
 8503                 i += e->ipfe_size;
 8504         }
 8505         return (0);
 8506 }
 8507 
 8508 
 8509 /* ------------------------------------------------------------------------ */
 8510 /* Function:    ipf_fr_matcharray                                           */
 8511 /* Returns:     int      - 0 = match failed, else positive match            */
 8512 /* Parameters:  fin(I)   - pointer to packet information                    */
 8513 /*              array(I) - pointer to matching array                        */
 8514 /*                                                                          */
 8515 /* This function is used to apply a matching array against a packet and     */
 8516 /* return an indication of whether or not the packet successfully matches   */
 8517 /* all of the commands in it.                                               */
 8518 /* ------------------------------------------------------------------------ */
 8519 static int
 8520 ipf_fr_matcharray(fr_info_t *fin, int *array)
 8521 {
 8522         int i, n, *x, rv, p;
 8523         ipfexp_t *e;
 8524 
 8525         rv = 0;
 8526         n = array[0];
 8527         x = array + 1;
 8528 
 8529         for (; n > 0; x += 3 + x[3], rv = 0) {
 8530                 e = (ipfexp_t *)x;
 8531                 if (e->ipfe_cmd == IPF_EXP_END)
 8532                         break;
 8533                 n -= e->ipfe_size;
 8534 
 8535                 /*
 8536                  * The upper 16 bits currently store the protocol value.
 8537                  * This is currently used with TCP and UDP port compares and
 8538                  * allows "tcp.port = 80" without requiring an explicit
 8539                  " "ip.pr = tcp" first.
 8540                  */
 8541                 p = e->ipfe_cmd >> 16;
 8542                 if ((p != 0) && (p != fin->fin_p))
 8543                         break;
 8544 
 8545                 switch (e->ipfe_cmd)
 8546                 {
 8547                 case IPF_EXP_IP_PR :
 8548                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
 8549                                 rv |= (fin->fin_p == e->ipfe_arg0[i]);
 8550                         }
 8551                         break;
 8552 
 8553                 case IPF_EXP_IP_SRCADDR :
 8554                         if (fin->fin_v != 4)
 8555                                 break;
 8556                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
 8557                                 rv |= ((fin->fin_saddr &
 8558                                         e->ipfe_arg0[i * 2 + 1]) ==
 8559                                        e->ipfe_arg0[i * 2]);
 8560                         }
 8561                         break;
 8562 
 8563                 case IPF_EXP_IP_DSTADDR :
 8564                         if (fin->fin_v != 4)
 8565                                 break;
 8566                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
 8567                                 rv |= ((fin->fin_daddr &
 8568                                         e->ipfe_arg0[i * 2 + 1]) ==
 8569                                        e->ipfe_arg0[i * 2]);
 8570                         }
 8571                         break;
 8572 
 8573                 case IPF_EXP_IP_ADDR :
 8574                         if (fin->fin_v != 4)
 8575                                 break;
 8576                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
 8577                                 rv |= ((fin->fin_saddr &
 8578                                         e->ipfe_arg0[i * 2 + 1]) ==
 8579                                        e->ipfe_arg0[i * 2]) ||
 8580                                       ((fin->fin_daddr &
 8581                                         e->ipfe_arg0[i * 2 + 1]) ==
 8582                                        e->ipfe_arg0[i * 2]);
 8583                         }
 8584                         break;
 8585 
 8586 #ifdef USE_INET6
 8587                 case IPF_EXP_IP6_SRCADDR :
 8588                         if (fin->fin_v != 6)
 8589                                 break;
 8590                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
 8591                                 rv |= IP6_MASKEQ(&fin->fin_src6,
 8592                                                  &e->ipfe_arg0[i * 8 + 4],
 8593                                                  &e->ipfe_arg0[i * 8]);
 8594                         }
 8595                         break;
 8596 
 8597                 case IPF_EXP_IP6_DSTADDR :
 8598                         if (fin->fin_v != 6)
 8599                                 break;
 8600                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
 8601                                 rv |= IP6_MASKEQ(&fin->fin_dst6,
 8602                                                  &e->ipfe_arg0[i * 8 + 4],
 8603                                                  &e->ipfe_arg0[i * 8]);
 8604                         }
 8605                         break;
 8606 
 8607                 case IPF_EXP_IP6_ADDR :
 8608                         if (fin->fin_v != 6)
 8609                                 break;
 8610                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
 8611                                 rv |= IP6_MASKEQ(&fin->fin_src6,
 8612                                                  &e->ipfe_arg0[i * 8 + 4],
 8613                                                  &e->ipfe_arg0[i * 8]) ||
 8614                                       IP6_MASKEQ(&fin->fin_dst6,
 8615                                                  &e->ipfe_arg0[i * 8 + 4],
 8616                                                  &e->ipfe_arg0[i * 8]);
 8617                         }
 8618                         break;
 8619 #endif
 8620 
 8621                 case IPF_EXP_UDP_PORT :
 8622                 case IPF_EXP_TCP_PORT :
 8623                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
 8624                                 rv |= (fin->fin_sport == e->ipfe_arg0[i]) ||
 8625                                       (fin->fin_dport == e->ipfe_arg0[i]);
 8626                         }
 8627                         break;
 8628 
 8629                 case IPF_EXP_UDP_SPORT :
 8630                 case IPF_EXP_TCP_SPORT :
 8631                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
 8632                                 rv |= (fin->fin_sport == e->ipfe_arg0[i]);
 8633                         }
 8634                         break;
 8635 
 8636                 case IPF_EXP_UDP_DPORT :
 8637                 case IPF_EXP_TCP_DPORT :
 8638                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
 8639                                 rv |= (fin->fin_dport == e->ipfe_arg0[i]);
 8640                         }
 8641                         break;
 8642 
 8643                 case IPF_EXP_TCP_FLAGS :
 8644                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
 8645                                 rv |= ((fin->fin_tcpf &
 8646                                         e->ipfe_arg0[i * 2 + 1]) ==
 8647                                        e->ipfe_arg0[i * 2]);
 8648                         }
 8649                         break;
 8650                 }
 8651                 rv ^= e->ipfe_not;
 8652 
 8653                 if (rv == 0)
 8654                         break;
 8655         }
 8656 
 8657         return (rv);
 8658 }
 8659 
 8660 
 8661 /* ------------------------------------------------------------------------ */
 8662 /* Function:    ipf_queueflush                                              */
 8663 /* Returns:     int - number of entries flushed (0 = none)                  */
 8664 /* Parameters:  softc(I)    - pointer to soft context main structure        */
 8665 /*              deletefn(I) - function to call to delete entry              */
 8666 /*              ipfqs(I)    - top of the list of ipf internal queues        */
 8667 /*              userqs(I)   - top of the list of user defined timeouts      */
 8668 /*                                                                          */
 8669 /* This fucntion gets called when the state/NAT hash tables fill up and we  */
 8670 /* need to try a bit harder to free up some space.  The algorithm used here */
 8671 /* split into two parts but both halves have the same goal: to reduce the   */
 8672 /* number of connections considered to be "active" to the low watermark.    */
 8673 /* There are two steps in doing this:                                       */
 8674 /* 1) Remove any TCP connections that are already considered to be "closed" */
 8675 /*    but have not yet been removed from the state table.  The two states   */
 8676 /*    TCPS_TIME_WAIT and TCPS_CLOSED are considered to be the perfect       */
 8677 /*    candidates for this style of removal.  If freeing up entries in       */
 8678 /*    CLOSED or both CLOSED and TIME_WAIT brings us to the low watermark,   */
 8679 /*    we do not go on to step 2.                                            */
 8680 /*                                                                          */
 8681 /* 2) Look for the oldest entries on each timeout queue and free them if    */
 8682 /*    they are within the given window we are considering.  Where the       */
 8683 /*    window starts and the steps taken to increase its size depend upon    */
 8684 /*    how long ipf has been running (ipf_ticks.)  Anything modified in the  */
 8685 /*    last 30 seconds is not touched.                                       */
 8686 /*                                              touched                     */
 8687 /*         die     ipf_ticks  30*1.5    1800*1.5   |  43200*1.5             */
 8688 /*           |          |        |           |     |     |                  */
 8689 /* future <--+----------+--------+-----------+-----+-----+-----------> past */
 8690 /*                     now        \_int=30s_/ \_int=1hr_/ \_int=12hr        */
 8691 /*                                                                          */
 8692 /* Points to note:                                                          */
 8693 /* - tqe_die is the time, in the future, when entries die.                  */
 8694 /* - tqe_die - ipf_ticks is how long left the connection has to live in ipf */
 8695 /*   ticks.                                                                 */
 8696 /* - tqe_touched is when the entry was last used by NAT/state               */
 8697 /* - the closer tqe_touched is to ipf_ticks, the further tqe_die will be    */
 8698 /*   ipf_ticks any given timeout queue and vice versa.                      */
 8699 /* - both tqe_die and tqe_touched increase over time                        */
 8700 /* - timeout queues are sorted with the highest value of tqe_die at the     */
 8701 /*   bottom and therefore the smallest values of each are at the top        */
 8702 /* - the pointer passed in as ipfqs should point to an array of timeout     */
 8703 /*   queues representing each of the TCP states                             */
 8704 /*                                                                          */
 8705 /* We start by setting up a maximum range to scan for things to move of     */
 8706 /* iend (newest) to istart (oldest) in chunks of "interval".  If nothing is */
 8707 /* found in that range, "interval" is adjusted (so long as it isn't 30) and */
 8708 /* we start again with a new value for "iend" and "istart".  This is        */
 8709 /* continued until we either finish the scan of 30 second intervals or the  */
 8710 /* low water mark is reached.                                               */
 8711 /* ------------------------------------------------------------------------ */
 8712 int
 8713 ipf_queueflush(ipf_main_softc_t *softc, ipftq_delete_fn_t deletefn,
 8714         ipftq_t *ipfqs, ipftq_t *userqs, u_int *activep, int size, int low)
 8715 {
 8716         u_long interval, istart, iend;
 8717         ipftq_t *ifq, *ifqnext;
 8718         ipftqent_t *tqe, *tqn;
 8719         int removed = 0;
 8720 
 8721         for (tqn = ipfqs[IPF_TCPS_CLOSED].ifq_head; ((tqe = tqn) != NULL); ) {
 8722                 tqn = tqe->tqe_next;
 8723                 if ((*deletefn)(softc, tqe->tqe_parent) == 0)
 8724                         removed++;
 8725         }
 8726         if ((*activep * 100 / size) > low) {
 8727                 for (tqn = ipfqs[IPF_TCPS_TIME_WAIT].ifq_head;
 8728                      ((tqe = tqn) != NULL); ) {
 8729                         tqn = tqe->tqe_next;
 8730                         if ((*deletefn)(softc, tqe->tqe_parent) == 0)
 8731                                 removed++;
 8732                 }
 8733         }
 8734 
 8735         if ((*activep * 100 / size) <= low) {
 8736                 return (removed);
 8737         }
 8738 
 8739         /*
 8740          * NOTE: Use of "* 15 / 10" is required here because if "* 1.5" is
 8741          *       used then the operations are upgraded to floating point
 8742          *       and kernels don't like floating point...
 8743          */
 8744         if (softc->ipf_ticks > IPF_TTLVAL(43200 * 15 / 10)) {
 8745                 istart = IPF_TTLVAL(86400 * 4);
 8746                 interval = IPF_TTLVAL(43200);
 8747         } else if (softc->ipf_ticks > IPF_TTLVAL(1800 * 15 / 10)) {
 8748                 istart = IPF_TTLVAL(43200);
 8749                 interval = IPF_TTLVAL(1800);
 8750         } else if (softc->ipf_ticks > IPF_TTLVAL(30 * 15 / 10)) {
 8751                 istart = IPF_TTLVAL(1800);
 8752                 interval = IPF_TTLVAL(30);
 8753         } else {
 8754                 return (0);
 8755         }
 8756         if (istart > softc->ipf_ticks) {
 8757                 if (softc->ipf_ticks - interval < interval)
 8758                         istart = interval;
 8759                 else
 8760                         istart = (softc->ipf_ticks / interval) * interval;
 8761         }
 8762 
 8763         iend = softc->ipf_ticks - interval;
 8764 
 8765         while ((*activep * 100 / size) > low) {
 8766                 u_long try;
 8767 
 8768                 try = softc->ipf_ticks - istart;
 8769 
 8770                 for (ifq = ipfqs; ifq != NULL; ifq = ifq->ifq_next) {
 8771                         for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
 8772                                 if (try < tqe->tqe_touched)
 8773                                         break;
 8774                                 tqn = tqe->tqe_next;
 8775                                 if ((*deletefn)(softc, tqe->tqe_parent) == 0)
 8776                                         removed++;
 8777                         }
 8778                 }
 8779 
 8780                 for (ifq = userqs; ifq != NULL; ifq = ifqnext) {
 8781                         ifqnext = ifq->ifq_next;
 8782 
 8783                         for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
 8784                                 if (try < tqe->tqe_touched)
 8785                                         break;
 8786                                 tqn = tqe->tqe_next;
 8787                                 if ((*deletefn)(softc, tqe->tqe_parent) == 0)
 8788                                         removed++;
 8789                         }
 8790                 }
 8791 
 8792                 if (try >= iend) {
 8793                         if (interval == IPF_TTLVAL(43200)) {
 8794                                 interval = IPF_TTLVAL(1800);
 8795                         } else if (interval == IPF_TTLVAL(1800)) {
 8796                                 interval = IPF_TTLVAL(30);
 8797                         } else {
 8798                                 break;
 8799                         }
 8800                         if (interval >= softc->ipf_ticks)
 8801                                 break;
 8802 
 8803                         iend = softc->ipf_ticks - interval;
 8804                 }
 8805                 istart -= interval;
 8806         }
 8807 
 8808         return (removed);
 8809 }
 8810 
 8811 
 8812 /* ------------------------------------------------------------------------ */
 8813 /* Function:    ipf_deliverlocal                                            */
 8814 /* Returns:     int - 1 = local address, 0 = non-local address              */
 8815 /* Parameters:  softc(I)     - pointer to soft context main structure       */
 8816 /*              ipversion(I) - IP protocol version (4 or 6)                 */
 8817 /*              ifp(I)       - network interface pointer                    */
 8818 /*              ipaddr(I)    - IPv4/6 destination address                   */
 8819 /*                                                                          */
 8820 /* This fucntion is used to determine in the address "ipaddr" belongs to    */
 8821 /* the network interface represented by ifp.                                */
 8822 /* ------------------------------------------------------------------------ */
 8823 int
 8824 ipf_deliverlocal(ipf_main_softc_t *softc, int ipversion, void *ifp,
 8825         i6addr_t *ipaddr)
 8826 {
 8827         i6addr_t addr;
 8828         int islocal = 0;
 8829 
 8830         if (ipversion == 4) {
 8831                 if (ipf_ifpaddr(softc, 4, FRI_NORMAL, ifp, &addr, NULL) == 0) {
 8832                         if (addr.in4.s_addr == ipaddr->in4.s_addr)
 8833                                 islocal = 1;
 8834                 }
 8835 
 8836 #ifdef USE_INET6
 8837         } else if (ipversion == 6) {
 8838                 if (ipf_ifpaddr(softc, 6, FRI_NORMAL, ifp, &addr, NULL) == 0) {
 8839                         if (IP6_EQ(&addr, ipaddr))
 8840                                 islocal = 1;
 8841                 }
 8842 #endif
 8843         }
 8844 
 8845         return (islocal);
 8846 }
 8847 
 8848 
 8849 /* ------------------------------------------------------------------------ */
 8850 /* Function:    ipf_settimeout                                              */
 8851 /* Returns:     int - 0 = success, -1 = failure                             */
 8852 /* Parameters:  softc(I) - pointer to soft context main structure           */
 8853 /*              t(I)     - pointer to tuneable array entry                  */
 8854 /*              p(I)     - pointer to values passed in to apply             */
 8855 /*                                                                          */
 8856 /* This function is called to set the timeout values for each distinct      */
 8857 /* queue timeout that is available.  When called, it calls into both the    */
 8858 /* state and NAT code, telling them to update their timeout queues.         */
 8859 /* ------------------------------------------------------------------------ */
 8860 static int
 8861 ipf_settimeout(struct ipf_main_softc_s *softc, ipftuneable_t *t,
 8862         ipftuneval_t *p)
 8863 {
 8864 
 8865         /*
 8866          * ipf_interror should be set by the functions called here, not
 8867          * by this function - it's just a middle man.
 8868          */
 8869         if (ipf_state_settimeout(softc, t, p) == -1)
 8870                 return (-1);
 8871         if (ipf_nat_settimeout(softc, t, p) == -1)
 8872                 return (-1);
 8873         return (0);
 8874 }
 8875 
 8876 
 8877 /* ------------------------------------------------------------------------ */
 8878 /* Function:    ipf_apply_timeout                                           */
 8879 /* Returns:     int - 0 = success, -1 = failure                             */
 8880 /* Parameters:  head(I)    - pointer to tuneable array entry                */
 8881 /*              seconds(I) - pointer to values passed in to apply           */
 8882 /*                                                                          */
 8883 /* This function applies a timeout of "seconds" to the timeout queue that   */
 8884 /* is pointed to by "head".  All entries on this list have an expiration    */
 8885 /* set to be the current tick value of ipf plus the ttl.  Given that this   */
 8886 /* function should only be called when the delta is non-zero, the task is   */
 8887 /* to walk the entire list and apply the change.  The sort order will not   */
 8888 /* change.  The only catch is that this is O(n) across the list, so if the  */
 8889 /* queue has lots of entries (10s of thousands or 100s of thousands), it    */
 8890 /* could take a relatively long time to work through them all.              */
 8891 /* ------------------------------------------------------------------------ */
 8892 void
 8893 ipf_apply_timeout(ipftq_t *head, u_int seconds)
 8894 {
 8895         u_int oldtimeout, newtimeout;
 8896         ipftqent_t *tqe;
 8897         int delta;
 8898 
 8899         MUTEX_ENTER(&head->ifq_lock);
 8900         oldtimeout = head->ifq_ttl;
 8901         newtimeout = IPF_TTLVAL(seconds);
 8902         delta = oldtimeout - newtimeout;
 8903 
 8904         head->ifq_ttl = newtimeout;
 8905 
 8906         for (tqe = head->ifq_head; tqe != NULL; tqe = tqe->tqe_next) {
 8907                 tqe->tqe_die += delta;
 8908         }
 8909         MUTEX_EXIT(&head->ifq_lock);
 8910 }
 8911 
 8912 
 8913 /* ------------------------------------------------------------------------ */
 8914 /* Function:   ipf_settimeout_tcp                                           */
 8915 /* Returns:    int - 0 = successfully applied, -1 = failed                  */
 8916 /* Parameters: t(I)   - pointer to tuneable to change                       */
 8917 /*             p(I)   - pointer to new timeout information                  */
 8918 /*             tab(I) - pointer to table of TCP queues                      */
 8919 /*                                                                          */
 8920 /* This function applies the new timeout (p) to the TCP tunable (t) and     */
 8921 /* updates all of the entries on the relevant timeout queue by calling      */
 8922 /* ipf_apply_timeout().                                                     */
 8923 /* ------------------------------------------------------------------------ */
 8924 int
 8925 ipf_settimeout_tcp(ipftuneable_t *t, ipftuneval_t *p, ipftq_t *tab)
 8926 {
 8927         if (!strcmp(t->ipft_name, "tcp_idle_timeout") ||
 8928             !strcmp(t->ipft_name, "tcp_established")) {
 8929                 ipf_apply_timeout(&tab[IPF_TCPS_ESTABLISHED], p->ipftu_int);
 8930         } else if (!strcmp(t->ipft_name, "tcp_close_wait")) {
 8931                 ipf_apply_timeout(&tab[IPF_TCPS_CLOSE_WAIT], p->ipftu_int);
 8932         } else if (!strcmp(t->ipft_name, "tcp_last_ack")) {
 8933                 ipf_apply_timeout(&tab[IPF_TCPS_LAST_ACK], p->ipftu_int);
 8934         } else if (!strcmp(t->ipft_name, "tcp_timeout")) {
 8935                 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int);
 8936                 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int);
 8937                 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int);
 8938         } else if (!strcmp(t->ipft_name, "tcp_listen")) {
 8939                 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int);
 8940         } else if (!strcmp(t->ipft_name, "tcp_half_established")) {
 8941                 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int);
 8942         } else if (!strcmp(t->ipft_name, "tcp_closing")) {
 8943                 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int);
 8944         } else if (!strcmp(t->ipft_name, "tcp_syn_received")) {
 8945                 ipf_apply_timeout(&tab[IPF_TCPS_SYN_RECEIVED], p->ipftu_int);
 8946         } else if (!strcmp(t->ipft_name, "tcp_syn_sent")) {
 8947                 ipf_apply_timeout(&tab[IPF_TCPS_SYN_SENT], p->ipftu_int);
 8948         } else if (!strcmp(t->ipft_name, "tcp_closed")) {
 8949                 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int);
 8950         } else if (!strcmp(t->ipft_name, "tcp_half_closed")) {
 8951                 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int);
 8952         } else if (!strcmp(t->ipft_name, "tcp_time_wait")) {
 8953                 ipf_apply_timeout(&tab[IPF_TCPS_TIME_WAIT], p->ipftu_int);
 8954         } else {
 8955                 /*
 8956                  * ipf_interror isn't set here because it should be set
 8957                  * by whatever called this function.
 8958                  */
 8959                 return (-1);
 8960         }
 8961         return (0);
 8962 }
 8963 
 8964 
 8965 /* ------------------------------------------------------------------------ */
 8966 /* Function:   ipf_main_soft_create                                         */
 8967 /* Returns:    NULL = failure, else success                                 */
 8968 /* Parameters: arg(I) - pointer to soft context structure if already allocd */
 8969 /*                                                                          */
 8970 /* Create the foundation soft context structure. In circumstances where it  */
 8971 /* is not required to dynamically allocate the context, a pointer can be    */
 8972 /* passed in (rather than NULL) to a structure to be initialised.           */
 8973 /* The main thing of interest is that a number of locks are initialised     */
 8974 /* here instead of in the where might be expected - in the relevant create  */
 8975 /* function elsewhere.  This is done because the current locking design has */
 8976 /* some areas where these locks are used outside of their module.           */
 8977 /* Possibly the most important exercise that is done here is setting of all */
 8978 /* the timeout values, allowing them to be changed before init().           */
 8979 /* ------------------------------------------------------------------------ */
 8980 void *
 8981 ipf_main_soft_create(void *arg)
 8982 {
 8983         ipf_main_softc_t *softc;
 8984 
 8985         if (arg == NULL) {
 8986                 KMALLOC(softc, ipf_main_softc_t *);
 8987                 if (softc == NULL)
 8988                         return (NULL);
 8989         } else {
 8990                 softc = arg;
 8991         }
 8992 
 8993         bzero((char *)softc, sizeof(*softc));
 8994 
 8995         /*
 8996          * This serves as a flag as to whether or not the softc should be
 8997          * free'd when _destroy is called.
 8998          */
 8999         softc->ipf_dynamic_softc = (arg == NULL) ? 1 : 0;
 9000 
 9001         softc->ipf_tuners = ipf_tune_array_copy(softc,
 9002                                                 sizeof(ipf_main_tuneables),
 9003                                                 ipf_main_tuneables);
 9004         if (softc->ipf_tuners == NULL) {
 9005                 ipf_main_soft_destroy(softc);
 9006                 return (NULL);
 9007         }
 9008 
 9009         MUTEX_INIT(&softc->ipf_rw, "ipf rw mutex");
 9010         MUTEX_INIT(&softc->ipf_timeoutlock, "ipf timeout lock");
 9011         RWLOCK_INIT(&softc->ipf_global, "ipf filter load/unload mutex");
 9012         RWLOCK_INIT(&softc->ipf_mutex, "ipf filter rwlock");
 9013         RWLOCK_INIT(&softc->ipf_tokens, "ipf token rwlock");
 9014         RWLOCK_INIT(&softc->ipf_state, "ipf state rwlock");
 9015         RWLOCK_INIT(&softc->ipf_nat, "ipf IP NAT rwlock");
 9016         RWLOCK_INIT(&softc->ipf_poolrw, "ipf pool rwlock");
 9017         RWLOCK_INIT(&softc->ipf_frag, "ipf frag rwlock");
 9018 
 9019         softc->ipf_token_head = NULL;
 9020         softc->ipf_token_tail = &softc->ipf_token_head;
 9021 
 9022         softc->ipf_tcpidletimeout = FIVE_DAYS;
 9023         softc->ipf_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL);
 9024         softc->ipf_tcplastack = IPF_TTLVAL(30);
 9025         softc->ipf_tcptimewait = IPF_TTLVAL(2 * TCP_MSL);
 9026         softc->ipf_tcptimeout = IPF_TTLVAL(2 * TCP_MSL);
 9027         softc->ipf_tcpsynsent = IPF_TTLVAL(2 * TCP_MSL);
 9028         softc->ipf_tcpsynrecv = IPF_TTLVAL(2 * TCP_MSL);
 9029         softc->ipf_tcpclosed = IPF_TTLVAL(30);
 9030         softc->ipf_tcphalfclosed = IPF_TTLVAL(2 * 3600);
 9031         softc->ipf_udptimeout = IPF_TTLVAL(120);
 9032         softc->ipf_udpacktimeout = IPF_TTLVAL(12);
 9033         softc->ipf_icmptimeout = IPF_TTLVAL(60);
 9034         softc->ipf_icmpacktimeout = IPF_TTLVAL(6);
 9035         softc->ipf_iptimeout = IPF_TTLVAL(60);
 9036 
 9037 #if defined(IPFILTER_DEFAULT_BLOCK)
 9038         softc->ipf_pass = FR_BLOCK|FR_NOMATCH;
 9039 #else
 9040         softc->ipf_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH;
 9041 #endif
 9042         softc->ipf_minttl = 4;
 9043         softc->ipf_icmpminfragmtu = 68;
 9044         softc->ipf_flags = IPF_LOGGING;
 9045 
 9046 #ifdef LARGE_NAT
 9047         softc->ipf_large_nat = 1;
 9048 #endif
 9049         ipf_fbsd_kenv_get(softc);
 9050 
 9051         return (softc);
 9052 }
 9053 
 9054 /* ------------------------------------------------------------------------ */
 9055 /* Function:   ipf_main_soft_init                                           */
 9056 /* Returns:    0 = success, -1 = failure                                    */
 9057 /* Parameters: softc(I) - pointer to soft context main structure            */
 9058 /*                                                                          */
 9059 /* A null-op function that exists as a placeholder so that the flow in      */
 9060 /* other functions is obvious.                                              */
 9061 /* ------------------------------------------------------------------------ */
 9062 /*ARGSUSED*/
 9063 int
 9064 ipf_main_soft_init(ipf_main_softc_t *softc)
 9065 {
 9066         return (0);
 9067 }
 9068 
 9069 
 9070 /* ------------------------------------------------------------------------ */
 9071 /* Function:   ipf_main_soft_destroy                                        */
 9072 /* Returns:    void                                                         */
 9073 /* Parameters: softc(I) - pointer to soft context main structure            */
 9074 /*                                                                          */
 9075 /* Undo everything that we did in ipf_main_soft_create.                     */
 9076 /*                                                                          */
 9077 /* The most important check that needs to be made here is whether or not    */
 9078 /* the structure was allocated by ipf_main_soft_create() by checking what   */
 9079 /* value is stored in ipf_dynamic_main.                                     */
 9080 /* ------------------------------------------------------------------------ */
 9081 /*ARGSUSED*/
 9082 void
 9083 ipf_main_soft_destroy(ipf_main_softc_t *softc)
 9084 {
 9085 
 9086         RW_DESTROY(&softc->ipf_frag);
 9087         RW_DESTROY(&softc->ipf_poolrw);
 9088         RW_DESTROY(&softc->ipf_nat);
 9089         RW_DESTROY(&softc->ipf_state);
 9090         RW_DESTROY(&softc->ipf_tokens);
 9091         RW_DESTROY(&softc->ipf_mutex);
 9092         RW_DESTROY(&softc->ipf_global);
 9093         MUTEX_DESTROY(&softc->ipf_timeoutlock);
 9094         MUTEX_DESTROY(&softc->ipf_rw);
 9095 
 9096         if (softc->ipf_tuners != NULL) {
 9097                 KFREES(softc->ipf_tuners, sizeof(ipf_main_tuneables));
 9098         }
 9099         if (softc->ipf_dynamic_softc == 1) {
 9100                 KFREE(softc);
 9101         }
 9102 }
 9103 
 9104 
 9105 /* ------------------------------------------------------------------------ */
 9106 /* Function:   ipf_main_soft_fini                                           */
 9107 /* Returns:    0 = success, -1 = failure                                    */
 9108 /* Parameters: softc(I) - pointer to soft context main structure            */
 9109 /*                                                                          */
 9110 /* Clean out the rules which have been added since _init was last called,   */
 9111 /* the only dynamic part of the mainline.                                   */
 9112 /* ------------------------------------------------------------------------ */
 9113 int
 9114 ipf_main_soft_fini(ipf_main_softc_t *softc)
 9115 {
 9116         (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
 9117         (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE);
 9118         (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
 9119         (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE);
 9120 
 9121         return (0);
 9122 }
 9123 
 9124 
 9125 /* ------------------------------------------------------------------------ */
 9126 /* Function:   ipf_main_load                                                */
 9127 /* Returns:    0 = success, -1 = failure                                    */
 9128 /* Parameters: none                                                         */
 9129 /*                                                                          */
 9130 /* Handle global initialisation that needs to be done for the base part of  */
 9131 /* IPFilter. At present this just amounts to initialising some ICMP lookup  */
 9132 /* arrays that get used by the state/NAT code.                              */
 9133 /* ------------------------------------------------------------------------ */
 9134 int
 9135 ipf_main_load(void)
 9136 {
 9137         int i;
 9138 
 9139         /* fill icmp reply type table */
 9140         for (i = 0; i <= ICMP_MAXTYPE; i++)
 9141                 icmpreplytype4[i] = -1;
 9142         icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY;
 9143         icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY;
 9144         icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY;
 9145         icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY;
 9146 
 9147 #ifdef  USE_INET6
 9148         /* fill icmp reply type table */
 9149         for (i = 0; i <= ICMP6_MAXTYPE; i++)
 9150                 icmpreplytype6[i] = -1;
 9151         icmpreplytype6[ICMP6_ECHO_REQUEST] = ICMP6_ECHO_REPLY;
 9152         icmpreplytype6[ICMP6_MEMBERSHIP_QUERY] = ICMP6_MEMBERSHIP_REPORT;
 9153         icmpreplytype6[ICMP6_NI_QUERY] = ICMP6_NI_REPLY;
 9154         icmpreplytype6[ND_ROUTER_SOLICIT] = ND_ROUTER_ADVERT;
 9155         icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT;
 9156 #endif
 9157 
 9158         return (0);
 9159 }
 9160 
 9161 
 9162 /* ------------------------------------------------------------------------ */
 9163 /* Function:   ipf_main_unload                                              */
 9164 /* Returns:    0 = success, -1 = failure                                    */
 9165 /* Parameters: none                                                         */
 9166 /*                                                                          */
 9167 /* A null-op function that exists as a placeholder so that the flow in      */
 9168 /* other functions is obvious.                                              */
 9169 /* ------------------------------------------------------------------------ */
 9170 int
 9171 ipf_main_unload(void)
 9172 {
 9173         return (0);
 9174 }
 9175 
 9176 
 9177 /* ------------------------------------------------------------------------ */
 9178 /* Function:   ipf_load_all                                                 */
 9179 /* Returns:    0 = success, -1 = failure                                    */
 9180 /* Parameters: none                                                         */
 9181 /*                                                                          */
 9182 /* Work through all of the subsystems inside IPFilter and call the load     */
 9183 /* function for each in an order that won't lead to a crash :)              */
 9184 /* ------------------------------------------------------------------------ */
 9185 int
 9186 ipf_load_all(void)
 9187 {
 9188         if (ipf_main_load() == -1)
 9189                 return (-1);
 9190 
 9191         if (ipf_state_main_load() == -1)
 9192                 return (-1);
 9193 
 9194         if (ipf_nat_main_load() == -1)
 9195                 return (-1);
 9196 
 9197         if (ipf_frag_main_load() == -1)
 9198                 return (-1);
 9199 
 9200         if (ipf_auth_main_load() == -1)
 9201                 return (-1);
 9202 
 9203         if (ipf_proxy_main_load() == -1)
 9204                 return (-1);
 9205 
 9206         return (0);
 9207 }
 9208 
 9209 
 9210 /* ------------------------------------------------------------------------ */
 9211 /* Function:   ipf_unload_all                                               */
 9212 /* Returns:    0 = success, -1 = failure                                    */
 9213 /* Parameters: none                                                         */
 9214 /*                                                                          */
 9215 /* Work through all of the subsystems inside IPFilter and call the unload   */
 9216 /* function for each in an order that won't lead to a crash :)              */
 9217 /* ------------------------------------------------------------------------ */
 9218 int
 9219 ipf_unload_all(void)
 9220 {
 9221         if (ipf_proxy_main_unload() == -1)
 9222                 return (-1);
 9223 
 9224         if (ipf_auth_main_unload() == -1)
 9225                 return (-1);
 9226 
 9227         if (ipf_frag_main_unload() == -1)
 9228                 return (-1);
 9229 
 9230         if (ipf_nat_main_unload() == -1)
 9231                 return (-1);
 9232 
 9233         if (ipf_state_main_unload() == -1)
 9234                 return (-1);
 9235 
 9236         if (ipf_main_unload() == -1)
 9237                 return (-1);
 9238 
 9239         return (0);
 9240 }
 9241 
 9242 
 9243 /* ------------------------------------------------------------------------ */
 9244 /* Function:   ipf_create_all                                               */
 9245 /* Returns:    NULL = failure, else success                                 */
 9246 /* Parameters: arg(I) - pointer to soft context main structure              */
 9247 /*                                                                          */
 9248 /* Work through all of the subsystems inside IPFilter and call the create   */
 9249 /* function for each in an order that won't lead to a crash :)              */
 9250 /* ------------------------------------------------------------------------ */
 9251 ipf_main_softc_t *
 9252 ipf_create_all(void *arg)
 9253 {
 9254         ipf_main_softc_t *softc;
 9255 
 9256         softc = ipf_main_soft_create(arg);
 9257         if (softc == NULL)
 9258                 return (NULL);
 9259 
 9260 #ifdef IPFILTER_LOG
 9261         softc->ipf_log_soft = ipf_log_soft_create(softc);
 9262         if (softc->ipf_log_soft == NULL) {
 9263                 ipf_destroy_all(softc);
 9264                 return (NULL);
 9265         }
 9266 #endif
 9267 
 9268         softc->ipf_lookup_soft = ipf_lookup_soft_create(softc);
 9269         if (softc->ipf_lookup_soft == NULL) {
 9270                 ipf_destroy_all(softc);
 9271                 return (NULL);
 9272         }
 9273 
 9274         softc->ipf_sync_soft = ipf_sync_soft_create(softc);
 9275         if (softc->ipf_sync_soft == NULL) {
 9276                 ipf_destroy_all(softc);
 9277                 return (NULL);
 9278         }
 9279 
 9280         softc->ipf_state_soft = ipf_state_soft_create(softc);
 9281         if (softc->ipf_state_soft == NULL) {
 9282                 ipf_destroy_all(softc);
 9283                 return (NULL);
 9284         }
 9285 
 9286         softc->ipf_nat_soft = ipf_nat_soft_create(softc);
 9287         if (softc->ipf_nat_soft == NULL) {
 9288                 ipf_destroy_all(softc);
 9289                 return (NULL);
 9290         }
 9291 
 9292         softc->ipf_frag_soft = ipf_frag_soft_create(softc);
 9293         if (softc->ipf_frag_soft == NULL) {
 9294                 ipf_destroy_all(softc);
 9295                 return (NULL);
 9296         }
 9297 
 9298         softc->ipf_auth_soft = ipf_auth_soft_create(softc);
 9299         if (softc->ipf_auth_soft == NULL) {
 9300                 ipf_destroy_all(softc);
 9301                 return (NULL);
 9302         }
 9303 
 9304         softc->ipf_proxy_soft = ipf_proxy_soft_create(softc);
 9305         if (softc->ipf_proxy_soft == NULL) {
 9306                 ipf_destroy_all(softc);
 9307                 return (NULL);
 9308         }
 9309 
 9310         return (softc);
 9311 }
 9312 
 9313 
 9314 /* ------------------------------------------------------------------------ */
 9315 /* Function:   ipf_destroy_all                                              */
 9316 /* Returns:    void                                                         */
 9317 /* Parameters: softc(I) - pointer to soft context main structure            */
 9318 /*                                                                          */
 9319 /* Work through all of the subsystems inside IPFilter and call the destroy  */
 9320 /* function for each in an order that won't lead to a crash :)              */
 9321 /*                                                                          */
 9322 /* Every one of these functions is expected to succeed, so there is no      */
 9323 /* checking of return values.                                               */
 9324 /* ------------------------------------------------------------------------ */
 9325 void
 9326 ipf_destroy_all(ipf_main_softc_t *softc)
 9327 {
 9328 
 9329         if (softc->ipf_state_soft != NULL) {
 9330                 ipf_state_soft_destroy(softc, softc->ipf_state_soft);
 9331                 softc->ipf_state_soft = NULL;
 9332         }
 9333 
 9334         if (softc->ipf_nat_soft != NULL) {
 9335                 ipf_nat_soft_destroy(softc, softc->ipf_nat_soft);
 9336                 softc->ipf_nat_soft = NULL;
 9337         }
 9338 
 9339         if (softc->ipf_frag_soft != NULL) {
 9340                 ipf_frag_soft_destroy(softc, softc->ipf_frag_soft);
 9341                 softc->ipf_frag_soft = NULL;
 9342         }
 9343 
 9344         if (softc->ipf_auth_soft != NULL) {
 9345                 ipf_auth_soft_destroy(softc, softc->ipf_auth_soft);
 9346                 softc->ipf_auth_soft = NULL;
 9347         }
 9348 
 9349         if (softc->ipf_proxy_soft != NULL) {
 9350                 ipf_proxy_soft_destroy(softc, softc->ipf_proxy_soft);
 9351                 softc->ipf_proxy_soft = NULL;
 9352         }
 9353 
 9354         if (softc->ipf_sync_soft != NULL) {
 9355                 ipf_sync_soft_destroy(softc, softc->ipf_sync_soft);
 9356                 softc->ipf_sync_soft = NULL;
 9357         }
 9358 
 9359         if (softc->ipf_lookup_soft != NULL) {
 9360                 ipf_lookup_soft_destroy(softc, softc->ipf_lookup_soft);
 9361                 softc->ipf_lookup_soft = NULL;
 9362         }
 9363 
 9364 #ifdef IPFILTER_LOG
 9365         if (softc->ipf_log_soft != NULL) {
 9366                 ipf_log_soft_destroy(softc, softc->ipf_log_soft);
 9367                 softc->ipf_log_soft = NULL;
 9368         }
 9369 #endif
 9370 
 9371         ipf_main_soft_destroy(softc);
 9372 }
 9373 
 9374 
 9375 /* ------------------------------------------------------------------------ */
 9376 /* Function:   ipf_init_all                                                 */
 9377 /* Returns:    0 = success, -1 = failure                                    */
 9378 /* Parameters: softc(I) - pointer to soft context main structure            */
 9379 /*                                                                          */
 9380 /* Work through all of the subsystems inside IPFilter and call the init     */
 9381 /* function for each in an order that won't lead to a crash :)              */
 9382 /* ------------------------------------------------------------------------ */
 9383 int
 9384 ipf_init_all(ipf_main_softc_t *softc)
 9385 {
 9386 
 9387         if (ipf_main_soft_init(softc) == -1)
 9388                 return (-1);
 9389 
 9390 #ifdef IPFILTER_LOG
 9391         if (ipf_log_soft_init(softc, softc->ipf_log_soft) == -1)
 9392                 return (-1);
 9393 #endif
 9394 
 9395         if (ipf_lookup_soft_init(softc, softc->ipf_lookup_soft) == -1)
 9396                 return (-1);
 9397 
 9398         if (ipf_sync_soft_init(softc, softc->ipf_sync_soft) == -1)
 9399                 return (-1);
 9400 
 9401         if (ipf_state_soft_init(softc, softc->ipf_state_soft) == -1)
 9402                 return (-1);
 9403 
 9404         if (ipf_nat_soft_init(softc, softc->ipf_nat_soft) == -1)
 9405                 return (-1);
 9406 
 9407         if (ipf_frag_soft_init(softc, softc->ipf_frag_soft) == -1)
 9408                 return (-1);
 9409 
 9410         if (ipf_auth_soft_init(softc, softc->ipf_auth_soft) == -1)
 9411                 return (-1);
 9412 
 9413         if (ipf_proxy_soft_init(softc, softc->ipf_proxy_soft) == -1)
 9414                 return (-1);
 9415 
 9416         return (0);
 9417 }
 9418 
 9419 
 9420 /* ------------------------------------------------------------------------ */
 9421 /* Function:   ipf_fini_all                                                 */
 9422 /* Returns:    0 = success, -1 = failure                                    */
 9423 /* Parameters: softc(I) - pointer to soft context main structure            */
 9424 /*                                                                          */
 9425 /* Work through all of the subsystems inside IPFilter and call the fini     */
 9426 /* function for each in an order that won't lead to a crash :)              */
 9427 /* ------------------------------------------------------------------------ */
 9428 int
 9429 ipf_fini_all(ipf_main_softc_t *softc)
 9430 {
 9431 
 9432         ipf_token_flush(softc);
 9433 
 9434         if (ipf_proxy_soft_fini(softc, softc->ipf_proxy_soft) == -1)
 9435                 return (-1);
 9436 
 9437         if (ipf_auth_soft_fini(softc, softc->ipf_auth_soft) == -1)
 9438                 return (-1);
 9439 
 9440         if (ipf_frag_soft_fini(softc, softc->ipf_frag_soft) == -1)
 9441                 return (-1);
 9442 
 9443         if (ipf_nat_soft_fini(softc, softc->ipf_nat_soft) == -1)
 9444                 return (-1);
 9445 
 9446         if (ipf_state_soft_fini(softc, softc->ipf_state_soft) == -1)
 9447                 return (-1);
 9448 
 9449         if (ipf_sync_soft_fini(softc, softc->ipf_sync_soft) == -1)
 9450                 return (-1);
 9451 
 9452         if (ipf_lookup_soft_fini(softc, softc->ipf_lookup_soft) == -1)
 9453                 return (-1);
 9454 
 9455 #ifdef IPFILTER_LOG
 9456         if (ipf_log_soft_fini(softc, softc->ipf_log_soft) == -1)
 9457                 return (-1);
 9458 #endif
 9459 
 9460         if (ipf_main_soft_fini(softc) == -1)
 9461                 return (-1);
 9462 
 9463         return (0);
 9464 }
 9465 
 9466 
 9467 /* ------------------------------------------------------------------------ */
 9468 /* Function:    ipf_rule_expire                                             */
 9469 /* Returns:     Nil                                                         */
 9470 /* Parameters:  softc(I) - pointer to soft context main structure           */
 9471 /*                                                                          */
 9472 /* At present this function exists just to support temporary addition of    */
 9473 /* firewall rules. Both inactive and active lists are scanned for items to  */
 9474 /* purge, as by rights, the expiration is computed as soon as the rule is   */
 9475 /* loaded in.                                                               */
 9476 /* ------------------------------------------------------------------------ */
 9477 void
 9478 ipf_rule_expire(ipf_main_softc_t *softc)
 9479 {
 9480         frentry_t *fr;
 9481 
 9482         if ((softc->ipf_rule_explist[0] == NULL) &&
 9483             (softc->ipf_rule_explist[1] == NULL))
 9484                 return;
 9485 
 9486         WRITE_ENTER(&softc->ipf_mutex);
 9487 
 9488         while ((fr = softc->ipf_rule_explist[0]) != NULL) {
 9489                 /*
 9490                  * Because the list is kept sorted on insertion, the fist
 9491                  * one that dies in the future means no more work to do.
 9492                  */
 9493                 if (fr->fr_die > softc->ipf_ticks)
 9494                         break;
 9495                 ipf_rule_delete(softc, fr, IPL_LOGIPF, 0);
 9496         }
 9497 
 9498         while ((fr = softc->ipf_rule_explist[1]) != NULL) {
 9499                 /*
 9500                  * Because the list is kept sorted on insertion, the fist
 9501                  * one that dies in the future means no more work to do.
 9502                  */
 9503                 if (fr->fr_die > softc->ipf_ticks)
 9504                         break;
 9505                 ipf_rule_delete(softc, fr, IPL_LOGIPF, 1);
 9506         }
 9507 
 9508         RWLOCK_EXIT(&softc->ipf_mutex);
 9509 }
 9510 
 9511 
 9512 static int ipf_ht_node_cmp(struct host_node_s *, struct host_node_s *);
 9513 static void ipf_ht_node_make_key(host_track_t *, host_node_t *, int,
 9514                                       i6addr_t *);
 9515 
 9516 host_node_t RBI_ZERO(ipf_rb);
 9517 RBI_CODE(ipf_rb, host_node_t, hn_entry, ipf_ht_node_cmp)
 9518 
 9519 
 9520 /* ------------------------------------------------------------------------ */
 9521 /* Function:    ipf_ht_node_cmp                                             */
 9522 /* Returns:     int   - 0 == nodes are the same, ..                         */
 9523 /* Parameters:  k1(I) - pointer to first key to compare                     */
 9524 /*              k2(I) - pointer to second key to compare                    */
 9525 /*                                                                          */
 9526 /* The "key" for the node is a combination of two fields: the address       */
 9527 /* family and the address itself.                                           */
 9528 /*                                                                          */
 9529 /* Because we're not actually interpreting the address data, it isn't       */
 9530 /* necessary to convert them to/from network/host byte order. The mask is   */
 9531 /* just used to remove bits that aren't significant - it doesn't matter     */
 9532 /* where they are, as long as they're always in the same place.             */
 9533 /*                                                                          */
 9534 /* As with IP6_EQ, comparing IPv6 addresses starts at the bottom because    */
 9535 /* this is where individual ones will differ the most - but not true for    */
 9536 /* for /48's, etc.                                                          */
 9537 /* ------------------------------------------------------------------------ */
 9538 static int
 9539 ipf_ht_node_cmp(struct host_node_s *k1, struct host_node_s *k2)
 9540 {
 9541         int i;
 9542 
 9543         i = (k2->hn_addr.adf_family - k1->hn_addr.adf_family);
 9544         if (i != 0)
 9545                 return (i);
 9546 
 9547         if (k1->hn_addr.adf_family == AF_INET)
 9548                 return (k2->hn_addr.adf_addr.in4.s_addr -
 9549                         k1->hn_addr.adf_addr.in4.s_addr);
 9550 
 9551         i = k2->hn_addr.adf_addr.i6[3] - k1->hn_addr.adf_addr.i6[3];
 9552         if (i != 0)
 9553                 return (i);
 9554         i = k2->hn_addr.adf_addr.i6[2] - k1->hn_addr.adf_addr.i6[2];
 9555         if (i != 0)
 9556                 return (i);
 9557         i = k2->hn_addr.adf_addr.i6[1] - k1->hn_addr.adf_addr.i6[1];
 9558         if (i != 0)
 9559                 return (i);
 9560         i = k2->hn_addr.adf_addr.i6[0] - k1->hn_addr.adf_addr.i6[0];
 9561         return (i);
 9562 }
 9563 
 9564 
 9565 /* ------------------------------------------------------------------------ */
 9566 /* Function:    ipf_ht_node_make_key                                        */
 9567 /* Returns:     Nil                                                         */
 9568 /* parameters:  htp(I)    - pointer to address tracking structure           */
 9569 /*              key(I)    - where to store masked address for lookup        */
 9570 /*              family(I) - protocol family of address                      */
 9571 /*              addr(I)   - pointer to network address                      */
 9572 /*                                                                          */
 9573 /* Using the "netmask" (number of bits) stored parent host tracking struct, */
 9574 /* copy the address passed in into the key structure whilst masking out the */
 9575 /* bits that we don't want.                                                 */
 9576 /*                                                                          */
 9577 /* Because the parser will set ht_netmask to 128 if there is no protocol    */
 9578 /* specified (the parser doesn't know if it should be a v4 or v6 rule), we  */
 9579 /* have to be wary of that and not allow 32-128 to happen.                  */
 9580 /* ------------------------------------------------------------------------ */
 9581 static void
 9582 ipf_ht_node_make_key(host_track_t *htp, host_node_t *key, int family,
 9583         i6addr_t *addr)
 9584 {
 9585         key->hn_addr.adf_family = family;
 9586         if (family == AF_INET) {
 9587                 u_32_t mask;
 9588                 int bits;
 9589 
 9590                 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in4);
 9591                 bits = htp->ht_netmask;
 9592                 if (bits >= 32) {
 9593                         mask = 0xffffffff;
 9594                 } else {
 9595                         mask = htonl(0xffffffff << (32 - bits));
 9596                 }
 9597                 key->hn_addr.adf_addr.in4.s_addr = addr->in4.s_addr & mask;
 9598 #ifdef USE_INET6
 9599         } else {
 9600                 int bits = htp->ht_netmask;
 9601 
 9602                 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in6);
 9603                 if (bits > 96) {
 9604                         key->hn_addr.adf_addr.i6[3] = addr->i6[3] &
 9605                                              htonl(0xffffffff << (128 - bits));
 9606                         key->hn_addr.adf_addr.i6[2] = addr->i6[2];
 9607                         key->hn_addr.adf_addr.i6[1] = addr->i6[2];
 9608                         key->hn_addr.adf_addr.i6[0] = addr->i6[2];
 9609                 } else if (bits > 64) {
 9610                         key->hn_addr.adf_addr.i6[3] = 0;
 9611                         key->hn_addr.adf_addr.i6[2] = addr->i6[2] &
 9612                                              htonl(0xffffffff << (96 - bits));
 9613                         key->hn_addr.adf_addr.i6[1] = addr->i6[1];
 9614                         key->hn_addr.adf_addr.i6[0] = addr->i6[0];
 9615                 } else if (bits > 32) {
 9616                         key->hn_addr.adf_addr.i6[3] = 0;
 9617                         key->hn_addr.adf_addr.i6[2] = 0;
 9618                         key->hn_addr.adf_addr.i6[1] = addr->i6[1] &
 9619                                              htonl(0xffffffff << (64 - bits));
 9620                         key->hn_addr.adf_addr.i6[0] = addr->i6[0];
 9621                 } else {
 9622                         key->hn_addr.adf_addr.i6[3] = 0;
 9623                         key->hn_addr.adf_addr.i6[2] = 0;
 9624                         key->hn_addr.adf_addr.i6[1] = 0;
 9625                         key->hn_addr.adf_addr.i6[0] = addr->i6[0] &
 9626                                              htonl(0xffffffff << (32 - bits));
 9627                 }
 9628 #endif
 9629         }
 9630 }
 9631 
 9632 
 9633 /* ------------------------------------------------------------------------ */
 9634 /* Function:    ipf_ht_node_add                                             */
 9635 /* Returns:     int       - 0 == success,  -1 == failure                    */
 9636 /* Parameters:  softc(I)  - pointer to soft context main structure          */
 9637 /*              htp(I)    - pointer to address tracking structure           */
 9638 /*              family(I) - protocol family of address                      */
 9639 /*              addr(I)   - pointer to network address                      */
 9640 /*                                                                          */
 9641 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS  */
 9642 /*       ipf_ht_node_del FROM RUNNING CONCURRENTLY ON THE SAME htp.         */
 9643 /*                                                                          */
 9644 /* After preparing the key with the address information to find, look in    */
 9645 /* the red-black tree to see if the address is known. A successful call to  */
 9646 /* this function can mean one of two things: a new node was added to the    */
 9647 /* tree or a matching node exists and we're able to bump up its activity.   */
 9648 /* ------------------------------------------------------------------------ */
 9649 int
 9650 ipf_ht_node_add(ipf_main_softc_t *softc, host_track_t *htp, int family,
 9651         i6addr_t *addr)
 9652 {
 9653         host_node_t *h;
 9654         host_node_t k;
 9655 
 9656         ipf_ht_node_make_key(htp, &k, family, addr);
 9657 
 9658         h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k);
 9659         if (h == NULL) {
 9660                 if (htp->ht_cur_nodes >= htp->ht_max_nodes)
 9661                         return (-1);
 9662                 KMALLOC(h, host_node_t *);
 9663                 if (h == NULL) {
 9664                         DT(ipf_rb_no_mem);
 9665                         LBUMP(ipf_rb_no_mem);
 9666                         return (-1);
 9667                 }
 9668 
 9669                 /*
 9670                  * If there was a macro to initialise the RB node then that
 9671                  * would get used here, but there isn't...
 9672                  */
 9673                 bzero((char *)h, sizeof(*h));
 9674                 h->hn_addr = k.hn_addr;
 9675                 h->hn_addr.adf_family = k.hn_addr.adf_family;
 9676                 RBI_INSERT(ipf_rb, &htp->ht_root, h);
 9677                 htp->ht_cur_nodes++;
 9678         } else {
 9679                 if ((htp->ht_max_per_node != 0) &&
 9680                     (h->hn_active >= htp->ht_max_per_node)) {
 9681                         DT(ipf_rb_node_max);
 9682                         LBUMP(ipf_rb_node_max);
 9683                         return (-1);
 9684                 }
 9685         }
 9686 
 9687         h->hn_active++;
 9688 
 9689         return (0);
 9690 }
 9691 
 9692 
 9693 /* ------------------------------------------------------------------------ */
 9694 /* Function:    ipf_ht_node_del                                             */
 9695 /* Returns:     int       - 0 == success,  -1 == failure                    */
 9696 /* parameters:  htp(I)    - pointer to address tracking structure           */
 9697 /*              family(I) - protocol family of address                      */
 9698 /*              addr(I)   - pointer to network address                      */
 9699 /*                                                                          */
 9700 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS  */
 9701 /*       ipf_ht_node_add FROM RUNNING CONCURRENTLY ON THE SAME htp.         */
 9702 /*                                                                          */
 9703 /* Try and find the address passed in amongst the leavese on this tree to   */
 9704 /* be friend. If found then drop the active account for that node drops by  */
 9705 /* one. If that count reaches 0, it is time to free it all up.              */
 9706 /* ------------------------------------------------------------------------ */
 9707 int
 9708 ipf_ht_node_del(host_track_t *htp, int family, i6addr_t *addr)
 9709 {
 9710         host_node_t *h;
 9711         host_node_t k;
 9712 
 9713         ipf_ht_node_make_key(htp, &k, family, addr);
 9714 
 9715         h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k);
 9716         if (h == NULL) {
 9717                 return (-1);
 9718         } else {
 9719                 h->hn_active--;
 9720                 if (h->hn_active == 0) {
 9721                         (void) RBI_DELETE(ipf_rb, &htp->ht_root, h);
 9722                         htp->ht_cur_nodes--;
 9723                         KFREE(h);
 9724                 }
 9725         }
 9726 
 9727         return (0);
 9728 }
 9729 
 9730 
 9731 /* ------------------------------------------------------------------------ */
 9732 /* Function:    ipf_rb_ht_init                                              */
 9733 /* Returns:     Nil                                                         */
 9734 /* Parameters:  head(I) - pointer to host tracking structure                */
 9735 /*                                                                          */
 9736 /* Initialise the host tracking structure to be ready for use above.        */
 9737 /* ------------------------------------------------------------------------ */
 9738 void
 9739 ipf_rb_ht_init(host_track_t *head)
 9740 {
 9741         RBI_INIT(ipf_rb, &head->ht_root);
 9742 }
 9743 
 9744 
 9745 /* ------------------------------------------------------------------------ */
 9746 /* Function:    ipf_rb_ht_freenode                                          */
 9747 /* Returns:     Nil                                                         */
 9748 /* Parameters:  head(I) - pointer to host tracking structure                */
 9749 /*              arg(I)  - additional argument from walk caller              */
 9750 /*                                                                          */
 9751 /* Free an actual host_node_t structure.                                    */
 9752 /* ------------------------------------------------------------------------ */
 9753 void
 9754 ipf_rb_ht_freenode(host_node_t *node, void *arg)
 9755 {
 9756         KFREE(node);
 9757 }
 9758 
 9759 
 9760 /* ------------------------------------------------------------------------ */
 9761 /* Function:    ipf_rb_ht_flush                                             */
 9762 /* Returns:     Nil                                                         */
 9763 /* Parameters:  head(I) - pointer to host tracking structure                */
 9764 /*                                                                          */
 9765 /* Remove all of the nodes in the tree tracking hosts by calling a walker   */
 9766 /* and free'ing each one.                                                   */
 9767 /* ------------------------------------------------------------------------ */
 9768 void
 9769 ipf_rb_ht_flush(host_track_t *head)
 9770 {
 9771         RBI_WALK(ipf_rb, &head->ht_root, ipf_rb_ht_freenode, NULL);
 9772 }
 9773 
 9774 
 9775 /* ------------------------------------------------------------------------ */
 9776 /* Function:    ipf_slowtimer                                               */
 9777 /* Returns:     Nil                                                         */
 9778 /* Parameters:  ptr(I) - pointer to main ipf soft context structure         */
 9779 /*                                                                          */
 9780 /* Slowly expire held state for fragments.  Timeouts are set * in           */
 9781 /* expectation of this being called twice per second.                       */
 9782 /* ------------------------------------------------------------------------ */
 9783 void
 9784 ipf_slowtimer(ipf_main_softc_t *softc)
 9785 {
 9786 
 9787         ipf_token_expire(softc);
 9788         ipf_frag_expire(softc);
 9789         ipf_state_expire(softc);
 9790         ipf_nat_expire(softc);
 9791         ipf_auth_expire(softc);
 9792         ipf_lookup_expire(softc);
 9793         ipf_rule_expire(softc);
 9794         ipf_sync_expire(softc);
 9795         softc->ipf_ticks++;
 9796 }
 9797 
 9798 
 9799 /* ------------------------------------------------------------------------ */
 9800 /* Function:    ipf_inet_mask_add                                           */
 9801 /* Returns:     Nil                                                         */
 9802 /* Parameters:  bits(I) - pointer to nat context information                */
 9803 /*              mtab(I) - pointer to mask hash table structure              */
 9804 /*                                                                          */
 9805 /* When called, bits represents the mask of a new NAT rule that has just    */
 9806 /* been added. This function inserts a bitmask into the array of masks to   */
 9807 /* search when searching for a matching NAT rule for a packet.              */
 9808 /* Prevention of duplicate masks is achieved by checking the use count for  */
 9809 /* a given netmask.                                                         */
 9810 /* ------------------------------------------------------------------------ */
 9811 void
 9812 ipf_inet_mask_add(int bits, ipf_v4_masktab_t *mtab)
 9813 {
 9814         u_32_t mask;
 9815         int i, j;
 9816 
 9817         mtab->imt4_masks[bits]++;
 9818         if (mtab->imt4_masks[bits] > 1)
 9819                 return;
 9820 
 9821         if (bits == 0)
 9822                 mask = 0;
 9823         else
 9824                 mask = 0xffffffff << (32 - bits);
 9825 
 9826         for (i = 0; i < 33; i++) {
 9827                 if (ntohl(mtab->imt4_active[i]) < mask) {
 9828                         for (j = 32; j > i; j--)
 9829                                 mtab->imt4_active[j] = mtab->imt4_active[j - 1];
 9830                         mtab->imt4_active[i] = htonl(mask);
 9831                         break;
 9832                 }
 9833         }
 9834         mtab->imt4_max++;
 9835 }
 9836 
 9837 
 9838 /* ------------------------------------------------------------------------ */
 9839 /* Function:    ipf_inet_mask_del                                           */
 9840 /* Returns:     Nil                                                         */
 9841 /* Parameters:  bits(I) - number of bits set in the netmask                 */
 9842 /*              mtab(I) - pointer to mask hash table structure              */
 9843 /*                                                                          */
 9844 /* Remove the 32bit bitmask represented by "bits" from the collection of    */
 9845 /* netmasks stored inside of mtab.                                          */
 9846 /* ------------------------------------------------------------------------ */
 9847 void
 9848 ipf_inet_mask_del(int bits, ipf_v4_masktab_t *mtab)
 9849 {
 9850         u_32_t mask;
 9851         int i, j;
 9852 
 9853         mtab->imt4_masks[bits]--;
 9854         if (mtab->imt4_masks[bits] > 0)
 9855                 return;
 9856 
 9857         mask = htonl(0xffffffff << (32 - bits));
 9858         for (i = 0; i < 33; i++) {
 9859                 if (mtab->imt4_active[i] == mask) {
 9860                         for (j = i + 1; j < 33; j++)
 9861                                 mtab->imt4_active[j - 1] = mtab->imt4_active[j];
 9862                         break;
 9863                 }
 9864         }
 9865         mtab->imt4_max--;
 9866         ASSERT(mtab->imt4_max >= 0);
 9867 }
 9868 
 9869 
 9870 #ifdef USE_INET6
 9871 /* ------------------------------------------------------------------------ */
 9872 /* Function:    ipf_inet6_mask_add                                          */
 9873 /* Returns:     Nil                                                         */
 9874 /* Parameters:  bits(I) - number of bits set in mask                        */
 9875 /*              mask(I) - pointer to mask to add                            */
 9876 /*              mtab(I) - pointer to mask hash table structure              */
 9877 /*                                                                          */
 9878 /* When called, bitcount represents the mask of a IPv6 NAT map rule that    */
 9879 /* has just been added. This function inserts a bitmask into the array of   */
 9880 /* masks to search when searching for a matching NAT rule for a packet.     */
 9881 /* Prevention of duplicate masks is achieved by checking the use count for  */
 9882 /* a given netmask.                                                         */
 9883 /* ------------------------------------------------------------------------ */
 9884 void
 9885 ipf_inet6_mask_add(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab)
 9886 {
 9887         i6addr_t zero;
 9888         int i, j;
 9889 
 9890         mtab->imt6_masks[bits]++;
 9891         if (mtab->imt6_masks[bits] > 1)
 9892                 return;
 9893 
 9894         if (bits == 0) {
 9895                 mask = &zero;
 9896                 zero.i6[0] = 0;
 9897                 zero.i6[1] = 0;
 9898                 zero.i6[2] = 0;
 9899                 zero.i6[3] = 0;
 9900         }
 9901 
 9902         for (i = 0; i < 129; i++) {
 9903                 if (IP6_LT(&mtab->imt6_active[i], mask)) {
 9904                         for (j = 128; j > i; j--)
 9905                                 mtab->imt6_active[j] = mtab->imt6_active[j - 1];
 9906                         mtab->imt6_active[i] = *mask;
 9907                         break;
 9908                 }
 9909         }
 9910         mtab->imt6_max++;
 9911 }
 9912 
 9913 
 9914 /* ------------------------------------------------------------------------ */
 9915 /* Function:    ipf_inet6_mask_del                                          */
 9916 /* Returns:     Nil                                                         */
 9917 /* Parameters:  bits(I) - number of bits set in mask                        */
 9918 /*              mask(I) - pointer to mask to remove                         */
 9919 /*              mtab(I) - pointer to mask hash table structure              */
 9920 /*                                                                          */
 9921 /* Remove the 128bit bitmask represented by "bits" from the collection of   */
 9922 /* netmasks stored inside of mtab.                                          */
 9923 /* ------------------------------------------------------------------------ */
 9924 void
 9925 ipf_inet6_mask_del(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab)
 9926 {
 9927         i6addr_t zero;
 9928         int i, j;
 9929 
 9930         mtab->imt6_masks[bits]--;
 9931         if (mtab->imt6_masks[bits] > 0)
 9932                 return;
 9933 
 9934         if (bits == 0)
 9935                 mask = &zero;
 9936         zero.i6[0] = 0;
 9937         zero.i6[1] = 0;
 9938         zero.i6[2] = 0;
 9939         zero.i6[3] = 0;
 9940 
 9941         for (i = 0; i < 129; i++) {
 9942                 if (IP6_EQ(&mtab->imt6_active[i], mask)) {
 9943                         for (j = i + 1; j < 129; j++) {
 9944                                 mtab->imt6_active[j - 1] = mtab->imt6_active[j];
 9945                                 if (IP6_EQ(&mtab->imt6_active[j - 1], &zero))
 9946                                         break;
 9947                         }
 9948                         break;
 9949                 }
 9950         }
 9951         mtab->imt6_max--;
 9952         ASSERT(mtab->imt6_max >= 0);
 9953 }
 9954 #endif

Cache object: cab6d052be0211509fdb9c8d7ec23f7d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.