]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/ipfilter/netinet/ip_lookup.c
MFC 57785538c6e0d7e8ca0f161ab95bae10fd304047 and
[FreeBSD/FreeBSD.git] / sys / contrib / ipfilter / netinet / ip_lookup.c
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__) && 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(ipf_main_softc_t *, caddr_t, int);
70 static int ipf_lookup_delnode(ipf_main_softc_t *, caddr_t, int);
71 static int ipf_lookup_addtable(ipf_main_softc_t *, caddr_t);
72 static int ipf_lookup_deltable(ipf_main_softc_t *, caddr_t);
73 static int ipf_lookup_stats(ipf_main_softc_t *, caddr_t);
74 static int ipf_lookup_flush(ipf_main_softc_t *, caddr_t);
75 static int ipf_lookup_iterate(ipf_main_softc_t *, void *, int, void *);
76 static int ipf_lookup_deltok(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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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 *
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 *
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
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
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