]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/contrib/ipfilter/netinet/ip_frag.c
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[FreeBSD/stable/10.git] / sys / contrib / ipfilter / netinet / ip_frag.c
1 /*      $FreeBSD$       */
2
3 /*
4  * Copyright (C) 2012 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 #if defined(KERNEL) || defined(_KERNEL)
9 # undef KERNEL
10 # undef _KERNEL
11 # define        KERNEL  1
12 # define        _KERNEL 1
13 #endif
14 #include <sys/errno.h>
15 #include <sys/types.h>
16 #include <sys/param.h>
17 #include <sys/time.h>
18 #include <sys/file.h>
19 #ifdef __hpux
20 # include <sys/timeout.h>
21 #endif
22 #if !defined(_KERNEL)
23 # include <stdio.h>
24 # include <string.h>
25 # include <stdlib.h>
26 # define _KERNEL
27 # ifdef __OpenBSD__
28 struct file;
29 # endif
30 # include <sys/uio.h>
31 # undef _KERNEL
32 #endif
33 #if defined(_KERNEL) && \
34     defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
35 # include <sys/filio.h>
36 # include <sys/fcntl.h>
37 #else
38 # include <sys/ioctl.h>
39 #endif
40 #if !defined(linux)
41 # include <sys/protosw.h>
42 #endif
43 #include <sys/socket.h>
44 #if defined(_KERNEL)
45 # include <sys/systm.h>
46 # if !defined(__SVR4) && !defined(__svr4__)
47 #  include <sys/mbuf.h>
48 # endif
49 #endif
50 #if !defined(__SVR4) && !defined(__svr4__)
51 # if defined(_KERNEL) && !defined(__sgi) && !defined(AIX)
52 #  include <sys/kernel.h>
53 # endif
54 #else
55 # include <sys/byteorder.h>
56 # ifdef _KERNEL
57 #  include <sys/dditypes.h>
58 # endif
59 # include <sys/stream.h>
60 # include <sys/kmem.h>
61 #endif
62 #include <net/if.h>
63 #ifdef sun
64 # include <net/af.h>
65 #endif
66 #include <netinet/in.h>
67 #include <netinet/in_systm.h>
68 #include <netinet/ip.h>
69 #if !defined(linux)
70 # include <netinet/ip_var.h>
71 #endif
72 #include <netinet/tcp.h>
73 #include <netinet/udp.h>
74 #include <netinet/ip_icmp.h>
75 #include "netinet/ip_compat.h"
76 #include <netinet/tcpip.h>
77 #include "netinet/ip_fil.h"
78 #include "netinet/ip_nat.h"
79 #include "netinet/ip_frag.h"
80 #include "netinet/ip_state.h"
81 #include "netinet/ip_auth.h"
82 #include "netinet/ip_lookup.h"
83 #include "netinet/ip_proxy.h"
84 #include "netinet/ip_sync.h"
85 /* END OF INCLUDES */
86
87 #if !defined(lint)
88 static const char sccsid[] = "@(#)ip_frag.c     1.11 3/24/96 (C) 1993-2000 Darren Reed";
89 static const char rcsid[] = "@(#)$FreeBSD$";
90 /* static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.12 2007/09/20 12:51:51 darrenr Exp $"; */
91 #endif
92
93
94 typedef struct ipf_frag_softc_s  {
95         ipfrwlock_t     ipfr_ipidfrag;
96         ipfrwlock_t     ipfr_frag;
97         ipfrwlock_t     ipfr_natfrag;
98         int             ipfr_size;
99         int             ipfr_ttl;
100         int             ipfr_lock;
101         int             ipfr_inited;
102         ipfr_t          *ipfr_list;
103         ipfr_t          **ipfr_tail;
104         ipfr_t          *ipfr_natlist;
105         ipfr_t          **ipfr_nattail;
106         ipfr_t          *ipfr_ipidlist;
107         ipfr_t          **ipfr_ipidtail;
108         ipfr_t          **ipfr_heads;
109         ipfr_t          **ipfr_nattab;
110         ipfr_t          **ipfr_ipidtab;
111         ipfrstat_t      ipfr_stats;
112 } ipf_frag_softc_t;
113
114
115 #ifdef USE_MUTEXES
116 static ipfr_t *ipfr_frag_new __P((ipf_main_softc_t *, ipf_frag_softc_t *,
117                                   fr_info_t *, u_32_t, ipfr_t **,
118                                   ipfrwlock_t *));
119 static ipfr_t *ipf_frag_lookup __P((ipf_main_softc_t *, ipf_frag_softc_t *, fr_info_t *, ipfr_t **, ipfrwlock_t *));
120 static void ipf_frag_deref __P((void *, ipfr_t **, ipfrwlock_t *));
121 static int ipf_frag_next __P((ipf_main_softc_t *, ipftoken_t *, ipfgeniter_t *,
122                               ipfr_t **, ipfrwlock_t *));
123 #else
124 static ipfr_t *ipfr_frag_new __P((ipf_main_softc_t *, ipf_frag_softc_t *,
125                                   fr_info_t *, u_32_t, ipfr_t **));
126 static ipfr_t *ipf_frag_lookup __P((ipf_main_softc_t *, ipf_frag_softc_t *, fr_info_t *, ipfr_t **));
127 static void ipf_frag_deref __P((void *, ipfr_t **));
128 static int ipf_frag_next __P((ipf_main_softc_t *, ipftoken_t *, ipfgeniter_t *,
129                               ipfr_t **));
130 #endif
131 static void ipf_frag_delete __P((ipf_main_softc_t *, ipfr_t *, ipfr_t ***));
132 static void ipf_frag_free __P((ipf_frag_softc_t *, ipfr_t *));
133
134 static frentry_t ipfr_block;
135
136 ipftuneable_t ipf_tuneables[] = {
137         { { (void *)offsetof(ipf_frag_softc_t, ipfr_size) },
138                 "frag_size",            1,      0x7fffffff,
139                 stsizeof(ipf_frag_softc_t, ipfr_size),
140                 IPFT_WRDISABLED,        NULL,   NULL },
141         { { (void *)offsetof(ipf_frag_softc_t, ipfr_ttl) },
142                 "frag_ttl",             1,      0x7fffffff,
143                 stsizeof(ipf_frag_softc_t, ipfr_ttl),
144                 0,                      NULL,   NULL },
145         { { NULL },
146                 NULL,                   0,      0,
147                 0,
148                 0,                      NULL,   NULL }
149 };
150
151 #define FBUMP(x)        softf->ipfr_stats.x++
152 #define FBUMPD(x)       do { softf->ipfr_stats.x++; DT(x); } while (0)
153
154
155 /* ------------------------------------------------------------------------ */
156 /* Function:    ipf_frag_main_load                                          */
157 /* Returns:     int - 0 == success, -1 == error                             */
158 /* Parameters:  Nil                                                         */
159 /*                                                                          */
160 /* Initialise the filter rule associted with blocked packets - everyone can */
161 /* use it.                                                                  */
162 /* ------------------------------------------------------------------------ */
163 int
164 ipf_frag_main_load()
165 {
166         bzero((char *)&ipfr_block, sizeof(ipfr_block));
167         ipfr_block.fr_flags = FR_BLOCK|FR_QUICK;
168         ipfr_block.fr_ref = 1;
169
170         return 0;
171 }
172
173
174 /* ------------------------------------------------------------------------ */
175 /* Function:    ipf_frag_main_unload                                        */
176 /* Returns:     int - 0 == success, -1 == error                             */
177 /* Parameters:  Nil                                                         */
178 /*                                                                          */
179 /* A null-op function that exists as a placeholder so that the flow in      */
180 /* other functions is obvious.                                              */
181 /* ------------------------------------------------------------------------ */
182 int
183 ipf_frag_main_unload()
184 {
185         return 0;
186 }
187
188
189 /* ------------------------------------------------------------------------ */
190 /* Function:    ipf_frag_soft_create                                        */
191 /* Returns:     void *   - NULL = failure, else pointer to local context    */
192 /* Parameters:  softc(I) - pointer to soft context main structure           */
193 /*                                                                          */
194 /* Allocate a new soft context structure to track fragment related info.    */
195 /* ------------------------------------------------------------------------ */
196 /*ARGSUSED*/
197 void *
198 ipf_frag_soft_create(softc)
199         ipf_main_softc_t *softc;
200 {
201         ipf_frag_softc_t *softf;
202
203         KMALLOC(softf, ipf_frag_softc_t *);
204         if (softf == NULL)
205                 return NULL;
206
207         bzero((char *)softf, sizeof(*softf));
208
209         RWLOCK_INIT(&softf->ipfr_ipidfrag, "frag ipid lock");
210         RWLOCK_INIT(&softf->ipfr_frag, "ipf fragment rwlock");
211         RWLOCK_INIT(&softf->ipfr_natfrag, "ipf NAT fragment rwlock");
212
213         softf->ipfr_size = IPFT_SIZE;
214         softf->ipfr_ttl = IPF_TTLVAL(60);
215         softf->ipfr_lock = 1;
216         softf->ipfr_tail = &softf->ipfr_list;
217         softf->ipfr_nattail = &softf->ipfr_natlist;
218         softf->ipfr_ipidtail = &softf->ipfr_ipidlist;
219
220         return softf;
221 }
222
223
224 /* ------------------------------------------------------------------------ */
225 /* Function:    ipf_frag_soft_destroy                                       */
226 /* Returns:     Nil                                                         */
227 /* Parameters:  softc(I) - pointer to soft context main structure           */
228 /*              arg(I)   - pointer to local context to use                  */
229 /*                                                                          */
230 /* Initialise the hash tables for the fragment cache lookups.               */
231 /* ------------------------------------------------------------------------ */
232 void
233 ipf_frag_soft_destroy(softc, arg)
234         ipf_main_softc_t *softc;
235         void *arg;
236 {
237         ipf_frag_softc_t *softf = arg;
238
239         RW_DESTROY(&softf->ipfr_ipidfrag);
240         RW_DESTROY(&softf->ipfr_frag);
241         RW_DESTROY(&softf->ipfr_natfrag);
242
243         KFREE(softf);
244 }
245
246
247 /* ------------------------------------------------------------------------ */
248 /* Function:    ipf_frag_soft_init                                          */
249 /* Returns:     int      - 0 == success, -1 == error                        */
250 /* Parameters:  softc(I) - pointer to soft context main structure           */
251 /*              arg(I)   - pointer to local context to use                  */
252 /*                                                                          */
253 /* Initialise the hash tables for the fragment cache lookups.               */
254 /* ------------------------------------------------------------------------ */
255 /*ARGSUSED*/
256 int
257 ipf_frag_soft_init(softc, arg)
258         ipf_main_softc_t *softc;
259         void *arg;
260 {
261         ipf_frag_softc_t *softf = arg;
262
263         KMALLOCS(softf->ipfr_heads, ipfr_t **,
264                  softf->ipfr_size * sizeof(ipfr_t *));
265         if (softf->ipfr_heads == NULL)
266                 return -1;
267
268         bzero((char *)softf->ipfr_heads, softf->ipfr_size * sizeof(ipfr_t *));
269
270         KMALLOCS(softf->ipfr_nattab, ipfr_t **,
271                  softf->ipfr_size * sizeof(ipfr_t *));
272         if (softf->ipfr_nattab == NULL)
273                 return -2;
274
275         bzero((char *)softf->ipfr_nattab, softf->ipfr_size * sizeof(ipfr_t *));
276
277         KMALLOCS(softf->ipfr_ipidtab, ipfr_t **,
278                  softf->ipfr_size * sizeof(ipfr_t *));
279         if (softf->ipfr_ipidtab == NULL)
280                 return -3;
281
282         bzero((char *)softf->ipfr_ipidtab,
283               softf->ipfr_size * sizeof(ipfr_t *));
284
285         softf->ipfr_lock = 0;
286         softf->ipfr_inited = 1;
287
288         return 0;
289 }
290
291
292 /* ------------------------------------------------------------------------ */
293 /* Function:    ipf_frag_soft_fini                                          */
294 /* Returns:     int      - 0 == success, -1 == error                        */
295 /* Parameters:  softc(I) - pointer to soft context main structure           */
296 /*              arg(I)   - pointer to local context to use                  */
297 /*                                                                          */
298 /* Free all memory allocated whilst running and from initialisation.        */
299 /* ------------------------------------------------------------------------ */
300 int
301 ipf_frag_soft_fini(softc, arg)
302         ipf_main_softc_t *softc;
303         void *arg;
304 {
305         ipf_frag_softc_t *softf = arg;
306
307         softf->ipfr_lock = 1;
308
309         if (softf->ipfr_inited == 1) {
310                 ipf_frag_clear(softc);
311
312                 softf->ipfr_inited = 0;
313         }
314
315         if (softf->ipfr_heads != NULL)
316                 KFREES(softf->ipfr_heads,
317                        softf->ipfr_size * sizeof(ipfr_t *));
318         softf->ipfr_heads = NULL;
319
320         if (softf->ipfr_nattab != NULL)
321                 KFREES(softf->ipfr_nattab,
322                        softf->ipfr_size * sizeof(ipfr_t *));
323         softf->ipfr_nattab = NULL;
324
325         if (softf->ipfr_ipidtab != NULL)
326                 KFREES(softf->ipfr_ipidtab,
327                        softf->ipfr_size * sizeof(ipfr_t *));
328         softf->ipfr_ipidtab = NULL;
329
330         return 0;
331 }
332
333
334 /* ------------------------------------------------------------------------ */
335 /* Function:    ipf_frag_set_lock                                           */
336 /* Returns:     Nil                                                         */
337 /* Parameters:  arg(I) - pointer to local context to use                    */
338 /*              tmp(I) - new value for lock                                 */
339 /*                                                                          */
340 /* Stub function that allows for external manipulation of ipfr_lock         */
341 /* ------------------------------------------------------------------------ */
342 void
343 ipf_frag_setlock(arg, tmp)
344         void *arg;
345         int tmp;
346 {
347         ipf_frag_softc_t *softf = arg;
348
349         softf->ipfr_lock = tmp;
350 }
351
352
353 /* ------------------------------------------------------------------------ */
354 /* Function:    ipf_frag_stats                                              */
355 /* Returns:     ipfrstat_t* - pointer to struct with current frag stats     */
356 /* Parameters:  arg(I) - pointer to local context to use                    */
357 /*                                                                          */
358 /* Updates ipfr_stats with current information and returns a pointer to it  */
359 /* ------------------------------------------------------------------------ */
360 ipfrstat_t *
361 ipf_frag_stats(arg)
362         void *arg;
363 {
364         ipf_frag_softc_t *softf = arg;
365
366         softf->ipfr_stats.ifs_table = softf->ipfr_heads;
367         softf->ipfr_stats.ifs_nattab = softf->ipfr_nattab;
368         return &softf->ipfr_stats;
369 }
370
371
372 /* ------------------------------------------------------------------------ */
373 /* Function:    ipfr_frag_new                                               */
374 /* Returns:     ipfr_t * - pointer to fragment cache state info or NULL     */
375 /* Parameters:  fin(I)   - pointer to packet information                    */
376 /*              table(I) - pointer to frag table to add to                  */
377 /*              lock(I)  - pointer to lock to get a write hold of           */
378 /*                                                                          */
379 /* Add a new entry to the fragment cache, registering it as having come     */
380 /* through this box, with the result of the filter operation.               */
381 /*                                                                          */
382 /* If this function succeeds, it returns with a write lock held on "lock".  */
383 /* If it fails, no lock is held on return.                                  */
384 /* ------------------------------------------------------------------------ */
385 static ipfr_t *
386 ipfr_frag_new(softc, softf, fin, pass, table
387 #ifdef USE_MUTEXES
388 , lock
389 #endif
390 )
391         ipf_main_softc_t *softc;
392         ipf_frag_softc_t *softf;
393         fr_info_t *fin;
394         u_32_t pass;
395         ipfr_t *table[];
396 #ifdef USE_MUTEXES
397         ipfrwlock_t *lock;
398 #endif
399 {
400         ipfr_t *fra, frag, *fran;
401         u_int idx, off;
402         frentry_t *fr;
403
404         if (softf->ipfr_stats.ifs_inuse >= softf->ipfr_size) {
405                 FBUMPD(ifs_maximum);
406                 return NULL;
407         }
408
409         if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) {
410                 FBUMPD(ifs_newbad);
411                 return NULL;
412         }
413
414         if (pass & FR_FRSTRICT) {
415                 if (fin->fin_off != 0) {
416                         FBUMPD(ifs_newrestrictnot0);
417                         return NULL;
418                 }
419         }
420
421         frag.ipfr_v = fin->fin_v;
422         idx = fin->fin_v;
423         frag.ipfr_p = fin->fin_p;
424         idx += fin->fin_p;
425         frag.ipfr_id = fin->fin_id;
426         idx += fin->fin_id;
427         frag.ipfr_source = fin->fin_fi.fi_src;
428         idx += frag.ipfr_src.s_addr;
429         frag.ipfr_dest = fin->fin_fi.fi_dst;
430         idx += frag.ipfr_dst.s_addr;
431         frag.ipfr_ifp = fin->fin_ifp;
432         idx *= 127;
433         idx %= softf->ipfr_size;
434
435         frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
436         frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
437         frag.ipfr_auth = fin->fin_fi.fi_auth;
438
439         off = fin->fin_off >> 3;
440         if (off == 0) {
441                 char *ptr;
442                 int end;
443
444 #ifdef USE_INET6
445                 if (fin->fin_v == 6) {
446
447                         ptr = (char *)fin->fin_fraghdr +
448                               sizeof(struct ip6_frag);
449                 } else
450 #endif
451                 {
452                         ptr = fin->fin_dp;
453                 }
454                 end = fin->fin_plen - (ptr - (char *)fin->fin_ip);
455                 frag.ipfr_firstend = end >> 3;
456         } else {
457                 frag.ipfr_firstend = 0;
458         }
459
460         /*
461          * allocate some memory, if possible, if not, just record that we
462          * failed to do so.
463          */
464         KMALLOC(fran, ipfr_t *);
465         if (fran == NULL) {
466                 FBUMPD(ifs_nomem);
467                 return NULL;
468         }
469
470         WRITE_ENTER(lock);
471
472         /*
473          * first, make sure it isn't already there...
474          */
475         for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext)
476                 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp,
477                           IPFR_CMPSZ)) {
478                         RWLOCK_EXIT(lock);
479                         FBUMPD(ifs_exists);
480                         KFREE(fra);
481                         return NULL;
482                 }
483
484         fra = fran;
485         fran = NULL;
486         fr = fin->fin_fr;
487         fra->ipfr_rule = fr;
488         if (fr != NULL) {
489                 MUTEX_ENTER(&fr->fr_lock);
490                 fr->fr_ref++;
491                 MUTEX_EXIT(&fr->fr_lock);
492         }
493
494         /*
495          * Insert the fragment into the fragment table, copy the struct used
496          * in the search using bcopy rather than reassign each field.
497          * Set the ttl to the default.
498          */
499         if ((fra->ipfr_hnext = table[idx]) != NULL)
500                 table[idx]->ipfr_hprev = &fra->ipfr_hnext;
501         fra->ipfr_hprev = table + idx;
502         fra->ipfr_data = NULL;
503         table[idx] = fra;
504         bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ);
505         fra->ipfr_v = fin->fin_v;
506         fra->ipfr_ttl = softc->ipf_ticks + softf->ipfr_ttl;
507         fra->ipfr_firstend = frag.ipfr_firstend;
508
509         /*
510          * Compute the offset of the expected start of the next packet.
511          */
512         if (off == 0)
513                 fra->ipfr_seen0 = 1;
514         fra->ipfr_off = off + (fin->fin_dlen >> 3);
515         fra->ipfr_pass = pass;
516         fra->ipfr_ref = 1;
517         fra->ipfr_pkts = 1;
518         fra->ipfr_bytes = fin->fin_plen;
519         FBUMP(ifs_inuse);
520         FBUMP(ifs_new);
521         return fra;
522 }
523
524
525 /* ------------------------------------------------------------------------ */
526 /* Function:    ipf_frag_new                                                */
527 /* Returns:     int - 0 == success, -1 == error                             */
528 /* Parameters:  fin(I)  - pointer to packet information                     */
529 /*                                                                          */
530 /* Add a new entry to the fragment cache table based on the current packet  */
531 /* ------------------------------------------------------------------------ */
532 int
533 ipf_frag_new(softc, fin, pass)
534         ipf_main_softc_t *softc;
535         u_32_t pass;
536         fr_info_t *fin;
537 {
538         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
539         ipfr_t  *fra;
540
541         if (softf->ipfr_lock != 0)
542                 return -1;
543
544 #ifdef USE_MUTEXES
545         fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_heads, &softc->ipf_frag);
546 #else
547         fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_heads);
548 #endif
549         if (fra != NULL) {
550                 *softf->ipfr_tail = fra;
551                 fra->ipfr_prev = softf->ipfr_tail;
552                 softf->ipfr_tail = &fra->ipfr_next;
553                 fra->ipfr_next = NULL;
554                 RWLOCK_EXIT(&softc->ipf_frag);
555         }
556         return fra ? 0 : -1;
557 }
558
559
560 /* ------------------------------------------------------------------------ */
561 /* Function:    ipf_frag_natnew                                             */
562 /* Returns:     int - 0 == success, -1 == error                             */
563 /* Parameters:  fin(I)  - pointer to packet information                     */
564 /*              nat(I)  - pointer to NAT structure                          */
565 /*                                                                          */
566 /* Create a new NAT fragment cache entry based on the current packet and    */
567 /* the NAT structure for this "session".                                    */
568 /* ------------------------------------------------------------------------ */
569 int
570 ipf_frag_natnew(softc, fin, pass, nat)
571         ipf_main_softc_t *softc;
572         fr_info_t *fin;
573         u_32_t pass;
574         nat_t *nat;
575 {
576         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
577         ipfr_t  *fra;
578
579         if (softf->ipfr_lock != 0)
580                 return 0;
581
582 #ifdef USE_MUTEXES
583         fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_nattab,
584                             &softf->ipfr_natfrag);
585 #else
586         fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_nattab);
587 #endif
588         if (fra != NULL) {
589                 fra->ipfr_data = nat;
590                 nat->nat_data = fra;
591                 *softf->ipfr_nattail = fra;
592                 fra->ipfr_prev = softf->ipfr_nattail;
593                 softf->ipfr_nattail = &fra->ipfr_next;
594                 fra->ipfr_next = NULL;
595                 RWLOCK_EXIT(&softf->ipfr_natfrag);
596                 return 0;
597         }
598         return -1;
599 }
600
601
602 /* ------------------------------------------------------------------------ */
603 /* Function:    ipf_frag_ipidnew                                            */
604 /* Returns:     int - 0 == success, -1 == error                             */
605 /* Parameters:  fin(I)  - pointer to packet information                     */
606 /*              ipid(I) - new IP ID for this fragmented packet              */
607 /*                                                                          */
608 /* Create a new fragment cache entry for this packet and store, as a data   */
609 /* pointer, the new IP ID value.                                            */
610 /* ------------------------------------------------------------------------ */
611 int
612 ipf_frag_ipidnew(fin, ipid)
613         fr_info_t *fin;
614         u_32_t ipid;
615 {
616         ipf_main_softc_t *softc = fin->fin_main_soft;
617         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
618         ipfr_t  *fra;
619
620         if (softf->ipfr_lock)
621                 return 0;
622
623 #ifdef USE_MUTEXES
624         fra = ipfr_frag_new(softc, softf, fin, 0, softf->ipfr_ipidtab, &softf->ipfr_ipidfrag);
625 #else
626         fra = ipfr_frag_new(softc, softf, fin, 0, softf->ipfr_ipidtab);
627 #endif
628         if (fra != NULL) {
629                 fra->ipfr_data = (void *)(intptr_t)ipid;
630                 *softf->ipfr_ipidtail = fra;
631                 fra->ipfr_prev = softf->ipfr_ipidtail;
632                 softf->ipfr_ipidtail = &fra->ipfr_next;
633                 fra->ipfr_next = NULL;
634                 RWLOCK_EXIT(&softf->ipfr_ipidfrag);
635         }
636         return fra ? 0 : -1;
637 }
638
639
640 /* ------------------------------------------------------------------------ */
641 /* Function:    ipf_frag_lookup                                             */
642 /* Returns:     ipfr_t * - pointer to ipfr_t structure if there's a         */
643 /*                         matching entry in the frag table, else NULL      */
644 /* Parameters:  fin(I)   - pointer to packet information                    */
645 /*              table(I) - pointer to fragment cache table to search        */
646 /*                                                                          */
647 /* Check the fragment cache to see if there is already a record of this     */
648 /* packet with its filter result known.                                     */
649 /*                                                                          */
650 /* If this function succeeds, it returns with a write lock held on "lock".  */
651 /* If it fails, no lock is held on return.                                  */
652 /* ------------------------------------------------------------------------ */
653 static ipfr_t *
654 ipf_frag_lookup(softc, softf, fin, table
655 #ifdef USE_MUTEXES
656 , lock
657 #endif
658 )
659         ipf_main_softc_t *softc;
660         ipf_frag_softc_t *softf;
661         fr_info_t *fin;
662         ipfr_t *table[];
663 #ifdef USE_MUTEXES
664         ipfrwlock_t *lock;
665 #endif
666 {
667         ipfr_t *f, frag;
668         u_int idx;
669
670         /*
671          * We don't want to let short packets match because they could be
672          * compromising the security of other rules that want to match on
673          * layer 4 fields (and can't because they have been fragmented off.)
674          * Why do this check here?  The counter acts as an indicator of this
675          * kind of attack, whereas if it was elsewhere, it wouldn't know if
676          * other matching packets had been seen.
677          */
678         if (fin->fin_flx & FI_SHORT) {
679                 FBUMPD(ifs_short);
680                 return NULL;
681         }
682
683         if ((fin->fin_flx & FI_BAD) != 0) {
684                 FBUMPD(ifs_bad);
685                 return NULL;
686         }
687
688         /*
689          * For fragments, we record protocol, packet id, TOS and both IP#'s
690          * (these should all be the same for all fragments of a packet).
691          *
692          * build up a hash value to index the table with.
693          */
694         frag.ipfr_v = fin->fin_v;
695         idx = fin->fin_v;
696         frag.ipfr_p = fin->fin_p;
697         idx += fin->fin_p;
698         frag.ipfr_id = fin->fin_id;
699         idx += fin->fin_id;
700         frag.ipfr_source = fin->fin_fi.fi_src;
701         idx += frag.ipfr_src.s_addr;
702         frag.ipfr_dest = fin->fin_fi.fi_dst;
703         idx += frag.ipfr_dst.s_addr;
704         frag.ipfr_ifp = fin->fin_ifp;
705         idx *= 127;
706         idx %= softf->ipfr_size;
707
708         frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
709         frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
710         frag.ipfr_auth = fin->fin_fi.fi_auth;
711
712         READ_ENTER(lock);
713
714         /*
715          * check the table, careful to only compare the right amount of data
716          */
717         for (f = table[idx]; f; f = f->ipfr_hnext) {
718                 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp,
719                           IPFR_CMPSZ)) {
720                         u_short off;
721
722                         /*
723                          * XXX - We really need to be guarding against the
724                          * retransmission of (src,dst,id,offset-range) here
725                          * because a fragmented packet is never resent with
726                          * the same IP ID# (or shouldn't).
727                          */
728                         off = fin->fin_off >> 3;
729                         if (f->ipfr_seen0) {
730                                 if (off == 0) {
731                                         FBUMPD(ifs_retrans0);
732                                         continue;
733                                 }
734
735                                 /*
736                                  * Case 3. See comment for frpr_fragment6.
737                                  */
738                                 if ((f->ipfr_firstend != 0) &&
739                                     (off < f->ipfr_firstend)) {
740                                         FBUMP(ifs_overlap);
741                                         DT2(ifs_overlap, u_short, off,
742                                             ipfr_t *, f);
743                                         fin->fin_flx |= FI_BAD;
744                                         break;
745                                 }
746                         } else if (off == 0)
747                                 f->ipfr_seen0 = 1;
748
749                         if (f != table[idx]) {
750                                 ipfr_t **fp;
751
752                                 /*
753                                  * Move fragment info. to the top of the list
754                                  * to speed up searches.  First, delink...
755                                  */
756                                 fp = f->ipfr_hprev;
757                                 (*fp) = f->ipfr_hnext;
758                                 if (f->ipfr_hnext != NULL)
759                                         f->ipfr_hnext->ipfr_hprev = fp;
760                                 /*
761                                  * Then put back at the top of the chain.
762                                  */
763                                 f->ipfr_hnext = table[idx];
764                                 table[idx]->ipfr_hprev = &f->ipfr_hnext;
765                                 f->ipfr_hprev = table + idx;
766                                 table[idx] = f;
767                         }
768
769                         /*
770                          * If we've follwed the fragments, and this is the
771                          * last (in order), shrink expiration time.
772                          */
773                         if (off == f->ipfr_off) {
774                                 f->ipfr_off = (fin->fin_dlen >> 3) + off;
775
776                                 /*
777                                  * Well, we could shrink the expiration time
778                                  * but only if every fragment has been seen
779                                  * in order upto this, the last. ipfr_badorder
780                                  * is used here to count those out of order
781                                  * and if it equals 0 when we get to the last
782                                  * fragment then we can assume all of the
783                                  * fragments have been seen and in order.
784                                  */
785 #if 0
786                                 /*
787                                  * Doing this properly requires moving it to
788                                  * the head of the list which is infesible.
789                                  */
790                                 if ((more == 0) && (f->ipfr_badorder == 0))
791                                         f->ipfr_ttl = softc->ipf_ticks + 1;
792 #endif
793                         } else {
794                                 f->ipfr_badorder++;
795                                 FBUMPD(ifs_unordered);
796                                 if (f->ipfr_pass & FR_FRSTRICT) {
797                                         FBUMPD(ifs_strict);
798                                         continue;
799                                 }
800                         }
801                         f->ipfr_pkts++;
802                         f->ipfr_bytes += fin->fin_plen;
803                         FBUMP(ifs_hits);
804                         return f;
805                 }
806         }
807
808         RWLOCK_EXIT(lock);
809         FBUMP(ifs_miss);
810         return NULL;
811 }
812
813
814 /* ------------------------------------------------------------------------ */
815 /* Function:    ipf_frag_natknown                                           */
816 /* Returns:     nat_t* - pointer to 'parent' NAT structure if frag table    */
817 /*                       match found, else NULL                             */
818 /* Parameters:  fin(I)  - pointer to packet information                     */
819 /*                                                                          */
820 /* Functional interface for NAT lookups of the NAT fragment cache           */
821 /* ------------------------------------------------------------------------ */
822 nat_t *
823 ipf_frag_natknown(fin)
824         fr_info_t *fin;
825 {
826         ipf_main_softc_t *softc = fin->fin_main_soft;
827         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
828         nat_t   *nat;
829         ipfr_t  *ipf;
830
831         if ((softf->ipfr_lock) || !softf->ipfr_natlist)
832                 return NULL;
833 #ifdef USE_MUTEXES
834         ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab,
835                               &softf->ipfr_natfrag);
836 #else
837         ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab);
838 #endif
839         if (ipf != NULL) {
840                 nat = ipf->ipfr_data;
841                 /*
842                  * This is the last fragment for this packet.
843                  */
844                 if ((ipf->ipfr_ttl == softc->ipf_ticks + 1) && (nat != NULL)) {
845                         nat->nat_data = NULL;
846                         ipf->ipfr_data = NULL;
847                 }
848                 RWLOCK_EXIT(&softf->ipfr_natfrag);
849         } else
850                 nat = NULL;
851         return nat;
852 }
853
854
855 /* ------------------------------------------------------------------------ */
856 /* Function:    ipf_frag_ipidknown                                          */
857 /* Returns:     u_32_t - IPv4 ID for this packet if match found, else       */
858 /*                       return 0xfffffff to indicate no match.             */
859 /* Parameters:  fin(I) - pointer to packet information                      */
860 /*                                                                          */
861 /* Functional interface for IP ID lookups of the IP ID fragment cache       */
862 /* ------------------------------------------------------------------------ */
863 u_32_t
864 ipf_frag_ipidknown(fin)
865         fr_info_t *fin;
866 {
867         ipf_main_softc_t *softc = fin->fin_main_soft;
868         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
869         ipfr_t  *ipf;
870         u_32_t  id;
871
872         if (softf->ipfr_lock || !softf->ipfr_ipidlist)
873                 return 0xffffffff;
874
875 #ifdef USE_MUTEXES
876         ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab,
877                               &softf->ipfr_ipidfrag);
878 #else
879         ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab);
880 #endif
881         if (ipf != NULL) {
882                 id = (u_32_t)(intptr_t)ipf->ipfr_data;
883                 RWLOCK_EXIT(&softf->ipfr_ipidfrag);
884         } else
885                 id = 0xffffffff;
886         return id;
887 }
888
889
890 /* ------------------------------------------------------------------------ */
891 /* Function:    ipf_frag_known                                              */
892 /* Returns:     frentry_t* - pointer to filter rule if a match is found in  */
893 /*                           the frag cache table, else NULL.               */
894 /* Parameters:  fin(I)   - pointer to packet information                    */
895 /*              passp(O) - pointer to where to store rule flags resturned   */
896 /*                                                                          */
897 /* Functional interface for normal lookups of the fragment cache.  If a     */
898 /* match is found, return the rule pointer and flags from the rule, except  */
899 /* that if FR_LOGFIRST is set, reset FR_LOG.                                */
900 /* ------------------------------------------------------------------------ */
901 frentry_t *
902 ipf_frag_known(fin, passp)
903         fr_info_t *fin;
904         u_32_t *passp;
905 {
906         ipf_main_softc_t *softc = fin->fin_main_soft;
907         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
908         frentry_t *fr = NULL;
909         ipfr_t  *fra;
910         u_32_t pass;
911
912         if ((softf->ipfr_lock) || (softf->ipfr_list == NULL))
913                 return NULL;
914
915 #ifdef USE_MUTEXES
916         fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads,
917                               &softc->ipf_frag);
918 #else
919         fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads);
920 #endif
921         if (fra != NULL) {
922                 if (fin->fin_flx & FI_BAD) {
923                         fr = &ipfr_block;
924                         fin->fin_reason = FRB_BADFRAG;
925                 } else {
926                         fr = fra->ipfr_rule;
927                 }
928                 fin->fin_fr = fr;
929                 if (fr != NULL) {
930                         pass = fr->fr_flags;
931                         if ((pass & FR_KEEPSTATE) != 0) {
932                                 fin->fin_flx |= FI_STATE;
933                                 /*
934                                  * Reset the keep state flag here so that we
935                                  * don't try and add a new state entry because
936                                  * of a match here. That leads to blocking of
937                                  * the packet later because the add fails.
938                                  */
939                                 pass &= ~FR_KEEPSTATE;
940                         }
941                         if ((pass & FR_LOGFIRST) != 0)
942                                 pass &= ~(FR_LOGFIRST|FR_LOG);
943                         *passp = pass;
944                 }
945                 RWLOCK_EXIT(&softc->ipf_frag);
946         }
947         return fr;
948 }
949
950
951 /* ------------------------------------------------------------------------ */
952 /* Function:    ipf_frag_natforget                                          */
953 /* Returns:     Nil                                                         */
954 /* Parameters:  ptr(I) - pointer to data structure                          */
955 /*                                                                          */
956 /* Search through all of the fragment cache entries for NAT and wherever a  */
957 /* pointer  is found to match ptr, reset it to NULL.                        */
958 /* ------------------------------------------------------------------------ */
959 void
960 ipf_frag_natforget(softc, ptr)
961         ipf_main_softc_t *softc;
962         void *ptr;
963 {
964         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
965         ipfr_t  *fr;
966
967         WRITE_ENTER(&softf->ipfr_natfrag);
968         for (fr = softf->ipfr_natlist; fr; fr = fr->ipfr_next)
969                 if (fr->ipfr_data == ptr)
970                         fr->ipfr_data = NULL;
971         RWLOCK_EXIT(&softf->ipfr_natfrag);
972 }
973
974
975 /* ------------------------------------------------------------------------ */
976 /* Function:    ipf_frag_delete                                             */
977 /* Returns:     Nil                                                         */
978 /* Parameters:  fra(I)   - pointer to fragment structure to delete          */
979 /*              tail(IO) - pointer to the pointer to the tail of the frag   */
980 /*                         list                                             */
981 /*                                                                          */
982 /* Remove a fragment cache table entry from the table & list.  Also free    */
983 /* the filter rule it is associated with it if it is no longer used as a    */
984 /* result of decreasing the reference count.                                */
985 /* ------------------------------------------------------------------------ */
986 static void
987 ipf_frag_delete(softc, fra, tail)
988         ipf_main_softc_t *softc;
989         ipfr_t *fra, ***tail;
990 {
991         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
992
993         if (fra->ipfr_next)
994                 fra->ipfr_next->ipfr_prev = fra->ipfr_prev;
995         *fra->ipfr_prev = fra->ipfr_next;
996         if (*tail == &fra->ipfr_next)
997                 *tail = fra->ipfr_prev;
998
999         if (fra->ipfr_hnext)
1000                 fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev;
1001         *fra->ipfr_hprev = fra->ipfr_hnext;
1002
1003         if (fra->ipfr_rule != NULL) {
1004                 (void) ipf_derefrule(softc, &fra->ipfr_rule);
1005         }
1006
1007         if (fra->ipfr_ref <= 0)
1008                 ipf_frag_free(softf, fra);
1009 }
1010
1011
1012 /* ------------------------------------------------------------------------ */
1013 /* Function:    ipf_frag_free                                               */
1014 /* Returns:     Nil                                                         */
1015 /*                                                                          */
1016 /* ------------------------------------------------------------------------ */
1017 static void
1018 ipf_frag_free(softf, fra)
1019         ipf_frag_softc_t *softf;
1020         ipfr_t *fra;
1021 {
1022         KFREE(fra);
1023         FBUMP(ifs_expire);
1024         softf->ipfr_stats.ifs_inuse--;
1025 }
1026
1027
1028 /* ------------------------------------------------------------------------ */
1029 /* Function:    ipf_frag_clear                                              */
1030 /* Returns:     Nil                                                         */
1031 /* Parameters:  Nil                                                         */
1032 /*                                                                          */
1033 /* Free memory in use by fragment state information kept.  Do the normal    */
1034 /* fragment state stuff first and then the NAT-fragment table.              */
1035 /* ------------------------------------------------------------------------ */
1036 void
1037 ipf_frag_clear(softc)
1038         ipf_main_softc_t *softc;
1039 {
1040         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1041         ipfr_t  *fra;
1042         nat_t   *nat;
1043
1044         WRITE_ENTER(&softc->ipf_frag);
1045         while ((fra = softf->ipfr_list) != NULL) {
1046                 fra->ipfr_ref--;
1047                 ipf_frag_delete(softc, fra, &softf->ipfr_tail);
1048         }
1049         softf->ipfr_tail = &softf->ipfr_list;
1050         RWLOCK_EXIT(&softc->ipf_frag);
1051
1052         WRITE_ENTER(&softc->ipf_nat);
1053         WRITE_ENTER(&softf->ipfr_natfrag);
1054         while ((fra = softf->ipfr_natlist) != NULL) {
1055                 nat = fra->ipfr_data;
1056                 if (nat != NULL) {
1057                         if (nat->nat_data == fra)
1058                                 nat->nat_data = NULL;
1059                 }
1060                 fra->ipfr_ref--;
1061                 ipf_frag_delete(softc, fra, &softf->ipfr_nattail);
1062         }
1063         softf->ipfr_nattail = &softf->ipfr_natlist;
1064         RWLOCK_EXIT(&softf->ipfr_natfrag);
1065         RWLOCK_EXIT(&softc->ipf_nat);
1066 }
1067
1068
1069 /* ------------------------------------------------------------------------ */
1070 /* Function:    ipf_frag_expire                                             */
1071 /* Returns:     Nil                                                         */
1072 /* Parameters:  Nil                                                         */
1073 /*                                                                          */
1074 /* Expire entries in the fragment cache table that have been there too long */
1075 /* ------------------------------------------------------------------------ */
1076 void
1077 ipf_frag_expire(softc)
1078         ipf_main_softc_t *softc;
1079 {
1080         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1081         ipfr_t  **fp, *fra;
1082         nat_t   *nat;
1083         SPL_INT(s);
1084
1085         if (softf->ipfr_lock)
1086                 return;
1087
1088         SPL_NET(s);
1089         WRITE_ENTER(&softc->ipf_frag);
1090         /*
1091          * Go through the entire table, looking for entries to expire,
1092          * which is indicated by the ttl being less than or equal to ipf_ticks.
1093          */
1094         for (fp = &softf->ipfr_list; ((fra = *fp) != NULL); ) {
1095                 if (fra->ipfr_ttl > softc->ipf_ticks)
1096                         break;
1097                 fra->ipfr_ref--;
1098                 ipf_frag_delete(softc, fra, &softf->ipfr_tail);
1099         }
1100         RWLOCK_EXIT(&softc->ipf_frag);
1101
1102         WRITE_ENTER(&softf->ipfr_ipidfrag);
1103         for (fp = &softf->ipfr_ipidlist; ((fra = *fp) != NULL); ) {
1104                 if (fra->ipfr_ttl > softc->ipf_ticks)
1105                         break;
1106                 fra->ipfr_ref--;
1107                 ipf_frag_delete(softc, fra, &softf->ipfr_ipidtail);
1108         }
1109         RWLOCK_EXIT(&softf->ipfr_ipidfrag);
1110
1111         /*
1112          * Same again for the NAT table, except that if the structure also
1113          * still points to a NAT structure, and the NAT structure points back
1114          * at the one to be free'd, NULL the reference from the NAT struct.
1115          * NOTE: We need to grab both mutex's early, and in this order so as
1116          * to prevent a deadlock if both try to expire at the same time.
1117          * The extra if() statement here is because it locks out all NAT
1118          * operations - no need to do that if there are no entries in this
1119          * list, right?
1120          */
1121         if (softf->ipfr_natlist != NULL) {
1122                 WRITE_ENTER(&softc->ipf_nat);
1123                 WRITE_ENTER(&softf->ipfr_natfrag);
1124                 for (fp = &softf->ipfr_natlist; ((fra = *fp) != NULL); ) {
1125                         if (fra->ipfr_ttl > softc->ipf_ticks)
1126                                 break;
1127                         nat = fra->ipfr_data;
1128                         if (nat != NULL) {
1129                                 if (nat->nat_data == fra)
1130                                         nat->nat_data = NULL;
1131                         }
1132                         fra->ipfr_ref--;
1133                         ipf_frag_delete(softc, fra, &softf->ipfr_nattail);
1134                 }
1135                 RWLOCK_EXIT(&softf->ipfr_natfrag);
1136                 RWLOCK_EXIT(&softc->ipf_nat);
1137         }
1138         SPL_X(s);
1139 }
1140
1141
1142 /* ------------------------------------------------------------------------ */
1143 /* Function:    ipf_frag_pkt_next                                           */
1144 /* ------------------------------------------------------------------------ */
1145 int
1146 ipf_frag_pkt_next(softc, token, itp)
1147         ipf_main_softc_t *softc;
1148         ipftoken_t *token;
1149         ipfgeniter_t *itp;
1150 {
1151         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1152
1153 #ifdef USE_MUTEXES
1154         return ipf_frag_next(softc, token, itp, &softf->ipfr_list,
1155                              &softf->ipfr_frag);
1156 #else
1157         return ipf_frag_next(softc, token, itp, &softf->ipfr_list);
1158 #endif
1159 }
1160
1161
1162 /* ------------------------------------------------------------------------ */
1163 /* Function:    ipf_frag_nat_next                                           */
1164 /* ------------------------------------------------------------------------ */
1165 int
1166 ipf_frag_nat_next(softc, token, itp)
1167         ipf_main_softc_t *softc;
1168         ipftoken_t *token;
1169         ipfgeniter_t *itp;
1170 {
1171         ipf_frag_softc_t *softf = softc->ipf_frag_soft;;
1172
1173 #ifdef USE_MUTEXES
1174         return ipf_frag_next(softc, token, itp, &softf->ipfr_natlist, 
1175                              &softf->ipfr_natfrag);
1176 #else
1177         return ipf_frag_next(softc, token, itp, &softf->ipfr_natlist);
1178 #endif
1179 }
1180
1181 /* ------------------------------------------------------------------------ */
1182 /* Function:    ipf_frag_next                                               */
1183 /* Returns:     int      - 0 == success, else error                         */
1184 /* Parameters:  token(I) - pointer to token information for this caller     */
1185 /*              itp(I)   - pointer to generic iterator from caller          */
1186 /*              top(I)   - top of the fragment list                         */
1187 /*              lock(I)  - fragment cache lock                              */
1188 /*                                                                          */
1189 /* This function is used to interate through the list of entries in the     */
1190 /* fragment cache.  It increases the reference count on the one currently   */
1191 /* being returned so that the caller can come back and resume from it later.*/
1192 /*                                                                          */
1193 /* This function is used for both the NAT fragment cache as well as the ipf */
1194 /* fragment cache - hence the reason for passing in top and lock.           */
1195 /* ------------------------------------------------------------------------ */
1196 static int
1197 ipf_frag_next(softc, token, itp, top
1198 #ifdef USE_MUTEXES
1199 , lock
1200 #endif
1201 )
1202         ipf_main_softc_t *softc;
1203         ipftoken_t *token;
1204         ipfgeniter_t *itp;
1205         ipfr_t **top;
1206 #ifdef USE_MUTEXES
1207         ipfrwlock_t *lock;
1208 #endif
1209 {
1210         ipfr_t *frag, *next, zero;
1211         int error = 0;
1212
1213         if (itp->igi_data == NULL) {
1214                 IPFERROR(20001);
1215                 return EFAULT;
1216         }
1217
1218         if (itp->igi_nitems != 1) {
1219                 IPFERROR(20003);
1220                 return EFAULT;
1221         }
1222
1223         frag = token->ipt_data;
1224
1225         READ_ENTER(lock);
1226
1227         if (frag == NULL)
1228                 next = *top;
1229         else
1230                 next = frag->ipfr_next;
1231
1232         if (next != NULL) {
1233                 ATOMIC_INC(next->ipfr_ref);
1234                 token->ipt_data = next;
1235         } else {
1236                 bzero(&zero, sizeof(zero));
1237                 next = &zero;
1238                 token->ipt_data = NULL;
1239         }
1240         if (next->ipfr_next == NULL)
1241                 ipf_token_mark_complete(token);
1242
1243         RWLOCK_EXIT(lock);
1244
1245         error = COPYOUT(next, itp->igi_data, sizeof(*next));
1246         if (error != 0)
1247                 IPFERROR(20002);
1248
1249         if (frag != NULL) {
1250 #ifdef USE_MUTEXES
1251                 ipf_frag_deref(softc, &frag, lock);
1252 #else
1253                 ipf_frag_deref(softc, &frag);
1254 #endif
1255         }
1256         return error;
1257 }
1258
1259
1260 /* ------------------------------------------------------------------------ */
1261 /* Function:    ipf_frag_pkt_deref                                          */
1262 /* Returns:     Nil                                                         */
1263 /*                                                                          */
1264 /* ------------------------------------------------------------------------ */
1265 void
1266 ipf_frag_pkt_deref(softc, data)
1267         ipf_main_softc_t *softc;
1268         void *data;
1269 {
1270         ipfr_t **frp = data;
1271
1272 #ifdef USE_MUTEXES
1273         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1274
1275         ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_frag);
1276 #else
1277         ipf_frag_deref(softc->ipf_frag_soft, frp);
1278 #endif
1279 }
1280
1281
1282 /* ------------------------------------------------------------------------ */
1283 /* Function:    ipf_frag_nat_deref                                          */
1284 /* Returns:     Nil                                                         */
1285 /*                                                                          */
1286 /* ------------------------------------------------------------------------ */
1287 void
1288 ipf_frag_nat_deref(softc, data)
1289         ipf_main_softc_t *softc;
1290         void *data;
1291 {
1292         ipfr_t **frp = data;
1293
1294 #ifdef USE_MUTEXES
1295         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1296
1297         ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_natfrag);
1298 #else
1299         ipf_frag_deref(softc->ipf_frag_soft, frp);
1300 #endif
1301 }
1302
1303
1304 /* ------------------------------------------------------------------------ */
1305 /* Function:    ipf_frag_deref                                              */
1306 /* Returns:     Nil                                                         */
1307 /* Parameters:  frp(IO) - pointer to fragment structure to deference        */
1308 /*              lock(I) - lock associated with the fragment                 */
1309 /*                                                                          */
1310 /* This function dereferences a fragment structure (ipfr_t).  The pointer   */
1311 /* passed in will always be reset back to NULL, even if the structure is    */
1312 /* not freed, to enforce the notion that the caller is no longer entitled   */
1313 /* to use the pointer it is dropping the reference to.                      */
1314 /* ------------------------------------------------------------------------ */
1315 static void
1316 ipf_frag_deref(arg, frp
1317 #ifdef USE_MUTEXES
1318 , lock
1319 #endif
1320 )
1321         void *arg;
1322         ipfr_t **frp;
1323 #ifdef USE_MUTEXES
1324         ipfrwlock_t *lock;
1325 #endif
1326 {
1327         ipf_frag_softc_t *softf = arg;
1328         ipfr_t *fra;
1329
1330         fra = *frp;
1331         *frp = NULL;
1332
1333         WRITE_ENTER(lock);
1334         fra->ipfr_ref--;
1335         if (fra->ipfr_ref <= 0)
1336                 ipf_frag_free(softf, fra);
1337         RWLOCK_EXIT(lock);
1338 }