1145516Sdarrenr/*	$FreeBSD$	*/
2145516Sdarrenr
3145516Sdarrenr/*
4255332Scy * Copyright (C) 2012 by Darren Reed.
5145516Sdarrenr *
6145516Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
7145516Sdarrenr */
8145516Sdarrenr#if defined(KERNEL) || defined(_KERNEL)
9145516Sdarrenr# undef KERNEL
10145516Sdarrenr# undef _KERNEL
11145516Sdarrenr# define        KERNEL	1
12145516Sdarrenr# define        _KERNEL	1
13145516Sdarrenr#endif
14145516Sdarrenr#include <sys/param.h>
15145516Sdarrenr#include <sys/types.h>
16145516Sdarrenr#include <sys/errno.h>
17145516Sdarrenr#include <sys/time.h>
18145516Sdarrenr#include <sys/file.h>
19145516Sdarrenr#if !defined(_KERNEL)
20145516Sdarrenr# include <stdlib.h>
21145516Sdarrenr# include <string.h>
22145516Sdarrenr# define _KERNEL
23145516Sdarrenr# ifdef __OpenBSD__
24145516Sdarrenrstruct file;
25145516Sdarrenr# endif
26145516Sdarrenr# include <sys/uio.h>
27145516Sdarrenr# undef _KERNEL
28145516Sdarrenr#endif
29145516Sdarrenr#include <sys/socket.h>
30145516Sdarrenr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
31145516Sdarrenr# include <sys/malloc.h>
32145516Sdarrenr#endif
33145516Sdarrenr#if defined(__FreeBSD__)
34145516Sdarrenr#  include <sys/cdefs.h>
35145516Sdarrenr#  include <sys/proc.h>
36145516Sdarrenr#endif
37145516Sdarrenr#if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \
38145516Sdarrenr    !defined(linux)
39145516Sdarrenr# include <sys/mbuf.h>
40145516Sdarrenr#endif
41145516Sdarrenr#if defined(_KERNEL)
42145516Sdarrenr# include <sys/systm.h>
43145516Sdarrenr#else
44255332Scy# include "ipf.h"
45145516Sdarrenr#endif
46145516Sdarrenr#include <netinet/in.h>
47145516Sdarrenr#include <net/if.h>
48145516Sdarrenr
49145516Sdarrenr#include "netinet/ip_compat.h"
50145516Sdarrenr#include "netinet/ip_fil.h"
51145516Sdarrenr#include "netinet/ip_lookup.h"
52145516Sdarrenr#include "netinet/ip_htable.h"
53145516Sdarrenr/* END OF INCLUDES */
54145516Sdarrenr
55145516Sdarrenr#if !defined(lint)
56255332Scystatic const char rcsid[] = "@(#)$Id$";
57145516Sdarrenr#endif
58145516Sdarrenr
59255332Scy# ifdef USE_INET6
60255332Scystatic iphtent_t *ipf_iphmfind6 __P((iphtable_t *, i6addr_t *));
61255332Scy# endif
62255332Scystatic iphtent_t *ipf_iphmfind __P((iphtable_t *, struct in_addr *));
63255332Scystatic int ipf_iphmfindip __P((ipf_main_softc_t *, void *, int, void *, u_int));
64255332Scystatic int ipf_htable_clear __P((ipf_main_softc_t *, void *, iphtable_t *));
65255332Scystatic int ipf_htable_create __P((ipf_main_softc_t *, void *, iplookupop_t *));
66255332Scystatic int ipf_htable_deref __P((ipf_main_softc_t *, void *, void *));
67255332Scystatic int ipf_htable_destroy __P((ipf_main_softc_t *, void *, int, char *));
68255332Scystatic void *ipf_htable_exists __P((void *, int, char *));
69255332Scystatic size_t ipf_htable_flush __P((ipf_main_softc_t *, void *,
70255332Scy				    iplookupflush_t *));
71255332Scystatic void ipf_htable_free __P((void *, iphtable_t *));
72255332Scystatic int ipf_htable_iter_deref __P((ipf_main_softc_t *, void *, int,
73255332Scy				      int, void *));
74255332Scystatic int ipf_htable_iter_next __P((ipf_main_softc_t *, void *, ipftoken_t *,
75255332Scy				     ipflookupiter_t *));
76255332Scystatic int ipf_htable_node_add __P((ipf_main_softc_t *, void *,
77255332Scy				    iplookupop_t *, int));
78255332Scystatic int ipf_htable_node_del __P((ipf_main_softc_t *, void *,
79255332Scy				    iplookupop_t *, int));
80255332Scystatic int ipf_htable_remove __P((ipf_main_softc_t *, void *, iphtable_t *));
81255332Scystatic void *ipf_htable_soft_create __P((ipf_main_softc_t *));
82255332Scystatic void ipf_htable_soft_destroy __P((ipf_main_softc_t *, void *));
83255332Scystatic int ipf_htable_soft_init __P((ipf_main_softc_t *, void *));
84255332Scystatic void ipf_htable_soft_fini __P((ipf_main_softc_t *, void *));
85255332Scystatic int ipf_htable_stats_get __P((ipf_main_softc_t *, void *,
86255332Scy				     iplookupop_t *));
87255332Scystatic int ipf_htable_table_add __P((ipf_main_softc_t *, void *,
88255332Scy				     iplookupop_t *));
89255332Scystatic int ipf_htable_table_del __P((ipf_main_softc_t *, void *,
90255332Scy				     iplookupop_t *));
91255332Scystatic int ipf_htent_deref __P((void *, iphtent_t *));
92255332Scystatic iphtent_t *ipf_htent_find __P((iphtable_t *, iphtent_t *));
93255332Scystatic int ipf_htent_insert __P((ipf_main_softc_t *, void *, iphtable_t *,
94255332Scy				 iphtent_t *));
95255332Scystatic int ipf_htent_remove __P((ipf_main_softc_t *, void *, iphtable_t *,
96255332Scy				 iphtent_t *));
97255332Scystatic void *ipf_htable_select_add_ref __P((void *, int, char *));
98255332Scystatic void ipf_htable_expire __P((ipf_main_softc_t *, void *));
99145516Sdarrenr
100145516Sdarrenr
101255332Scytypedef struct ipf_htable_softc_s {
102255332Scy	u_long		ipht_nomem[LOOKUP_POOL_SZ];
103255332Scy	u_long		ipf_nhtables[LOOKUP_POOL_SZ];
104255332Scy	u_long		ipf_nhtnodes[LOOKUP_POOL_SZ];
105255332Scy	iphtable_t	*ipf_htables[LOOKUP_POOL_SZ];
106255332Scy	iphtent_t	*ipf_node_explist;
107255332Scy} ipf_htable_softc_t;
108145516Sdarrenr
109255332Scyipf_lookup_t ipf_htable_backend = {
110255332Scy	IPLT_HASH,
111255332Scy	ipf_htable_soft_create,
112255332Scy	ipf_htable_soft_destroy,
113255332Scy	ipf_htable_soft_init,
114255332Scy	ipf_htable_soft_fini,
115255332Scy	ipf_iphmfindip,
116255332Scy	ipf_htable_flush,
117255332Scy	ipf_htable_iter_deref,
118255332Scy	ipf_htable_iter_next,
119255332Scy	ipf_htable_node_add,
120255332Scy	ipf_htable_node_del,
121255332Scy	ipf_htable_stats_get,
122255332Scy	ipf_htable_table_add,
123255332Scy	ipf_htable_table_del,
124255332Scy	ipf_htable_deref,
125255332Scy	ipf_htable_exists,
126255332Scy	ipf_htable_select_add_ref,
127255332Scy	NULL,
128255332Scy	ipf_htable_expire,
129255332Scy	NULL
130255332Scy};
131255332Scy
132255332Scy
133255332Scy/* ------------------------------------------------------------------------ */
134255332Scy/* Function:    ipf_htable_soft_create                                      */
135255332Scy/* Returns:     void *   - NULL = failure, else pointer to local context    */
136255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
137255332Scy/*                                                                          */
138255332Scy/* Initialise the routing table data structures where required.             */
139255332Scy/* ------------------------------------------------------------------------ */
140255332Scystatic void *
141255332Scyipf_htable_soft_create(softc)
142255332Scy	ipf_main_softc_t *softc;
143145516Sdarrenr{
144255332Scy	ipf_htable_softc_t *softh;
145255332Scy
146255332Scy	KMALLOC(softh, ipf_htable_softc_t *);
147255332Scy	if (softh == NULL) {
148255332Scy		IPFERROR(30026);
149255332Scy		return NULL;
150255332Scy	}
151255332Scy
152255332Scy	bzero((char *)softh, sizeof(*softh));
153255332Scy
154255332Scy	return softh;
155255332Scy}
156255332Scy
157255332Scy
158255332Scy/* ------------------------------------------------------------------------ */
159255332Scy/* Function:    ipf_htable_soft_destroy                                     */
160255332Scy/* Returns:     Nil                                                         */
161255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
162255332Scy/*              arg(I)   - pointer to local context to use                  */
163255332Scy/*                                                                          */
164255332Scy/* Clean up the pool by free'ing the radix tree associated with it and free */
165255332Scy/* up the pool context too.                                                 */
166255332Scy/* ------------------------------------------------------------------------ */
167255332Scystatic void
168255332Scyipf_htable_soft_destroy(softc, arg)
169255332Scy	ipf_main_softc_t *softc;
170255332Scy	void *arg;
171255332Scy{
172255332Scy	ipf_htable_softc_t *softh = arg;
173255332Scy
174255332Scy	KFREE(softh);
175255332Scy}
176255332Scy
177255332Scy
178255332Scy/* ------------------------------------------------------------------------ */
179255332Scy/* Function:    ipf_htable_soft_init                                        */
180255332Scy/* Returns:     int     - 0 = success, else error                           */
181255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
182255332Scy/*              arg(I)   - pointer to local context to use                  */
183255332Scy/*                                                                          */
184255332Scy/* Initialise the hash table ready for use.                                 */
185255332Scy/* ------------------------------------------------------------------------ */
186255332Scystatic int
187255332Scyipf_htable_soft_init(softc, arg)
188255332Scy	ipf_main_softc_t *softc;
189255332Scy	void *arg;
190255332Scy{
191255332Scy	ipf_htable_softc_t *softh = arg;
192255332Scy
193255332Scy	bzero((char *)softh, sizeof(*softh));
194255332Scy
195255332Scy	return 0;
196255332Scy}
197255332Scy
198255332Scy
199255332Scy/* ------------------------------------------------------------------------ */
200255332Scy/* Function:    ipf_htable_soft_fini                                        */
201255332Scy/* Returns:     Nil                                                         */
202255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
203255332Scy/*              arg(I)   - pointer to local context to use                  */
204255332Scy/* Locks:       WRITE(ipf_global)                                           */
205255332Scy/*                                                                          */
206255332Scy/* Clean up all the pool data structures allocated and call the cleanup     */
207255332Scy/* function for the radix tree that supports the pools. ipf_pool_destroy is */
208255332Scy/* used to delete the pools one by one to ensure they're properly freed up. */
209255332Scy/* ------------------------------------------------------------------------ */
210255332Scystatic void
211255332Scyipf_htable_soft_fini(softc, arg)
212255332Scy	ipf_main_softc_t *softc;
213255332Scy	void *arg;
214255332Scy{
215145516Sdarrenr	iplookupflush_t fop;
216145516Sdarrenr
217255332Scy	fop.iplf_type = IPLT_HASH;
218145516Sdarrenr	fop.iplf_unit = IPL_LOGALL;
219255332Scy	fop.iplf_arg = 0;
220255332Scy	fop.iplf_count = 0;
221255332Scy	*fop.iplf_name = '\0';
222255332Scy	ipf_htable_flush(softc, arg, &fop);
223145516Sdarrenr}
224145516Sdarrenr
225145516Sdarrenr
226255332Scy/* ------------------------------------------------------------------------ */
227255332Scy/* Function:    ipf_htable_stats_get                                        */
228255332Scy/* Returns:     int - 0 = success, else error                               */
229255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
230255332Scy/*              arg(I)   - pointer to local context to use                  */
231255332Scy/*              op(I)    - pointer to lookup operation data                 */
232255332Scy/*                                                                          */
233255332Scy/* Copy the relevant statistics out of internal structures and into the     */
234255332Scy/* structure used to export statistics.                                     */
235255332Scy/* ------------------------------------------------------------------------ */
236255332Scystatic int
237255332Scyipf_htable_stats_get(softc, arg, op)
238255332Scy	ipf_main_softc_t *softc;
239255332Scy	void *arg;
240255332Scy	iplookupop_t *op;
241145516Sdarrenr{
242255332Scy	ipf_htable_softc_t *softh = arg;
243145516Sdarrenr	iphtstat_t stats;
244255332Scy	int err;
245145516Sdarrenr
246255332Scy	if (op->iplo_size != sizeof(stats)) {
247255332Scy		IPFERROR(30001);
248145516Sdarrenr		return EINVAL;
249255332Scy	}
250145516Sdarrenr
251255332Scy	stats.iphs_tables = softh->ipf_htables[op->iplo_unit + 1];
252255332Scy	stats.iphs_numtables = softh->ipf_nhtables[op->iplo_unit + 1];
253255332Scy	stats.iphs_numnodes = softh->ipf_nhtnodes[op->iplo_unit + 1];
254255332Scy	stats.iphs_nomem = softh->ipht_nomem[op->iplo_unit + 1];
255145516Sdarrenr
256255332Scy	err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
257255332Scy	if (err != 0) {
258255332Scy		IPFERROR(30013);
259255332Scy		return EFAULT;
260255332Scy	}
261255332Scy	return 0;
262145516Sdarrenr
263145516Sdarrenr}
264145516Sdarrenr
265145516Sdarrenr
266255332Scy/* ------------------------------------------------------------------------ */
267255332Scy/* Function:    ipf_htable_create                                           */
268255332Scy/* Returns:     int - 0 = success, else error                               */
269255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
270255332Scy/*              arg(I)   - pointer to local context to use                  */
271255332Scy/*              op(I)    - pointer to lookup operation data                 */
272255332Scy/*                                                                          */
273255332Scy/* Create a new hash table using the template passed.                       */
274255332Scy/* ------------------------------------------------------------------------ */
275255332Scystatic int
276255332Scyipf_htable_create(softc, arg, op)
277255332Scy	ipf_main_softc_t *softc;
278255332Scy	void *arg;
279255332Scy	iplookupop_t *op;
280145516Sdarrenr{
281255332Scy	ipf_htable_softc_t *softh = arg;
282255332Scy	iphtable_t htab, *iph, *oiph;
283145516Sdarrenr	char name[FR_GROUPLEN];
284145516Sdarrenr	int err, i, unit;
285145516Sdarrenr
286255332Scy	if (op->iplo_size != sizeof(htab)) {
287255332Scy		IPFERROR(30024);
288255332Scy		return EINVAL;
289255332Scy	}
290255332Scy	err = COPYIN(op->iplo_struct, &htab, sizeof(htab));
291255332Scy	if (err != 0) {
292255332Scy		IPFERROR(30003);
293255332Scy		return EFAULT;
294255332Scy	}
295255332Scy
296170268Sdarrenr	unit = op->iplo_unit;
297255332Scy	if (htab.iph_unit != unit) {
298255332Scy		IPFERROR(30005);
299255332Scy		return EINVAL;
300255332Scy	}
301255332Scy	if (htab.iph_size < 1) {
302255332Scy		IPFERROR(30025);
303255332Scy		return EINVAL;
304255332Scy	}
305255332Scy
306255332Scy
307172776Sdarrenr	if ((op->iplo_arg & IPHASH_ANON) == 0) {
308255332Scy		iph = ipf_htable_exists(softh, unit, op->iplo_name);
309172776Sdarrenr		if (iph != NULL) {
310255332Scy			if ((iph->iph_flags & IPHASH_DELETE) == 0) {
311255332Scy				IPFERROR(30004);
312172776Sdarrenr				return EEXIST;
313255332Scy			}
314172776Sdarrenr			iph->iph_flags &= ~IPHASH_DELETE;
315255332Scy			iph->iph_ref++;
316172776Sdarrenr			return 0;
317172776Sdarrenr		}
318172776Sdarrenr	}
319170268Sdarrenr
320172776Sdarrenr	KMALLOC(iph, iphtable_t *);
321147547Sdarrenr	if (iph == NULL) {
322255332Scy		softh->ipht_nomem[op->iplo_unit + 1]++;
323255332Scy		IPFERROR(30002);
324172776Sdarrenr		return ENOMEM;
325147547Sdarrenr	}
326255332Scy	*iph = htab;
327145516Sdarrenr
328170268Sdarrenr	if ((op->iplo_arg & IPHASH_ANON) != 0) {
329145516Sdarrenr		i = IPHASH_ANON;
330145516Sdarrenr		do {
331145516Sdarrenr			i++;
332145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL)
333145516Sdarrenr			SNPRINTF(name, sizeof(name), "%u", i);
334145516Sdarrenr#else
335145516Sdarrenr			(void)sprintf(name, "%u", i);
336145516Sdarrenr#endif
337255332Scy			for (oiph = softh->ipf_htables[unit + 1]; oiph != NULL;
338145516Sdarrenr			     oiph = oiph->iph_next)
339145516Sdarrenr				if (strncmp(oiph->iph_name, name,
340145516Sdarrenr					    sizeof(oiph->iph_name)) == 0)
341145516Sdarrenr					break;
342145516Sdarrenr		} while (oiph != NULL);
343153876Sguido
344145516Sdarrenr		(void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
345153876Sguido		(void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
346145516Sdarrenr		iph->iph_type |= IPHASH_ANON;
347255332Scy	} else {
348255332Scy		(void)strncpy(iph->iph_name, op->iplo_name,
349255332Scy			      sizeof(iph->iph_name));
350255332Scy		iph->iph_name[sizeof(iph->iph_name) - 1] = '\0';
351145516Sdarrenr	}
352145516Sdarrenr
353172776Sdarrenr	KMALLOCS(iph->iph_table, iphtent_t **,
354172776Sdarrenr		 iph->iph_size * sizeof(*iph->iph_table));
355172776Sdarrenr	if (iph->iph_table == NULL) {
356172776Sdarrenr		KFREE(iph);
357255332Scy		softh->ipht_nomem[unit + 1]++;
358255332Scy		IPFERROR(30006);
359172776Sdarrenr		return ENOMEM;
360172776Sdarrenr	}
361145516Sdarrenr
362172776Sdarrenr	bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
363255332Scy	iph->iph_maskset[0] = 0;
364255332Scy	iph->iph_maskset[1] = 0;
365255332Scy	iph->iph_maskset[2] = 0;
366255332Scy	iph->iph_maskset[3] = 0;
367145516Sdarrenr
368172776Sdarrenr	iph->iph_ref = 1;
369255332Scy	iph->iph_list = NULL;
370255332Scy	iph->iph_tail = &iph->iph_list;
371255332Scy	iph->iph_next = softh->ipf_htables[unit + 1];
372255332Scy	iph->iph_pnext = &softh->ipf_htables[unit + 1];
373255332Scy	if (softh->ipf_htables[unit + 1] != NULL)
374255332Scy		softh->ipf_htables[unit + 1]->iph_pnext = &iph->iph_next;
375255332Scy	softh->ipf_htables[unit + 1] = iph;
376145516Sdarrenr
377255332Scy	softh->ipf_nhtables[unit + 1]++;
378255332Scy
379145516Sdarrenr	return 0;
380145516Sdarrenr}
381145516Sdarrenr
382145516Sdarrenr
383255332Scy/* ------------------------------------------------------------------------ */
384255332Scy/* Function:    ipf_htable_table_del                                        */
385255332Scy/* Returns:     int      - 0 = success, else error                          */
386255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
387255332Scy/*              arg(I)   - pointer to local context to use                  */
388255332Scy/*              op(I)    - pointer to lookup operation data                 */
389255332Scy/*                                                                          */
390255332Scy/* ------------------------------------------------------------------------ */
391255332Scystatic int
392255332Scyipf_htable_table_del(softc, arg, op)
393255332Scy	ipf_main_softc_t *softc;
394255332Scy	void *arg;
395255332Scy	iplookupop_t *op;
396145516Sdarrenr{
397255332Scy	return ipf_htable_destroy(softc, arg, op->iplo_unit, op->iplo_name);
398255332Scy}
399255332Scy
400255332Scy
401255332Scy/* ------------------------------------------------------------------------ */
402255332Scy/* Function:    ipf_htable_destroy                                          */
403255332Scy/* Returns:     int      - 0 = success, else error                          */
404255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
405255332Scy/*              arg(I)   - pointer to local context to use                  */
406255332Scy/*              op(I)    - pointer to lookup operation data                 */
407255332Scy/*                                                                          */
408255332Scy/* Find the hash table that belongs to the relevant part of ipfilter with a */
409255332Scy/* matching name and attempt to destroy it.  If it is in use, empty it out  */
410255332Scy/* and mark it for deletion so that when all the references disappear, it   */
411255332Scy/* can be removed.                                                          */
412255332Scy/* ------------------------------------------------------------------------ */
413255332Scystatic int
414255332Scyipf_htable_destroy(softc, arg, unit, name)
415255332Scy	ipf_main_softc_t *softc;
416255332Scy	void *arg;
417255332Scy	int unit;
418255332Scy	char *name;
419255332Scy{
420145516Sdarrenr	iphtable_t *iph;
421145516Sdarrenr
422255332Scy	iph = ipf_htable_find(arg, unit, name);
423255332Scy	if (iph == NULL) {
424255332Scy		IPFERROR(30007);
425145516Sdarrenr		return ESRCH;
426255332Scy	}
427145516Sdarrenr
428170268Sdarrenr	if (iph->iph_unit != unit) {
429255332Scy		IPFERROR(30008);
430145516Sdarrenr		return EINVAL;
431145516Sdarrenr	}
432145516Sdarrenr
433145516Sdarrenr	if (iph->iph_ref != 0) {
434255332Scy		ipf_htable_clear(softc, arg, iph);
435170268Sdarrenr		iph->iph_flags |= IPHASH_DELETE;
436170268Sdarrenr		return 0;
437145516Sdarrenr	}
438145516Sdarrenr
439255332Scy	ipf_htable_remove(softc, arg, iph);
440145516Sdarrenr
441145516Sdarrenr	return 0;
442145516Sdarrenr}
443145516Sdarrenr
444145516Sdarrenr
445255332Scy/* ------------------------------------------------------------------------ */
446255332Scy/* Function:    ipf_htable_clear                                            */
447255332Scy/* Returns:     int      - 0 = success, else error                          */
448255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
449255332Scy/*              arg(I)   - pointer to local context to use                  */
450255332Scy/*              iph(I)   - pointer to hash table to destroy                 */
451255332Scy/*                                                                          */
452255332Scy/* Clean out the hash table by walking the list of entries and removing     */
453255332Scy/* each one, one by one.                                                    */
454255332Scy/* ------------------------------------------------------------------------ */
455255332Scystatic int
456255332Scyipf_htable_clear(softc, arg, iph)
457255332Scy	ipf_main_softc_t *softc;
458255332Scy	void *arg;
459255332Scy	iphtable_t *iph;
460145516Sdarrenr{
461145516Sdarrenr	iphtent_t *ipe;
462145516Sdarrenr
463170268Sdarrenr	while ((ipe = iph->iph_list) != NULL)
464255332Scy		if (ipf_htent_remove(softc, arg, iph, ipe) != 0)
465170268Sdarrenr			return 1;
466170268Sdarrenr	return 0;
467170268Sdarrenr}
468145516Sdarrenr
469170268Sdarrenr
470255332Scy/* ------------------------------------------------------------------------ */
471255332Scy/* Function:    ipf_htable_free                                             */
472255332Scy/* Returns:     Nil                                                         */
473255332Scy/* Parameters:  arg(I) - pointer to local context to use                    */
474255332Scy/*              iph(I) - pointer to hash table to destroy                   */
475255332Scy/*                                                                          */
476255332Scy/* ------------------------------------------------------------------------ */
477255332Scystatic void
478255332Scyipf_htable_free(arg, iph)
479255332Scy	void *arg;
480255332Scy	iphtable_t *iph;
481170268Sdarrenr{
482255332Scy	ipf_htable_softc_t *softh = arg;
483170268Sdarrenr
484255332Scy	if (iph->iph_next != NULL)
485255332Scy		iph->iph_next->iph_pnext = iph->iph_pnext;
486255332Scy	if (iph->iph_pnext != NULL)
487255332Scy		*iph->iph_pnext = iph->iph_next;
488255332Scy	iph->iph_pnext = NULL;
489255332Scy	iph->iph_next = NULL;
490255332Scy
491255332Scy	softh->ipf_nhtables[iph->iph_unit + 1]--;
492255332Scy
493255332Scy	KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
494255332Scy	KFREE(iph);
495255332Scy}
496255332Scy
497255332Scy
498255332Scy/* ------------------------------------------------------------------------ */
499255332Scy/* Function:    ipf_htable_remove                                           */
500255332Scy/* Returns:     int      - 0 = success, else error                          */
501255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
502255332Scy/*              arg(I)   - pointer to local context to use                  */
503255332Scy/*              iph(I)   - pointer to hash table to destroy                 */
504255332Scy/*                                                                          */
505255332Scy/* It is necessary to unlink here as well as free (called by deref) so that */
506255332Scy/* the while loop in ipf_htable_flush() functions properly.                 */
507255332Scy/* ------------------------------------------------------------------------ */
508255332Scystatic int
509255332Scyipf_htable_remove(softc, arg, iph)
510255332Scy	ipf_main_softc_t *softc;
511255332Scy	void *arg;
512255332Scy	iphtable_t *iph;
513255332Scy{
514255332Scy
515255332Scy	if (ipf_htable_clear(softc, arg, iph) != 0)
516170268Sdarrenr		return 1;
517170268Sdarrenr
518170268Sdarrenr	if (iph->iph_pnext != NULL)
519170268Sdarrenr		*iph->iph_pnext = iph->iph_next;
520145516Sdarrenr	if (iph->iph_next != NULL)
521145516Sdarrenr		iph->iph_next->iph_pnext = iph->iph_pnext;
522255332Scy	iph->iph_pnext = NULL;
523255332Scy	iph->iph_next = NULL;
524145516Sdarrenr
525255332Scy	return ipf_htable_deref(softc, arg, iph);
526255332Scy}
527145516Sdarrenr
528255332Scy
529255332Scy/* ------------------------------------------------------------------------ */
530255332Scy/* Function:    ipf_htable_node_del                                         */
531255332Scy/* Returns:     int      - 0 = success, else error                          */
532255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
533255332Scy/*              arg(I)   - pointer to local context to use                  */
534255332Scy/*              op(I)    - pointer to lookup operation data                 */
535255332Scy/*              uid(I)   - real uid of process doing operation              */
536255332Scy/*                                                                          */
537255332Scy/* ------------------------------------------------------------------------ */
538255332Scystatic int
539255332Scyipf_htable_node_del(softc, arg, op, uid)
540255332Scy	ipf_main_softc_t *softc;
541255332Scy	void *arg;
542255332Scy	iplookupop_t *op;
543255332Scy	int uid;
544255332Scy{
545255332Scy        iphtable_t *iph;
546255332Scy        iphtent_t hte, *ent;
547255332Scy	int err;
548255332Scy
549255332Scy	if (op->iplo_size != sizeof(hte)) {
550255332Scy		IPFERROR(30014);
551255332Scy		return EINVAL;
552255332Scy	}
553255332Scy
554255332Scy	err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
555255332Scy	if (err != 0) {
556255332Scy		IPFERROR(30015);
557255332Scy		return EFAULT;
558255332Scy	}
559255332Scy
560255332Scy	iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
561255332Scy	if (iph == NULL) {
562255332Scy		IPFERROR(30016);
563255332Scy		return ESRCH;
564255332Scy	}
565255332Scy
566255332Scy	ent = ipf_htent_find(iph, &hte);
567255332Scy	if (ent == NULL) {
568255332Scy		IPFERROR(30022);
569255332Scy		return ESRCH;
570255332Scy	}
571255332Scy
572255332Scy	if ((uid != 0) && (ent->ipe_uid != uid)) {
573255332Scy		IPFERROR(30023);
574255332Scy		return EACCES;
575255332Scy	}
576255332Scy
577255332Scy	err = ipf_htent_remove(softc, arg, iph, ent);
578255332Scy
579255332Scy	return err;
580170268Sdarrenr}
581170268Sdarrenr
582170268Sdarrenr
583255332Scy/* ------------------------------------------------------------------------ */
584255332Scy/* Function:    ipf_htable_node_del                                         */
585255332Scy/* Returns:     int      - 0 = success, else error                          */
586255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
587255332Scy/*              arg(I)   - pointer to local context to use                  */
588255332Scy/*              op(I)    - pointer to lookup operation data                 */
589255332Scy/*                                                                          */
590255332Scy/* ------------------------------------------------------------------------ */
591255332Scystatic int
592255332Scyipf_htable_table_add(softc, arg, op)
593255332Scy	ipf_main_softc_t *softc;
594255332Scy	void *arg;
595255332Scy        iplookupop_t *op;
596170268Sdarrenr{
597255332Scy	int err;
598170268Sdarrenr
599255332Scy	if (ipf_htable_find(arg, op->iplo_unit, op->iplo_name) != NULL) {
600255332Scy		IPFERROR(30017);
601255332Scy		err = EEXIST;
602255332Scy	} else {
603255332Scy		err = ipf_htable_create(softc, arg, op);
604255332Scy	}
605255332Scy
606255332Scy	return err;
607255332Scy}
608255332Scy
609255332Scy
610255332Scy/* ------------------------------------------------------------------------ */
611255332Scy/* Function:    ipf_htent_remove                                            */
612255332Scy/* Returns:     int      - 0 = success, else error                          */
613255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
614255332Scy/*              arg(I)   - pointer to local context to use                  */
615255332Scy/*              iph(I)   - pointer to hash table                            */
616255332Scy/*              ipe(I)   - pointer to hash table entry to remove            */
617255332Scy/*                                                                          */
618255332Scy/* Delete an entry from a hash table.                                       */
619255332Scy/* ------------------------------------------------------------------------ */
620255332Scystatic int
621255332Scyipf_htent_remove(softc, arg, iph, ipe)
622255332Scy	ipf_main_softc_t *softc;
623255332Scy	void *arg;
624255332Scy	iphtable_t *iph;
625255332Scy	iphtent_t *ipe;
626255332Scy{
627255332Scy
628255332Scy	if (iph->iph_tail == &ipe->ipe_next)
629255332Scy		iph->iph_tail = ipe->ipe_pnext;
630255332Scy
631255332Scy	if (ipe->ipe_hnext != NULL)
632255332Scy		ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext;
633170268Sdarrenr	if (ipe->ipe_phnext != NULL)
634170268Sdarrenr		*ipe->ipe_phnext = ipe->ipe_hnext;
635255332Scy	ipe->ipe_phnext = NULL;
636255332Scy	ipe->ipe_hnext = NULL;
637170268Sdarrenr
638255332Scy	if (ipe->ipe_dnext != NULL)
639255332Scy		ipe->ipe_dnext->ipe_pdnext = ipe->ipe_pdnext;
640255332Scy	if (ipe->ipe_pdnext != NULL)
641255332Scy		*ipe->ipe_pdnext = ipe->ipe_dnext;
642255332Scy	ipe->ipe_pdnext = NULL;
643255332Scy	ipe->ipe_dnext = NULL;
644255332Scy
645255332Scy	if (ipe->ipe_next != NULL)
646255332Scy		ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
647170268Sdarrenr	if (ipe->ipe_pnext != NULL)
648170268Sdarrenr		*ipe->ipe_pnext = ipe->ipe_next;
649255332Scy	ipe->ipe_pnext = NULL;
650255332Scy	ipe->ipe_next = NULL;
651170268Sdarrenr
652170268Sdarrenr	switch (iph->iph_type & ~IPHASH_ANON)
653170268Sdarrenr	{
654170268Sdarrenr	case IPHASH_GROUPMAP :
655170268Sdarrenr		if (ipe->ipe_group != NULL)
656255332Scy			ipf_group_del(softc, ipe->ipe_ptr, NULL);
657170268Sdarrenr		break;
658170268Sdarrenr
659170268Sdarrenr	default :
660170268Sdarrenr		ipe->ipe_ptr = NULL;
661170268Sdarrenr		ipe->ipe_value = 0;
662170268Sdarrenr		break;
663170268Sdarrenr	}
664170268Sdarrenr
665255332Scy	return ipf_htent_deref(arg, ipe);
666170268Sdarrenr}
667170268Sdarrenr
668170268Sdarrenr
669255332Scy/* ------------------------------------------------------------------------ */
670255332Scy/* Function:    ipf_htable_deref                                            */
671255332Scy/* Returns:     int       - 0 = success, else error                         */
672255332Scy/* Parameters:  softc(I)  - pointer to soft context main structure          */
673255332Scy/*              arg(I)    - pointer to local context to use                 */
674255332Scy/*              object(I) - pointer to hash table                           */
675255332Scy/*                                                                          */
676255332Scy/* ------------------------------------------------------------------------ */
677255332Scystatic int
678255332Scyipf_htable_deref(softc, arg, object)
679255332Scy	ipf_main_softc_t *softc;
680255332Scy	void *arg, *object;
681170268Sdarrenr{
682255332Scy	ipf_htable_softc_t *softh = arg;
683255332Scy	iphtable_t *iph = object;
684170268Sdarrenr	int refs;
685170268Sdarrenr
686170268Sdarrenr	iph->iph_ref--;
687170268Sdarrenr	refs = iph->iph_ref;
688170268Sdarrenr
689145516Sdarrenr	if (iph->iph_ref == 0) {
690255332Scy		ipf_htable_free(softh, iph);
691145516Sdarrenr	}
692170268Sdarrenr
693170268Sdarrenr	return refs;
694145516Sdarrenr}
695145516Sdarrenr
696145516Sdarrenr
697255332Scy/* ------------------------------------------------------------------------ */
698255332Scy/* Function:    ipf_htent_deref                                             */
699255332Scy/* Parameters:  arg(I) - pointer to local context to use                    */
700255332Scy/*              ipe(I) -                                                    */
701255332Scy/*                                                                          */
702255332Scy/* ------------------------------------------------------------------------ */
703255332Scystatic int
704255332Scyipf_htent_deref(arg, ipe)
705255332Scy	void *arg;
706255332Scy	iphtent_t *ipe;
707145516Sdarrenr{
708255332Scy	ipf_htable_softc_t *softh = arg;
709170268Sdarrenr
710170268Sdarrenr	ipe->ipe_ref--;
711170268Sdarrenr	if (ipe->ipe_ref == 0) {
712255332Scy		softh->ipf_nhtnodes[ipe->ipe_unit + 1]--;
713170268Sdarrenr		KFREE(ipe);
714170268Sdarrenr
715170268Sdarrenr		return 0;
716170268Sdarrenr	}
717170268Sdarrenr
718170268Sdarrenr	return ipe->ipe_ref;
719145516Sdarrenr}
720145516Sdarrenr
721145516Sdarrenr
722255332Scy/* ------------------------------------------------------------------------ */
723255332Scy/* Function:    ipf_htable_exists                                           */
724255332Scy/* Parameters:  arg(I) - pointer to local context to use                    */
725255332Scy/*                                                                          */
726255332Scy/* ------------------------------------------------------------------------ */
727255332Scystatic void *
728255332Scyipf_htable_exists(arg, unit, name)
729255332Scy	void *arg;
730255332Scy	int unit;
731255332Scy	char *name;
732145516Sdarrenr{
733255332Scy	ipf_htable_softc_t *softh = arg;
734145516Sdarrenr	iphtable_t *iph;
735145516Sdarrenr
736255332Scy	if (unit == IPL_LOGALL) {
737255332Scy		int i;
738255332Scy
739255332Scy		for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
740255332Scy			for (iph = softh->ipf_htables[i]; iph != NULL;
741255332Scy			     iph = iph->iph_next) {
742255332Scy				if (strncmp(iph->iph_name, name,
743255332Scy					    sizeof(iph->iph_name)) == 0)
744255332Scy					break;
745255332Scy			}
746255332Scy			if (iph != NULL)
747255332Scy				break;
748255332Scy		}
749255332Scy	} else {
750255332Scy		for (iph = softh->ipf_htables[unit + 1]; iph != NULL;
751255332Scy		     iph = iph->iph_next) {
752255332Scy			if (strncmp(iph->iph_name, name,
753255332Scy				    sizeof(iph->iph_name)) == 0)
754255332Scy				break;
755255332Scy		}
756255332Scy	}
757145516Sdarrenr	return iph;
758145516Sdarrenr}
759145516Sdarrenr
760145516Sdarrenr
761255332Scy/* ------------------------------------------------------------------------ */
762255332Scy/* Function:    ipf_htable_select_add_ref                                   */
763255332Scy/* Returns:     void *  - NULL = failure, else pointer to the hash table    */
764255332Scy/* Parameters:  arg(I)  - pointer to local context to use                   */
765255332Scy/*              unit(I) - ipfilter device to which we are working on        */
766255332Scy/*              name(I) - name of the hash table                            */
767255332Scy/*                                                                          */
768255332Scy/* ------------------------------------------------------------------------ */
769255332Scystatic void *
770255332Scyipf_htable_select_add_ref(arg, unit, name)
771255332Scy	void *arg;
772255332Scy	int unit;
773255332Scy	char *name;
774170268Sdarrenr{
775170268Sdarrenr	iphtable_t *iph;
776170268Sdarrenr
777255332Scy	iph = ipf_htable_exists(arg, unit, name);
778255332Scy	if (iph != NULL) {
779255332Scy		ATOMIC_INC32(iph->iph_ref);
780255332Scy	}
781255332Scy	return iph;
782255332Scy}
783255332Scy
784255332Scy
785255332Scy/* ------------------------------------------------------------------------ */
786255332Scy/* Function:    ipf_htable_find                                             */
787255332Scy/* Returns:     void *  - NULL = failure, else pointer to the hash table    */
788255332Scy/* Parameters:  arg(I)  - pointer to local context to use                   */
789255332Scy/*              unit(I) - ipfilter device to which we are working on        */
790255332Scy/*              name(I) - name of the hash table                            */
791255332Scy/*                                                                          */
792255332Scy/* This function is exposed becaues it is used in the group-map feature.    */
793255332Scy/* ------------------------------------------------------------------------ */
794255332Scyiphtable_t *
795255332Scyipf_htable_find(arg, unit, name)
796255332Scy	void *arg;
797255332Scy	int unit;
798255332Scy	char *name;
799255332Scy{
800255332Scy	iphtable_t *iph;
801255332Scy
802255332Scy	iph = ipf_htable_exists(arg, unit, name);
803170268Sdarrenr	if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0)
804170268Sdarrenr		return iph;
805170268Sdarrenr
806170268Sdarrenr	return NULL;
807170268Sdarrenr}
808170268Sdarrenr
809170268Sdarrenr
810255332Scy/* ------------------------------------------------------------------------ */
811255332Scy/* Function:    ipf_htable_flush                                            */
812255332Scy/* Returns:     size_t   - number of entries flushed                        */
813255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
814255332Scy/*              arg(I)   - pointer to local context to use                  */
815255332Scy/*              op(I)    - pointer to lookup operation data                 */
816255332Scy/*                                                                          */
817255332Scy/* ------------------------------------------------------------------------ */
818255332Scystatic size_t
819255332Scyipf_htable_flush(softc, arg, op)
820255332Scy	ipf_main_softc_t *softc;
821255332Scy	void *arg;
822255332Scy	iplookupflush_t *op;
823145516Sdarrenr{
824255332Scy	ipf_htable_softc_t *softh = arg;
825145516Sdarrenr	iphtable_t *iph;
826145516Sdarrenr	size_t freed;
827145516Sdarrenr	int i;
828145516Sdarrenr
829145516Sdarrenr	freed = 0;
830145516Sdarrenr
831255332Scy	for (i = -1; i <= IPL_LOGMAX; i++) {
832145516Sdarrenr		if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
833255332Scy			while ((iph = softh->ipf_htables[i + 1]) != NULL) {
834255332Scy				if (ipf_htable_remove(softc, arg, iph) == 0) {
835170268Sdarrenr					freed++;
836170268Sdarrenr				} else {
837170268Sdarrenr					iph->iph_flags |= IPHASH_DELETE;
838170268Sdarrenr				}
839145516Sdarrenr			}
840145516Sdarrenr		}
841145516Sdarrenr	}
842145516Sdarrenr
843145516Sdarrenr	return freed;
844145516Sdarrenr}
845145516Sdarrenr
846145516Sdarrenr
847255332Scy/* ------------------------------------------------------------------------ */
848255332Scy/* Function:    ipf_htable_node_add                                         */
849255332Scy/* Returns:     int      - 0 = success, else error                          */
850255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
851255332Scy/*              arg(I)   - pointer to local context to use                  */
852255332Scy/*              op(I)    - pointer to lookup operation data                 */
853255332Scy/*              uid(I)   - real uid of process doing operation              */
854255332Scy/*                                                                          */
855255332Scy/* ------------------------------------------------------------------------ */
856255332Scystatic int
857255332Scyipf_htable_node_add(softc, arg, op, uid)
858255332Scy	ipf_main_softc_t *softc;
859255332Scy	void *arg;
860255332Scy	iplookupop_t *op;
861255332Scy	int uid;
862145516Sdarrenr{
863255332Scy	iphtable_t *iph;
864255332Scy	iphtent_t hte;
865255332Scy	int err;
866255332Scy
867255332Scy	if (op->iplo_size != sizeof(hte)) {
868255332Scy		IPFERROR(30018);
869255332Scy		return EINVAL;
870255332Scy	}
871255332Scy
872255332Scy	err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
873255332Scy	if (err != 0) {
874255332Scy		IPFERROR(30019);
875255332Scy		return EFAULT;
876255332Scy	}
877255332Scy	hte.ipe_uid = uid;
878255332Scy
879255332Scy	iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
880255332Scy	if (iph == NULL) {
881255332Scy		IPFERROR(30020);
882255332Scy		return ESRCH;
883255332Scy	}
884255332Scy
885255332Scy	if (ipf_htent_find(iph, &hte) != NULL) {
886255332Scy		IPFERROR(30021);
887255332Scy		return EEXIST;
888255332Scy	}
889255332Scy
890255332Scy	err = ipf_htent_insert(softc, arg, iph, &hte);
891255332Scy
892255332Scy	return err;
893255332Scy}
894255332Scy
895255332Scy
896255332Scy/* ------------------------------------------------------------------------ */
897255332Scy/* Function:    ipf_htent_insert                                            */
898255332Scy/* Returns:     int      - 0 = success, -1 =  error                         */
899255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
900255332Scy/*              arg(I)   - pointer to local context to use                  */
901255332Scy/*              op(I)    - pointer to lookup operation data                 */
902255332Scy/*              ipeo(I)  -                                                  */
903255332Scy/*                                                                          */
904255332Scy/* Add an entry to a hash table.                                            */
905255332Scy/* ------------------------------------------------------------------------ */
906255332Scystatic int
907255332Scyipf_htent_insert(softc, arg, iph, ipeo)
908255332Scy	ipf_main_softc_t *softc;
909255332Scy	void *arg;
910255332Scy	iphtable_t *iph;
911255332Scy	iphtent_t *ipeo;
912255332Scy{
913255332Scy	ipf_htable_softc_t *softh = arg;
914145516Sdarrenr	iphtent_t *ipe;
915145516Sdarrenr	u_int hv;
916145516Sdarrenr	int bits;
917145516Sdarrenr
918145516Sdarrenr	KMALLOC(ipe, iphtent_t *);
919145516Sdarrenr	if (ipe == NULL)
920145516Sdarrenr		return -1;
921145516Sdarrenr
922145516Sdarrenr	bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
923255332Scy	ipe->ipe_addr.i6[0] &= ipe->ipe_mask.i6[0];
924255332Scy	if (ipe->ipe_family == AF_INET) {
925255332Scy		bits = count4bits(ipe->ipe_mask.in4_addr);
926255332Scy		ipe->ipe_addr.i6[1] = 0;
927255332Scy		ipe->ipe_addr.i6[2] = 0;
928255332Scy		ipe->ipe_addr.i6[3] = 0;
929255332Scy		ipe->ipe_mask.i6[1] = 0;
930255332Scy		ipe->ipe_mask.i6[2] = 0;
931255332Scy		ipe->ipe_mask.i6[3] = 0;
932255332Scy		hv = IPE_V4_HASH_FN(ipe->ipe_addr.in4_addr,
933255332Scy				    ipe->ipe_mask.in4_addr, iph->iph_size);
934255332Scy	} else
935255332Scy#ifdef USE_INET6
936255332Scy	if (ipe->ipe_family == AF_INET6) {
937255332Scy		ipe->ipe_addr.i6[1] &= ipe->ipe_mask.i6[1];
938255332Scy		ipe->ipe_addr.i6[2] &= ipe->ipe_mask.i6[2];
939255332Scy		ipe->ipe_addr.i6[3] &= ipe->ipe_mask.i6[3];
940145516Sdarrenr
941255332Scy		bits = count6bits(ipe->ipe_mask.i6);
942255332Scy		hv = IPE_V6_HASH_FN(ipe->ipe_addr.i6,
943255332Scy				    ipe->ipe_mask.i6, iph->iph_size);
944255332Scy	} else
945255332Scy#endif
946255332Scy	{
947255332Scy		KFREE(ipe);
948255332Scy		return -1;
949255332Scy	}
950255332Scy
951255332Scy	ipe->ipe_owner = iph;
952170268Sdarrenr	ipe->ipe_ref = 1;
953170268Sdarrenr	ipe->ipe_hnext = iph->iph_table[hv];
954170268Sdarrenr	ipe->ipe_phnext = iph->iph_table + hv;
955145516Sdarrenr
956145516Sdarrenr	if (iph->iph_table[hv] != NULL)
957170268Sdarrenr		iph->iph_table[hv]->ipe_phnext = &ipe->ipe_hnext;
958145516Sdarrenr	iph->iph_table[hv] = ipe;
959170268Sdarrenr
960255332Scy	ipe->ipe_pnext = iph->iph_tail;
961255332Scy	*iph->iph_tail = ipe;
962255332Scy	iph->iph_tail = &ipe->ipe_next;
963255332Scy	ipe->ipe_next = NULL;
964170268Sdarrenr
965255332Scy	if (ipe->ipe_die != 0) {
966255332Scy		/*
967255332Scy		 * If the new node has a given expiration time, insert it
968255332Scy		 * into the list of expiring nodes with the ones to be
969255332Scy		 * removed first added to the front of the list. The
970255332Scy		 * insertion is O(n) but it is kept sorted for quick scans
971255332Scy		 * at expiration interval checks.
972255332Scy		 */
973255332Scy		iphtent_t *n;
974145516Sdarrenr
975255332Scy		ipe->ipe_die = softc->ipf_ticks + IPF_TTLVAL(ipe->ipe_die);
976255332Scy		for (n = softh->ipf_node_explist; n != NULL; n = n->ipe_dnext) {
977255332Scy			if (ipe->ipe_die < n->ipe_die)
978255332Scy				break;
979255332Scy			if (n->ipe_dnext == NULL) {
980255332Scy				/*
981255332Scy				 * We've got to the last node and everything
982255332Scy				 * wanted to be expired before this new node,
983255332Scy				 * so we have to tack it on the end...
984255332Scy				 */
985255332Scy				n->ipe_dnext = ipe;
986255332Scy				ipe->ipe_pdnext = &n->ipe_dnext;
987255332Scy				n = NULL;
988255332Scy				break;
989255332Scy			}
990255332Scy		}
991255332Scy
992255332Scy		if (softh->ipf_node_explist == NULL) {
993255332Scy			softh->ipf_node_explist = ipe;
994255332Scy			ipe->ipe_pdnext = &softh->ipf_node_explist;
995255332Scy		} else if (n != NULL) {
996255332Scy			ipe->ipe_dnext = n;
997255332Scy			ipe->ipe_pdnext = n->ipe_pdnext;
998255332Scy			n->ipe_pdnext = &ipe->ipe_dnext;
999255332Scy		}
1000255332Scy	}
1001255332Scy
1002255332Scy	if (ipe->ipe_family == AF_INET) {
1003255332Scy		ipf_inet_mask_add(bits, &iph->iph_v4_masks);
1004255332Scy	}
1005255332Scy#ifdef USE_INET6
1006255332Scy	else if (ipe->ipe_family == AF_INET6) {
1007255332Scy		ipf_inet6_mask_add(bits, &ipe->ipe_mask, &iph->iph_v6_masks);
1008255332Scy	}
1009255332Scy#endif
1010255332Scy
1011145516Sdarrenr	switch (iph->iph_type & ~IPHASH_ANON)
1012145516Sdarrenr	{
1013145516Sdarrenr	case IPHASH_GROUPMAP :
1014255332Scy		ipe->ipe_ptr = ipf_group_add(softc, ipe->ipe_group, NULL,
1015145516Sdarrenr					   iph->iph_flags, IPL_LOGIPF,
1016255332Scy					   softc->ipf_active);
1017145516Sdarrenr		break;
1018145516Sdarrenr
1019145516Sdarrenr	default :
1020145516Sdarrenr		ipe->ipe_ptr = NULL;
1021145516Sdarrenr		ipe->ipe_value = 0;
1022145516Sdarrenr		break;
1023145516Sdarrenr	}
1024145516Sdarrenr
1025170268Sdarrenr	ipe->ipe_unit = iph->iph_unit;
1026255332Scy	softh->ipf_nhtnodes[ipe->ipe_unit + 1]++;
1027145516Sdarrenr
1028145516Sdarrenr	return 0;
1029145516Sdarrenr}
1030145516Sdarrenr
1031145516Sdarrenr
1032255332Scy/* ------------------------------------------------------------------------ */
1033255332Scy/* Function:    ipf_htent_find                                              */
1034255332Scy/* Returns:     int     - 0 = success, else error                           */
1035255332Scy/* Parameters:  iph(I)  - pointer to table to search                        */
1036255332Scy/*              ipeo(I) - pointer to entry to find                          */
1037255332Scy/*                                                                          */
1038255332Scy/* While it isn't absolutely necessary to for the address and mask to be    */
1039255332Scy/* passed in through an iphtent_t structure, one is always present when it  */
1040255332Scy/* is time to call this function, so it is just more convenient.            */
1041255332Scy/* ------------------------------------------------------------------------ */
1042255332Scystatic iphtent_t *
1043255332Scyipf_htent_find(iph, ipeo)
1044255332Scy	iphtable_t *iph;
1045255332Scy	iphtent_t *ipeo;
1046145516Sdarrenr{
1047255332Scy	iphtent_t ipe, *ent;
1048255332Scy	u_int hv;
1049255332Scy	int bits;
1050255332Scy
1051255332Scy	bcopy((char *)ipeo, (char *)&ipe, sizeof(ipe));
1052255332Scy	ipe.ipe_addr.i6[0] &= ipe.ipe_mask.i6[0];
1053255332Scy	ipe.ipe_addr.i6[1] &= ipe.ipe_mask.i6[1];
1054255332Scy	ipe.ipe_addr.i6[2] &= ipe.ipe_mask.i6[2];
1055255332Scy	ipe.ipe_addr.i6[3] &= ipe.ipe_mask.i6[3];
1056255332Scy	if (ipe.ipe_family == AF_INET) {
1057255332Scy		bits = count4bits(ipe.ipe_mask.in4_addr);
1058255332Scy		ipe.ipe_addr.i6[1] = 0;
1059255332Scy		ipe.ipe_addr.i6[2] = 0;
1060255332Scy		ipe.ipe_addr.i6[3] = 0;
1061255332Scy		ipe.ipe_mask.i6[1] = 0;
1062255332Scy		ipe.ipe_mask.i6[2] = 0;
1063255332Scy		ipe.ipe_mask.i6[3] = 0;
1064255332Scy		hv = IPE_V4_HASH_FN(ipe.ipe_addr.in4_addr,
1065255332Scy				    ipe.ipe_mask.in4_addr, iph->iph_size);
1066255332Scy	} else
1067255332Scy#ifdef USE_INET6
1068255332Scy	if (ipe.ipe_family == AF_INET6) {
1069255332Scy		bits = count6bits(ipe.ipe_mask.i6);
1070255332Scy		hv = IPE_V6_HASH_FN(ipe.ipe_addr.i6,
1071255332Scy				    ipe.ipe_mask.i6, iph->iph_size);
1072255332Scy	} else
1073255332Scy#endif
1074255332Scy		return NULL;
1075255332Scy
1076255332Scy	for (ent = iph->iph_table[hv]; ent != NULL; ent = ent->ipe_hnext) {
1077255332Scy		if (ent->ipe_family != ipe.ipe_family)
1078255332Scy			continue;
1079255332Scy		if (IP6_NEQ(&ipe.ipe_addr, &ent->ipe_addr))
1080255332Scy			continue;
1081255332Scy		if (IP6_NEQ(&ipe.ipe_mask, &ent->ipe_mask))
1082255332Scy			continue;
1083255332Scy		break;
1084255332Scy	}
1085255332Scy
1086255332Scy	return ent;
1087255332Scy}
1088255332Scy
1089255332Scy
1090255332Scy/* ------------------------------------------------------------------------ */
1091255332Scy/* Function:    ipf_iphmfindgroup                                           */
1092255332Scy/* Returns:     int      - 0 = success, else error                          */
1093255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
1094255332Scy/*              tptr(I)  -                                                  */
1095255332Scy/*              aptr(I)  -                                                  */
1096255332Scy/*                                                                          */
1097255332Scy/* Search a hash table for a matching entry and return the pointer stored   */
1098255332Scy/* in it for use as the next group of rules to search.                      */
1099255332Scy/*                                                                          */
1100255332Scy/* This function is exposed becaues it is used in the group-map feature.    */
1101255332Scy/* ------------------------------------------------------------------------ */
1102255332Scyvoid *
1103255332Scyipf_iphmfindgroup(softc, tptr, aptr)
1104255332Scy	ipf_main_softc_t *softc;
1105255332Scy	void *tptr, *aptr;
1106255332Scy{
1107145516Sdarrenr	struct in_addr *addr;
1108145516Sdarrenr	iphtable_t *iph;
1109145516Sdarrenr	iphtent_t *ipe;
1110145516Sdarrenr	void *rval;
1111145516Sdarrenr
1112255332Scy	READ_ENTER(&softc->ipf_poolrw);
1113145516Sdarrenr	iph = tptr;
1114145516Sdarrenr	addr = aptr;
1115145516Sdarrenr
1116255332Scy	ipe = ipf_iphmfind(iph, addr);
1117145516Sdarrenr	if (ipe != NULL)
1118145516Sdarrenr		rval = ipe->ipe_ptr;
1119145516Sdarrenr	else
1120145516Sdarrenr		rval = NULL;
1121255332Scy	RWLOCK_EXIT(&softc->ipf_poolrw);
1122145516Sdarrenr	return rval;
1123145516Sdarrenr}
1124145516Sdarrenr
1125145516Sdarrenr
1126145516Sdarrenr/* ------------------------------------------------------------------------ */
1127255332Scy/* Function:    ipf_iphmfindip                                              */
1128145516Sdarrenr/* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
1129255332Scy/* Parameters:  softc(I)     - pointer to soft context main structure       */
1130255332Scy/*              tptr(I)      - pointer to the pool to search                */
1131170268Sdarrenr/*              ipversion(I) - IP protocol version (4 or 6)                 */
1132170268Sdarrenr/*              aptr(I)      - pointer to address information               */
1133255332Scy/*              bytes(I)     - packet length                                */
1134145516Sdarrenr/*                                                                          */
1135145516Sdarrenr/* Search the hash table for a given address and return a search result.    */
1136145516Sdarrenr/* ------------------------------------------------------------------------ */
1137255332Scystatic int
1138255332Scyipf_iphmfindip(softc, tptr, ipversion, aptr, bytes)
1139255332Scy	ipf_main_softc_t *softc;
1140255332Scy	void *tptr, *aptr;
1141255332Scy	int ipversion;
1142255332Scy	u_int bytes;
1143145516Sdarrenr{
1144145516Sdarrenr	struct in_addr *addr;
1145145516Sdarrenr	iphtable_t *iph;
1146145516Sdarrenr	iphtent_t *ipe;
1147145516Sdarrenr	int rval;
1148145516Sdarrenr
1149145516Sdarrenr	if (tptr == NULL || aptr == NULL)
1150145516Sdarrenr		return -1;
1151145516Sdarrenr
1152145516Sdarrenr	iph = tptr;
1153145516Sdarrenr	addr = aptr;
1154145516Sdarrenr
1155255332Scy	READ_ENTER(&softc->ipf_poolrw);
1156255332Scy	if (ipversion == 4) {
1157255332Scy		ipe = ipf_iphmfind(iph, addr);
1158255332Scy#ifdef USE_INET6
1159255332Scy	} else if (ipversion == 6) {
1160255332Scy		ipe = ipf_iphmfind6(iph, (i6addr_t *)addr);
1161255332Scy#endif
1162255332Scy	} else {
1163255332Scy		ipe = NULL;
1164255332Scy	}
1165255332Scy
1166255332Scy	if (ipe != NULL) {
1167145516Sdarrenr		rval = 0;
1168255332Scy		ipe->ipe_hits++;
1169255332Scy		ipe->ipe_bytes += bytes;
1170255332Scy	} else {
1171145516Sdarrenr		rval = 1;
1172255332Scy	}
1173255332Scy	RWLOCK_EXIT(&softc->ipf_poolrw);
1174145516Sdarrenr	return rval;
1175145516Sdarrenr}
1176145516Sdarrenr
1177145516Sdarrenr
1178255332Scy/* ------------------------------------------------------------------------ */
1179255332Scy/* Function:    ipf_iphmfindip                                              */
1180255332Scy/* Parameters:  iph(I)  - pointer to hash table                             */
1181255332Scy/*              addr(I) - pointer to IPv4 address                           */
1182255332Scy/* Locks:  ipf_poolrw                                                       */
1183255332Scy/*                                                                          */
1184255332Scy/* ------------------------------------------------------------------------ */
1185255332Scystatic iphtent_t *
1186255332Scyipf_iphmfind(iph, addr)
1187255332Scy	iphtable_t *iph;
1188255332Scy	struct in_addr *addr;
1189145516Sdarrenr{
1190255332Scy	u_32_t msk, ips;
1191145516Sdarrenr	iphtent_t *ipe;
1192145516Sdarrenr	u_int hv;
1193255332Scy	int i;
1194145516Sdarrenr
1195255332Scy	i = 0;
1196145516Sdarrenrmaskloop:
1197255332Scy	msk = iph->iph_v4_masks.imt4_active[i];
1198255332Scy	ips = addr->s_addr & msk;
1199255332Scy	hv = IPE_V4_HASH_FN(ips, msk, iph->iph_size);
1200170268Sdarrenr	for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_hnext) {
1201255332Scy		if ((ipe->ipe_family != AF_INET) ||
1202255332Scy		    (ipe->ipe_mask.in4_addr != msk) ||
1203255332Scy		    (ipe->ipe_addr.in4_addr != ips)) {
1204145516Sdarrenr			continue;
1205145516Sdarrenr		}
1206145516Sdarrenr		break;
1207145516Sdarrenr	}
1208145516Sdarrenr
1209255332Scy	if (ipe == NULL) {
1210255332Scy		i++;
1211255332Scy		if (i < iph->iph_v4_masks.imt4_max)
1212145516Sdarrenr			goto maskloop;
1213145516Sdarrenr	}
1214145516Sdarrenr	return ipe;
1215145516Sdarrenr}
1216145516Sdarrenr
1217170268Sdarrenr
1218255332Scy/* ------------------------------------------------------------------------ */
1219255332Scy/* Function:    ipf_htable_iter_next                                        */
1220255332Scy/* Returns:     int      - 0 = success, else error                          */
1221255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
1222255332Scy/*              arg(I)   - pointer to local context to use                  */
1223255332Scy/*              token(I) -                                                  */
1224255332Scy/*              ilp(I)   -                                                  */
1225255332Scy/*                                                                          */
1226255332Scy/* ------------------------------------------------------------------------ */
1227255332Scystatic int
1228255332Scyipf_htable_iter_next(softc, arg, token, ilp)
1229255332Scy	ipf_main_softc_t *softc;
1230255332Scy	void *arg;
1231255332Scy	ipftoken_t *token;
1232255332Scy	ipflookupiter_t *ilp;
1233170268Sdarrenr{
1234255332Scy	ipf_htable_softc_t *softh = arg;
1235170268Sdarrenr	iphtent_t *node, zn, *nextnode;
1236170268Sdarrenr	iphtable_t *iph, zp, *nextiph;
1237255332Scy	void *hnext;
1238170268Sdarrenr	int err;
1239170268Sdarrenr
1240170268Sdarrenr	err = 0;
1241170268Sdarrenr	iph = NULL;
1242170268Sdarrenr	node = NULL;
1243170268Sdarrenr	nextiph = NULL;
1244170268Sdarrenr	nextnode = NULL;
1245170268Sdarrenr
1246255332Scy	READ_ENTER(&softc->ipf_poolrw);
1247170268Sdarrenr
1248170268Sdarrenr	switch (ilp->ili_otype)
1249170268Sdarrenr	{
1250170268Sdarrenr	case IPFLOOKUPITER_LIST :
1251170268Sdarrenr		iph = token->ipt_data;
1252170268Sdarrenr		if (iph == NULL) {
1253255332Scy			nextiph = softh->ipf_htables[(int)ilp->ili_unit + 1];
1254170268Sdarrenr		} else {
1255170268Sdarrenr			nextiph = iph->iph_next;
1256170268Sdarrenr		}
1257170268Sdarrenr
1258170268Sdarrenr		if (nextiph != NULL) {
1259170268Sdarrenr			ATOMIC_INC(nextiph->iph_ref);
1260172776Sdarrenr			token->ipt_data = nextiph;
1261170268Sdarrenr		} else {
1262170268Sdarrenr			bzero((char *)&zp, sizeof(zp));
1263170268Sdarrenr			nextiph = &zp;
1264172776Sdarrenr			token->ipt_data = NULL;
1265170268Sdarrenr		}
1266255332Scy		hnext = nextiph->iph_next;
1267170268Sdarrenr		break;
1268170268Sdarrenr
1269170268Sdarrenr	case IPFLOOKUPITER_NODE :
1270170268Sdarrenr		node = token->ipt_data;
1271170268Sdarrenr		if (node == NULL) {
1272255332Scy			iph = ipf_htable_find(arg, ilp->ili_unit,
1273255332Scy					      ilp->ili_name);
1274255332Scy			if (iph == NULL) {
1275255332Scy				IPFERROR(30009);
1276170268Sdarrenr				err = ESRCH;
1277255332Scy			} else {
1278170268Sdarrenr				nextnode = iph->iph_list;
1279170268Sdarrenr			}
1280170268Sdarrenr		} else {
1281170268Sdarrenr			nextnode = node->ipe_next;
1282170268Sdarrenr		}
1283170268Sdarrenr
1284170268Sdarrenr		if (nextnode != NULL) {
1285170268Sdarrenr			ATOMIC_INC(nextnode->ipe_ref);
1286172776Sdarrenr			token->ipt_data = nextnode;
1287170268Sdarrenr		} else {
1288170268Sdarrenr			bzero((char *)&zn, sizeof(zn));
1289170268Sdarrenr			nextnode = &zn;
1290172776Sdarrenr			token->ipt_data = NULL;
1291170268Sdarrenr		}
1292255332Scy		hnext = nextnode->ipe_next;
1293170268Sdarrenr		break;
1294255332Scy
1295170268Sdarrenr	default :
1296255332Scy		IPFERROR(30010);
1297170268Sdarrenr		err = EINVAL;
1298255332Scy		hnext = NULL;
1299170268Sdarrenr		break;
1300170268Sdarrenr	}
1301170268Sdarrenr
1302255332Scy	RWLOCK_EXIT(&softc->ipf_poolrw);
1303170268Sdarrenr	if (err != 0)
1304170268Sdarrenr		return err;
1305170268Sdarrenr
1306170268Sdarrenr	switch (ilp->ili_otype)
1307170268Sdarrenr	{
1308170268Sdarrenr	case IPFLOOKUPITER_LIST :
1309255332Scy		err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
1310255332Scy		if (err != 0) {
1311255332Scy			IPFERROR(30011);
1312255332Scy			err = EFAULT;
1313255332Scy		}
1314170268Sdarrenr		if (iph != NULL) {
1315255332Scy			WRITE_ENTER(&softc->ipf_poolrw);
1316255332Scy			ipf_htable_deref(softc, softh, iph);
1317255332Scy			RWLOCK_EXIT(&softc->ipf_poolrw);
1318170268Sdarrenr		}
1319170268Sdarrenr		break;
1320170268Sdarrenr
1321170268Sdarrenr	case IPFLOOKUPITER_NODE :
1322255332Scy		err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
1323255332Scy		if (err != 0) {
1324255332Scy			IPFERROR(30012);
1325255332Scy			err = EFAULT;
1326255332Scy		}
1327170268Sdarrenr		if (node != NULL) {
1328255332Scy			WRITE_ENTER(&softc->ipf_poolrw);
1329255332Scy			ipf_htent_deref(softc, node);
1330255332Scy			RWLOCK_EXIT(&softc->ipf_poolrw);
1331170268Sdarrenr		}
1332170268Sdarrenr		break;
1333170268Sdarrenr	}
1334170268Sdarrenr
1335255332Scy	if (hnext == NULL)
1336255332Scy		ipf_token_mark_complete(token);
1337255332Scy
1338170268Sdarrenr	return err;
1339170268Sdarrenr}
1340170268Sdarrenr
1341170268Sdarrenr
1342255332Scy/* ------------------------------------------------------------------------ */
1343255332Scy/* Function:    ipf_htable_iter_deref                                       */
1344255332Scy/* Returns:     int      - 0 = success, else  error                         */
1345255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
1346255332Scy/*              arg(I)   - pointer to local context to use                  */
1347255332Scy/*              otype(I) - which data structure type is being walked        */
1348255332Scy/*              unit(I)  - ipfilter device to which we are working on       */
1349255332Scy/*              data(I)  - pointer to old data structure                    */
1350255332Scy/*                                                                          */
1351255332Scy/* ------------------------------------------------------------------------ */
1352255332Scystatic int
1353255332Scyipf_htable_iter_deref(softc, arg, otype, unit, data)
1354255332Scy	ipf_main_softc_t *softc;
1355255332Scy	void *arg;
1356255332Scy	int otype;
1357255332Scy	int unit;
1358255332Scy	void *data;
1359170268Sdarrenr{
1360170268Sdarrenr
1361170268Sdarrenr	if (data == NULL)
1362255332Scy		return EFAULT;
1363170268Sdarrenr
1364255332Scy	if (unit < -1 || unit > IPL_LOGMAX)
1365255332Scy		return EINVAL;
1366170268Sdarrenr
1367170268Sdarrenr	switch (otype)
1368170268Sdarrenr	{
1369170268Sdarrenr	case IPFLOOKUPITER_LIST :
1370255332Scy		ipf_htable_deref(softc, arg, (iphtable_t *)data);
1371170268Sdarrenr		break;
1372170268Sdarrenr
1373170268Sdarrenr	case IPFLOOKUPITER_NODE :
1374255332Scy		ipf_htent_deref(arg, (iphtent_t *)data);
1375170268Sdarrenr		break;
1376170268Sdarrenr	default :
1377170268Sdarrenr		break;
1378170268Sdarrenr	}
1379255332Scy
1380255332Scy	return 0;
1381170268Sdarrenr}
1382170268Sdarrenr
1383255332Scy
1384255332Scy#ifdef USE_INET6
1385255332Scy/* ------------------------------------------------------------------------ */
1386255332Scy/* Function:    ipf_iphmfind6                                               */
1387255332Scy/* Parameters:  iph(I)  - pointer to hash table                             */
1388255332Scy/*              addr(I) - pointer to IPv6 address                           */
1389255332Scy/* Locks:  ipf_poolrw                                                       */
1390255332Scy/*                                                                          */
1391255332Scy/* ------------------------------------------------------------------------ */
1392255332Scystatic iphtent_t *
1393255332Scyipf_iphmfind6(iph, addr)
1394255332Scy	iphtable_t *iph;
1395255332Scy	i6addr_t *addr;
1396255332Scy{
1397255332Scy	i6addr_t *msk, ips;
1398255332Scy	iphtent_t *ipe;
1399255332Scy	u_int hv;
1400255332Scy	int i;
1401255332Scy
1402255332Scy	i = 0;
1403255332Scymaskloop:
1404255332Scy	msk = iph->iph_v6_masks.imt6_active + i;
1405255332Scy	ips.i6[0] = addr->i6[0] & msk->i6[0];
1406255332Scy	ips.i6[1] = addr->i6[1] & msk->i6[1];
1407255332Scy	ips.i6[2] = addr->i6[2] & msk->i6[2];
1408255332Scy	ips.i6[3] = addr->i6[3] & msk->i6[3];
1409255332Scy	hv = IPE_V6_HASH_FN(ips.i6, msk->i6, iph->iph_size);
1410255332Scy	for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
1411255332Scy		if ((ipe->ipe_family != AF_INET6) ||
1412255332Scy		    IP6_NEQ(&ipe->ipe_mask, msk) ||
1413255332Scy		    IP6_NEQ(&ipe->ipe_addr, &ips)) {
1414255332Scy			continue;
1415255332Scy		}
1416255332Scy		break;
1417255332Scy	}
1418255332Scy
1419255332Scy	if (ipe == NULL) {
1420255332Scy		i++;
1421255332Scy		if (i < iph->iph_v6_masks.imt6_max)
1422255332Scy			goto maskloop;
1423255332Scy	}
1424255332Scy	return ipe;
1425255332Scy}
1426255332Scy#endif
1427255332Scy
1428255332Scy
1429255332Scystatic void
1430255332Scyipf_htable_expire(softc, arg)
1431255332Scy	ipf_main_softc_t *softc;
1432255332Scy	void *arg;
1433255332Scy{
1434255332Scy	ipf_htable_softc_t *softh = arg;
1435255332Scy	iphtent_t *n;
1436255332Scy
1437255332Scy	while ((n = softh->ipf_node_explist) != NULL) {
1438255332Scy		if (n->ipe_die > softc->ipf_ticks)
1439255332Scy			break;
1440255332Scy
1441255332Scy		ipf_htent_remove(softc, softh, n->ipe_owner, n);
1442255332Scy	}
1443255332Scy}
1444255332Scy
1445255332Scy
1446255332Scy#ifndef _KERNEL
1447255332Scy
1448255332Scy/* ------------------------------------------------------------------------ */
1449255332Scy/*                                                                          */
1450255332Scy/* ------------------------------------------------------------------------ */
1451255332Scyvoid
1452255332Scyipf_htable_dump(softc, arg)
1453255332Scy	ipf_main_softc_t *softc;
1454255332Scy	void *arg;
1455255332Scy{
1456255332Scy	ipf_htable_softc_t *softh = arg;
1457255332Scy	iphtable_t *iph;
1458255332Scy	int i;
1459255332Scy
1460255332Scy	printf("List of configured hash tables\n");
1461255332Scy	for (i = 0; i < IPL_LOGSIZE; i++)
1462255332Scy		for (iph = softh->ipf_htables[i]; iph != NULL;
1463255332Scy		     iph = iph->iph_next)
1464255332Scy			printhash(iph, bcopywrap, NULL, opts, NULL);
1465255332Scy
1466255332Scy}
1467255332Scy#endif
1468