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