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