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