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