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