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