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