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