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