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