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