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