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