1/* $FreeBSD$ */
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#if defined(__osf__)
14# define _PROTO_NET_H_
15#endif
16#include <sys/param.h>
17#include <sys/errno.h>
18#include <sys/types.h>
19#include <sys/time.h>
20#include <sys/file.h>
21#if __FreeBSD_version >= 220000 && defined(_KERNEL)
22# include <sys/fcntl.h>
23# include <sys/filio.h>
24#else
25# include <sys/ioctl.h>
26#endif
27#if !defined(_KERNEL)
28# include <stdio.h>
29# include <string.h>
30# include <stdlib.h>
31# define _KERNEL
32# ifdef __OpenBSD__
33struct file;
34# endif
35# include <sys/uio.h>
36# undef _KERNEL
37#endif
38#include <sys/socket.h>
39#include <net/if.h>
40#if defined(__FreeBSD__)
41# include <sys/cdefs.h>
42# include <sys/proc.h>
43#endif
44#if defined(_KERNEL)
45# include <sys/systm.h>
46# if !defined(__SVR4) && !defined(__svr4__)
47#  include <sys/mbuf.h>
48# endif
49#else
50# include "ipf.h"
51#endif
52#include <netinet/in.h>
53
54#include "netinet/ip_compat.h"
55#include "netinet/ip_fil.h"
56#include "netinet/ip_lookup.h"
57#include "netinet/ip_pool.h"
58#include "netinet/ip_htable.h"
59#include "netinet/ip_dstlist.h"
60/* END OF INCLUDES */
61
62#if !defined(lint)
63static const char rcsid[] = "@(#)$Id$";
64#endif
65
66/*
67 * In this file, ip_pool.c, ip_htable.c and ip_dstlist.c, you will find the
68 * range for unit is [-1,IPL_LOGMAX]. The -1 is considered to be a valid number
69 * and represents a "wildcard" or "all" units (IPL_LOGALL). The reason for not
70 * starting the numbering at 0 is because the numbers [0,IPL_LOGMAX] correspond
71 * to the minor device number for their respective device. Thus where there is
72 * array indexing on the unit, +1 is used to map [-1.IPL_LOGMAX] to
73 * [0.POOL_LOOKUP_MAX].
74 */
75static int ipf_lookup_addnode __P((ipf_main_softc_t *, caddr_t, int));
76static int ipf_lookup_delnode __P((ipf_main_softc_t *, caddr_t, int));
77static int ipf_lookup_addtable __P((ipf_main_softc_t *, caddr_t));
78static int ipf_lookup_deltable __P((ipf_main_softc_t *, caddr_t));
79static int ipf_lookup_stats __P((ipf_main_softc_t *, caddr_t));
80static int ipf_lookup_flush __P((ipf_main_softc_t *, caddr_t));
81static int ipf_lookup_iterate __P((ipf_main_softc_t *, void *, int, void *));
82static int ipf_lookup_deltok __P((ipf_main_softc_t *, void *, int, void *));
83
84#define	MAX_BACKENDS	3
85static ipf_lookup_t *backends[MAX_BACKENDS] = {
86	&ipf_pool_backend,
87	&ipf_htable_backend,
88	&ipf_dstlist_backend
89};
90
91
92typedef struct ipf_lookup_softc_s {
93	void		*ipf_back[MAX_BACKENDS];
94} ipf_lookup_softc_t;
95
96
97/* ------------------------------------------------------------------------ */
98/* Function:    ipf_lookup_init                                             */
99/* Returns:     int      - 0 = success, else error                          */
100/* Parameters:  softc(I) - pointer to soft context main structure           */
101/*                                                                          */
102/* Initialise all of the subcomponents of the lookup infrstructure.         */
103/* ------------------------------------------------------------------------ */
104void *
105ipf_lookup_soft_create(softc)
106	ipf_main_softc_t *softc;
107{
108	ipf_lookup_softc_t *softl;
109	ipf_lookup_t **l;
110	int i;
111
112	KMALLOC(softl, ipf_lookup_softc_t *);
113	if (softl == NULL)
114		return NULL;
115
116	bzero((char *)softl, sizeof(*softl));
117
118	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
119		softl->ipf_back[i] = (*(*l)->ipfl_create)(softc);
120		if (softl->ipf_back[i] == NULL) {
121			ipf_lookup_soft_destroy(softc, softl);
122			return NULL;
123		}
124	}
125
126	return softl;
127}
128
129
130/* ------------------------------------------------------------------------ */
131/* Function:    ipf_lookup_soft_init                                        */
132/* Returns:     int      - 0 = success, else error                          */
133/* Parameters:  softc(I) - pointer to soft context main structure           */
134/*              arg(I)   - pointer to local context to use                  */
135/*                                                                          */
136/* Initialise all of the subcomponents of the lookup infrstructure.         */
137/* ------------------------------------------------------------------------ */
138int
139ipf_lookup_soft_init(softc, arg)
140	ipf_main_softc_t *softc;
141	void *arg;
142{
143	ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
144	int err = 0;
145	int i;
146
147	for (i = 0; i < MAX_BACKENDS; i++) {
148		err = (*backends[i]->ipfl_init)(softc, softl->ipf_back[i]);
149		if (err != 0)
150			break;
151	}
152
153	return err;
154}
155
156
157/* ------------------------------------------------------------------------ */
158/* Function:    ipf_lookup_soft_fini                                        */
159/* Returns:     int      - 0 = success, else error                          */
160/* Parameters:  softc(I) - pointer to soft context main structure           */
161/*              arg(I)   - pointer to local context to use                  */
162/*                                                                          */
163/* Call the fini function in each backend to cleanup all allocated data.    */
164/* ------------------------------------------------------------------------ */
165int
166ipf_lookup_soft_fini(softc, arg)
167	ipf_main_softc_t *softc;
168	void *arg;
169{
170	ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
171	int i;
172
173	for (i = 0; i < MAX_BACKENDS; i++) {
174		if (softl->ipf_back[i] != NULL)
175			(*backends[i]->ipfl_fini)(softc,
176						  softl->ipf_back[i]);
177	}
178
179	return 0;
180}
181
182
183/* ------------------------------------------------------------------------ */
184/* Function:    ipf_lookup_expire                                           */
185/* Returns:     Nil                                                         */
186/* Parameters:  softc(I) - pointer to soft context main structure           */
187/*                                                                          */
188/* Step through each of the backends and call their expire functions,       */
189/* allowing them to delete any lifetime limited data.                       */
190/* ------------------------------------------------------------------------ */
191void
192ipf_lookup_expire(softc)
193	ipf_main_softc_t *softc;
194{
195	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
196	int i;
197
198	WRITE_ENTER(&softc->ipf_poolrw);
199	for (i = 0; i < MAX_BACKENDS; i++)
200		(*backends[i]->ipfl_expire)(softc, softl->ipf_back[i]);
201	RWLOCK_EXIT(&softc->ipf_poolrw);
202}
203
204
205/* ------------------------------------------------------------------------ */
206/* Function:    ipf_lookup_softc_destroy                                    */
207/* Returns:     int     - 0 = success, else error                           */
208/* Parameters:  softc(I) - pointer to soft context main structure           */
209/*              arg(I)   - pointer to local context to use                  */
210/*                                                                          */
211/* Free up all pool related memory that has been allocated whilst IPFilter  */
212/* has been running.  Also, do any other deinitialisation required such     */
213/* ipf_lookup_init() can be called again, safely.                           */
214/* ------------------------------------------------------------------------ */
215void
216ipf_lookup_soft_destroy(softc, arg)
217	ipf_main_softc_t *softc;
218	void *arg;
219{
220	ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
221	int i;
222
223	for (i = 0; i < MAX_BACKENDS; i++) {
224		if (softl->ipf_back[i] != NULL)
225			(*backends[i]->ipfl_destroy)(softc,
226						     softl->ipf_back[i]);
227	}
228
229	KFREE(softl);
230}
231
232
233/* ------------------------------------------------------------------------ */
234/* Function:    ipf_lookup_ioctl                                            */
235/* Returns:     int      - 0 = success, else error                          */
236/* Parameters:  softc(I) - pointer to soft context main structure           */
237/*              arg(I)   - pointer to local context to use                  */
238/*              data(IO) - pointer to ioctl data to be copied to/from user  */
239/*                         space.                                           */
240/*              cmd(I)   - ioctl command number                             */
241/*              mode(I)  - file mode bits used with open                    */
242/*              uid(I)   - uid of process doing ioctl                       */
243/*              ctx(I)   - pointer that represents context for uid          */
244/*                                                                          */
245/* Handle ioctl commands sent to the ioctl device.  For the most part, this */
246/* involves just calling another function to handle the specifics of each   */
247/* command.                                                                 */
248/* ------------------------------------------------------------------------ */
249int
250ipf_lookup_ioctl(softc, data, cmd, mode, uid, ctx)
251	ipf_main_softc_t *softc;
252	caddr_t data;
253	ioctlcmd_t cmd;
254	int mode, uid;
255	void *ctx;
256{
257	int err;
258	SPL_INT(s);
259
260	mode = mode;	/* LINT */
261
262	SPL_NET(s);
263
264	switch (cmd)
265	{
266	case SIOCLOOKUPADDNODE :
267	case SIOCLOOKUPADDNODEW :
268		WRITE_ENTER(&softc->ipf_poolrw);
269		err = ipf_lookup_addnode(softc, data, uid);
270		RWLOCK_EXIT(&softc->ipf_poolrw);
271		break;
272
273	case SIOCLOOKUPDELNODE :
274	case SIOCLOOKUPDELNODEW :
275		WRITE_ENTER(&softc->ipf_poolrw);
276		err = ipf_lookup_delnode(softc, data, uid);
277		RWLOCK_EXIT(&softc->ipf_poolrw);
278		break;
279
280	case SIOCLOOKUPADDTABLE :
281		WRITE_ENTER(&softc->ipf_poolrw);
282		err = ipf_lookup_addtable(softc, data);
283		RWLOCK_EXIT(&softc->ipf_poolrw);
284		break;
285
286	case SIOCLOOKUPDELTABLE :
287		WRITE_ENTER(&softc->ipf_poolrw);
288		err = ipf_lookup_deltable(softc, data);
289		RWLOCK_EXIT(&softc->ipf_poolrw);
290		break;
291
292	case SIOCLOOKUPSTAT :
293	case SIOCLOOKUPSTATW :
294		WRITE_ENTER(&softc->ipf_poolrw);
295		err = ipf_lookup_stats(softc, data);
296		RWLOCK_EXIT(&softc->ipf_poolrw);
297		break;
298
299	case SIOCLOOKUPFLUSH :
300		WRITE_ENTER(&softc->ipf_poolrw);
301		err = ipf_lookup_flush(softc, data);
302		RWLOCK_EXIT(&softc->ipf_poolrw);
303		break;
304
305	case SIOCLOOKUPITER :
306		err = ipf_lookup_iterate(softc, data, uid, ctx);
307		break;
308
309	case SIOCIPFDELTOK :
310		err = ipf_lookup_deltok(softc, data, uid, ctx);
311		break;
312
313	default :
314		IPFERROR(50001);
315		err = EINVAL;
316		break;
317	}
318	SPL_X(s);
319	return err;
320}
321
322
323/* ------------------------------------------------------------------------ */
324/* Function:    ipf_lookup_addnode                                          */
325/* Returns:     int     - 0 = success, else error                           */
326/* Parameters:  softc(I) - pointer to soft context main structure           */
327/*              data(I) - pointer to data from ioctl call                   */
328/*                                                                          */
329/* Add a new data node to a lookup structure.  First, check to see if the   */
330/* parent structure refered to by name exists and if it does, then go on to */
331/* add a node to it.                                                        */
332/* ------------------------------------------------------------------------ */
333static int
334ipf_lookup_addnode(softc, data, uid)
335	ipf_main_softc_t *softc;
336	caddr_t data;
337	int uid;
338{
339	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
340	iplookupop_t op;
341	ipf_lookup_t **l;
342	int err;
343	int i;
344
345	err = BCOPYIN(data, &op, sizeof(op));
346	if (err != 0) {
347		IPFERROR(50002);
348		return EFAULT;
349	}
350
351	if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
352	    (op.iplo_unit != IPLT_ALL)) {
353		IPFERROR(50003);
354		return EINVAL;
355	}
356
357	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
358
359	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
360		if (op.iplo_type == (*l)->ipfl_type) {
361			err = (*(*l)->ipfl_node_add)(softc,
362						     softl->ipf_back[i],
363						     &op, uid);
364			break;
365		}
366	}
367
368	if (i == MAX_BACKENDS) {
369		IPFERROR(50012);
370		err = EINVAL;
371	}
372
373	return err;
374}
375
376
377/* ------------------------------------------------------------------------ */
378/* Function:    ipf_lookup_delnode                                          */
379/* Returns:     int     - 0 = success, else error                           */
380/* Parameters:  softc(I) - pointer to soft context main structure           */
381/*              data(I) - pointer to data from ioctl call                   */
382/*                                                                          */
383/* Delete a node from a lookup table by first looking for the table it is   */
384/* in and then deleting the entry that gets found.                          */
385/* ------------------------------------------------------------------------ */
386static int
387ipf_lookup_delnode(softc, data, uid)
388	ipf_main_softc_t *softc;
389	caddr_t data;
390	int uid;
391{
392	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
393	iplookupop_t op;
394	ipf_lookup_t **l;
395	int err;
396	int i;
397
398	err = BCOPYIN(data, &op, sizeof(op));
399	if (err != 0) {
400		IPFERROR(50042);
401		return EFAULT;
402	}
403
404	if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
405	    (op.iplo_unit != IPLT_ALL)) {
406		IPFERROR(50013);
407		return EINVAL;
408	}
409
410	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
411
412	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
413		if (op.iplo_type == (*l)->ipfl_type) {
414			err = (*(*l)->ipfl_node_del)(softc, softl->ipf_back[i],
415						     &op, uid);
416			break;
417		}
418	}
419
420	if (i == MAX_BACKENDS) {
421		IPFERROR(50021);
422		err = EINVAL;
423	}
424	return err;
425}
426
427
428/* ------------------------------------------------------------------------ */
429/* Function:    ipf_lookup_addtable                                         */
430/* Returns:     int     - 0 = success, else error                           */
431/* Parameters:  softc(I) - pointer to soft context main structure           */
432/*              data(I) - pointer to data from ioctl call                   */
433/*                                                                          */
434/* Create a new lookup table, if one doesn't already exist using the name   */
435/* for this one.                                                            */
436/* ------------------------------------------------------------------------ */
437static int
438ipf_lookup_addtable(softc, data)
439	ipf_main_softc_t *softc;
440	caddr_t data;
441{
442	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
443	iplookupop_t op;
444	ipf_lookup_t **l;
445	int err, i;
446
447	err = BCOPYIN(data, &op, sizeof(op));
448	if (err != 0) {
449		IPFERROR(50022);
450		return EFAULT;
451	}
452
453	if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
454	    (op.iplo_unit != IPLT_ALL)) {
455		IPFERROR(50023);
456		return EINVAL;
457	}
458
459	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
460
461	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
462		if (op.iplo_type == (*l)->ipfl_type) {
463			err = (*(*l)->ipfl_table_add)(softc,
464						      softl->ipf_back[i],
465						      &op);
466			break;
467		}
468	}
469
470	if (i == MAX_BACKENDS) {
471		IPFERROR(50026);
472		err = EINVAL;
473	}
474
475	/*
476	 * For anonymous pools, copy back the operation struct because in the
477	 * case of success it will contain the new table's name.
478	 */
479	if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) {
480		err = BCOPYOUT(&op, data, sizeof(op));
481		if (err != 0) {
482			IPFERROR(50027);
483			err = EFAULT;
484		}
485	}
486
487	return err;
488}
489
490
491/* ------------------------------------------------------------------------ */
492/* Function:    ipf_lookup_deltable                                         */
493/* Returns:     int     - 0 = success, else error                           */
494/* Parameters:  softc(I) - pointer to soft context main structure           */
495/*              data(I) - pointer to data from ioctl call                   */
496/*                                                                          */
497/* Decodes ioctl request to remove a particular hash table or pool and      */
498/* calls the relevant function to do the cleanup.                           */
499/* ------------------------------------------------------------------------ */
500static int
501ipf_lookup_deltable(softc, data)
502	ipf_main_softc_t *softc;
503	caddr_t data;
504{
505	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
506	iplookupop_t op;
507	ipf_lookup_t **l;
508	int err, i;
509
510	err = BCOPYIN(data, &op, sizeof(op));
511	if (err != 0) {
512		IPFERROR(50028);
513		return EFAULT;
514	}
515
516	if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
517	    (op.iplo_unit != IPLT_ALL)) {
518		IPFERROR(50029);
519		return EINVAL;
520	}
521
522	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
523
524	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
525		if (op.iplo_type == (*l)->ipfl_type) {
526			err = (*(*l)->ipfl_table_del)(softc,
527						      softl->ipf_back[i],
528						      &op);
529			break;
530		}
531	}
532
533	if (i == MAX_BACKENDS) {
534		IPFERROR(50030);
535		err = EINVAL;
536	}
537	return err;
538}
539
540
541/* ------------------------------------------------------------------------ */
542/* Function:    ipf_lookup_stats                                            */
543/* Returns:     int     - 0 = success, else error                           */
544/* Parameters:  softc(I) - pointer to soft context main structure           */
545/*              data(I) - pointer to data from ioctl call                   */
546/*                                                                          */
547/* Copy statistical information from inside the kernel back to user space.  */
548/* ------------------------------------------------------------------------ */
549static int
550ipf_lookup_stats(softc, data)
551	ipf_main_softc_t *softc;
552	caddr_t data;
553{
554	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
555	iplookupop_t op;
556	ipf_lookup_t **l;
557	int err;
558	int i;
559
560	err = BCOPYIN(data, &op, sizeof(op));
561	if (err != 0) {
562		IPFERROR(50031);
563		return EFAULT;
564	}
565
566	if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
567	    (op.iplo_unit != IPLT_ALL)) {
568		IPFERROR(50032);
569		return EINVAL;
570	}
571
572	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
573		if (op.iplo_type == (*l)->ipfl_type) {
574			err = (*(*l)->ipfl_stats_get)(softc,
575						      softl->ipf_back[i],
576						      &op);
577			break;
578		}
579	}
580
581	if (i == MAX_BACKENDS) {
582		IPFERROR(50033);
583		err = EINVAL;
584	}
585
586	return err;
587}
588
589
590/* ------------------------------------------------------------------------ */
591/* Function:    ipf_lookup_flush                                            */
592/* Returns:     int     - 0 = success, else error                           */
593/* Parameters:  softc(I) - pointer to soft context main structure           */
594/*              data(I) - pointer to data from ioctl call                   */
595/*                                                                          */
596/* A flush is called when we want to flush all the nodes from a particular  */
597/* entry in the hash table/pool or want to remove all groups from those.    */
598/* ------------------------------------------------------------------------ */
599static int
600ipf_lookup_flush(softc, data)
601	ipf_main_softc_t *softc;
602	caddr_t data;
603{
604	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
605	int err, unit, num, type, i;
606	iplookupflush_t flush;
607	ipf_lookup_t **l;
608
609	err = BCOPYIN(data, &flush, sizeof(flush));
610	if (err != 0) {
611		IPFERROR(50034);
612		return EFAULT;
613	}
614
615	unit = flush.iplf_unit;
616	if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL)) {
617		IPFERROR(50035);
618		return EINVAL;
619	}
620
621	flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
622
623	type = flush.iplf_type;
624	IPFERROR(50036);
625	err = EINVAL;
626	num = 0;
627
628	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
629		if (type == (*l)->ipfl_type || type == IPLT_ALL) {
630			err = 0;
631			num += (*(*l)->ipfl_flush)(softc,
632						   softl->ipf_back[i],
633						   &flush);
634		}
635	}
636
637	if (err == 0) {
638		flush.iplf_count = num;
639		err = BCOPYOUT(&flush, data, sizeof(flush));
640		if (err != 0) {
641			IPFERROR(50037);
642			err = EFAULT;
643		}
644	}
645	return err;
646}
647
648
649/* ------------------------------------------------------------------------ */
650/* Function:    ipf_lookup_delref                                           */
651/* Returns:     void                                                        */
652/* Parameters:  softc(I) - pointer to soft context main structure           */
653/*              type(I) - table type to operate on                          */
654/*              ptr(I)  - pointer to object to remove reference for         */
655/*                                                                          */
656/* This function organises calling the correct deref function for a given   */
657/* type of object being passed into it.                                     */
658/* ------------------------------------------------------------------------ */
659void
660ipf_lookup_deref(softc, type, ptr)
661	ipf_main_softc_t *softc;
662	int type;
663	void *ptr;
664{
665	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
666	int i;
667
668	if (ptr == NULL)
669		return;
670
671	for (i = 0; i < MAX_BACKENDS; i++) {
672		if (type == backends[i]->ipfl_type) {
673			WRITE_ENTER(&softc->ipf_poolrw);
674			(*backends[i]->ipfl_table_deref)(softc,
675							 softl->ipf_back[i],
676							 ptr);
677			RWLOCK_EXIT(&softc->ipf_poolrw);
678			break;
679		}
680	}
681}
682
683
684/* ------------------------------------------------------------------------ */
685/* Function:    ipf_lookup_iterate                                          */
686/* Returns:     int     - 0 = success, else error                           */
687/* Parameters:  softc(I) - pointer to soft context main structure           */
688/*              data(I) - pointer to data from ioctl call                   */
689/*              uid(I)  - uid of caller                                     */
690/*              ctx(I)  - pointer to give the uid context                   */
691/*                                                                          */
692/* Decodes ioctl request to step through either hash tables or pools.       */
693/* ------------------------------------------------------------------------ */
694static int
695ipf_lookup_iterate(softc, data, uid, ctx)
696	ipf_main_softc_t *softc;
697	void *data;
698	int uid;
699	void *ctx;
700{
701	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
702	ipflookupiter_t iter;
703	ipftoken_t *token;
704	int err, i;
705	SPL_INT(s);
706
707	err = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_LOOKUPITER);
708	if (err != 0)
709		return err;
710
711	if (iter.ili_unit < IPL_LOGALL && iter.ili_unit > IPL_LOGMAX) {
712		IPFERROR(50038);
713		return EINVAL;
714	}
715
716	if (iter.ili_ival != IPFGENITER_LOOKUP) {
717		IPFERROR(50039);
718		return EINVAL;
719	}
720
721	SPL_SCHED(s);
722	token = ipf_token_find(softc, iter.ili_key, uid, ctx);
723	if (token == NULL) {
724		SPL_X(s);
725		IPFERROR(50040);
726		return ESRCH;
727	}
728
729	for (i = 0; i < MAX_BACKENDS; i++) {
730		if (iter.ili_type == backends[i]->ipfl_type) {
731			err = (*backends[i]->ipfl_iter_next)(softc,
732							     softl->ipf_back[i],
733							     token, &iter);
734			break;
735		}
736	}
737	SPL_X(s);
738
739	if (i == MAX_BACKENDS) {
740		IPFERROR(50041);
741		err = EINVAL;
742	}
743
744	WRITE_ENTER(&softc->ipf_tokens);
745	ipf_token_deref(softc, token);
746	RWLOCK_EXIT(&softc->ipf_tokens);
747
748	return err;
749}
750
751
752/* ------------------------------------------------------------------------ */
753/* Function:    ipf_lookup_iterderef                                        */
754/* Returns:     void                                                        */
755/* Parameters:  softc(I) - pointer to soft context main structure           */
756/*              type(I)  - backend type to iterate through                  */
757/*              data(I)  - pointer to data from ioctl call                  */
758/*                                                                          */
759/* Decodes ioctl request to remove a particular hash table or pool and      */
760/* calls the relevant function to do the cleanup.                           */
761/* Because each of the backend types has a different data structure,        */
762/* iteration is limited to one type at a time (i.e. it is not permitted to  */
763/* go on from pool types to hash types as part of the "get next".)          */
764/* ------------------------------------------------------------------------ */
765void
766ipf_lookup_iterderef(softc, type, data)
767	ipf_main_softc_t *softc;
768	u_32_t type;
769	void *data;
770{
771	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
772	struct iplookupiterkey *lkey;
773	iplookupiterkey_t key;
774	int i;
775
776	key.ilik_key = type;
777	lkey = &key.ilik_unstr;
778
779	if (lkey->ilik_ival != IPFGENITER_LOOKUP)
780		return;
781
782	WRITE_ENTER(&softc->ipf_poolrw);
783
784	for (i = 0; i < MAX_BACKENDS; i++) {
785		if (lkey->ilik_type == backends[i]->ipfl_type) {
786			(*backends[i]->ipfl_iter_deref)(softc,
787							softl->ipf_back[i],
788							lkey->ilik_otype,
789							lkey->ilik_unit,
790							data);
791			break;
792		}
793	}
794	RWLOCK_EXIT(&softc->ipf_poolrw);
795}
796
797
798/* ------------------------------------------------------------------------ */
799/* Function:    ipf_lookup_deltok                                           */
800/* Returns:     int     - 0 = success, else error                           */
801/* Parameters:  softc(I) - pointer to soft context main structure           */
802/*              data(I) - pointer to data from ioctl call                   */
803/*              uid(I)  - uid of caller                                     */
804/*              ctx(I)  - pointer to give the uid context                   */
805/*                                                                          */
806/* Deletes the token identified by the combination of (type,uid,ctx)        */
807/* "key" is a combination of the table type, iterator type and the unit for */
808/* which the token was being used.                                          */
809/* ------------------------------------------------------------------------ */
810int
811ipf_lookup_deltok(softc, data, uid, ctx)
812	ipf_main_softc_t *softc;
813	void *data;
814	int uid;
815	void *ctx;
816{
817	int error, key;
818	SPL_INT(s);
819
820	SPL_SCHED(s);
821	error = BCOPYIN(data, &key, sizeof(key));
822	if (error == 0)
823		error = ipf_token_del(softc, key, uid, ctx);
824	SPL_X(s);
825	return error;
826}
827
828
829/* ------------------------------------------------------------------------ */
830/* Function:    ipf_lookup_res_num                                          */
831/* Returns:     void * - NULL = failure, else success.                      */
832/* Parameters:  softc(I) - pointer to soft context main structure           */
833/*              unit(I)     - device for which this is for                  */
834/*              type(I)     - type of lookup these parameters are for.      */
835/*              number(I)   - table number to use when searching            */
836/*              funcptr(IO) - pointer to pointer for storing IP address     */
837/*                            searching function.                           */
838/*                                                                          */
839/* Search for the "table" number passed in amongst those configured for     */
840/* that particular type.  If the type is recognised then the function to    */
841/* call to do the IP address search will be change, regardless of whether   */
842/* or not the "table" number exists.                                        */
843/* ------------------------------------------------------------------------ */
844void *
845ipf_lookup_res_num(softc, unit, type, number, funcptr)
846	ipf_main_softc_t *softc;
847	int unit;
848	u_int type;
849	u_int number;
850	lookupfunc_t *funcptr;
851{
852	char name[FR_GROUPLEN];
853
854#if defined(SNPRINTF) && defined(_KERNEL)
855	SNPRINTF(name, sizeof(name), "%u", number);
856#else
857	(void) sprintf(name, "%u", number);
858#endif
859
860	return ipf_lookup_res_name(softc, unit, type, name, funcptr);
861}
862
863
864/* ------------------------------------------------------------------------ */
865/* Function:    ipf_lookup_res_name                                         */
866/* Returns:     void * - NULL = failure, else success.                      */
867/* Parameters:  softc(I) - pointer to soft context main structure           */
868/*              unit(I)     - device for which this is for                  */
869/*              type(I)     - type of lookup these parameters are for.      */
870/*              name(I)     - table name to use when searching              */
871/*              funcptr(IO) - pointer to pointer for storing IP address     */
872/*                            searching function.                           */
873/*                                                                          */
874/* Search for the "table" number passed in amongst those configured for     */
875/* that particular type.  If the type is recognised then the function to    */
876/* call to do the IP address search will be changed, regardless of whether  */
877/* or not the "table" number exists.                                        */
878/* ------------------------------------------------------------------------ */
879void *
880ipf_lookup_res_name(softc, unit, type, name, funcptr)
881	ipf_main_softc_t *softc;
882	int unit;
883	u_int type;
884	char *name;
885	lookupfunc_t *funcptr;
886{
887	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
888	ipf_lookup_t **l;
889	void *ptr = NULL;
890	int i;
891
892	READ_ENTER(&softc->ipf_poolrw);
893
894	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
895		if (type == (*l)->ipfl_type) {
896			ptr = (*(*l)->ipfl_select_add_ref)(softl->ipf_back[i],
897							   unit, name);
898			if (ptr != NULL && funcptr != NULL) {
899				*funcptr = (*l)->ipfl_addr_find;
900			}
901			break;
902		}
903	}
904
905	if (i == MAX_BACKENDS) {
906		ptr = NULL;
907		if (funcptr != NULL)
908			*funcptr = NULL;
909	}
910
911	RWLOCK_EXIT(&softc->ipf_poolrw);
912
913	return ptr;
914}
915
916
917/* ------------------------------------------------------------------------ */
918/* Function:    ipf_lookup_find_htable                                      */
919/* Returns:     void * - NULL = failure, else success.                      */
920/* Parameters:  softc(I) - pointer to soft context main structure           */
921/*              unit(I)     - device for which this is for                  */
922/*              name(I)     - table name to use when searching              */
923/*                                                                          */
924/* To support the group-map feature, where a hash table maps address        */
925/* networks to rule group numbers, we need to expose a function that uses   */
926/* only the hash table backend.                                             */
927/* ------------------------------------------------------------------------ */
928void *
929ipf_lookup_find_htable(softc, unit, name)
930	ipf_main_softc_t *softc;
931	int unit;
932	char *name;
933{
934	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
935	ipf_lookup_t **l;
936	void *tab = NULL;
937	int i;
938
939	READ_ENTER(&softc->ipf_poolrw);
940
941	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
942		if (IPLT_HASH == (*l)->ipfl_type) {
943			tab = ipf_htable_find(softl->ipf_back[i], unit, name);
944			break;
945		}
946
947	RWLOCK_EXIT(&softc->ipf_poolrw);
948
949	return tab;
950}
951
952
953/* ------------------------------------------------------------------------ */
954/* Function:    ipf_lookup_sync                                             */
955/* Returns:     void                                                        */
956/* Parameters:  softc(I) - pointer to soft context main structure           */
957/*                                                                          */
958/* This function is the interface that the machine dependent sync functions */
959/* call when a network interface name change occurs. It then calls the sync */
960/* functions of the lookup implementations - if they have one.              */
961/* ------------------------------------------------------------------------ */
962/*ARGSUSED*/
963void
964ipf_lookup_sync(softc, ifp)
965	ipf_main_softc_t *softc;
966	void *ifp;
967{
968	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
969	ipf_lookup_t **l;
970	int i;
971
972	READ_ENTER(&softc->ipf_poolrw);
973
974	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
975		if ((*l)->ipfl_sync != NULL)
976			(*(*l)->ipfl_sync)(softc, softl->ipf_back[i]);
977
978	RWLOCK_EXIT(&softc->ipf_poolrw);
979}
980
981
982#ifndef _KERNEL
983void
984ipf_lookup_dump(softc, arg)
985	ipf_main_softc_t *softc;
986	void *arg;
987{
988	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
989	ipf_lookup_t **l;
990	int i;
991
992	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
993		if (IPLT_POOL == (*l)->ipfl_type) {
994			ipf_pool_dump(softc, softl->ipf_back[i]);
995			break;
996		}
997
998	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
999		if (IPLT_HASH == (*l)->ipfl_type) {
1000			ipf_htable_dump(softc, softl->ipf_back[i]);
1001			break;
1002		}
1003}
1004#endif
1005