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