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