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