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