]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/ipfilter/netinet/ip_pool.c
MFV r348552: 9682 page fault in dsl_async_clone_destroy() while opening pool
[FreeBSD/FreeBSD.git] / sys / contrib / ipfilter / netinet / ip_pool.c
1 /*
2  * Copyright (C) 2012 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  */
6 #if defined(KERNEL) || defined(_KERNEL)
7 # undef KERNEL
8 # undef _KERNEL
9 # define        KERNEL  1
10 # define        _KERNEL 1
11 #endif
12 #include <sys/errno.h>
13 #include <sys/types.h>
14 #include <sys/param.h>
15 #include <sys/file.h>
16 #if !defined(_KERNEL) && !defined(__KERNEL__)
17 # include <stdio.h>
18 # include <stdlib.h>
19 # include <string.h>
20 # define _KERNEL
21 # include <sys/uio.h>
22 # undef _KERNEL
23 #else
24 # include <sys/systm.h>
25 # if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
26 #  include <sys/proc.h>
27 # endif
28 #endif
29 #include <sys/time.h>
30 #if defined(_KERNEL) && !defined(SOLARIS2)
31 # include <sys/mbuf.h>
32 #endif
33 #if defined(__SVR4)
34 # include <sys/byteorder.h>
35 # ifdef _KERNEL
36 #  include <sys/dditypes.h>
37 # endif
38 # include <sys/stream.h>
39 # include <sys/kmem.h>
40 #endif
41 #if defined(__FreeBSD_version)
42 # include <sys/malloc.h>
43 #endif
44
45 #include <sys/socket.h>
46 #include <net/if.h>
47 #include <netinet/in.h>
48 #if !defined(_KERNEL)
49 # include "ipf.h"
50 #endif
51
52 #include "netinet/ip_compat.h"
53 #include "netinet/ip_fil.h"
54 #include "netinet/ip_pool.h"
55 #include "netinet/radix_ipf.h"
56
57 /* END OF INCLUDES */
58
59 #if !defined(lint)
60 static const char sccsid[] = "@(#)ip_fil.c      2.41 6/5/96 (C) 1993-2000 Darren Reed";
61 static const char rcsid[] = "@(#)$Id$";
62 #endif
63
64 typedef struct ipf_pool_softc_s {
65         void            *ipf_radix;
66         ip_pool_t       *ipf_pool_list[LOOKUP_POOL_SZ];
67         ipf_pool_stat_t ipf_pool_stats;
68         ip_pool_node_t  *ipf_node_explist;
69 } ipf_pool_softc_t;
70
71
72 static void ipf_pool_clearnodes __P((ipf_main_softc_t *, ipf_pool_softc_t *,
73                                      ip_pool_t *));
74 static int ipf_pool_create __P((ipf_main_softc_t *, ipf_pool_softc_t *, iplookupop_t *));
75 static int ipf_pool_deref __P((ipf_main_softc_t *, void *, void *));
76 static int ipf_pool_destroy __P((ipf_main_softc_t *, ipf_pool_softc_t *, int, char *));
77 static void *ipf_pool_exists __P((ipf_pool_softc_t *, int, char *));
78 static void *ipf_pool_find __P((void *, int, char *));
79 static ip_pool_node_t *ipf_pool_findeq __P((ipf_pool_softc_t *, ip_pool_t *,
80                                             addrfamily_t *, addrfamily_t *));
81 static void ipf_pool_free __P((ipf_main_softc_t *, ipf_pool_softc_t *,
82                                ip_pool_t *));
83 static int ipf_pool_insert_node __P((ipf_main_softc_t *, ipf_pool_softc_t *,
84                                      ip_pool_t *, struct ip_pool_node *));
85 static int ipf_pool_iter_deref __P((ipf_main_softc_t *, void *, int, int, void *));
86 static int ipf_pool_iter_next __P((ipf_main_softc_t *,  void *, ipftoken_t *,
87                                    ipflookupiter_t *));
88 static size_t ipf_pool_flush __P((ipf_main_softc_t *, void *, iplookupflush_t *));
89 static int ipf_pool_node_add __P((ipf_main_softc_t *, void *, iplookupop_t *,
90                                   int));
91 static int ipf_pool_node_del __P((ipf_main_softc_t *, void *, iplookupop_t *,
92                                   int));
93 static void ipf_pool_node_deref __P((ipf_pool_softc_t *, ip_pool_node_t *));
94 static int ipf_pool_remove_node __P((ipf_main_softc_t *, ipf_pool_softc_t *,
95                                      ip_pool_t *, ip_pool_node_t *));
96 static int ipf_pool_search __P((ipf_main_softc_t *, void *, int,
97                                 void *, u_int));
98 static void *ipf_pool_soft_create __P((ipf_main_softc_t *));
99 static void ipf_pool_soft_destroy __P((ipf_main_softc_t *, void *));
100 static void ipf_pool_soft_fini __P((ipf_main_softc_t *, void *));
101 static int ipf_pool_soft_init __P((ipf_main_softc_t *, void *));
102 static int ipf_pool_stats_get __P((ipf_main_softc_t *, void *, iplookupop_t *));
103 static int ipf_pool_table_add __P((ipf_main_softc_t *, void *, iplookupop_t *));
104 static int ipf_pool_table_del __P((ipf_main_softc_t *, void *, iplookupop_t *));
105 static void *ipf_pool_select_add_ref __P((void *, int, char *));
106 static void ipf_pool_expire __P((ipf_main_softc_t *, void *));
107
108 ipf_lookup_t ipf_pool_backend = {
109         IPLT_POOL,
110         ipf_pool_soft_create,
111         ipf_pool_soft_destroy,
112         ipf_pool_soft_init,
113         ipf_pool_soft_fini,
114         ipf_pool_search,
115         ipf_pool_flush,
116         ipf_pool_iter_deref,
117         ipf_pool_iter_next,
118         ipf_pool_node_add,
119         ipf_pool_node_del,
120         ipf_pool_stats_get,
121         ipf_pool_table_add,
122         ipf_pool_table_del,
123         ipf_pool_deref,
124         ipf_pool_find,
125         ipf_pool_select_add_ref,
126         NULL,
127         ipf_pool_expire,
128         NULL
129 };
130
131
132 #ifdef TEST_POOL
133 void treeprint __P((ip_pool_t *));
134
135 int
136 main(argc, argv)
137         int argc;
138         char *argv[];
139 {
140         ip_pool_node_t node;
141         addrfamily_t a, b;
142         iplookupop_t op;
143         ip_pool_t *ipo;
144         i6addr_t ip;
145
146         RWLOCK_INIT(softc->ipf_poolrw, "poolrw");
147         ipf_pool_init();
148
149         bzero((char *)&ip, sizeof(ip));
150         bzero((char *)&op, sizeof(op));
151         bzero((char *)&node, sizeof(node));
152         strcpy(op.iplo_name, "0");
153
154         if (ipf_pool_create(&op) == 0)
155                 ipo = ipf_pool_exists(0, "0");
156
157         node.ipn_addr.adf_family = AF_INET;
158
159         node.ipn_addr.adf_addr.in4.s_addr = 0x0a010203;
160         node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
161         node.ipn_info = 1;
162         ipf_pool_insert_node(ipo, &node);
163
164         node.ipn_addr.adf_addr.in4.s_addr = 0x0a000000;
165         node.ipn_mask.adf_addr.in4.s_addr = 0xff000000;
166         node.ipn_info = 0;
167         ipf_pool_insert_node(ipo, &node);
168
169         node.ipn_addr.adf_addr.in4.s_addr = 0x0a010100;
170         node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
171         node.ipn_info = 1;
172         ipf_pool_insert_node(ipo, &node);
173
174         node.ipn_addr.adf_addr.in4.s_addr = 0x0a010200;
175         node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
176         node.ipn_info = 0;
177         ipf_pool_insert_node(ipo, &node);
178
179         node.ipn_addr.adf_addr.in4.s_addr = 0x0a010000;
180         node.ipn_mask.adf_addr.in4.s_addr = 0xffff0000;
181         node.ipn_info = 1;
182         ipf_pool_insert_node(ipo, &node);
183
184         node.ipn_addr.adf_addr.in4.s_addr = 0x0a01020f;
185         node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
186         node.ipn_info = 1;
187         ipf_pool_insert_node(ipo, &node);
188 #ifdef  DEBUG_POOL
189         treeprint(ipo);
190 #endif
191         ip.in4.s_addr = 0x0a00aabb;
192         printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
193                 ipf_pool_search(ipo, 4, &ip, 1));
194
195         ip.in4.s_addr = 0x0a000001;
196         printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
197                 ipf_pool_search(ipo, 4, &ip, 1));
198
199         ip.in4.s_addr = 0x0a000101;
200         printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
201                 ipf_pool_search(ipo, 4, &ip, 1));
202
203         ip.in4.s_addr = 0x0a010001;
204         printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
205                 ipf_pool_search(ipo, 4, &ip, 1));
206
207         ip.in4.s_addr = 0x0a010101;
208         printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
209                 ipf_pool_search(ipo, 4, &ip, 1));
210
211         ip.in4.s_addr = 0x0a010201;
212         printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
213                 ipf_pool_search(ipo, 4, &ip, 1));
214
215         ip.in4.s_addr = 0x0a010203;
216         printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
217                 ipf_pool_search(ipo, 4, &ip, 1));
218
219         ip.in4.s_addr = 0x0a01020f;
220         printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
221                 ipf_pool_search(ipo, 4, &ip, 1));
222
223         ip.in4.s_addr = 0x0b00aabb;
224         printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
225                 ipf_pool_search(ipo, 4, &ip, 1));
226
227 #ifdef  DEBUG_POOL
228         treeprint(ipo);
229 #endif
230
231         ipf_pool_fini();
232
233         return 0;
234 }
235
236
237 void
238 treeprint(ipo)
239         ip_pool_t *ipo;
240 {
241         ip_pool_node_t *c;
242
243         for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
244                 printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
245                         c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
246                         c->ipn_mask.adf_addr.in4.s_addr,
247                         c->ipn_info, c->ipn_hits);
248 }
249 #endif /* TEST_POOL */
250
251
252 /* ------------------------------------------------------------------------ */
253 /* Function:    ipf_pool_soft_create                                        */
254 /* Returns:     void *   - NULL = failure, else pointer to local context    */
255 /* Parameters:  softc(I) - pointer to soft context main structure           */
256 /*                                                                          */
257 /* Initialise the routing table data structures where required.             */
258 /* ------------------------------------------------------------------------ */
259 static void *
260 ipf_pool_soft_create(softc)
261         ipf_main_softc_t *softc;
262 {
263         ipf_pool_softc_t *softp;
264
265         KMALLOC(softp, ipf_pool_softc_t *);
266         if (softp == NULL) {
267                 IPFERROR(70032);
268                 return NULL;
269         }
270
271         bzero((char *)softp, sizeof(*softp));
272
273         softp->ipf_radix = ipf_rx_create();
274         if (softp->ipf_radix == NULL) {
275                 IPFERROR(70033);
276                 KFREE(softp);
277                 return NULL;
278         }
279
280         return softp;
281 }
282
283
284 /* ------------------------------------------------------------------------ */
285 /* Function:    ipf_pool_soft_init                                          */
286 /* Returns:     int     - 0 = success, else error                           */
287 /* Parameters:  softc(I) - pointer to soft context main structure           */
288 /*              arg(I)   - pointer to local context to use                  */
289 /*                                                                          */
290 /* Initialise the routing table data structures where required.             */
291 /* ------------------------------------------------------------------------ */
292 static int
293 ipf_pool_soft_init(softc, arg)
294         ipf_main_softc_t *softc;
295         void *arg;
296 {
297         ipf_pool_softc_t *softp = arg;
298
299         ipf_rx_init(softp->ipf_radix);
300
301         return 0;
302 }
303
304
305 /* ------------------------------------------------------------------------ */
306 /* Function:    ipf_pool_soft_fini                                          */
307 /* Returns:     Nil                                                         */
308 /* Parameters:  softc(I) - pointer to soft context main structure           */
309 /*              arg(I)   - pointer to local context to use                  */
310 /* Locks:       WRITE(ipf_global)                                           */
311 /*                                                                          */
312 /* Clean up all the pool data structures allocated and call the cleanup     */
313 /* function for the radix tree that supports the pools. ipf_pool_destroy is */
314 /* used to delete the pools one by one to ensure they're properly freed up. */
315 /* ------------------------------------------------------------------------ */
316 static void
317 ipf_pool_soft_fini(softc, arg)
318         ipf_main_softc_t *softc;
319         void *arg;
320 {
321         ipf_pool_softc_t *softp = arg;
322         ip_pool_t *p, *q;
323         int i;
324
325         softc = arg;
326
327         for (i = -1; i <= IPL_LOGMAX; i++) {
328                 for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
329                         q = p->ipo_next;
330                         (void) ipf_pool_destroy(softc, arg, i, p->ipo_name);
331                 }
332         }
333 }
334
335
336 /* ------------------------------------------------------------------------ */
337 /* Function:    ipf_pool_soft_destroy                                       */
338 /* Returns:     Nil                                                         */
339 /* Parameters:  softc(I) - pointer to soft context main structure           */
340 /*              arg(I)   - pointer to local context to use                  */
341 /*                                                                          */
342 /* Clean up the pool by free'ing the radix tree associated with it and free */
343 /* up the pool context too.                                                 */
344 /* ------------------------------------------------------------------------ */
345 static void
346 ipf_pool_soft_destroy(softc, arg)
347         ipf_main_softc_t *softc;
348         void *arg;
349 {
350         ipf_pool_softc_t *softp = arg;
351
352         ipf_rx_destroy(softp->ipf_radix);
353
354         KFREE(softp);
355 }
356
357
358 /* ------------------------------------------------------------------------ */
359 /* Function:   ipf_pool_node_add                                            */
360 /* Returns:    int - 0 = success, else error                                */
361 /* Parameters: softc(I) - pointer to soft context main structure            */
362 /*             arg(I)   - pointer to local context to use                   */
363 /*             op(I) - pointer to lookup operatin data                      */
364 /*                                                                          */
365 /* When adding a new node, a check is made to ensure that the address/mask  */
366 /* pair supplied has been appropriately prepared by applying the mask to    */
367 /* the address prior to calling for the pair to be added.                   */
368 /* ------------------------------------------------------------------------ */
369 static int
370 ipf_pool_node_add(softc, arg, op, uid)
371         ipf_main_softc_t *softc;
372         void *arg;
373         iplookupop_t *op;
374         int uid;
375 {
376         ip_pool_node_t node, *m;
377         ip_pool_t *p;
378         int err;
379
380         if (op->iplo_size != sizeof(node)) {
381                 IPFERROR(70014);
382                 return EINVAL;
383         }
384
385         err = COPYIN(op->iplo_struct, &node, sizeof(node));
386         if (err != 0) {
387                 IPFERROR(70015);
388                 return EFAULT;
389         }
390
391         p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
392         if (p == NULL) {
393                 IPFERROR(70017);
394                 return ESRCH;
395         }
396
397         if (node.ipn_addr.adf_family == AF_INET) {
398                 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
399                                              sizeof(struct in_addr)) {
400                         IPFERROR(70028);
401                         return EINVAL;
402                 }
403         }
404 #ifdef USE_INET6
405         else if (node.ipn_addr.adf_family == AF_INET6) {
406                 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
407                                              sizeof(struct in6_addr)) {
408                         IPFERROR(70034);
409                         return EINVAL;
410                 }
411         }
412 #endif
413         if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
414                 IPFERROR(70029);
415                 return EINVAL;
416         }
417
418         /*
419          * Check that the address/mask pair works.
420          */
421         if (node.ipn_addr.adf_family == AF_INET) {
422                 if ((node.ipn_addr.adf_addr.in4.s_addr &
423                      node.ipn_mask.adf_addr.in4.s_addr) !=
424                     node.ipn_addr.adf_addr.in4.s_addr) {
425                         IPFERROR(70035);
426                         return EINVAL;
427                 }
428         }
429 #ifdef USE_INET6
430         else if (node.ipn_addr.adf_family == AF_INET6) {
431                 if (IP6_MASKNEQ(&node.ipn_addr.adf_addr.in6,
432                                 &node.ipn_mask.adf_addr.in6,
433                                 &node.ipn_addr.adf_addr.in6)) {
434                         IPFERROR(70036);
435                         return EINVAL;
436                 }
437         }
438 #endif
439
440         /*
441          * add an entry to a pool - return an error if it already
442          * exists remove an entry from a pool - if it exists
443          * - in both cases, the pool *must* exist!
444          */
445         m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
446         if (m != NULL) {
447                 IPFERROR(70018);
448                 return EEXIST;
449         }
450         err = ipf_pool_insert_node(softc, arg, p, &node);
451
452         return err;
453 }
454
455
456 /* ------------------------------------------------------------------------ */
457 /* Function:   ipf_pool_node_del                                            */
458 /* Returns:    int - 0 = success, else error                                */
459 /* Parameters: softc(I) - pointer to soft context main structure            */
460 /*             arg(I)   - pointer to local context to use                   */
461 /*             op(I)    - pointer to lookup operatin data                   */
462 /*                                                                          */
463 /* ------------------------------------------------------------------------ */
464 static int
465 ipf_pool_node_del(softc, arg, op, uid)
466         ipf_main_softc_t *softc;
467         void *arg;
468         iplookupop_t *op;
469         int uid;
470 {
471         ip_pool_node_t node, *m;
472         ip_pool_t *p;
473         int err;
474
475
476         if (op->iplo_size != sizeof(node)) {
477                 IPFERROR(70019);
478                 return EINVAL;
479         }
480         node.ipn_uid = uid;
481
482         err = COPYIN(op->iplo_struct, &node, sizeof(node));
483         if (err != 0) {
484                 IPFERROR(70020);
485                 return EFAULT;
486         }
487
488         if (node.ipn_addr.adf_family == AF_INET) {
489                 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
490                                              sizeof(struct in_addr)) {
491                         IPFERROR(70030);
492                         return EINVAL;
493                 }
494         }
495 #ifdef USE_INET6
496         else if (node.ipn_addr.adf_family == AF_INET6) {
497                 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
498                                              sizeof(struct in6_addr)) {
499                         IPFERROR(70037);
500                         return EINVAL;
501                 }
502         }
503 #endif
504         if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
505                 IPFERROR(70031);
506                 return EINVAL;
507         }
508
509         p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
510         if (p == NULL) {
511                 IPFERROR(70021);
512                 return ESRCH;
513         }
514
515         m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
516         if (m == NULL) {
517                 IPFERROR(70022);
518                 return ENOENT;
519         }
520
521         if ((uid != 0) && (uid != m->ipn_uid)) {
522                 IPFERROR(70024);
523                 return EACCES;
524         }
525
526         err = ipf_pool_remove_node(softc, arg, p, m);
527
528         return err;
529 }
530
531
532 /* ------------------------------------------------------------------------ */
533 /* Function:   ipf_pool_table_add                                           */
534 /* Returns:    int - 0 = success, else error                                */
535 /* Parameters: softc(I) - pointer to soft context main structure            */
536 /*             arg(I)   - pointer to local context to use                   */
537 /*             op(I)    - pointer to lookup operatin data                   */
538 /*                                                                          */
539 /* ------------------------------------------------------------------------ */
540 static int
541 ipf_pool_table_add(softc, arg, op)
542         ipf_main_softc_t *softc;
543         void *arg;
544         iplookupop_t *op;
545 {
546         int err;
547
548         if (((op->iplo_arg & LOOKUP_ANON) == 0) &&
549             (ipf_pool_find(arg, op->iplo_unit, op->iplo_name) != NULL)) {
550                 IPFERROR(70023);
551                 err = EEXIST;
552         } else {
553                 err = ipf_pool_create(softc, arg, op);
554         }
555
556         return err;
557 }
558
559
560 /* ------------------------------------------------------------------------ */
561 /* Function:   ipf_pool_table_del                                           */
562 /* Returns:    int - 0 = success, else error                                */
563 /* Parameters: softc(I) - pointer to soft context main structure            */
564 /*             arg(I)   - pointer to local context to use                   */
565 /*             op(I)    - pointer to lookup operatin data                   */
566 /*                                                                          */
567 /* ------------------------------------------------------------------------ */
568 static int
569 ipf_pool_table_del(softc, arg, op)
570         ipf_main_softc_t *softc;
571         void *arg;
572         iplookupop_t *op;
573 {
574         return ipf_pool_destroy(softc, arg, op->iplo_unit, op->iplo_name);
575 }
576
577
578 /* ------------------------------------------------------------------------ */
579 /* Function:    ipf_pool_statistics                                         */
580 /* Returns:     int      - 0 = success, else error                          */
581 /* Parameters:  softc(I) - pointer to soft context main structure           */
582 /*              arg(I)   - pointer to local context to use                  */
583 /*              op(I)    - pointer to lookup operatin data                  */
584 /*                                                                          */
585 /* Copy the current statistics out into user space, collecting pool list    */
586 /* pointers as appropriate for later use.                                   */
587 /* ------------------------------------------------------------------------ */
588 static int
589 ipf_pool_stats_get(softc, arg, op)
590         ipf_main_softc_t *softc;
591         void *arg;
592         iplookupop_t *op;
593 {
594         ipf_pool_softc_t *softp = arg;
595         ipf_pool_stat_t stats;
596         int unit, i, err = 0;
597
598         if (op->iplo_size != sizeof(ipf_pool_stat_t)) {
599                 IPFERROR(70001);
600                 return EINVAL;
601         }
602
603         bcopy((char *)&softp->ipf_pool_stats, (char *)&stats, sizeof(stats));
604         unit = op->iplo_unit;
605         if (unit == IPL_LOGALL) {
606                 for (i = 0; i <= LOOKUP_POOL_MAX; i++)
607                         stats.ipls_list[i] = softp->ipf_pool_list[i];
608         } else if (unit >= 0 && unit <= IPL_LOGMAX) {
609                 unit++;                                         /* -1 => 0 */
610                 if (op->iplo_name[0] != '\0')
611                         stats.ipls_list[unit] = ipf_pool_exists(softp, unit - 1,
612                                                                 op->iplo_name);
613                 else
614                         stats.ipls_list[unit] = softp->ipf_pool_list[unit];
615         } else {
616                 IPFERROR(70025);
617                 err = EINVAL;
618         }
619         if (err == 0) {
620                 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
621                 if (err != 0) {
622                         IPFERROR(70026);
623                         return EFAULT;
624                 }
625         }
626         return 0;
627 }
628
629
630 /* ------------------------------------------------------------------------ */
631 /* Function:    ipf_pool_exists                                             */
632 /* Returns:     int      - 0 = success, else error                          */
633 /* Parameters:  softp(I) - pointer to soft context pool information         */
634 /*              unit(I)  - ipfilter device to which we are working on       */
635 /*              name(I)  - name of the pool                                 */
636 /*                                                                          */
637 /* Find a matching pool inside the collection of pools for a particular     */
638 /* device, indicated by the unit number.                                    */
639 /* ------------------------------------------------------------------------ */
640 static void *
641 ipf_pool_exists(softp, unit, name)
642         ipf_pool_softc_t *softp;
643         int unit;
644         char *name;
645 {
646         ip_pool_t *p;
647         int i;
648
649         if (unit == IPL_LOGALL) {
650                 for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
651                         for (p = softp->ipf_pool_list[i]; p != NULL;
652                              p = p->ipo_next) {
653                                 if (strncmp(p->ipo_name, name,
654                                             sizeof(p->ipo_name)) == 0)
655                                         break;
656                         }
657                         if (p != NULL)
658                                 break;
659                 }
660         } else {
661                 for (p = softp->ipf_pool_list[unit + 1]; p != NULL;
662                      p = p->ipo_next)
663                         if (strncmp(p->ipo_name, name,
664                                     sizeof(p->ipo_name)) == 0)
665                                 break;
666         }
667         return p;
668 }
669
670
671 /* ------------------------------------------------------------------------ */
672 /* Function:    ipf_pool_find                                               */
673 /* Returns:     int    - 0 = success, else error                            */
674 /* Parameters:  arg(I)  - pointer to local context to use                   */
675 /*              unit(I) - ipfilter device to which we are working on        */
676 /*              name(I)  - name of the pool                                 */
677 /*                                                                          */
678 /* Find a matching pool inside the collection of pools for a particular     */
679 /* device, indicated by the unit number.  If it is marked for deletion then */
680 /* pretend it does not exist.                                               */
681 /* ------------------------------------------------------------------------ */
682 static void *
683 ipf_pool_find(arg, unit, name)
684         void *arg;
685         int unit;
686         char *name;
687 {
688         ipf_pool_softc_t *softp = arg;
689         ip_pool_t *p;
690
691         p = ipf_pool_exists(softp, unit, name);
692         if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
693                 return NULL;
694
695         return p;
696 }
697
698
699 /* ------------------------------------------------------------------------ */
700 /* Function:    ipf_pool_select_add_ref                                     */
701 /* Returns:     int - 0 = success, else error                               */
702 /* Parameters:  arg(I)  - pointer to local context to use                   */
703 /*              unit(I) - ipfilter device to which we are working on        */
704 /*              name(I)  - name of the pool                                 */
705 /*                                                                          */
706 /* ------------------------------------------------------------------------ */
707 static void *
708 ipf_pool_select_add_ref(arg, unit, name)
709         void *arg;
710         int unit;
711         char *name;
712 {
713         ip_pool_t *p;
714
715         p = ipf_pool_find(arg, -1, name);
716         if (p == NULL)
717                 p = ipf_pool_find(arg, unit, name);
718         if (p != NULL) {
719                 ATOMIC_INC32(p->ipo_ref);
720         }
721         return p;
722 }
723
724
725 /* ------------------------------------------------------------------------ */
726 /* Function:    ipf_pool_findeq                                             */
727 /* Returns:     int     - 0 = success, else error                           */
728 /* Parameters:  softp(I) - pointer to soft context pool information         */
729 /*              ipo(I)  - pointer to the pool getting the new node.         */
730 /*              addr(I) - pointer to address information to match on        */
731 /*              mask(I) - pointer to the address mask to match              */
732 /*                                                                          */
733 /* Searches for an exact match of an entry in the pool.                     */
734 /* ------------------------------------------------------------------------ */
735 extern void printhostmask __P((int, u_32_t *, u_32_t *));
736 static ip_pool_node_t *
737 ipf_pool_findeq(softp, ipo, addr, mask)
738         ipf_pool_softc_t *softp;
739         ip_pool_t *ipo;
740         addrfamily_t *addr, *mask;
741 {
742         ipf_rdx_node_t *n;
743
744         n = ipo->ipo_head->lookup(ipo->ipo_head, addr, mask);
745         return (ip_pool_node_t *)n;
746 }
747
748
749 /* ------------------------------------------------------------------------ */
750 /* Function:    ipf_pool_search                                             */
751 /* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
752 /* Parameters:  softc(I) - pointer to soft context main structure           */
753 /*              tptr(I)    - pointer to the pool to search                  */
754 /*              version(I) - IP protocol version (4 or 6)                   */
755 /*              dptr(I)    - pointer to address information                 */
756 /*              bytes(I)   - length of packet                               */
757 /*                                                                          */
758 /* Search the pool for a given address and return a search result.          */
759 /* ------------------------------------------------------------------------ */
760 static int
761 ipf_pool_search(softc, tptr, ipversion, dptr, bytes)
762         ipf_main_softc_t *softc;
763         void *tptr;
764         int ipversion;
765         void *dptr;
766         u_int bytes;
767 {
768         ipf_rdx_node_t *rn;
769         ip_pool_node_t *m;
770         i6addr_t *addr;
771         addrfamily_t v;
772         ip_pool_t *ipo;
773         int rv;
774
775         ipo = tptr;
776         if (ipo == NULL)
777                 return -1;
778
779         rv = 1;
780         m = NULL;
781         addr = (i6addr_t *)dptr;
782         bzero(&v, sizeof(v));
783
784         if (ipversion == 4) {
785                 v.adf_family = AF_INET;
786                 v.adf_len = offsetof(addrfamily_t, adf_addr) +
787                             sizeof(struct in_addr);
788                 v.adf_addr.in4 = addr->in4;
789 #ifdef USE_INET6
790         } else if (ipversion == 6) {
791                 v.adf_family = AF_INET6;
792                 v.adf_len = offsetof(addrfamily_t, adf_addr) +
793                             sizeof(struct in6_addr);
794                 v.adf_addr.in6 = addr->in6;
795 #endif
796         } else
797                 return -1;
798
799         READ_ENTER(&softc->ipf_poolrw);
800
801         rn = ipo->ipo_head->matchaddr(ipo->ipo_head, &v);
802
803         if ((rn != NULL) && (rn->root == 0)) {
804                 m = (ip_pool_node_t *)rn;
805                 ipo->ipo_hits++;
806                 m->ipn_bytes += bytes;
807                 m->ipn_hits++;
808                 rv = m->ipn_info;
809         }
810         RWLOCK_EXIT(&softc->ipf_poolrw);
811         return rv;
812 }
813
814
815 /* ------------------------------------------------------------------------ */
816 /* Function:    ipf_pool_insert_node                                        */
817 /* Returns:     int      - 0 = success, else error                          */
818 /* Parameters:  softc(I) - pointer to soft context main structure           */
819 /*              softp(I) - pointer to soft context pool information         */
820 /*              ipo(I)   - pointer to the pool getting the new node.        */
821 /*              node(I)  - structure with address/mask to add               */
822 /* Locks:       WRITE(ipf_poolrw)                                           */
823 /*                                                                          */
824 /* Add another node to the pool given by ipo.  The three parameters passed  */
825 /* in (addr, mask, info) shold all be stored in the node.                   */
826 /* ------------------------------------------------------------------------ */
827 static int
828 ipf_pool_insert_node(softc, softp, ipo, node)
829         ipf_main_softc_t *softc;
830         ipf_pool_softc_t *softp;
831         ip_pool_t *ipo;
832         struct ip_pool_node *node;
833 {
834         ipf_rdx_node_t *rn;
835         ip_pool_node_t *x;
836
837         if ((node->ipn_addr.adf_len > sizeof(*rn)) ||
838             (node->ipn_addr.adf_len < 4)) {
839                 IPFERROR(70003);
840                 return EINVAL;
841         }
842
843         if ((node->ipn_mask.adf_len > sizeof(*rn)) ||
844             (node->ipn_mask.adf_len < 4)) {
845                 IPFERROR(70004);
846                 return EINVAL;
847         }
848
849         KMALLOC(x, ip_pool_node_t *);
850         if (x == NULL) {
851                 IPFERROR(70002);
852                 return ENOMEM;
853         }
854
855         *x = *node;
856         bzero((char *)x->ipn_nodes, sizeof(x->ipn_nodes));
857         x->ipn_owner = ipo;
858         x->ipn_hits = 0;
859         x->ipn_next = NULL;
860         x->ipn_pnext = NULL;
861         x->ipn_dnext = NULL;
862         x->ipn_pdnext = NULL;
863
864         if (x->ipn_die != 0) {
865                 /*
866                  * If the new node has a given expiration time, insert it
867                  * into the list of expiring nodes with the ones to be
868                  * removed first added to the front of the list. The
869                  * insertion is O(n) but it is kept sorted for quick scans
870                  * at expiration interval checks.
871                  */
872                 ip_pool_node_t *n;
873
874                 x->ipn_die = softc->ipf_ticks + IPF_TTLVAL(x->ipn_die);
875                 for (n = softp->ipf_node_explist; n != NULL; n = n->ipn_dnext) {
876                         if (x->ipn_die < n->ipn_die)
877                                 break;
878                         if (n->ipn_dnext == NULL) {
879                                 /*
880                                  * We've got to the last node and everything
881                                  * wanted to be expired before this new node,
882                                  * so we have to tack it on the end...
883                                  */
884                                 n->ipn_dnext = x;
885                                 x->ipn_pdnext = &n->ipn_dnext;
886                                 n = NULL;
887                                 break;
888                         }
889                 }
890
891                 if (softp->ipf_node_explist == NULL) {
892                         softp->ipf_node_explist = x;
893                         x->ipn_pdnext = &softp->ipf_node_explist;
894                 } else if (n != NULL) {
895                         x->ipn_dnext = n;
896                         x->ipn_pdnext = n->ipn_pdnext;
897                         n->ipn_pdnext = &x->ipn_dnext;
898                 }
899         }
900
901         rn = ipo->ipo_head->addaddr(ipo->ipo_head, &x->ipn_addr, &x->ipn_mask,
902                                     x->ipn_nodes);
903 #ifdef  DEBUG_POOL
904         printf("Added %p at %p\n", x, rn);
905 #endif
906
907         if (rn == NULL) {
908                 KFREE(x);
909                 IPFERROR(70005);
910                 return ENOMEM;
911         }
912
913         x->ipn_ref = 1;
914         x->ipn_pnext = ipo->ipo_tail;
915         *ipo->ipo_tail = x;
916         ipo->ipo_tail = &x->ipn_next;
917
918         softp->ipf_pool_stats.ipls_nodes++;
919
920         return 0;
921 }
922
923
924 /* ------------------------------------------------------------------------ */
925 /* Function:    ipf_pool_create                                             */
926 /* Returns:     int      - 0 = success, else error                          */
927 /* Parameters:  softc(I) - pointer to soft context main structure           */
928 /*              softp(I) - pointer to soft context pool information         */
929 /*              op(I)    - pointer to iplookup struct with call details     */
930 /* Locks:       WRITE(ipf_poolrw)                                           */
931 /*                                                                          */
932 /* Creates a new group according to the paramters passed in via the         */
933 /* iplookupop structure.  Does not check to see if the group already exists */
934 /* when being inserted - assume this has already been done.  If the pool is */
935 /* marked as being anonymous, give it a new, unique, identifier.  Call any  */
936 /* other functions required to initialise the structure.                    */
937 /*                                                                          */
938 /* If the structure is flagged for deletion then reset the flag and return, */
939 /* as this likely means we've tried to free a pool that is in use (flush)   */
940 /* and now want to repopulate it with "new" data.                           */
941 /* ------------------------------------------------------------------------ */
942 static int
943 ipf_pool_create(softc, softp, op)
944         ipf_main_softc_t *softc;
945         ipf_pool_softc_t *softp;
946         iplookupop_t *op;
947 {
948         char name[FR_GROUPLEN];
949         int poolnum, unit;
950         ip_pool_t *h;
951
952         unit = op->iplo_unit;
953
954         if ((op->iplo_arg & LOOKUP_ANON) == 0) {
955                 h = ipf_pool_exists(softp, unit, op->iplo_name);
956                 if (h != NULL) {
957                         if ((h->ipo_flags & IPOOL_DELETE) == 0) {
958                                 IPFERROR(70006);
959                                 return EEXIST;
960                         }
961                         h->ipo_flags &= ~IPOOL_DELETE;
962                         return 0;
963                 }
964         }
965
966         KMALLOC(h, ip_pool_t *);
967         if (h == NULL) {
968                 IPFERROR(70007);
969                 return ENOMEM;
970         }
971         bzero(h, sizeof(*h));
972
973         if (ipf_rx_inithead(softp->ipf_radix, &h->ipo_head) != 0) {
974                 KFREE(h);
975                 IPFERROR(70008);
976                 return ENOMEM;
977         }
978
979         if ((op->iplo_arg & LOOKUP_ANON) != 0) {
980                 ip_pool_t *p;
981
982                 h->ipo_flags |= IPOOL_ANON;
983                 poolnum = LOOKUP_ANON;
984
985 #if defined(SNPRINTF) && defined(_KERNEL)
986                 SNPRINTF(name, sizeof(name), "%x", poolnum);
987 #else
988                 (void)sprintf(name, "%x", poolnum);
989 #endif
990
991                 for (p = softp->ipf_pool_list[unit + 1]; p != NULL; ) {
992                         if (strncmp(name, p->ipo_name,
993                                     sizeof(p->ipo_name)) == 0) {
994                                 poolnum++;
995 #if defined(SNPRINTF) && defined(_KERNEL)
996                                 SNPRINTF(name, sizeof(name), "%x", poolnum);
997 #else
998                                 (void)sprintf(name, "%x", poolnum);
999 #endif
1000                                 p = softp->ipf_pool_list[unit + 1];
1001                         } else
1002                                 p = p->ipo_next;
1003                 }
1004
1005                 (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
1006                 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
1007         } else {
1008                 (void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
1009         }
1010
1011         h->ipo_radix = softp->ipf_radix;
1012         h->ipo_ref = 1;
1013         h->ipo_list = NULL;
1014         h->ipo_tail = &h->ipo_list;
1015         h->ipo_unit = unit;
1016         h->ipo_next = softp->ipf_pool_list[unit + 1];
1017         if (softp->ipf_pool_list[unit + 1] != NULL)
1018                 softp->ipf_pool_list[unit + 1]->ipo_pnext = &h->ipo_next;
1019         h->ipo_pnext = &softp->ipf_pool_list[unit + 1];
1020         softp->ipf_pool_list[unit + 1] = h;
1021
1022         softp->ipf_pool_stats.ipls_pools++;
1023
1024         return 0;
1025 }
1026
1027
1028 /* ------------------------------------------------------------------------ */
1029 /* Function:    ipf_pool_remove_node                                        */
1030 /* Returns:     int      - 0 = success, else error                          */
1031 /* Parameters:  softc(I) - pointer to soft context main structure           */
1032 /*              ipo(I)   - pointer to the pool to remove the node from.     */
1033 /*              ipe(I)   - address being deleted as a node                  */
1034 /* Locks:       WRITE(ipf_poolrw)                                           */
1035 /*                                                                          */
1036 /* Remove a node from the pool given by ipo.                                */
1037 /* ------------------------------------------------------------------------ */
1038 static int
1039 ipf_pool_remove_node(softc, softp, ipo, ipe)
1040         ipf_main_softc_t *softc;
1041         ipf_pool_softc_t *softp;
1042         ip_pool_t *ipo;
1043         ip_pool_node_t *ipe;
1044 {
1045         void *ptr;
1046
1047         if (ipo->ipo_tail == &ipe->ipn_next)
1048                 ipo->ipo_tail = ipe->ipn_pnext;
1049
1050         if (ipe->ipn_pnext != NULL)
1051                 *ipe->ipn_pnext = ipe->ipn_next;
1052         if (ipe->ipn_next != NULL)
1053                 ipe->ipn_next->ipn_pnext = ipe->ipn_pnext;
1054
1055         if (ipe->ipn_pdnext != NULL)
1056                 *ipe->ipn_pdnext = ipe->ipn_dnext;
1057         if (ipe->ipn_dnext != NULL)
1058                 ipe->ipn_dnext->ipn_pdnext = ipe->ipn_pdnext;
1059
1060         ptr = ipo->ipo_head->deladdr(ipo->ipo_head, &ipe->ipn_addr,
1061                                      &ipe->ipn_mask);
1062
1063         if (ptr != NULL) {
1064                 ipf_pool_node_deref(softp, ipe);
1065                 return 0;
1066         }
1067         IPFERROR(70027);
1068         return ESRCH;
1069 }
1070
1071
1072 /* ------------------------------------------------------------------------ */
1073 /* Function:    ipf_pool_destroy                                            */
1074 /* Returns:     int    - 0 = success, else error                            */
1075 /* Parameters:  softc(I) - pointer to soft context main structure           */
1076 /*              softp(I) - pointer to soft context pool information         */
1077 /*              unit(I)  - ipfilter device to which we are working on      */
1078 /*              name(I)  - name of the pool                                 */
1079 /* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
1080 /*                                                                          */
1081 /* Search for a pool using paramters passed in and if it's not otherwise    */
1082 /* busy, free it.  If it is busy, clear all of its nodes, mark it for being */
1083 /* deleted and return an error saying it is busy.                           */
1084 /*                                                                          */
1085 /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
1086 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
1087 /* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
1088 /* ------------------------------------------------------------------------ */
1089 static int
1090 ipf_pool_destroy(softc, softp, unit, name)
1091         ipf_main_softc_t *softc;
1092         ipf_pool_softc_t *softp;
1093         int unit;
1094         char *name;
1095 {
1096         ip_pool_t *ipo;
1097
1098         ipo = ipf_pool_exists(softp, unit, name);
1099         if (ipo == NULL) {
1100                 IPFERROR(70009);
1101                 return ESRCH;
1102         }
1103
1104         if (ipo->ipo_ref != 1) {
1105                 ipf_pool_clearnodes(softc, softp, ipo);
1106                 ipo->ipo_flags |= IPOOL_DELETE;
1107                 return 0;
1108         }
1109
1110         ipf_pool_free(softc, softp, ipo);
1111         return 0;
1112 }
1113
1114
1115 /* ------------------------------------------------------------------------ */
1116 /* Function:    ipf_pool_flush                                              */
1117 /* Returns:     int    - number of pools deleted                            */
1118 /* Parameters:  softc(I) - pointer to soft context main structure           */
1119 /*              arg(I)   - pointer to local context to use                  */
1120 /*              fp(I)    - which pool(s) to flush                           */
1121 /* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
1122 /*                                                                          */
1123 /* Free all pools associated with the device that matches the unit number   */
1124 /* passed in with operation.                                                */
1125 /*                                                                          */
1126 /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
1127 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
1128 /* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
1129 /* ------------------------------------------------------------------------ */
1130 static size_t
1131 ipf_pool_flush(softc, arg, fp)
1132         ipf_main_softc_t *softc;
1133         void *arg;
1134         iplookupflush_t *fp;
1135 {
1136         ipf_pool_softc_t *softp = arg;
1137         int i, num = 0, unit, err;
1138         ip_pool_t *p, *q;
1139
1140         unit = fp->iplf_unit;
1141         for (i = -1; i <= IPL_LOGMAX; i++) {
1142                 if (unit != IPLT_ALL && i != unit)
1143                         continue;
1144                 for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
1145                         q = p->ipo_next;
1146                         err = ipf_pool_destroy(softc, softp, i, p->ipo_name);
1147                         if (err == 0)
1148                                 num++;
1149                 }
1150         }
1151         return num;
1152 }
1153
1154
1155 /* ------------------------------------------------------------------------ */
1156 /* Function:    ipf_pool_free                                               */
1157 /* Returns:     void                                                        */
1158 /* Parameters:  softc(I) - pointer to soft context main structure           */
1159 /*              softp(I) - pointer to soft context pool information         */
1160 /*              ipo(I) - pointer to pool structure                          */
1161 /* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
1162 /*                                                                          */
1163 /* Deletes the pool strucutre passed in from the list of pools and deletes  */
1164 /* all of the address information stored in it, including any tree data     */
1165 /* structures also allocated.                                               */
1166 /*                                                                          */
1167 /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
1168 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
1169 /* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
1170 /* ------------------------------------------------------------------------ */
1171 static void
1172 ipf_pool_free(softc, softp, ipo)
1173         ipf_main_softc_t *softc;
1174         ipf_pool_softc_t *softp;
1175         ip_pool_t *ipo;
1176 {
1177
1178         ipf_pool_clearnodes(softc, softp, ipo);
1179
1180         if (ipo->ipo_next != NULL)
1181                 ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
1182         *ipo->ipo_pnext = ipo->ipo_next;
1183         ipf_rx_freehead(ipo->ipo_head);
1184         KFREE(ipo);
1185
1186         softp->ipf_pool_stats.ipls_pools--;
1187 }
1188
1189
1190 /* ------------------------------------------------------------------------ */
1191 /* Function:    ipf_pool_clearnodes                                         */
1192 /* Returns:     void                                                        */
1193 /* Parameters:  softc(I) - pointer to soft context main structure           */
1194 /*              softp(I) - pointer to soft context pool information         */
1195 /*              ipo(I)   - pointer to pool structure                        */
1196 /* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
1197 /*                                                                          */
1198 /* Deletes all nodes stored in a pool structure.                            */
1199 /* ------------------------------------------------------------------------ */
1200 static void
1201 ipf_pool_clearnodes(softc, softp, ipo)
1202         ipf_main_softc_t *softc;
1203         ipf_pool_softc_t *softp;
1204         ip_pool_t *ipo;
1205 {
1206         ip_pool_node_t *n, **next;
1207
1208         for (next = &ipo->ipo_list; (n = *next) != NULL; )
1209                 ipf_pool_remove_node(softc, softp, ipo, n);
1210
1211         ipo->ipo_list = NULL;
1212 }
1213
1214
1215 /* ------------------------------------------------------------------------ */
1216 /* Function:    ipf_pool_deref                                              */
1217 /* Returns:     void                                                        */
1218 /* Parameters:  softc(I) - pointer to soft context main structure           */
1219 /*              arg(I)   - pointer to local context to use                  */
1220 /*              pool(I)  - pointer to pool structure                        */
1221 /* Locks:       WRITE(ipf_poolrw)                                           */
1222 /*                                                                          */
1223 /* Drop the number of known references to this pool structure by one and if */
1224 /* we arrive at zero known references, free it.                             */
1225 /* ------------------------------------------------------------------------ */
1226 static int
1227 ipf_pool_deref(softc, arg, pool)
1228         ipf_main_softc_t *softc;
1229         void *arg, *pool;
1230 {
1231         ip_pool_t *ipo = pool;
1232
1233         ipo->ipo_ref--;
1234
1235         if (ipo->ipo_ref == 0)
1236                 ipf_pool_free(softc, arg, ipo);
1237
1238         else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
1239                 ipf_pool_destroy(softc, arg, ipo->ipo_unit, ipo->ipo_name);
1240
1241         return 0;
1242 }
1243
1244
1245 /* ------------------------------------------------------------------------ */
1246 /* Function:    ipf_pool_node_deref                                         */
1247 /* Returns:     void                                                        */
1248 /* Parameters:  softp(I) - pointer to soft context pool information         */
1249 /*              ipn(I)   - pointer to pool structure                        */
1250 /* Locks:       WRITE(ipf_poolrw)                                           */
1251 /*                                                                          */
1252 /* Drop a reference to the pool node passed in and if we're the last, free  */
1253 /* it all up and adjust the stats accordingly.                              */
1254 /* ------------------------------------------------------------------------ */
1255 static void
1256 ipf_pool_node_deref(softp, ipn)
1257         ipf_pool_softc_t *softp;
1258         ip_pool_node_t *ipn;
1259 {
1260
1261         ipn->ipn_ref--;
1262
1263         if (ipn->ipn_ref == 0) {
1264                 KFREE(ipn);
1265                 softp->ipf_pool_stats.ipls_nodes--;
1266         }
1267 }
1268
1269
1270 /* ------------------------------------------------------------------------ */
1271 /* Function:    ipf_pool_iter_next                                          */
1272 /* Returns:     void                                                        */
1273 /* Parameters:  softc(I) - pointer to soft context main structure           */
1274 /*              arg(I)   - pointer to local context to use                  */
1275 /*              token(I) - pointer to pool structure                        */
1276 /*              ilp(IO)  - pointer to pool iterating structure              */
1277 /*                                                                          */
1278 /* ------------------------------------------------------------------------ */
1279 static int
1280 ipf_pool_iter_next(softc, arg, token, ilp)
1281         ipf_main_softc_t *softc;
1282         void *arg;
1283         ipftoken_t *token;
1284         ipflookupiter_t *ilp;
1285 {
1286         ipf_pool_softc_t *softp = arg;
1287         ip_pool_node_t *node, zn, *nextnode;
1288         ip_pool_t *ipo, zp, *nextipo;
1289         void *pnext;
1290         int err;
1291
1292         err = 0;
1293         node = NULL;
1294         nextnode = NULL;
1295         ipo = NULL;
1296         nextipo = NULL;
1297
1298         READ_ENTER(&softc->ipf_poolrw);
1299
1300         switch (ilp->ili_otype)
1301         {
1302         case IPFLOOKUPITER_LIST :
1303                 ipo = token->ipt_data;
1304                 if (ipo == NULL) {
1305                         nextipo = softp->ipf_pool_list[(int)ilp->ili_unit + 1];
1306                 } else {
1307                         nextipo = ipo->ipo_next;
1308                 }
1309
1310                 if (nextipo != NULL) {
1311                         ATOMIC_INC32(nextipo->ipo_ref);
1312                         token->ipt_data = nextipo;
1313                 } else {
1314                         bzero((char *)&zp, sizeof(zp));
1315                         nextipo = &zp;
1316                         token->ipt_data = NULL;
1317                 }
1318                 pnext = nextipo->ipo_next;
1319                 break;
1320
1321         case IPFLOOKUPITER_NODE :
1322                 node = token->ipt_data;
1323                 if (node == NULL) {
1324                         ipo = ipf_pool_exists(arg, ilp->ili_unit,
1325                                               ilp->ili_name);
1326                         if (ipo == NULL) {
1327                                 IPFERROR(70010);
1328                                 err = ESRCH;
1329                         } else {
1330                                 nextnode = ipo->ipo_list;
1331                                 ipo = NULL;
1332                         }
1333                 } else {
1334                         nextnode = node->ipn_next;
1335                 }
1336
1337                 if (nextnode != NULL) {
1338                         ATOMIC_INC32(nextnode->ipn_ref);
1339                         token->ipt_data = nextnode;
1340                 } else {
1341                         bzero((char *)&zn, sizeof(zn));
1342                         nextnode = &zn;
1343                         token->ipt_data = NULL;
1344                 }
1345                 pnext = nextnode->ipn_next;
1346                 break;
1347
1348         default :
1349                 IPFERROR(70011);
1350                 pnext = NULL;
1351                 err = EINVAL;
1352                 break;
1353         }
1354
1355         RWLOCK_EXIT(&softc->ipf_poolrw);
1356         if (err != 0)
1357                 return err;
1358
1359         switch (ilp->ili_otype)
1360         {
1361         case IPFLOOKUPITER_LIST :
1362                 err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
1363                 if (err != 0)  {
1364                         IPFERROR(70012);
1365                         err = EFAULT;
1366                 }
1367                 if (ipo != NULL) {
1368                         WRITE_ENTER(&softc->ipf_poolrw);
1369                         ipf_pool_deref(softc, softp, ipo);
1370                         RWLOCK_EXIT(&softc->ipf_poolrw);
1371                 }
1372                 break;
1373
1374         case IPFLOOKUPITER_NODE :
1375                 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
1376                 if (err != 0) {
1377                         IPFERROR(70013);
1378                         err = EFAULT;
1379                 }
1380                 if (node != NULL) {
1381                         WRITE_ENTER(&softc->ipf_poolrw);
1382                         ipf_pool_node_deref(softp, node);
1383                         RWLOCK_EXIT(&softc->ipf_poolrw);
1384                 }
1385                 break;
1386         }
1387         if (pnext == NULL)
1388                 ipf_token_mark_complete(token);
1389
1390         return err;
1391 }
1392
1393
1394 /* ------------------------------------------------------------------------ */
1395 /* Function:    ipf_pool_iterderef                                          */
1396 /* Returns:     void                                                        */
1397 /* Parameters:  softc(I) - pointer to soft context main structure           */
1398 /*              arg(I)   - pointer to local context to use                  */
1399 /*              unit(I)  - ipfilter device to which we are working on       */
1400 /* Locks:       WRITE(ipf_poolrw)                                           */
1401 /*                                                                          */
1402 /* ------------------------------------------------------------------------ */
1403 static int
1404 ipf_pool_iter_deref(softc, arg, otype, unit, data)
1405         ipf_main_softc_t *softc;
1406         void *arg;
1407         int otype;
1408         int unit;
1409         void *data;
1410 {
1411         ipf_pool_softc_t *softp = arg;
1412
1413         if (data == NULL)
1414                 return EINVAL;
1415
1416         if (unit < 0 || unit > IPL_LOGMAX)
1417                 return EINVAL;
1418
1419         switch (otype)
1420         {
1421         case IPFLOOKUPITER_LIST :
1422                 ipf_pool_deref(softc, softp, (ip_pool_t *)data);
1423                 break;
1424
1425         case IPFLOOKUPITER_NODE :
1426                 ipf_pool_node_deref(softp, (ip_pool_node_t *)data);
1427                 break;
1428         default :
1429                 break;
1430         }
1431
1432         return 0;
1433 }
1434
1435
1436 /* ------------------------------------------------------------------------ */
1437 /* Function:    ipf_pool_expire                                             */
1438 /* Returns:     Nil                                                         */
1439 /* Parameters:  softc(I) - pointer to soft context main structure           */
1440 /*              arg(I)   - pointer to local context to use                  */
1441 /*                                                                          */
1442 /* At present this function exists just to support temporary addition of    */
1443 /* nodes to the address pool.                                               */
1444 /* ------------------------------------------------------------------------ */
1445 static void
1446 ipf_pool_expire(softc, arg)
1447         ipf_main_softc_t *softc;
1448         void *arg;
1449 {
1450         ipf_pool_softc_t *softp = arg;
1451         ip_pool_node_t *n;
1452
1453         while ((n = softp->ipf_node_explist) != NULL) {
1454                 /*
1455                  * Because the list is kept sorted on insertion, the fist
1456                  * one that dies in the future means no more work to do.
1457                  */
1458                 if (n->ipn_die > softc->ipf_ticks)
1459                         break;
1460                 ipf_pool_remove_node(softc, softp, n->ipn_owner, n);
1461         }
1462 }
1463
1464
1465
1466
1467 #ifndef _KERNEL
1468 void
1469 ipf_pool_dump(softc, arg)
1470         ipf_main_softc_t *softc;
1471         void *arg;
1472 {
1473         ipf_pool_softc_t *softp = arg;
1474         ip_pool_t *ipl;
1475         int i;
1476
1477         printf("List of configured pools\n");
1478         for (i = 0; i <= LOOKUP_POOL_MAX; i++)
1479                 for (ipl = softp->ipf_pool_list[i]; ipl != NULL;
1480                      ipl = ipl->ipo_next)
1481                         printpool(ipl, bcopywrap, NULL, opts, NULL);
1482 }
1483 #endif