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