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