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