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