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