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