]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/contrib/ipfilter/netinet/ip_htable.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / contrib / ipfilter / netinet / ip_htable.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/param.h>
15 #include <sys/types.h>
16 #include <sys/errno.h>
17 #include <sys/time.h>
18 #include <sys/file.h>
19 #if !defined(_KERNEL)
20 # include <stdlib.h>
21 # include <string.h>
22 # define _KERNEL
23 # ifdef __OpenBSD__
24 struct file;
25 # endif
26 # include <sys/uio.h>
27 # undef _KERNEL
28 #endif
29 #include <sys/socket.h>
30 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
31 # include <sys/malloc.h>
32 #endif
33 #if defined(__FreeBSD__)
34 #  include <sys/cdefs.h>
35 #  include <sys/proc.h>
36 #endif
37 #if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \
38     !defined(linux)
39 # include <sys/mbuf.h>
40 #endif
41 #if defined(_KERNEL)
42 # include <sys/systm.h>
43 #else
44 # include "ipf.h"
45 #endif
46 #include <netinet/in.h>
47 #include <net/if.h>
48
49 #include "netinet/ip_compat.h"
50 #include "netinet/ip_fil.h"
51 #include "netinet/ip_lookup.h"
52 #include "netinet/ip_htable.h"
53 /* END OF INCLUDES */
54
55 #if !defined(lint)
56 static const char rcsid[] = "@(#)$Id$";
57 #endif
58
59 # ifdef USE_INET6
60 static iphtent_t *ipf_iphmfind6 __P((iphtable_t *, i6addr_t *));
61 # endif
62 static iphtent_t *ipf_iphmfind __P((iphtable_t *, struct in_addr *));
63 static int ipf_iphmfindip __P((ipf_main_softc_t *, void *, int, void *, u_int));
64 static int ipf_htable_clear __P((ipf_main_softc_t *, void *, iphtable_t *));
65 static int ipf_htable_create __P((ipf_main_softc_t *, void *, iplookupop_t *));
66 static int ipf_htable_deref __P((ipf_main_softc_t *, void *, void *));
67 static int ipf_htable_destroy __P((ipf_main_softc_t *, void *, int, char *));
68 static void *ipf_htable_exists __P((void *, int, char *));
69 static size_t ipf_htable_flush __P((ipf_main_softc_t *, void *,
70                                     iplookupflush_t *));
71 static void ipf_htable_free __P((void *, iphtable_t *));
72 static int ipf_htable_iter_deref __P((ipf_main_softc_t *, void *, int,
73                                       int, void *));
74 static int ipf_htable_iter_next __P((ipf_main_softc_t *, void *, ipftoken_t *,
75                                      ipflookupiter_t *));
76 static int ipf_htable_node_add __P((ipf_main_softc_t *, void *,
77                                     iplookupop_t *, int));
78 static int ipf_htable_node_del __P((ipf_main_softc_t *, void *,
79                                     iplookupop_t *, int));
80 static int ipf_htable_remove __P((ipf_main_softc_t *, void *, iphtable_t *));
81 static void *ipf_htable_soft_create __P((ipf_main_softc_t *));
82 static void ipf_htable_soft_destroy __P((ipf_main_softc_t *, void *));
83 static int ipf_htable_soft_init __P((ipf_main_softc_t *, void *));
84 static void ipf_htable_soft_fini __P((ipf_main_softc_t *, void *));
85 static int ipf_htable_stats_get __P((ipf_main_softc_t *, void *,
86                                      iplookupop_t *));
87 static int ipf_htable_table_add __P((ipf_main_softc_t *, void *,
88                                      iplookupop_t *));
89 static int ipf_htable_table_del __P((ipf_main_softc_t *, void *,
90                                      iplookupop_t *));
91 static int ipf_htent_deref __P((void *, iphtent_t *));
92 static iphtent_t *ipf_htent_find __P((iphtable_t *, iphtent_t *));
93 static int ipf_htent_insert __P((ipf_main_softc_t *, void *, iphtable_t *,
94                                  iphtent_t *));
95 static int ipf_htent_remove __P((ipf_main_softc_t *, void *, iphtable_t *,
96                                  iphtent_t *));
97 static void *ipf_htable_select_add_ref __P((void *, int, char *));
98 static void ipf_htable_expire __P((ipf_main_softc_t *, void *));
99
100
101 typedef struct ipf_htable_softc_s {
102         u_long          ipht_nomem[LOOKUP_POOL_SZ];
103         u_long          ipf_nhtables[LOOKUP_POOL_SZ];
104         u_long          ipf_nhtnodes[LOOKUP_POOL_SZ];
105         iphtable_t      *ipf_htables[LOOKUP_POOL_SZ];
106         iphtent_t       *ipf_node_explist;
107 } ipf_htable_softc_t;
108
109 ipf_lookup_t ipf_htable_backend = {
110         IPLT_HASH,
111         ipf_htable_soft_create,
112         ipf_htable_soft_destroy,
113         ipf_htable_soft_init,
114         ipf_htable_soft_fini,
115         ipf_iphmfindip,
116         ipf_htable_flush,
117         ipf_htable_iter_deref,
118         ipf_htable_iter_next,
119         ipf_htable_node_add,
120         ipf_htable_node_del,
121         ipf_htable_stats_get,
122         ipf_htable_table_add,
123         ipf_htable_table_del,
124         ipf_htable_deref,
125         ipf_htable_exists,
126         ipf_htable_select_add_ref,
127         NULL,
128         ipf_htable_expire,
129         NULL
130 };
131
132
133 /* ------------------------------------------------------------------------ */
134 /* Function:    ipf_htable_soft_create                                      */
135 /* Returns:     void *   - NULL = failure, else pointer to local context    */
136 /* Parameters:  softc(I) - pointer to soft context main structure           */
137 /*                                                                          */
138 /* Initialise the routing table data structures where required.             */
139 /* ------------------------------------------------------------------------ */
140 static void *
141 ipf_htable_soft_create(softc)
142         ipf_main_softc_t *softc;
143 {
144         ipf_htable_softc_t *softh;
145
146         KMALLOC(softh, ipf_htable_softc_t *);
147         if (softh == NULL) {
148                 IPFERROR(30026);
149                 return NULL;
150         }
151
152         bzero((char *)softh, sizeof(*softh));
153
154         return softh;
155 }
156
157
158 /* ------------------------------------------------------------------------ */
159 /* Function:    ipf_htable_soft_destroy                                     */
160 /* Returns:     Nil                                                         */
161 /* Parameters:  softc(I) - pointer to soft context main structure           */
162 /*              arg(I)   - pointer to local context to use                  */
163 /*                                                                          */
164 /* Clean up the pool by free'ing the radix tree associated with it and free */
165 /* up the pool context too.                                                 */
166 /* ------------------------------------------------------------------------ */
167 static void
168 ipf_htable_soft_destroy(softc, arg)
169         ipf_main_softc_t *softc;
170         void *arg;
171 {
172         ipf_htable_softc_t *softh = arg;
173
174         KFREE(softh);
175 }
176
177
178 /* ------------------------------------------------------------------------ */
179 /* Function:    ipf_htable_soft_init                                        */
180 /* Returns:     int     - 0 = success, else error                           */
181 /* Parameters:  softc(I) - pointer to soft context main structure           */
182 /*              arg(I)   - pointer to local context to use                  */
183 /*                                                                          */
184 /* Initialise the hash table ready for use.                                 */
185 /* ------------------------------------------------------------------------ */
186 static int
187 ipf_htable_soft_init(softc, arg)
188         ipf_main_softc_t *softc;
189         void *arg;
190 {
191         ipf_htable_softc_t *softh = arg;
192
193         bzero((char *)softh, sizeof(*softh));
194
195         return 0;
196 }
197
198
199 /* ------------------------------------------------------------------------ */
200 /* Function:    ipf_htable_soft_fini                                        */
201 /* Returns:     Nil                                                         */
202 /* Parameters:  softc(I) - pointer to soft context main structure           */
203 /*              arg(I)   - pointer to local context to use                  */
204 /* Locks:       WRITE(ipf_global)                                           */
205 /*                                                                          */
206 /* Clean up all the pool data structures allocated and call the cleanup     */
207 /* function for the radix tree that supports the pools. ipf_pool_destroy is */
208 /* used to delete the pools one by one to ensure they're properly freed up. */
209 /* ------------------------------------------------------------------------ */
210 static void
211 ipf_htable_soft_fini(softc, arg)
212         ipf_main_softc_t *softc;
213         void *arg;
214 {
215         iplookupflush_t fop;
216
217         fop.iplf_type = IPLT_HASH;
218         fop.iplf_unit = IPL_LOGALL;
219         fop.iplf_arg = 0;
220         fop.iplf_count = 0;
221         *fop.iplf_name = '\0';
222         ipf_htable_flush(softc, arg, &fop);
223 }
224
225
226 /* ------------------------------------------------------------------------ */
227 /* Function:    ipf_htable_stats_get                                        */
228 /* Returns:     int - 0 = success, else error                               */
229 /* Parameters:  softc(I) - pointer to soft context main structure           */
230 /*              arg(I)   - pointer to local context to use                  */
231 /*              op(I)    - pointer to lookup operation data                 */
232 /*                                                                          */
233 /* Copy the relevant statistics out of internal structures and into the     */
234 /* structure used to export statistics.                                     */
235 /* ------------------------------------------------------------------------ */
236 static int
237 ipf_htable_stats_get(softc, arg, op)
238         ipf_main_softc_t *softc;
239         void *arg;
240         iplookupop_t *op;
241 {
242         ipf_htable_softc_t *softh = arg;
243         iphtstat_t stats;
244         int err;
245
246         if (op->iplo_size != sizeof(stats)) {
247                 IPFERROR(30001);
248                 return EINVAL;
249         }
250
251         stats.iphs_tables = softh->ipf_htables[op->iplo_unit + 1];
252         stats.iphs_numtables = softh->ipf_nhtables[op->iplo_unit + 1];
253         stats.iphs_numnodes = softh->ipf_nhtnodes[op->iplo_unit + 1];
254         stats.iphs_nomem = softh->ipht_nomem[op->iplo_unit + 1];
255
256         err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
257         if (err != 0) {
258                 IPFERROR(30013);
259                 return EFAULT;
260         }
261         return 0;
262
263 }
264
265
266 /* ------------------------------------------------------------------------ */
267 /* Function:    ipf_htable_create                                           */
268 /* Returns:     int - 0 = success, else error                               */
269 /* Parameters:  softc(I) - pointer to soft context main structure           */
270 /*              arg(I)   - pointer to local context to use                  */
271 /*              op(I)    - pointer to lookup operation data                 */
272 /*                                                                          */
273 /* Create a new hash table using the template passed.                       */
274 /* ------------------------------------------------------------------------ */
275 static int
276 ipf_htable_create(softc, arg, op)
277         ipf_main_softc_t *softc;
278         void *arg;
279         iplookupop_t *op;
280 {
281         ipf_htable_softc_t *softh = arg;
282         iphtable_t htab, *iph, *oiph;
283         char name[FR_GROUPLEN];
284         int err, i, unit;
285
286         if (op->iplo_size != sizeof(htab)) {
287                 IPFERROR(30024);
288                 return EINVAL;
289         }
290         err = COPYIN(op->iplo_struct, &htab, sizeof(htab));
291         if (err != 0) {
292                 IPFERROR(30003);
293                 return EFAULT;
294         }
295
296         unit = op->iplo_unit;
297         if (htab.iph_unit != unit) {
298                 IPFERROR(30005);
299                 return EINVAL;
300         }
301         if (htab.iph_size < 1) {
302                 IPFERROR(30025);
303                 return EINVAL;
304         }
305
306
307         if ((op->iplo_arg & IPHASH_ANON) == 0) {
308                 iph = ipf_htable_exists(softh, unit, op->iplo_name);
309                 if (iph != NULL) {
310                         if ((iph->iph_flags & IPHASH_DELETE) == 0) {
311                                 IPFERROR(30004);
312                                 return EEXIST;
313                         }
314                         iph->iph_flags &= ~IPHASH_DELETE;
315                         iph->iph_ref++;
316                         return 0;
317                 }
318         }
319
320         KMALLOC(iph, iphtable_t *);
321         if (iph == NULL) {
322                 softh->ipht_nomem[op->iplo_unit + 1]++;
323                 IPFERROR(30002);
324                 return ENOMEM;
325         }
326         *iph = htab;
327
328         if ((op->iplo_arg & IPHASH_ANON) != 0) {
329                 i = IPHASH_ANON;
330                 do {
331                         i++;
332 #if defined(SNPRINTF) && defined(_KERNEL)
333                         SNPRINTF(name, sizeof(name), "%u", i);
334 #else
335                         (void)sprintf(name, "%u", i);
336 #endif
337                         for (oiph = softh->ipf_htables[unit + 1]; oiph != NULL;
338                              oiph = oiph->iph_next)
339                                 if (strncmp(oiph->iph_name, name,
340                                             sizeof(oiph->iph_name)) == 0)
341                                         break;
342                 } while (oiph != NULL);
343
344                 (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
345                 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
346                 iph->iph_type |= IPHASH_ANON;
347         } else {
348                 (void)strncpy(iph->iph_name, op->iplo_name,
349                               sizeof(iph->iph_name));
350                 iph->iph_name[sizeof(iph->iph_name) - 1] = '\0';
351         }
352
353         KMALLOCS(iph->iph_table, iphtent_t **,
354                  iph->iph_size * sizeof(*iph->iph_table));
355         if (iph->iph_table == NULL) {
356                 KFREE(iph);
357                 softh->ipht_nomem[unit + 1]++;
358                 IPFERROR(30006);
359                 return ENOMEM;
360         }
361
362         bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
363         iph->iph_maskset[0] = 0;
364         iph->iph_maskset[1] = 0;
365         iph->iph_maskset[2] = 0;
366         iph->iph_maskset[3] = 0;
367
368         iph->iph_ref = 1;
369         iph->iph_list = NULL;
370         iph->iph_tail = &iph->iph_list;
371         iph->iph_next = softh->ipf_htables[unit + 1];
372         iph->iph_pnext = &softh->ipf_htables[unit + 1];
373         if (softh->ipf_htables[unit + 1] != NULL)
374                 softh->ipf_htables[unit + 1]->iph_pnext = &iph->iph_next;
375         softh->ipf_htables[unit + 1] = iph;
376
377         softh->ipf_nhtables[unit + 1]++;
378
379         return 0;
380 }
381
382
383 /* ------------------------------------------------------------------------ */
384 /* Function:    ipf_htable_table_del                                        */
385 /* Returns:     int      - 0 = success, else error                          */
386 /* Parameters:  softc(I) - pointer to soft context main structure           */
387 /*              arg(I)   - pointer to local context to use                  */
388 /*              op(I)    - pointer to lookup operation data                 */
389 /*                                                                          */
390 /* ------------------------------------------------------------------------ */
391 static int
392 ipf_htable_table_del(softc, arg, op)
393         ipf_main_softc_t *softc;
394         void *arg;
395         iplookupop_t *op;
396 {
397         return ipf_htable_destroy(softc, arg, op->iplo_unit, op->iplo_name);
398 }
399
400
401 /* ------------------------------------------------------------------------ */
402 /* Function:    ipf_htable_destroy                                          */
403 /* Returns:     int      - 0 = success, else error                          */
404 /* Parameters:  softc(I) - pointer to soft context main structure           */
405 /*              arg(I)   - pointer to local context to use                  */
406 /*              op(I)    - pointer to lookup operation data                 */
407 /*                                                                          */
408 /* Find the hash table that belongs to the relevant part of ipfilter with a */
409 /* matching name and attempt to destroy it.  If it is in use, empty it out  */
410 /* and mark it for deletion so that when all the references disappear, it   */
411 /* can be removed.                                                          */
412 /* ------------------------------------------------------------------------ */
413 static int
414 ipf_htable_destroy(softc, arg, unit, name)
415         ipf_main_softc_t *softc;
416         void *arg;
417         int unit;
418         char *name;
419 {
420         iphtable_t *iph;
421
422         iph = ipf_htable_find(arg, unit, name);
423         if (iph == NULL) {
424                 IPFERROR(30007);
425                 return ESRCH;
426         }
427
428         if (iph->iph_unit != unit) {
429                 IPFERROR(30008);
430                 return EINVAL;
431         }
432
433         if (iph->iph_ref != 0) {
434                 ipf_htable_clear(softc, arg, iph);
435                 iph->iph_flags |= IPHASH_DELETE;
436                 return 0;
437         }
438
439         ipf_htable_remove(softc, arg, iph);
440
441         return 0;
442 }
443
444
445 /* ------------------------------------------------------------------------ */
446 /* Function:    ipf_htable_clear                                            */
447 /* Returns:     int      - 0 = success, else error                          */
448 /* Parameters:  softc(I) - pointer to soft context main structure           */
449 /*              arg(I)   - pointer to local context to use                  */
450 /*              iph(I)   - pointer to hash table to destroy                 */
451 /*                                                                          */
452 /* Clean out the hash table by walking the list of entries and removing     */
453 /* each one, one by one.                                                    */
454 /* ------------------------------------------------------------------------ */
455 static int
456 ipf_htable_clear(softc, arg, iph)
457         ipf_main_softc_t *softc;
458         void *arg;
459         iphtable_t *iph;
460 {
461         iphtent_t *ipe;
462
463         while ((ipe = iph->iph_list) != NULL)
464                 if (ipf_htent_remove(softc, arg, iph, ipe) != 0)
465                         return 1;
466         return 0;
467 }
468
469
470 /* ------------------------------------------------------------------------ */
471 /* Function:    ipf_htable_free                                             */
472 /* Returns:     Nil                                                         */
473 /* Parameters:  arg(I) - pointer to local context to use                    */
474 /*              iph(I) - pointer to hash table to destroy                   */
475 /*                                                                          */
476 /* ------------------------------------------------------------------------ */
477 static void
478 ipf_htable_free(arg, iph)
479         void *arg;
480         iphtable_t *iph;
481 {
482         ipf_htable_softc_t *softh = arg;
483
484         if (iph->iph_next != NULL)
485                 iph->iph_next->iph_pnext = iph->iph_pnext;
486         if (iph->iph_pnext != NULL)
487                 *iph->iph_pnext = iph->iph_next;
488         iph->iph_pnext = NULL;
489         iph->iph_next = NULL;
490
491         softh->ipf_nhtables[iph->iph_unit + 1]--;
492
493         KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
494         KFREE(iph);
495 }
496
497
498 /* ------------------------------------------------------------------------ */
499 /* Function:    ipf_htable_remove                                           */
500 /* Returns:     int      - 0 = success, else error                          */
501 /* Parameters:  softc(I) - pointer to soft context main structure           */
502 /*              arg(I)   - pointer to local context to use                  */
503 /*              iph(I)   - pointer to hash table to destroy                 */
504 /*                                                                          */
505 /* It is necessary to unlink here as well as free (called by deref) so that */
506 /* the while loop in ipf_htable_flush() functions properly.                 */
507 /* ------------------------------------------------------------------------ */
508 static int
509 ipf_htable_remove(softc, arg, iph)
510         ipf_main_softc_t *softc;
511         void *arg;
512         iphtable_t *iph;
513 {
514
515         if (ipf_htable_clear(softc, arg, iph) != 0)
516                 return 1;
517
518         if (iph->iph_pnext != NULL)
519                 *iph->iph_pnext = iph->iph_next;
520         if (iph->iph_next != NULL)
521                 iph->iph_next->iph_pnext = iph->iph_pnext;
522         iph->iph_pnext = NULL;
523         iph->iph_next = NULL;
524
525         return ipf_htable_deref(softc, arg, iph);
526 }
527
528
529 /* ------------------------------------------------------------------------ */
530 /* Function:    ipf_htable_node_del                                         */
531 /* Returns:     int      - 0 = success, else error                          */
532 /* Parameters:  softc(I) - pointer to soft context main structure           */
533 /*              arg(I)   - pointer to local context to use                  */
534 /*              op(I)    - pointer to lookup operation data                 */
535 /*              uid(I)   - real uid of process doing operation              */
536 /*                                                                          */
537 /* ------------------------------------------------------------------------ */
538 static int
539 ipf_htable_node_del(softc, arg, op, uid)
540         ipf_main_softc_t *softc;
541         void *arg;
542         iplookupop_t *op;
543         int uid;
544 {
545         iphtable_t *iph;
546         iphtent_t hte, *ent;
547         int err;
548
549         if (op->iplo_size != sizeof(hte)) {
550                 IPFERROR(30014);
551                 return EINVAL;
552         }
553
554         err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
555         if (err != 0) {
556                 IPFERROR(30015);
557                 return EFAULT;
558         }
559
560         iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
561         if (iph == NULL) {
562                 IPFERROR(30016);
563                 return ESRCH;
564         }
565
566         ent = ipf_htent_find(iph, &hte);
567         if (ent == NULL) {
568                 IPFERROR(30022);
569                 return ESRCH;
570         }
571
572         if ((uid != 0) && (ent->ipe_uid != uid)) {
573                 IPFERROR(30023);
574                 return EACCES;
575         }
576
577         err = ipf_htent_remove(softc, arg, iph, ent);
578
579         return err;
580 }
581
582
583 /* ------------------------------------------------------------------------ */
584 /* Function:    ipf_htable_node_del                                         */
585 /* Returns:     int      - 0 = success, else error                          */
586 /* Parameters:  softc(I) - pointer to soft context main structure           */
587 /*              arg(I)   - pointer to local context to use                  */
588 /*              op(I)    - pointer to lookup operation data                 */
589 /*                                                                          */
590 /* ------------------------------------------------------------------------ */
591 static int
592 ipf_htable_table_add(softc, arg, op)
593         ipf_main_softc_t *softc;
594         void *arg;
595         iplookupop_t *op;
596 {
597         int err;
598
599         if (ipf_htable_find(arg, op->iplo_unit, op->iplo_name) != NULL) {
600                 IPFERROR(30017);
601                 err = EEXIST;
602         } else {
603                 err = ipf_htable_create(softc, arg, op);
604         }
605
606         return err;
607 }
608
609
610 /* ------------------------------------------------------------------------ */
611 /* Function:    ipf_htent_remove                                            */
612 /* Returns:     int      - 0 = success, else error                          */
613 /* Parameters:  softc(I) - pointer to soft context main structure           */
614 /*              arg(I)   - pointer to local context to use                  */
615 /*              iph(I)   - pointer to hash table                            */
616 /*              ipe(I)   - pointer to hash table entry to remove            */
617 /*                                                                          */
618 /* Delete an entry from a hash table.                                       */
619 /* ------------------------------------------------------------------------ */
620 static int
621 ipf_htent_remove(softc, arg, iph, ipe)
622         ipf_main_softc_t *softc;
623         void *arg;
624         iphtable_t *iph;
625         iphtent_t *ipe;
626 {
627
628         if (iph->iph_tail == &ipe->ipe_next)
629                 iph->iph_tail = ipe->ipe_pnext;
630
631         if (ipe->ipe_hnext != NULL)
632                 ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext;
633         if (ipe->ipe_phnext != NULL)
634                 *ipe->ipe_phnext = ipe->ipe_hnext;
635         ipe->ipe_phnext = NULL;
636         ipe->ipe_hnext = NULL;
637
638         if (ipe->ipe_dnext != NULL)
639                 ipe->ipe_dnext->ipe_pdnext = ipe->ipe_pdnext;
640         if (ipe->ipe_pdnext != NULL)
641                 *ipe->ipe_pdnext = ipe->ipe_dnext;
642         ipe->ipe_pdnext = NULL;
643         ipe->ipe_dnext = NULL;
644
645         if (ipe->ipe_next != NULL)
646                 ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
647         if (ipe->ipe_pnext != NULL)
648                 *ipe->ipe_pnext = ipe->ipe_next;
649         ipe->ipe_pnext = NULL;
650         ipe->ipe_next = NULL;
651
652         switch (iph->iph_type & ~IPHASH_ANON)
653         {
654         case IPHASH_GROUPMAP :
655                 if (ipe->ipe_group != NULL)
656                         ipf_group_del(softc, ipe->ipe_ptr, NULL);
657                 break;
658
659         default :
660                 ipe->ipe_ptr = NULL;
661                 ipe->ipe_value = 0;
662                 break;
663         }
664
665         return ipf_htent_deref(arg, ipe);
666 }
667
668
669 /* ------------------------------------------------------------------------ */
670 /* Function:    ipf_htable_deref                                            */
671 /* Returns:     int       - 0 = success, else error                         */
672 /* Parameters:  softc(I)  - pointer to soft context main structure          */
673 /*              arg(I)    - pointer to local context to use                 */
674 /*              object(I) - pointer to hash table                           */
675 /*                                                                          */
676 /* ------------------------------------------------------------------------ */
677 static int
678 ipf_htable_deref(softc, arg, object)
679         ipf_main_softc_t *softc;
680         void *arg, *object;
681 {
682         ipf_htable_softc_t *softh = arg;
683         iphtable_t *iph = object;
684         int refs;
685
686         iph->iph_ref--;
687         refs = iph->iph_ref;
688
689         if (iph->iph_ref == 0) {
690                 ipf_htable_free(softh, iph);
691         }
692
693         return refs;
694 }
695
696
697 /* ------------------------------------------------------------------------ */
698 /* Function:    ipf_htent_deref                                             */
699 /* Parameters:  arg(I) - pointer to local context to use                    */
700 /*              ipe(I) -                                                    */
701 /*                                                                          */
702 /* ------------------------------------------------------------------------ */
703 static int
704 ipf_htent_deref(arg, ipe)
705         void *arg;
706         iphtent_t *ipe;
707 {
708         ipf_htable_softc_t *softh = arg;
709
710         ipe->ipe_ref--;
711         if (ipe->ipe_ref == 0) {
712                 softh->ipf_nhtnodes[ipe->ipe_unit + 1]--;
713                 KFREE(ipe);
714
715                 return 0;
716         }
717
718         return ipe->ipe_ref;
719 }
720
721
722 /* ------------------------------------------------------------------------ */
723 /* Function:    ipf_htable_exists                                           */
724 /* Parameters:  arg(I) - pointer to local context to use                    */
725 /*                                                                          */
726 /* ------------------------------------------------------------------------ */
727 static void *
728 ipf_htable_exists(arg, unit, name)
729         void *arg;
730         int unit;
731         char *name;
732 {
733         ipf_htable_softc_t *softh = arg;
734         iphtable_t *iph;
735
736         if (unit == IPL_LOGALL) {
737                 int i;
738
739                 for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
740                         for (iph = softh->ipf_htables[i]; iph != NULL;
741                              iph = iph->iph_next) {
742                                 if (strncmp(iph->iph_name, name,
743                                             sizeof(iph->iph_name)) == 0)
744                                         break;
745                         }
746                         if (iph != NULL)
747                                 break;
748                 }
749         } else {
750                 for (iph = softh->ipf_htables[unit + 1]; iph != NULL;
751                      iph = iph->iph_next) {
752                         if (strncmp(iph->iph_name, name,
753                                     sizeof(iph->iph_name)) == 0)
754                                 break;
755                 }
756         }
757         return iph;
758 }
759
760
761 /* ------------------------------------------------------------------------ */
762 /* Function:    ipf_htable_select_add_ref                                   */
763 /* Returns:     void *  - NULL = failure, else pointer to the hash table    */
764 /* Parameters:  arg(I)  - pointer to local context to use                   */
765 /*              unit(I) - ipfilter device to which we are working on        */
766 /*              name(I) - name of the hash table                            */
767 /*                                                                          */
768 /* ------------------------------------------------------------------------ */
769 static void *
770 ipf_htable_select_add_ref(arg, unit, name)
771         void *arg;
772         int unit;
773         char *name;
774 {
775         iphtable_t *iph;
776
777         iph = ipf_htable_exists(arg, unit, name);
778         if (iph != NULL) {
779                 ATOMIC_INC32(iph->iph_ref);
780         }
781         return iph;
782 }
783
784
785 /* ------------------------------------------------------------------------ */
786 /* Function:    ipf_htable_find                                             */
787 /* Returns:     void *  - NULL = failure, else pointer to the hash table    */
788 /* Parameters:  arg(I)  - pointer to local context to use                   */
789 /*              unit(I) - ipfilter device to which we are working on        */
790 /*              name(I) - name of the hash table                            */
791 /*                                                                          */
792 /* This function is exposed becaues it is used in the group-map feature.    */
793 /* ------------------------------------------------------------------------ */
794 iphtable_t *
795 ipf_htable_find(arg, unit, name)
796         void *arg;
797         int unit;
798         char *name;
799 {
800         iphtable_t *iph;
801
802         iph = ipf_htable_exists(arg, unit, name);
803         if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0)
804                 return iph;
805
806         return NULL;
807 }
808
809
810 /* ------------------------------------------------------------------------ */
811 /* Function:    ipf_htable_flush                                            */
812 /* Returns:     size_t   - number of entries flushed                        */
813 /* Parameters:  softc(I) - pointer to soft context main structure           */
814 /*              arg(I)   - pointer to local context to use                  */
815 /*              op(I)    - pointer to lookup operation data                 */
816 /*                                                                          */
817 /* ------------------------------------------------------------------------ */
818 static size_t
819 ipf_htable_flush(softc, arg, op)
820         ipf_main_softc_t *softc;
821         void *arg;
822         iplookupflush_t *op;
823 {
824         ipf_htable_softc_t *softh = arg;
825         iphtable_t *iph;
826         size_t freed;
827         int i;
828
829         freed = 0;
830
831         for (i = -1; i <= IPL_LOGMAX; i++) {
832                 if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
833                         while ((iph = softh->ipf_htables[i + 1]) != NULL) {
834                                 if (ipf_htable_remove(softc, arg, iph) == 0) {
835                                         freed++;
836                                 } else {
837                                         iph->iph_flags |= IPHASH_DELETE;
838                                 }
839                         }
840                 }
841         }
842
843         return freed;
844 }
845
846
847 /* ------------------------------------------------------------------------ */
848 /* Function:    ipf_htable_node_add                                         */
849 /* Returns:     int      - 0 = success, else error                          */
850 /* Parameters:  softc(I) - pointer to soft context main structure           */
851 /*              arg(I)   - pointer to local context to use                  */
852 /*              op(I)    - pointer to lookup operation data                 */
853 /*              uid(I)   - real uid of process doing operation              */
854 /*                                                                          */
855 /* ------------------------------------------------------------------------ */
856 static int
857 ipf_htable_node_add(softc, arg, op, uid)
858         ipf_main_softc_t *softc;
859         void *arg;
860         iplookupop_t *op;
861         int uid;
862 {
863         iphtable_t *iph;
864         iphtent_t hte;
865         int err;
866
867         if (op->iplo_size != sizeof(hte)) {
868                 IPFERROR(30018);
869                 return EINVAL;
870         }
871
872         err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
873         if (err != 0) {
874                 IPFERROR(30019);
875                 return EFAULT;
876         }
877         hte.ipe_uid = uid;
878
879         iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
880         if (iph == NULL) {
881                 IPFERROR(30020);
882                 return ESRCH;
883         }
884
885         if (ipf_htent_find(iph, &hte) != NULL) {
886                 IPFERROR(30021);
887                 return EEXIST;
888         }
889
890         err = ipf_htent_insert(softc, arg, iph, &hte);
891
892         return err;
893 }
894
895
896 /* ------------------------------------------------------------------------ */
897 /* Function:    ipf_htent_insert                                            */
898 /* Returns:     int      - 0 = success, -1 =  error                         */
899 /* Parameters:  softc(I) - pointer to soft context main structure           */
900 /*              arg(I)   - pointer to local context to use                  */
901 /*              op(I)    - pointer to lookup operation data                 */
902 /*              ipeo(I)  -                                                  */
903 /*                                                                          */
904 /* Add an entry to a hash table.                                            */
905 /* ------------------------------------------------------------------------ */
906 static int
907 ipf_htent_insert(softc, arg, iph, ipeo)
908         ipf_main_softc_t *softc;
909         void *arg;
910         iphtable_t *iph;
911         iphtent_t *ipeo;
912 {
913         ipf_htable_softc_t *softh = arg;
914         iphtent_t *ipe;
915         u_int hv;
916         int bits;
917
918         KMALLOC(ipe, iphtent_t *);
919         if (ipe == NULL)
920                 return -1;
921
922         bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
923         ipe->ipe_addr.i6[0] &= ipe->ipe_mask.i6[0];
924         if (ipe->ipe_family == AF_INET) {
925                 bits = count4bits(ipe->ipe_mask.in4_addr);
926                 ipe->ipe_addr.i6[1] = 0;
927                 ipe->ipe_addr.i6[2] = 0;
928                 ipe->ipe_addr.i6[3] = 0;
929                 ipe->ipe_mask.i6[1] = 0;
930                 ipe->ipe_mask.i6[2] = 0;
931                 ipe->ipe_mask.i6[3] = 0;
932                 hv = IPE_V4_HASH_FN(ipe->ipe_addr.in4_addr,
933                                     ipe->ipe_mask.in4_addr, iph->iph_size);
934         } else
935 #ifdef USE_INET6
936         if (ipe->ipe_family == AF_INET6) {
937                 ipe->ipe_addr.i6[1] &= ipe->ipe_mask.i6[1];
938                 ipe->ipe_addr.i6[2] &= ipe->ipe_mask.i6[2];
939                 ipe->ipe_addr.i6[3] &= ipe->ipe_mask.i6[3];
940
941                 bits = count6bits(ipe->ipe_mask.i6);
942                 hv = IPE_V6_HASH_FN(ipe->ipe_addr.i6,
943                                     ipe->ipe_mask.i6, iph->iph_size);
944         } else
945 #endif
946         {
947                 KFREE(ipe);
948                 return -1;
949         }
950
951         ipe->ipe_owner = iph;
952         ipe->ipe_ref = 1;
953         ipe->ipe_hnext = iph->iph_table[hv];
954         ipe->ipe_phnext = iph->iph_table + hv;
955
956         if (iph->iph_table[hv] != NULL)
957                 iph->iph_table[hv]->ipe_phnext = &ipe->ipe_hnext;
958         iph->iph_table[hv] = ipe;
959
960         ipe->ipe_pnext = iph->iph_tail;
961         *iph->iph_tail = ipe;
962         iph->iph_tail = &ipe->ipe_next;
963         ipe->ipe_next = NULL;
964
965         if (ipe->ipe_die != 0) {
966                 /*
967                  * If the new node has a given expiration time, insert it
968                  * into the list of expiring nodes with the ones to be
969                  * removed first added to the front of the list. The
970                  * insertion is O(n) but it is kept sorted for quick scans
971                  * at expiration interval checks.
972                  */
973                 iphtent_t *n;
974
975                 ipe->ipe_die = softc->ipf_ticks + IPF_TTLVAL(ipe->ipe_die);
976                 for (n = softh->ipf_node_explist; n != NULL; n = n->ipe_dnext) {
977                         if (ipe->ipe_die < n->ipe_die)
978                                 break;
979                         if (n->ipe_dnext == NULL) {
980                                 /*
981                                  * We've got to the last node and everything
982                                  * wanted to be expired before this new node,
983                                  * so we have to tack it on the end...
984                                  */
985                                 n->ipe_dnext = ipe;
986                                 ipe->ipe_pdnext = &n->ipe_dnext;
987                                 n = NULL;
988                                 break;
989                         }
990                 }
991
992                 if (softh->ipf_node_explist == NULL) {
993                         softh->ipf_node_explist = ipe;
994                         ipe->ipe_pdnext = &softh->ipf_node_explist;
995                 } else if (n != NULL) {
996                         ipe->ipe_dnext = n;
997                         ipe->ipe_pdnext = n->ipe_pdnext;
998                         n->ipe_pdnext = &ipe->ipe_dnext;
999                 }
1000         }
1001
1002         if (ipe->ipe_family == AF_INET) {
1003                 ipf_inet_mask_add(bits, &iph->iph_v4_masks);
1004         }
1005 #ifdef USE_INET6
1006         else if (ipe->ipe_family == AF_INET6) {
1007                 ipf_inet6_mask_add(bits, &ipe->ipe_mask, &iph->iph_v6_masks);
1008         }
1009 #endif
1010
1011         switch (iph->iph_type & ~IPHASH_ANON)
1012         {
1013         case IPHASH_GROUPMAP :
1014                 ipe->ipe_ptr = ipf_group_add(softc, ipe->ipe_group, NULL,
1015                                            iph->iph_flags, IPL_LOGIPF,
1016                                            softc->ipf_active);
1017                 break;
1018
1019         default :
1020                 ipe->ipe_ptr = NULL;
1021                 ipe->ipe_value = 0;
1022                 break;
1023         }
1024
1025         ipe->ipe_unit = iph->iph_unit;
1026         softh->ipf_nhtnodes[ipe->ipe_unit + 1]++;
1027
1028         return 0;
1029 }
1030
1031
1032 /* ------------------------------------------------------------------------ */
1033 /* Function:    ipf_htent_find                                              */
1034 /* Returns:     int     - 0 = success, else error                           */
1035 /* Parameters:  iph(I)  - pointer to table to search                        */
1036 /*              ipeo(I) - pointer to entry to find                          */
1037 /*                                                                          */
1038 /* While it isn't absolutely necessary to for the address and mask to be    */
1039 /* passed in through an iphtent_t structure, one is always present when it  */
1040 /* is time to call this function, so it is just more convenient.            */
1041 /* ------------------------------------------------------------------------ */
1042 static iphtent_t *
1043 ipf_htent_find(iph, ipeo)
1044         iphtable_t *iph;
1045         iphtent_t *ipeo;
1046 {
1047         iphtent_t ipe, *ent;
1048         u_int hv;
1049         int bits;
1050
1051         bcopy((char *)ipeo, (char *)&ipe, sizeof(ipe));
1052         ipe.ipe_addr.i6[0] &= ipe.ipe_mask.i6[0];
1053         ipe.ipe_addr.i6[1] &= ipe.ipe_mask.i6[1];
1054         ipe.ipe_addr.i6[2] &= ipe.ipe_mask.i6[2];
1055         ipe.ipe_addr.i6[3] &= ipe.ipe_mask.i6[3];
1056         if (ipe.ipe_family == AF_INET) {
1057                 bits = count4bits(ipe.ipe_mask.in4_addr);
1058                 ipe.ipe_addr.i6[1] = 0;
1059                 ipe.ipe_addr.i6[2] = 0;
1060                 ipe.ipe_addr.i6[3] = 0;
1061                 ipe.ipe_mask.i6[1] = 0;
1062                 ipe.ipe_mask.i6[2] = 0;
1063                 ipe.ipe_mask.i6[3] = 0;
1064                 hv = IPE_V4_HASH_FN(ipe.ipe_addr.in4_addr,
1065                                     ipe.ipe_mask.in4_addr, iph->iph_size);
1066         } else
1067 #ifdef USE_INET6
1068         if (ipe.ipe_family == AF_INET6) {
1069                 bits = count6bits(ipe.ipe_mask.i6);
1070                 hv = IPE_V6_HASH_FN(ipe.ipe_addr.i6,
1071                                     ipe.ipe_mask.i6, iph->iph_size);
1072         } else
1073 #endif
1074                 return NULL;
1075
1076         for (ent = iph->iph_table[hv]; ent != NULL; ent = ent->ipe_hnext) {
1077                 if (ent->ipe_family != ipe.ipe_family)
1078                         continue;
1079                 if (IP6_NEQ(&ipe.ipe_addr, &ent->ipe_addr))
1080                         continue;
1081                 if (IP6_NEQ(&ipe.ipe_mask, &ent->ipe_mask))
1082                         continue;
1083                 break;
1084         }
1085
1086         return ent;
1087 }
1088
1089
1090 /* ------------------------------------------------------------------------ */
1091 /* Function:    ipf_iphmfindgroup                                           */
1092 /* Returns:     int      - 0 = success, else error                          */
1093 /* Parameters:  softc(I) - pointer to soft context main structure           */
1094 /*              tptr(I)  -                                                  */
1095 /*              aptr(I)  -                                                  */
1096 /*                                                                          */
1097 /* Search a hash table for a matching entry and return the pointer stored   */
1098 /* in it for use as the next group of rules to search.                      */
1099 /*                                                                          */
1100 /* This function is exposed becaues it is used in the group-map feature.    */
1101 /* ------------------------------------------------------------------------ */
1102 void *
1103 ipf_iphmfindgroup(softc, tptr, aptr)
1104         ipf_main_softc_t *softc;
1105         void *tptr, *aptr;
1106 {
1107         struct in_addr *addr;
1108         iphtable_t *iph;
1109         iphtent_t *ipe;
1110         void *rval;
1111
1112         READ_ENTER(&softc->ipf_poolrw);
1113         iph = tptr;
1114         addr = aptr;
1115
1116         ipe = ipf_iphmfind(iph, addr);
1117         if (ipe != NULL)
1118                 rval = ipe->ipe_ptr;
1119         else
1120                 rval = NULL;
1121         RWLOCK_EXIT(&softc->ipf_poolrw);
1122         return rval;
1123 }
1124
1125
1126 /* ------------------------------------------------------------------------ */
1127 /* Function:    ipf_iphmfindip                                              */
1128 /* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
1129 /* Parameters:  softc(I)     - pointer to soft context main structure       */
1130 /*              tptr(I)      - pointer to the pool to search                */
1131 /*              ipversion(I) - IP protocol version (4 or 6)                 */
1132 /*              aptr(I)      - pointer to address information               */
1133 /*              bytes(I)     - packet length                                */
1134 /*                                                                          */
1135 /* Search the hash table for a given address and return a search result.    */
1136 /* ------------------------------------------------------------------------ */
1137 static int
1138 ipf_iphmfindip(softc, tptr, ipversion, aptr, bytes)
1139         ipf_main_softc_t *softc;
1140         void *tptr, *aptr;
1141         int ipversion;
1142         u_int bytes;
1143 {
1144         struct in_addr *addr;
1145         iphtable_t *iph;
1146         iphtent_t *ipe;
1147         int rval;
1148
1149         if (tptr == NULL || aptr == NULL)
1150                 return -1;
1151
1152         iph = tptr;
1153         addr = aptr;
1154
1155         READ_ENTER(&softc->ipf_poolrw);
1156         if (ipversion == 4) {
1157                 ipe = ipf_iphmfind(iph, addr);
1158 #ifdef USE_INET6
1159         } else if (ipversion == 6) {
1160                 ipe = ipf_iphmfind6(iph, (i6addr_t *)addr);
1161 #endif
1162         } else {
1163                 ipe = NULL;
1164         }
1165
1166         if (ipe != NULL) {
1167                 rval = 0;
1168                 ipe->ipe_hits++;
1169                 ipe->ipe_bytes += bytes;
1170         } else {
1171                 rval = 1;
1172         }
1173         RWLOCK_EXIT(&softc->ipf_poolrw);
1174         return rval;
1175 }
1176
1177
1178 /* ------------------------------------------------------------------------ */
1179 /* Function:    ipf_iphmfindip                                              */
1180 /* Parameters:  iph(I)  - pointer to hash table                             */
1181 /*              addr(I) - pointer to IPv4 address                           */
1182 /* Locks:  ipf_poolrw                                                       */
1183 /*                                                                          */
1184 /* ------------------------------------------------------------------------ */
1185 static iphtent_t *
1186 ipf_iphmfind(iph, addr)
1187         iphtable_t *iph;
1188         struct in_addr *addr;
1189 {
1190         u_32_t msk, ips;
1191         iphtent_t *ipe;
1192         u_int hv;
1193         int i;
1194
1195         i = 0;
1196 maskloop:
1197         msk = iph->iph_v4_masks.imt4_active[i];
1198         ips = addr->s_addr & msk;
1199         hv = IPE_V4_HASH_FN(ips, msk, iph->iph_size);
1200         for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_hnext) {
1201                 if ((ipe->ipe_family != AF_INET) ||
1202                     (ipe->ipe_mask.in4_addr != msk) ||
1203                     (ipe->ipe_addr.in4_addr != ips)) {
1204                         continue;
1205                 }
1206                 break;
1207         }
1208
1209         if (ipe == NULL) {
1210                 i++;
1211                 if (i < iph->iph_v4_masks.imt4_max)
1212                         goto maskloop;
1213         }
1214         return ipe;
1215 }
1216
1217
1218 /* ------------------------------------------------------------------------ */
1219 /* Function:    ipf_htable_iter_next                                        */
1220 /* Returns:     int      - 0 = success, else error                          */
1221 /* Parameters:  softc(I) - pointer to soft context main structure           */
1222 /*              arg(I)   - pointer to local context to use                  */
1223 /*              token(I) -                                                  */
1224 /*              ilp(I)   -                                                  */
1225 /*                                                                          */
1226 /* ------------------------------------------------------------------------ */
1227 static int
1228 ipf_htable_iter_next(softc, arg, token, ilp)
1229         ipf_main_softc_t *softc;
1230         void *arg;
1231         ipftoken_t *token;
1232         ipflookupiter_t *ilp;
1233 {
1234         ipf_htable_softc_t *softh = arg;
1235         iphtent_t *node, zn, *nextnode;
1236         iphtable_t *iph, zp, *nextiph;
1237         void *hnext;
1238         int err;
1239
1240         err = 0;
1241         iph = NULL;
1242         node = NULL;
1243         nextiph = NULL;
1244         nextnode = NULL;
1245
1246         READ_ENTER(&softc->ipf_poolrw);
1247
1248         switch (ilp->ili_otype)
1249         {
1250         case IPFLOOKUPITER_LIST :
1251                 iph = token->ipt_data;
1252                 if (iph == NULL) {
1253                         nextiph = softh->ipf_htables[(int)ilp->ili_unit + 1];
1254                 } else {
1255                         nextiph = iph->iph_next;
1256                 }
1257
1258                 if (nextiph != NULL) {
1259                         ATOMIC_INC(nextiph->iph_ref);
1260                         token->ipt_data = nextiph;
1261                 } else {
1262                         bzero((char *)&zp, sizeof(zp));
1263                         nextiph = &zp;
1264                         token->ipt_data = NULL;
1265                 }
1266                 hnext = nextiph->iph_next;
1267                 break;
1268
1269         case IPFLOOKUPITER_NODE :
1270                 node = token->ipt_data;
1271                 if (node == NULL) {
1272                         iph = ipf_htable_find(arg, ilp->ili_unit,
1273                                               ilp->ili_name);
1274                         if (iph == NULL) {
1275                                 IPFERROR(30009);
1276                                 err = ESRCH;
1277                         } else {
1278                                 nextnode = iph->iph_list;
1279                         }
1280                 } else {
1281                         nextnode = node->ipe_next;
1282                 }
1283
1284                 if (nextnode != NULL) {
1285                         ATOMIC_INC(nextnode->ipe_ref);
1286                         token->ipt_data = nextnode;
1287                 } else {
1288                         bzero((char *)&zn, sizeof(zn));
1289                         nextnode = &zn;
1290                         token->ipt_data = NULL;
1291                 }
1292                 hnext = nextnode->ipe_next;
1293                 break;
1294
1295         default :
1296                 IPFERROR(30010);
1297                 err = EINVAL;
1298                 hnext = NULL;
1299                 break;
1300         }
1301
1302         RWLOCK_EXIT(&softc->ipf_poolrw);
1303         if (err != 0)
1304                 return err;
1305
1306         switch (ilp->ili_otype)
1307         {
1308         case IPFLOOKUPITER_LIST :
1309                 err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
1310                 if (err != 0) {
1311                         IPFERROR(30011);
1312                         err = EFAULT;
1313                 }
1314                 if (iph != NULL) {
1315                         WRITE_ENTER(&softc->ipf_poolrw);
1316                         ipf_htable_deref(softc, softh, iph);
1317                         RWLOCK_EXIT(&softc->ipf_poolrw);
1318                 }
1319                 break;
1320
1321         case IPFLOOKUPITER_NODE :
1322                 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
1323                 if (err != 0) {
1324                         IPFERROR(30012);
1325                         err = EFAULT;
1326                 }
1327                 if (node != NULL) {
1328                         WRITE_ENTER(&softc->ipf_poolrw);
1329                         ipf_htent_deref(softc, node);
1330                         RWLOCK_EXIT(&softc->ipf_poolrw);
1331                 }
1332                 break;
1333         }
1334
1335         if (hnext == NULL)
1336                 ipf_token_mark_complete(token);
1337
1338         return err;
1339 }
1340
1341
1342 /* ------------------------------------------------------------------------ */
1343 /* Function:    ipf_htable_iter_deref                                       */
1344 /* Returns:     int      - 0 = success, else  error                         */
1345 /* Parameters:  softc(I) - pointer to soft context main structure           */
1346 /*              arg(I)   - pointer to local context to use                  */
1347 /*              otype(I) - which data structure type is being walked        */
1348 /*              unit(I)  - ipfilter device to which we are working on       */
1349 /*              data(I)  - pointer to old data structure                    */
1350 /*                                                                          */
1351 /* ------------------------------------------------------------------------ */
1352 static int
1353 ipf_htable_iter_deref(softc, arg, otype, unit, data)
1354         ipf_main_softc_t *softc;
1355         void *arg;
1356         int otype;
1357         int unit;
1358         void *data;
1359 {
1360
1361         if (data == NULL)
1362                 return EFAULT;
1363
1364         if (unit < -1 || unit > IPL_LOGMAX)
1365                 return EINVAL;
1366
1367         switch (otype)
1368         {
1369         case IPFLOOKUPITER_LIST :
1370                 ipf_htable_deref(softc, arg, (iphtable_t *)data);
1371                 break;
1372
1373         case IPFLOOKUPITER_NODE :
1374                 ipf_htent_deref(arg, (iphtent_t *)data);
1375                 break;
1376         default :
1377                 break;
1378         }
1379
1380         return 0;
1381 }
1382
1383
1384 #ifdef USE_INET6
1385 /* ------------------------------------------------------------------------ */
1386 /* Function:    ipf_iphmfind6                                               */
1387 /* Parameters:  iph(I)  - pointer to hash table                             */
1388 /*              addr(I) - pointer to IPv6 address                           */
1389 /* Locks:  ipf_poolrw                                                       */
1390 /*                                                                          */
1391 /* ------------------------------------------------------------------------ */
1392 static iphtent_t *
1393 ipf_iphmfind6(iph, addr)
1394         iphtable_t *iph;
1395         i6addr_t *addr;
1396 {
1397         i6addr_t *msk, ips;
1398         iphtent_t *ipe;
1399         u_int hv;
1400         int i;
1401
1402         i = 0;
1403 maskloop:
1404         msk = iph->iph_v6_masks.imt6_active + i;
1405         ips.i6[0] = addr->i6[0] & msk->i6[0];
1406         ips.i6[1] = addr->i6[1] & msk->i6[1];
1407         ips.i6[2] = addr->i6[2] & msk->i6[2];
1408         ips.i6[3] = addr->i6[3] & msk->i6[3];
1409         hv = IPE_V6_HASH_FN(ips.i6, msk->i6, iph->iph_size);
1410         for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
1411                 if ((ipe->ipe_family != AF_INET6) ||
1412                     IP6_NEQ(&ipe->ipe_mask, msk) ||
1413                     IP6_NEQ(&ipe->ipe_addr, &ips)) {
1414                         continue;
1415                 }
1416                 break;
1417         }
1418
1419         if (ipe == NULL) {
1420                 i++;
1421                 if (i < iph->iph_v6_masks.imt6_max)
1422                         goto maskloop;
1423         }
1424         return ipe;
1425 }
1426 #endif
1427
1428
1429 static void
1430 ipf_htable_expire(softc, arg)
1431         ipf_main_softc_t *softc;
1432         void *arg;
1433 {
1434         ipf_htable_softc_t *softh = arg;
1435         iphtent_t *n;
1436
1437         while ((n = softh->ipf_node_explist) != NULL) {
1438                 if (n->ipe_die > softc->ipf_ticks)
1439                         break;
1440
1441                 ipf_htent_remove(softc, softh, n->ipe_owner, n);
1442         }
1443 }
1444
1445
1446 #ifndef _KERNEL
1447
1448 /* ------------------------------------------------------------------------ */
1449 /*                                                                          */
1450 /* ------------------------------------------------------------------------ */
1451 void
1452 ipf_htable_dump(softc, arg)
1453         ipf_main_softc_t *softc;
1454         void *arg;
1455 {
1456         ipf_htable_softc_t *softh = arg;
1457         iphtable_t *iph;
1458         int i;
1459
1460         printf("List of configured hash tables\n");
1461         for (i = 0; i < IPL_LOGSIZE; i++)
1462                 for (iph = softh->ipf_htables[i]; iph != NULL;
1463                      iph = iph->iph_next)
1464                         printhash(iph, bcopywrap, NULL, opts, NULL);
1465
1466 }
1467 #endif