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