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/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 /*
    2  * Copyright (C) 1993-1997 by Darren Reed.
    3  *
    4  * Redistribution and use in source and binary forms are permitted
    5  * provided that this notice is preserved and due credit is given
    6  * to the original author and the contributors.
    7  */
    8 #if !defined(lint)
    9 static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-1996 Darren Reed";
   10 static const char rcsid[] = "@(#)$FreeBSD$";
   11 #endif
   12 
   13 #include "opt_ipfilter.h"
   14 
   15 #include <sys/errno.h>
   16 #include <sys/types.h>
   17 #include <sys/param.h>
   18 #include <sys/time.h>
   19 #include <sys/file.h>
   20 #if !defined(__FreeBSD__)
   21 # include <sys/ioctl.h>
   22 #endif
   23 #if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux)
   24 # include <sys/systm.h>
   25 #else
   26 # include <stdio.h>
   27 # include <string.h>
   28 # include <stdlib.h>
   29 #endif
   30 #include <sys/uio.h>
   31 #if !defined(__SVR4) && !defined(__svr4__)
   32 # ifndef linux
   33 #  include <sys/mbuf.h>
   34 # endif
   35 #else
   36 # include <sys/byteorder.h>
   37 # include <sys/dditypes.h>
   38 # include <sys/stream.h>
   39 #endif
   40 #if defined(__FreeBSD__)
   41 # include <sys/malloc.h>
   42 #endif
   43 #ifndef linux
   44 # include <sys/protosw.h>
   45 # include <sys/socket.h>
   46 #endif
   47 #include <net/if.h>
   48 #ifdef sun
   49 # include <net/af.h>
   50 #endif
   51 #include <net/route.h>
   52 #include <netinet/in.h>
   53 #include <netinet/in_systm.h>
   54 #include <netinet/ip.h>
   55 #ifndef linux
   56 # include <netinet/ip_var.h>
   57 #endif
   58 #include <netinet/tcp.h>
   59 #include <netinet/udp.h>
   60 #include <netinet/ip_icmp.h>
   61 #include "netinet/ip_compat.h"
   62 #include <netinet/tcpip.h>
   63 #include "netinet/ip_fil.h"
   64 #include "netinet/ip_proxy.h"
   65 #include "netinet/ip_nat.h"
   66 #include "netinet/ip_frag.h"
   67 #include "netinet/ip_state.h"
   68 #include "netinet/ip_auth.h"
   69 #ifndef MIN
   70 #define MIN(a,b)        (((a)<(b))?(a):(b))
   71 #endif
   72 
   73 #ifndef _KERNEL
   74 # include "ipf.h"
   75 # include "ipt.h"
   76 extern  int     opts;
   77 
   78 # define        FR_IFVERBOSE(ex,second,verb_pr) if (ex) { verbose verb_pr; \
   79                                                           second; }
   80 # define        FR_IFDEBUG(ex,second,verb_pr)   if (ex) { debug verb_pr; \
   81                                                           second; }
   82 # define        FR_VERBOSE(verb_pr)                     verbose verb_pr
   83 # define        FR_DEBUG(verb_pr)                       debug verb_pr
   84 # define        SEND_RESET(ip, qif, if, m)              send_reset(ip, if)
   85 # define        IPLLOG(a, c, d, e)              ipllog()
   86 #  define       FR_NEWAUTH(m, fi, ip, qif)      fr_newauth((mb_t *)m, fi, ip)
   87 # if SOLARIS
   88 #  define       ICMP_ERROR(b, ip, t, c, if, src)        icmp_error(ip)
   89 # else
   90 #  define       ICMP_ERROR(b, ip, t, c, if, src)        icmp_error(b, ip, if)
   91 # endif
   92 #else /* #ifndef _KERNEL */
   93 # define        FR_IFVERBOSE(ex,second,verb_pr) ;
   94 # define        FR_IFDEBUG(ex,second,verb_pr)   ;
   95 # define        FR_VERBOSE(verb_pr)
   96 # define        FR_DEBUG(verb_pr)
   97 # define        IPLLOG(a, c, d, e)              ipflog(a, c, d, e)
   98 # if SOLARIS || defined(__sgi)
   99 extern  kmutex_t        ipf_mutex, ipf_auth;
  100 # endif
  101 # if SOLARIS
  102 #  define       FR_NEWAUTH(m, fi, ip, qif)      fr_newauth((mb_t *)m, fi, \
  103                                                            ip, qif)
  104 #  define       SEND_RESET(ip, qif, if)         send_reset(ip, qif)
  105 #  define       ICMP_ERROR(b, ip, t, c, if, src) \
  106                         icmp_error(ip, t, c, if, src)
  107 # else /* SOLARIS */
  108 #  define       FR_NEWAUTH(m, fi, ip, qif)      fr_newauth((mb_t *)m, fi, ip)
  109 #  ifdef linux
  110 #   define      SEND_RESET(ip, qif, if)         send_reset((tcpiphdr_t *)ip,\
  111                                                            ifp)
  112 #  else
  113 #   define      SEND_RESET(ip, qif, if)         send_reset((tcpiphdr_t *)ip)
  114 #  endif
  115 #  ifdef __sgi
  116 #   define      ICMP_ERROR(b, ip, t, c, if, src) \
  117                         icmp_error(b, t, c, if, src, if)
  118 #  else
  119 #   if BSD < 199103
  120 #    ifdef linux
  121 #     define    ICMP_ERROR(b, ip, t, c, if, src)        icmp_send(b,t,c,0,if)
  122 #    else
  123 #     define    ICMP_ERROR(b, ip, t, c, if, src) \
  124                         icmp_error(mtod(b, ip_t *), t, c, if, src)
  125 #    endif /* linux */
  126 #   else
  127 #    define     ICMP_ERROR(b, ip, t, c, if, src) \
  128                         icmp_error(b, t, c, (src).s_addr, if)
  129 #   endif /* BSD < 199103 */
  130 #  endif /* __sgi */
  131 # endif /* SOLARIS || __sgi */
  132 #endif /* _KERNEL */
  133 
  134 
  135 struct  filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}};
  136 struct  frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } },
  137                 *ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } };
  138 struct  frgroup *ipfgroups[3][2];
  139 int     fr_flags = IPF_LOGGING, fr_active = 0;
  140 #if defined(IPFILTER_DEFAULT_BLOCK)
  141 int     fr_pass = FR_NOMATCH|FR_BLOCK;
  142 #else
  143 int     fr_pass = (IPF_DEFAULT_PASS|FR_NOMATCH);
  144 #endif
  145 
  146 fr_info_t       frcache[2];
  147 
  148 static  void    fr_makefrip __P((int, ip_t *, fr_info_t *));
  149 static  int     fr_tcpudpchk __P((frentry_t *, fr_info_t *));
  150 static  int     frflushlist __P((int, int, int *, frentry_t *, frentry_t **));
  151 
  152 
  153 /*
  154  * bit values for identifying presence of individual IP options
  155  */
  156 static struct   optlist ipopts[20] = {
  157         { IPOPT_NOP,    0x000001 },
  158         { IPOPT_RR,     0x000002 },
  159         { IPOPT_ZSU,    0x000004 },
  160         { IPOPT_MTUP,   0x000008 },
  161         { IPOPT_MTUR,   0x000010 },
  162         { IPOPT_ENCODE, 0x000020 },
  163         { IPOPT_TS,     0x000040 },
  164         { IPOPT_TR,     0x000080 },
  165         { IPOPT_SECURITY, 0x000100 },
  166         { IPOPT_LSRR,   0x000200 },
  167         { IPOPT_E_SEC,  0x000400 },
  168         { IPOPT_CIPSO,  0x000800 },
  169         { IPOPT_SATID,  0x001000 },
  170         { IPOPT_SSRR,   0x002000 },
  171         { IPOPT_ADDEXT, 0x004000 },
  172         { IPOPT_VISA,   0x008000 },
  173         { IPOPT_IMITD,  0x010000 },
  174         { IPOPT_EIP,    0x020000 },
  175         { IPOPT_FINN,   0x040000 },
  176         { 0,            0x000000 }
  177 };
  178 
  179 /*
  180  * bit values for identifying presence of individual IP security options
  181  */
  182 static struct   optlist secopt[8] = {
  183         { IPSO_CLASS_RES4,      0x01 },
  184         { IPSO_CLASS_TOPS,      0x02 },
  185         { IPSO_CLASS_SECR,      0x04 },
  186         { IPSO_CLASS_RES3,      0x08 },
  187         { IPSO_CLASS_CONF,      0x10 },
  188         { IPSO_CLASS_UNCL,      0x20 },
  189         { IPSO_CLASS_RES2,      0x40 },
  190         { IPSO_CLASS_RES1,      0x80 }
  191 };
  192 
  193 
  194 /*
  195  * compact the IP header into a structure which contains just the info.
  196  * which is useful for comparing IP headers with.
  197  */
  198 static  void    fr_makefrip(hlen, ip, fin)
  199 int hlen;
  200 ip_t *ip;
  201 fr_info_t *fin;
  202 {
  203         struct optlist *op;
  204         tcphdr_t *tcp;
  205         icmphdr_t *icmp;
  206         fr_ip_t *fi = &fin->fin_fi;
  207         u_short optmsk = 0, secmsk = 0, auth = 0;
  208         int i, mv, ol, off;
  209         u_char *s, opt;
  210 
  211         fin->fin_fr = NULL;
  212         fin->fin_tcpf = 0;
  213         fin->fin_data[0] = 0;
  214         fin->fin_data[1] = 0;
  215         fin->fin_rule = -1;
  216         fin->fin_group = -1;
  217         fin->fin_id = ip->ip_id;
  218 #ifdef  _KERNEL
  219         fin->fin_icode = ipl_unreach;
  220 #endif
  221         fi->fi_v = ip->ip_v;
  222         fi->fi_tos = ip->ip_tos;
  223         fin->fin_hlen = hlen;
  224         fin->fin_dlen = ip->ip_len - hlen;
  225         tcp = (tcphdr_t *)((char *)ip + hlen);
  226         icmp = (icmphdr_t *)tcp;
  227         fin->fin_dp = (void *)tcp;
  228         (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4));
  229         (*(((u_32_t *)fi) + 1)) = (*(((u_32_t *)ip) + 3));
  230         (*(((u_32_t *)fi) + 2)) = (*(((u_32_t *)ip) + 4));
  231 
  232         fi->fi_fl = (hlen > sizeof(ip_t)) ? FI_OPTIONS : 0;
  233         off = (ip->ip_off & 0x1fff) << 3;
  234         if (ip->ip_off & 0x3fff)
  235                 fi->fi_fl |= FI_FRAG;
  236         switch (ip->ip_p)
  237         {
  238         case IPPROTO_ICMP :
  239         {
  240                 int minicmpsz = sizeof(struct icmp);
  241 
  242                 if (!off && ip->ip_len > ICMP_MINLEN + hlen &&
  243                     (icmp->icmp_type == ICMP_ECHOREPLY ||
  244                      icmp->icmp_type == ICMP_UNREACH))
  245                         minicmpsz = ICMP_MINLEN;
  246                 if ((!(ip->ip_len >= hlen + minicmpsz) && !off) ||
  247                     (off && off < sizeof(struct icmp)))
  248                         fi->fi_fl |= FI_SHORT;
  249                 if (fin->fin_dlen > 1)
  250                         fin->fin_data[0] = *(u_short *)tcp;
  251                 break;
  252         }
  253         case IPPROTO_TCP :
  254                 fi->fi_fl |= FI_TCPUDP;
  255                 if ((!IPMINLEN(ip, tcphdr) && !off) ||
  256                     (off && off < sizeof(struct tcphdr)))
  257                         fi->fi_fl |= FI_SHORT;
  258                 if (!(fi->fi_fl & FI_SHORT) && !off)
  259                         fin->fin_tcpf = tcp->th_flags;
  260                 goto getports;
  261         case IPPROTO_UDP :
  262                 fi->fi_fl |= FI_TCPUDP;
  263                 if ((!IPMINLEN(ip, udphdr) && !off) ||
  264                     (off && off < sizeof(struct udphdr)))
  265                         fi->fi_fl |= FI_SHORT;
  266 getports:
  267                 if (!off && (fin->fin_dlen > 3)) {
  268                         fin->fin_data[0] = ntohs(tcp->th_sport);
  269                         fin->fin_data[1] = ntohs(tcp->th_dport);
  270                 }
  271                 break;
  272         default :
  273                 break;
  274         }
  275 
  276         for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) {
  277                 opt = *s;
  278                 if (opt == '\0')
  279                         break;
  280                 else if (opt == IPOPT_NOP)
  281                         ol = 1;
  282                 else {
  283                         if (hlen < 2)
  284                                 break;
  285                         ol = (int)*(s + 1);
  286                         if (ol < 2 || ol > hlen)
  287                                 break;
  288                 }
  289                 for (i = 9, mv = 4; mv >= 0; ) {
  290                         op = ipopts + i;
  291                         if (opt == (u_char)op->ol_val) {
  292                                 optmsk |= op->ol_bit;
  293                                 if (opt == IPOPT_SECURITY) {
  294                                         struct optlist *sp;
  295                                         u_char  sec;
  296                                         int j, m;
  297 
  298                                         sec = *(s + 2); /* classification */
  299                                         for (j = 3, m = 2; m >= 0; ) {
  300                                                 sp = secopt + j;
  301                                                 if (sec == sp->ol_val) {
  302                                                         secmsk |= sp->ol_bit;
  303                                                         auth = *(s + 3);
  304                                                         auth *= 256;
  305                                                         auth += *(s + 4);
  306                                                         break;
  307                                                 }
  308                                                 if (sec < sp->ol_val)
  309                                                         j -= m--;
  310                                                 else
  311                                                         j += m--;
  312                                         }
  313                                 }
  314                                 break;
  315                         }
  316                         if (opt < op->ol_val)
  317                                 i -= mv--;
  318                         else
  319                                 i += mv--;
  320                 }
  321                 hlen -= ol;
  322                 s += ol;
  323         }
  324         if (auth && !(auth & 0x0100))
  325                 auth &= 0xff00;
  326         fi->fi_optmsk = optmsk;
  327         fi->fi_secmsk = secmsk;
  328         fi->fi_auth = auth;
  329 }
  330 
  331 
  332 /*
  333  * check an IP packet for TCP/UDP characteristics such as ports and flags.
  334  */
  335 static int fr_tcpudpchk(fr, fin)
  336 frentry_t *fr;
  337 fr_info_t *fin;
  338 {
  339         register u_short po, tup;
  340         register char i;
  341         register int err = 1;
  342 
  343         /*
  344          * Both ports should *always* be in the first fragment.
  345          * So far, I cannot find any cases where they can not be.
  346          *
  347          * compare destination ports
  348          */
  349         if ((i = (int)fr->fr_dcmp)) {
  350                 po = fr->fr_dport;
  351                 tup = fin->fin_data[1];
  352                 /*
  353                  * Do opposite test to that required and
  354                  * continue if that succeeds.
  355                  */
  356                 if (!--i && tup != po) /* EQUAL */
  357                         err = 0;
  358                 else if (!--i && tup == po) /* NOTEQUAL */
  359                         err = 0;
  360                 else if (!--i && tup >= po) /* LESSTHAN */
  361                         err = 0;
  362                 else if (!--i && tup <= po) /* GREATERTHAN */
  363                         err = 0;
  364                 else if (!--i && tup > po) /* LT or EQ */
  365                         err = 0;
  366                 else if (!--i && tup < po) /* GT or EQ */
  367                         err = 0;
  368                 else if (!--i &&           /* Out of range */
  369                          (tup >= po && tup <= fr->fr_dtop))
  370                         err = 0;
  371                 else if (!--i &&           /* In range */
  372                          (tup <= po || tup >= fr->fr_dtop))
  373                         err = 0;
  374         }
  375         /*
  376          * compare source ports
  377          */
  378         if (err && (i = (int)fr->fr_scmp)) {
  379                 po = fr->fr_sport;
  380                 tup = fin->fin_data[0];
  381                 if (!--i && tup != po)
  382                         err = 0;
  383                 else if (!--i && tup == po)
  384                         err = 0;
  385                 else if (!--i && tup >= po)
  386                         err = 0;
  387                 else if (!--i && tup <= po)
  388                         err = 0;
  389                 else if (!--i && tup > po)
  390                         err = 0;
  391                 else if (!--i && tup < po)
  392                         err = 0;
  393                 else if (!--i &&           /* Out of range */
  394                          (tup >= po && tup <= fr->fr_stop))
  395                         err = 0;
  396                 else if (!--i &&           /* In range */
  397                          (tup <= po || tup >= fr->fr_stop))
  398                         err = 0;
  399         }
  400 
  401         /*
  402          * If we don't have all the TCP/UDP header, then how can we
  403          * expect to do any sort of match on it ?  If we were looking for
  404          * TCP flags, then NO match.  If not, then match (which should
  405          * satisfy the "short" class too).
  406          */
  407         if (err && (fin->fin_fi.fi_p == IPPROTO_TCP)) {
  408                 if (fin->fin_fi.fi_fl & FI_SHORT)
  409                         return !(fr->fr_tcpf | fr->fr_tcpfm);
  410                 /*
  411                  * Match the flags ?  If not, abort this match.
  412                  */
  413                 if (fr->fr_tcpf &&
  414                     fr->fr_tcpf != (fin->fin_tcpf & fr->fr_tcpfm)) {
  415                         FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf,
  416                                  fr->fr_tcpfm, fr->fr_tcpf));
  417                         err = 0;
  418                 }
  419         }
  420         return err;
  421 }
  422 
  423 /*
  424  * Check the input/output list of rules for a match and result.
  425  * Could be per interface, but this gets real nasty when you don't have
  426  * kernel sauce.
  427  */
  428 int fr_scanlist(pass, ip, fin, m)
  429 int pass;
  430 ip_t *ip;
  431 register fr_info_t *fin;
  432 void *m;
  433 {
  434         register struct frentry *fr;
  435         register fr_ip_t *fi = &fin->fin_fi;
  436         int rulen, portcmp = 0, off, skip = 0;
  437 
  438         fr = fin->fin_fr;
  439         fin->fin_fr = NULL;
  440         fin->fin_rule = 0;
  441         fin->fin_group = 0;
  442         off = ip->ip_off & 0x1fff;
  443         pass |= (fi->fi_fl << 24);
  444 
  445          if ((fi->fi_fl & FI_TCPUDP) && (fin->fin_dlen > 3) && !off)
  446                 portcmp = 1;
  447 
  448         for (rulen = 0; fr; fr = fr->fr_next, rulen++) {
  449                 if (skip) {
  450                         skip--;
  451                         continue;
  452                 }
  453                 /*
  454                  * In all checks below, a null (zero) value in the
  455                  * filter struture is taken to mean a wildcard.
  456                  *
  457                  * check that we are working for the right interface
  458                  */
  459 #ifdef  _KERNEL
  460                 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
  461                         continue;
  462 #else
  463                 if (opts & (OPT_VERBOSE|OPT_DEBUG))
  464                         printf("\n");
  465                 FR_VERBOSE(("%c", (pass & FR_PASS) ? 'p' : 
  466                                   (pass & FR_AUTH) ? 'a' : 'b'));
  467                 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
  468                         continue;
  469                 FR_VERBOSE((":i"));
  470 #endif
  471                 {
  472                         register u_32_t *ld, *lm, *lip;
  473                         register int i;
  474 
  475                         lip = (u_32_t *)fi;
  476                         lm = (u_32_t *)&fr->fr_mip;
  477                         ld = (u_32_t *)&fr->fr_ip;
  478                         i = ((lip[0] & lm[0]) != ld[0]);
  479                         FR_IFDEBUG(i,continue,("0. %#08x & %#08x != %#08x\n",
  480                                    lip[0], lm[0], ld[0]));
  481                         i |= ((lip[1] & lm[1]) != ld[1]) << 21;
  482                         FR_IFDEBUG(i,continue,("1. %#08x & %#08x != %#08x\n",
  483                                    lip[1], lm[1], ld[1]));
  484                         i |= ((lip[2] & lm[2]) != ld[2]) << 22;
  485                         FR_IFDEBUG(i,continue,("2. %#08x & %#08x != %#08x\n",
  486                                    lip[2], lm[2], ld[2]));
  487                         i |= ((lip[3] & lm[3]) != ld[3]);
  488                         FR_IFDEBUG(i,continue,("3. %#08x & %#08x != %#08x\n",
  489                                    lip[3], lm[3], ld[3]));
  490                         i |= ((lip[4] & lm[4]) != ld[4]);
  491                         FR_IFDEBUG(i,continue,("4. %#08x & %#08x != %#08x\n",
  492                                    lip[4], lm[4], ld[4]));
  493                         i ^= (fi->fi_fl & (FR_NOTSRCIP|FR_NOTDSTIP));
  494                         if (i)
  495                                 continue;
  496                 }
  497 
  498                 /*
  499                  * If a fragment, then only the first has what we're looking
  500                  * for here...
  501                  */
  502                 if (!portcmp && (fr->fr_dcmp || fr->fr_scmp || fr->fr_tcpf ||
  503                                  fr->fr_tcpfm))
  504                         continue;
  505                 if (fi->fi_fl & FI_TCPUDP) {
  506                         if (!fr_tcpudpchk(fr, fin))
  507                                 continue;
  508                 } else if (fr->fr_icmpm || fr->fr_icmp) {
  509                         if ((fi->fi_p != IPPROTO_ICMP) || off ||
  510                             (fin->fin_dlen < 2))
  511                                 continue;
  512                         if ((fin->fin_data[0] & fr->fr_icmpm) != fr->fr_icmp) {
  513                                 FR_DEBUG(("i. %#x & %#x != %#x\n",
  514                                          fin->fin_data[0], fr->fr_icmpm,
  515                                          fr->fr_icmp));
  516                                 continue;
  517                         }
  518                 }
  519                 FR_VERBOSE(("*"));
  520                 /*
  521                  * Just log this packet...
  522                  */
  523                 if (!(skip = fr->fr_skip))
  524                         pass = fr->fr_flags;
  525                 if ((pass & FR_CALLNOW) && fr->fr_func)
  526                         pass = (*fr->fr_func)(pass, ip, fin);
  527 #ifdef  IPFILTER_LOG
  528                 if ((pass & FR_LOGMASK) == FR_LOG) {
  529                         if (!IPLLOG(fr->fr_flags, ip, fin, m))
  530                                 frstats[fin->fin_out].fr_skip++;
  531                         frstats[fin->fin_out].fr_pkl++;
  532                 }
  533 #endif /* IPFILTER_LOG */
  534                 FR_DEBUG(("pass %#x\n", pass));
  535                 fr->fr_hits++;
  536                 if (pass & FR_ACCOUNT)
  537                         fr->fr_bytes += (U_QUAD_T)ip->ip_len;
  538                 else
  539                         fin->fin_icode = fr->fr_icode;
  540                 fin->fin_rule = rulen;
  541                 fin->fin_group = fr->fr_group;
  542                 fin->fin_fr = fr;
  543                 if (fr->fr_grp) {
  544                         fin->fin_fr = fr->fr_grp;
  545                         pass = fr_scanlist(pass, ip, fin, m);
  546                         if (fin->fin_fr == NULL) {
  547                                 fin->fin_rule = rulen;
  548                                 fin->fin_group = fr->fr_group;
  549                                 fin->fin_fr = fr;
  550                         }
  551                 }
  552                 if (pass & FR_QUICK)
  553                         break;
  554         }
  555         return pass;
  556 }
  557 
  558 
  559 /*
  560  * frcheck - filter check
  561  * check using source and destination addresses/pors in a packet whether
  562  * or not to pass it on or not.
  563  */
  564 int fr_check(ip, hlen, ifp, out
  565 #if defined(_KERNEL) && SOLARIS
  566 , qif, mp)
  567 qif_t *qif;
  568 #else
  569 , mp)
  570 #endif
  571 mb_t **mp;
  572 ip_t *ip;
  573 int hlen;
  574 void *ifp;
  575 int out;
  576 {
  577         /*
  578          * The above really sucks, but short of writing a diff
  579          */
  580         fr_info_t frinfo, *fc;
  581         register fr_info_t *fin = &frinfo;
  582         frentry_t *fr = NULL;
  583         int pass, changed, apass, error = EHOSTUNREACH;
  584 #if !SOLARIS || !defined(_KERNEL)
  585         register mb_t *m = *mp;
  586 #endif
  587 
  588 #ifdef  _KERNEL
  589         mb_t *mc = NULL;
  590 # if !defined(__SVR4) && !defined(__svr4__)
  591 #  ifdef __sgi
  592         char hbuf[(0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8];
  593 #  endif
  594         int up;
  595 
  596 #ifdef M_CANFASTFWD
  597         /*
  598          * XXX For now, IP Filter and fast-forwarding of cached flows
  599          * XXX are mutually exclusive.  Eventually, IP Filter should
  600          * XXX get a "can-fast-forward" filter rule.
  601          */
  602         m->m_flags &= ~M_CANFASTFWD;
  603 #endif /* M_CANFASTFWD */
  604 
  605         if ((ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP ||
  606              ip->ip_p == IPPROTO_ICMP)) {
  607                 int plen = 0;
  608 
  609                 switch(ip->ip_p)
  610                 {
  611                 case IPPROTO_TCP:
  612                         plen = sizeof(tcphdr_t);
  613                         break;
  614                 case IPPROTO_UDP:
  615                         plen = sizeof(udphdr_t);
  616                         break;
  617                 case IPPROTO_ICMP:
  618                         /* 96 - enough for complete ICMP error IP header */
  619                         plen = sizeof(struct icmp) + sizeof(ip_t) + 8;
  620                         break;
  621                 }
  622                 up = MIN(hlen + plen, ip->ip_len);
  623 
  624                 if (up > m->m_len) {
  625 #ifdef __sgi /* Under IRIX, avoid m_pullup as it makes ping <hostname> panic */
  626                         if ((up > sizeof(hbuf)) || (m_length(m) < up)) {
  627                                 frstats[out].fr_pull[1]++;
  628                                 return -1;
  629                         }
  630                         m_copydata(m, 0, up, hbuf);
  631                         frstats[out].fr_pull[0]++;
  632                         ip = (ip_t *)hbuf;
  633 #else
  634 # ifndef linux
  635                         if ((*mp = m_pullup(m, up)) == 0) {
  636                                 frstats[out].fr_pull[1]++;
  637                                 return -1;
  638                         } else {
  639                                 frstats[out].fr_pull[0]++;
  640                                 m = *mp;
  641                                 ip = mtod(m, ip_t *);
  642                         }
  643 # endif
  644 #endif
  645                 } else
  646                         up = 0;
  647         } else
  648                 up = 0;
  649 # endif
  650 # if SOLARIS
  651         mb_t *m = qif->qf_m;
  652 # endif
  653 #endif
  654         fr_makefrip(hlen, ip, fin);
  655         fin->fin_ifp = ifp;
  656         fin->fin_out = out;
  657         fin->fin_mp = mp;
  658 
  659         MUTEX_ENTER(&ipf_mutex);
  660 
  661         /*
  662          * Check auth now.  This, combined with the check below to see if apass
  663          * is 0 is to ensure that we don't count the packet twice, which can
  664          * otherwise occur when we reprocess it.  As it is, we only count it
  665          * after it has no auth. table matchup.  This also stops NAT from
  666          * occuring until after the packet has been auth'd.
  667          */
  668         apass = fr_checkauth(ip, fin);
  669 
  670         if (!out) {
  671                 changed = ip_natin(ip, hlen, fin);
  672                 if (!apass && (fin->fin_fr = ipacct[0][fr_active]) &&
  673                     (FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT))
  674                         frstats[0].fr_acct++;
  675         }
  676 
  677         if (apass || (!(pass = ipfr_knownfrag(ip, fin)) &&
  678             !(pass = fr_checkstate(ip, fin)))) {
  679                 /*
  680                  * If a packet is found in the auth table, then skip checking
  681                  * the access lists for permission but we do need to consider
  682                  * the result as if it were from the ACL's.
  683                  */
  684                 if (!apass) {
  685                         fc = frcache + out;
  686                         if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) {
  687                                 /*
  688                                  * copy cached data so we can unlock the mutex
  689                                  * earlier.
  690                                  */
  691                                 bcopy((char *)fc, (char *)fin, FI_COPYSIZE);
  692                                 frstats[out].fr_chit++;
  693                                 if ((fr = fin->fin_fr)) {
  694                                         fr->fr_hits++;
  695                                         pass = fr->fr_flags;
  696                                 } else
  697                                         pass = fr_pass;
  698                         } else {
  699                                 pass = fr_pass;
  700                                 if ((fin->fin_fr = ipfilter[out][fr_active]))
  701                                         pass = FR_SCANLIST(fr_pass, ip, fin, m);
  702                                 bcopy((char *)fin, (char *)fc, FI_COPYSIZE);
  703                                 if (pass & FR_NOMATCH)
  704                                         frstats[out].fr_nom++;
  705                         }
  706                         fr = fin->fin_fr;
  707                 } else
  708                         pass = apass;
  709 
  710                 /*
  711                  * If we fail to add a packet to the authorization queue,
  712                  * then we drop the packet later.  However, if it was added
  713                  * then pretend we've dropped it already.
  714                  */
  715                 if ((pass & FR_AUTH))
  716                         if (FR_NEWAUTH(m, fin, ip, qif) != 0)
  717 #ifdef  _KERNEL
  718                                 m = *mp = NULL;
  719 #else
  720                                 ;
  721 #endif
  722 
  723                 if (pass & FR_PREAUTH) {
  724                         MUTEX_ENTER(&ipf_auth);
  725                         if ((fin->fin_fr = ipauth) &&
  726                             (pass = FR_SCANLIST(0, ip, fin, m)))
  727                                 fr_authstats.fas_hits++;
  728                         else
  729                                 fr_authstats.fas_miss++;
  730                         MUTEX_EXIT(&ipf_auth);
  731                 }
  732 
  733                 if (pass & FR_KEEPFRAG) {
  734                         if (fin->fin_fi.fi_fl & FI_FRAG) {
  735                                 if (ipfr_newfrag(ip, fin, pass) == -1)
  736                                         frstats[out].fr_bnfr++;
  737                                 else
  738                                         frstats[out].fr_nfr++;
  739                         } else
  740                                 frstats[out].fr_cfr++;
  741                 }
  742                 if (pass & FR_KEEPSTATE) {
  743                         if (fr_addstate(ip, fin, pass) == -1)
  744                                 frstats[out].fr_bads++;
  745                         else
  746                                 frstats[out].fr_ads++;
  747                 }
  748         }
  749 
  750         if (fr && fr->fr_func && !(pass & FR_CALLNOW))
  751                 pass = (*fr->fr_func)(pass, ip, fin);
  752 
  753         /*
  754          * Only count/translate packets which will be passed on, out the
  755          * interface.
  756          */
  757         if (out && (pass & FR_PASS)) {
  758                 if ((fin->fin_fr = ipacct[1][fr_active]) &&
  759                     (FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT))
  760                         frstats[1].fr_acct++;
  761                 fin->fin_fr = NULL;
  762                 changed = ip_natout(ip, hlen, fin);
  763         }
  764         fin->fin_fr = fr;
  765         MUTEX_EXIT(&ipf_mutex);
  766 
  767 #ifdef  IPFILTER_LOG
  768         if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
  769                 if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
  770                         pass |= FF_LOGNOMATCH;
  771                         frstats[out].fr_npkl++;
  772                         goto logit;
  773                 } else if (((pass & FR_LOGMASK) == FR_LOGP) ||
  774                     ((pass & FR_PASS) && (fr_flags & FF_LOGPASS))) {
  775                         if ((pass & FR_LOGMASK) != FR_LOGP)
  776                                 pass |= FF_LOGPASS;
  777                         frstats[out].fr_ppkl++;
  778                         goto logit;
  779                 } else if (((pass & FR_LOGMASK) == FR_LOGB) ||
  780                            ((pass & FR_BLOCK) && (fr_flags & FF_LOGBLOCK))) {
  781                         if ((pass & FR_LOGMASK) != FR_LOGB)
  782                                 pass |= FF_LOGBLOCK;
  783                         frstats[out].fr_bpkl++;
  784 logit:
  785                         if (!IPLLOG(pass, ip, fin, m)) {
  786                                 frstats[out].fr_skip++;
  787                                 if ((pass & (FR_PASS|FR_LOGORBLOCK)) ==
  788                                     (FR_PASS|FR_LOGORBLOCK))
  789                                         pass ^= FR_PASS|FR_BLOCK;
  790                         }
  791                 }
  792         }
  793 #endif /* IPFILTER_LOG */
  794 #ifdef  _KERNEL
  795         /*
  796          * Only allow FR_DUP to work if a rule matched - it makes no sense to
  797          * set FR_DUP as a "default" as there are no instructions about where
  798          * to send the packet.
  799          */
  800         if (fr && (pass & FR_DUP))
  801 # if    SOLARIS
  802                 mc = dupmsg(m);
  803 # else
  804 #  ifndef linux
  805                 mc = m_copy(m, 0, M_COPYALL);
  806 #  else
  807                 ;
  808 #  endif
  809 # endif
  810 #endif
  811         if (pass & FR_PASS)
  812                 frstats[out].fr_pass++;
  813         else if (pass & FR_BLOCK) {
  814                 frstats[out].fr_block++;
  815                 /*
  816                  * Should we return an ICMP packet to indicate error
  817                  * status passing through the packet filter ?
  818                  * WARNING: ICMP error packets AND TCP RST packets should
  819                  * ONLY be sent in repsonse to incoming packets.  Sending them
  820                  * in response to outbound packets can result in a panic on
  821                  * some operating systems.
  822                  */
  823                 if (!out) {
  824 #ifdef  _KERNEL
  825                         if (pass & FR_RETICMP) {
  826 # if SOLARIS
  827                                 ICMP_ERROR(q, ip, ICMP_UNREACH, fin->fin_icode,
  828                                            qif, ip->ip_src);
  829 # else
  830                                 ICMP_ERROR(m, ip, ICMP_UNREACH, fin->fin_icode,
  831                                            ifp, ip->ip_src);
  832                                 m = *mp = NULL; /* freed by icmp_error() */
  833 # endif
  834 
  835                                 frstats[0].fr_ret++;
  836                         } else if ((pass & FR_RETRST) &&
  837                                    !(fin->fin_fi.fi_fl & FI_SHORT)) {
  838                                 if (SEND_RESET(ip, qif, ifp) == 0)
  839                                         frstats[1].fr_ret++;
  840                         }
  841 #else
  842                         if (pass & FR_RETICMP) {
  843                                 verbose("- ICMP unreachable sent\n");
  844                                 frstats[0].fr_ret++;
  845                         } else if ((pass & FR_RETRST) &&
  846                                    !(fin->fin_fi.fi_fl & FI_SHORT)) {
  847                                 verbose("- TCP RST sent\n");
  848                                 frstats[1].fr_ret++;
  849                         }
  850 #endif
  851                 } else {
  852                         if (pass & FR_RETRST)
  853                                 error = ECONNRESET;
  854                 }
  855         }
  856 
  857         /*
  858          * If we didn't drop off the bottom of the list of rules (and thus
  859          * the 'current' rule fr is not NULL), then we may have some extra
  860          * instructions about what to do with a packet.
  861          * Once we're finished return to our caller, freeing the packet if
  862          * we are dropping it (* BSD ONLY *).
  863          */
  864 #if defined(_KERNEL)
  865 # if !SOLARIS
  866 #  if !defined(linux)
  867         if (fr) {
  868                 frdest_t *fdp = &fr->fr_tif;
  869 
  870                 if ((pass & FR_FASTROUTE) ||
  871                     (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) {
  872                         ipfr_fastroute(m, fin, fdp);
  873                         m = *mp = NULL;
  874                 }
  875                 if (mc)
  876                         ipfr_fastroute(mc, fin, &fr->fr_dif);
  877         }
  878         if (!(pass & FR_PASS) && m)
  879                 m_freem(m);
  880 #   ifdef __sgi
  881         else if (changed && up && m)
  882                 m_copyback(m, 0, up, hbuf);
  883 #   endif
  884 #  endif /* !linux */
  885         return (pass & FR_PASS) ? 0 : error;
  886 # else /* !SOLARIS */
  887         if (fr) {
  888                 frdest_t *fdp = &fr->fr_tif;
  889 
  890                 if ((pass & FR_FASTROUTE) ||
  891                     (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) {
  892                         ipfr_fastroute(qif, ip, m, mp, fin, fdp);
  893                         m = *mp = NULL;
  894                 }
  895                 if (mc)
  896                         ipfr_fastroute(qif, ip, mc, mp, fin, &fr->fr_dif);
  897         }
  898         return (pass & FR_PASS) ? changed : error;
  899 # endif /* !SOLARIS */
  900 #else /* _KERNEL */
  901         if (pass & FR_NOMATCH)
  902                 return 1;
  903         if (pass & FR_PASS)
  904                 return 0;
  905         if (pass & FR_AUTH)
  906                 return -2;
  907         return -1;
  908 #endif /* _KERNEL */
  909 }
  910 
  911 
  912 /*
  913  * ipf_cksum
  914  * addr should be 16bit aligned and len is in bytes.
  915  * length is in bytes
  916  */
  917 u_short ipf_cksum(addr, len)
  918 register u_short *addr;
  919 register int len;
  920 {
  921         register u_32_t sum = 0;
  922 
  923         for (sum = 0; len > 1; len -= 2)
  924                 sum += *addr++;
  925 
  926         /* mop up an odd byte, if necessary */
  927         if (len == 1)
  928                 sum += *(u_char *)addr;
  929 
  930         /*
  931          * add back carry outs from top 16 bits to low 16 bits
  932          */
  933         sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
  934         sum += (sum >> 16);                     /* add carry */
  935         return (u_short)(~sum);
  936 }
  937 
  938 
  939 /*
  940  * NB: This function assumes we've pullup'd enough for all of the IP header
  941  * and the TCP header.  We also assume that data blocks aren't allocated in
  942  * odd sizes.
  943  */
  944 u_short fr_tcpsum(m, ip, tcp, len)
  945 mb_t *m;
  946 ip_t *ip;
  947 tcphdr_t *tcp;
  948 int len;
  949 {
  950         union {
  951                 u_char  c[2];
  952                 u_short s;
  953         } bytes;
  954         u_32_t sum;
  955         u_short *sp;
  956 # if SOLARIS || defined(__sgi)
  957         int add, hlen;
  958 # endif
  959 
  960 # if SOLARIS
  961         /* skip any leading M_PROTOs */
  962         while(m && (MTYPE(m) != M_DATA))
  963                 m = m->b_cont;
  964         PANIC((!m),("fr_tcpsum: no M_DATA"));
  965 # endif
  966 
  967         /*
  968          * Add up IP Header portion
  969          */
  970         bytes.c[0] = 0;
  971         bytes.c[1] = IPPROTO_TCP;
  972         len -= (ip->ip_hl << 2);
  973         sum = bytes.s;
  974         sum += htons((u_short)len);
  975         sp = (u_short *)&ip->ip_src;
  976         sum += *sp++;
  977         sum += *sp++;
  978         sum += *sp++;
  979         sum += *sp++;
  980         if (sp != (u_short *)tcp)
  981                 sp = (u_short *)tcp;
  982         sum += *sp++;
  983         sum += *sp++;
  984         sum += *sp++;
  985         sum += *sp++;
  986         sum += *sp++;
  987         sum += *sp++;
  988         sum += *sp++;
  989         sum += *sp;
  990         sp += 2;        /* Skip over checksum */
  991         sum += *sp++;
  992 
  993 #if SOLARIS
  994         /*
  995          * In case we had to copy the IP & TCP header out of mblks,
  996          * skip over the mblk bits which are the header
  997          */
  998         if ((caddr_t)ip != (caddr_t)m->b_rptr) {
  999                 hlen = (caddr_t)sp - (caddr_t)ip;
 1000                 while (hlen) {
 1001                         add = MIN(hlen, m->b_wptr - m->b_rptr);
 1002                         sp = (u_short *)((caddr_t)m->b_rptr + add);
 1003                         hlen -= add;
 1004                         if ((caddr_t)sp >= (caddr_t)m->b_wptr) {
 1005                                 m = m->b_cont;
 1006                                 PANIC((!m),("fr_tcpsum: not enough data"));
 1007                                 if (!hlen)
 1008                                         sp = (u_short *)m->b_rptr;
 1009                         }
 1010                 }
 1011         }
 1012 #endif
 1013 #ifdef  __sgi
 1014         /*
 1015          * In case we had to copy the IP & TCP header out of mbufs,
 1016          * skip over the mbuf bits which are the header
 1017          */
 1018         if ((caddr_t)ip != mtod(m, caddr_t)) {
 1019                 hlen = (caddr_t)sp - (caddr_t)ip;
 1020                 while (hlen) {
 1021                         add = MIN(hlen, m->m_len);
 1022                         sp = (u_short *)(mtod(m, caddr_t) + add);
 1023                         hlen -= add;
 1024                         if (add >= m->m_len) {
 1025                                 m = m->m_next;
 1026                                 PANIC((!m),("fr_tcpsum: not enough data"));
 1027                                 if (!hlen)
 1028                                         sp = mtod(m, u_short *);
 1029                         }
 1030                 }
 1031         }
 1032 #endif
 1033 
 1034         if (!(len -= sizeof(*tcp)))
 1035                 goto nodata;
 1036         while (len > 0) {
 1037 #if SOLARIS
 1038                 while ((caddr_t)sp >= (caddr_t)m->b_wptr) {
 1039                         m = m->b_cont;
 1040                         PANIC((!m),("fr_tcpsum: not enough data"));
 1041                         sp = (u_short *)m->b_rptr;
 1042                 }
 1043 #else
 1044                 while (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len)
 1045                 {
 1046                         m = m->m_next;
 1047                         PANIC((!m),("fr_tcpsum: not enough data"));
 1048                         sp = mtod(m, u_short *);
 1049                 }
 1050 #endif /* SOLARIS */
 1051                 if (len < 2)
 1052                         break;
 1053                 if((u_32_t)sp & 1) {
 1054                         bcopy((char *)sp++, (char *)&bytes.s, sizeof(bytes.s));
 1055                         sum += bytes.s;
 1056                 } else
 1057                         sum += *sp++;
 1058                 len -= 2;
 1059         }
 1060         if (len) {
 1061                 bytes.c[1] = 0;
 1062                 bytes.c[0] = *(u_char *)sp;
 1063                 sum += bytes.s;
 1064         }
 1065 nodata:
 1066         sum = (sum >> 16) + (sum & 0xffff);
 1067         sum += (sum >> 16);
 1068         sum = (u_short)((~sum) & 0xffff);
 1069         return sum;
 1070 }
 1071 
 1072 
 1073 #if defined(_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || defined(__sgi) )
 1074 /*
 1075  * Copyright (c) 1982, 1986, 1988, 1991, 1993
 1076  *      The Regents of the University of California.  All rights reserved.
 1077  *
 1078  * Redistribution and use in source and binary forms, with or without
 1079  * modification, are permitted provided that the following conditions
 1080  * are met:
 1081  * 1. Redistributions of source code must retain the above copyright
 1082  *    notice, this list of conditions and the following disclaimer.
 1083  * 2. Redistributions in binary form must reproduce the above copyright
 1084  *    notice, this list of conditions and the following disclaimer in the
 1085  *    documentation and/or other materials provided with the distribution.
 1086  * 3. All advertising materials mentioning features or use of this software
 1087  *    must display the following acknowledgement:
 1088  *      This product includes software developed by the University of
 1089  *      California, Berkeley and its contributors.
 1090  * 4. Neither the name of the University nor the names of its contributors
 1091  *    may be used to endorse or promote products derived from this software
 1092  *    without specific prior written permission.
 1093  *
 1094  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 1095  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 1096  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 1097  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 1098  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 1099  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 1100  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 1101  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 1102  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 1103  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 1104  * SUCH DAMAGE.
 1105  *
 1106  *      @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
 1107  * $FreeBSD$
 1108  */
 1109 /*
 1110  * Copy data from an mbuf chain starting "off" bytes from the beginning,
 1111  * continuing for "len" bytes, into the indicated buffer.
 1112  */
 1113 void
 1114 m_copydata(m, off, len, cp)
 1115         register mb_t *m;
 1116         register int off;
 1117         register int len;
 1118         caddr_t cp;
 1119 {
 1120         register unsigned count;
 1121 
 1122         if (off < 0 || len < 0)
 1123                 panic("m_copydata");
 1124         while (off > 0) {
 1125                 if (m == 0)
 1126                         panic("m_copydata");
 1127                 if (off < m->m_len)
 1128                         break;
 1129                 off -= m->m_len;
 1130                 m = m->m_next;
 1131         }
 1132         while (len > 0) {
 1133                 if (m == 0)
 1134                         panic("m_copydata");
 1135                 count = MIN(m->m_len - off, len);
 1136                 bcopy(mtod(m, caddr_t) + off, cp, count);
 1137                 len -= count;
 1138                 cp += count;
 1139                 off = 0;
 1140                 m = m->m_next;
 1141         }
 1142 }
 1143 
 1144 
 1145 # ifndef linux
 1146 /*
 1147  * Copy data from a buffer back into the indicated mbuf chain,
 1148  * starting "off" bytes from the beginning, extending the mbuf
 1149  * chain if necessary.
 1150  */
 1151 void
 1152 m_copyback(m0, off, len, cp)
 1153         struct  mbuf *m0;
 1154         register int off;
 1155         register int len;
 1156         caddr_t cp;
 1157 {
 1158         register int mlen;
 1159         register struct mbuf *m = m0, *n;
 1160         int totlen = 0;
 1161 
 1162         if (m0 == 0)
 1163                 return;
 1164         while (off > (mlen = m->m_len)) {
 1165                 off -= mlen;
 1166                 totlen += mlen;
 1167                 if (m->m_next == 0) {
 1168                         n = m_getclr(M_DONTWAIT, m->m_type);
 1169                         if (n == 0)
 1170                                 goto out;
 1171                         n->m_len = min(MLEN, len + off);
 1172                         m->m_next = n;
 1173                 }
 1174                 m = m->m_next;
 1175         }
 1176         while (len > 0) {
 1177                 mlen = min (m->m_len - off, len);
 1178                 bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
 1179                 cp += mlen;
 1180                 len -= mlen;
 1181                 mlen += off;
 1182                 off = 0;
 1183                 totlen += mlen;
 1184                 if (len == 0)
 1185                         break;
 1186                 if (m->m_next == 0) {
 1187                         n = m_get(M_DONTWAIT, m->m_type);
 1188                         if (n == 0)
 1189                                 break;
 1190                         n->m_len = min(MLEN, len);
 1191                         m->m_next = n;
 1192                 }
 1193                 m = m->m_next;
 1194         }
 1195 out:
 1196 #if 0
 1197         if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
 1198                 m->m_pkthdr.len = totlen;
 1199 #endif
 1200         return;
 1201 }
 1202 # endif /* linux */
 1203 #endif /* (_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || __sgi) */
 1204 
 1205 
 1206 frgroup_t *fr_findgroup(num, flags, which, set, fgpp)
 1207 u_short num;
 1208 u_32_t flags;
 1209 int which, set;
 1210 frgroup_t ***fgpp;
 1211 {
 1212         frgroup_t *fg, **fgp;
 1213 
 1214         if (which == IPL_LOGAUTH)
 1215                 fgp = &ipfgroups[2][set];
 1216         else if (flags & FR_ACCOUNT)
 1217                 fgp = &ipfgroups[1][set];
 1218         else if (flags & (FR_OUTQUE|FR_INQUE))
 1219                 fgp = &ipfgroups[0][set];
 1220         else
 1221                 return NULL;
 1222 
 1223         while ((fg = *fgp))
 1224                 if (fg->fg_num == num)
 1225                         break;
 1226                 else
 1227                         fgp = &fg->fg_next;
 1228         if (fgpp)
 1229                 *fgpp = fgp;
 1230         return fg;
 1231 }
 1232 
 1233 
 1234 frgroup_t *fr_addgroup(num, fp, which, set)
 1235 u_short num;
 1236 frentry_t *fp;
 1237 int which, set;
 1238 {
 1239         frgroup_t *fg, **fgp;
 1240 
 1241         if ((fg = fr_findgroup(num, fp->fr_flags, which, set, &fgp)))
 1242                 return fg;
 1243 
 1244         KMALLOC(fg, frgroup_t *, sizeof(*fg));
 1245         if (fg) {
 1246                 fg->fg_num = num;
 1247                 fg->fg_next = *fgp;
 1248                 fg->fg_head = fp;
 1249                 fg->fg_start = &fp->fr_grp;
 1250                 *fgp = fg;
 1251         }
 1252         return fg;
 1253 }
 1254 
 1255 
 1256 void fr_delgroup(num, flags, which, set)
 1257 u_short num;
 1258 u_32_t flags;
 1259 int which, set;
 1260 {
 1261         frgroup_t *fg, **fgp;
 1262  
 1263         if (!(fg = fr_findgroup(num, flags, which, set, &fgp)))
 1264                 return;
 1265  
 1266         *fgp = fg->fg_next;
 1267         KFREE(fg);
 1268 }
 1269 
 1270 
 1271 
 1272 /*
 1273  * recursively flush rules from the list, descending groups as they are
 1274  * encountered.  if a rule is the head of a group and it has lost all its
 1275  * group members, then also delete the group reference.
 1276  */
 1277 static int frflushlist(set, unit, nfreedp, list, listp)
 1278 int set, unit, *nfreedp;
 1279 frentry_t *list, **listp;
 1280 {
 1281         register frentry_t *fp = list, *fpn;
 1282         register int freed = 0;
 1283 
 1284         while (fp) {
 1285                 fpn = fp->fr_next;
 1286                 if (fp->fr_grp) {
 1287                         fp->fr_ref -= frflushlist(set, unit, nfreedp,
 1288                                                   fp->fr_grp, &fp->fr_grp);
 1289                 }
 1290 
 1291                 if (fp->fr_ref == 1) {
 1292                         if (fp->fr_grhead)
 1293                                 fr_delgroup(fp->fr_grhead, fp->fr_flags, unit,
 1294                                             set);
 1295                         KFREE(fp);
 1296                         *listp = fpn;
 1297                         freed++;
 1298                 }
 1299                 fp = fpn;
 1300         }
 1301         *nfreedp += freed;
 1302         return freed;
 1303 }
 1304 
 1305 
 1306 void frflush(unit, result)
 1307 int unit;
 1308 int *result;
 1309 {
 1310         int flags = *result, flushed = 0, set = fr_active;
 1311 
 1312         bzero((char *)frcache, sizeof(frcache[0]) * 2);
 1313 
 1314         if (flags & FR_INACTIVE)
 1315                 set = 1 - set;
 1316 
 1317         if (unit == IPL_LOGIPF) {
 1318                 if (flags & FR_OUTQUE) {
 1319                         (void) frflushlist(set, unit, &flushed,
 1320                                            ipfilter[1][set],
 1321                                            &ipfilter[1][set]);
 1322                         (void) frflushlist(set, unit, &flushed,
 1323                                            ipacct[1][set], &ipacct[1][set]);
 1324                 }
 1325                 if (flags & FR_INQUE) {
 1326                         (void) frflushlist(set, unit, &flushed,
 1327                                            ipfilter[0][set],
 1328                                            &ipfilter[0][set]);
 1329                         (void) frflushlist(set, unit, &flushed,
 1330                                            ipacct[0][set], &ipacct[0][set]);
 1331                 }
 1332         }
 1333 
 1334         *result = flushed;
 1335 }

Cache object: d7674809d554b4fd60d4af725418ce1a


[ 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.