xref: /netbsd-src/external/bsd/ipf/dist/ip_htable.c (revision dd255ccea4286b0c44fa8fd48a9a19a768afe8e1)
1 /*	$NetBSD: ip_htable.c,v 1.2 2012/07/22 14:27:35 darrenr Exp $	*/
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: ip_htable.c,v 1.1.1.2 2012/07/22 13:44:17 darrenr Exp";
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
1468