]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - ip_pool.c
In preparation for the upcoming ipfilter vendor code import,
[FreeBSD/FreeBSD.git] / ip_pool.c
1 /*      $NetBSD$        */
2
3 /*
4  * Copyright (C) 1993-2001, 2003 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 #if defined(KERNEL) || defined(_KERNEL)
9 # undef KERNEL
10 # undef _KERNEL
11 # define        KERNEL  1
12 # define        _KERNEL 1
13 #endif
14 #if defined(__osf__)
15 # define _PROTO_NET_H_
16 #endif
17 #include <sys/errno.h>
18 #include <sys/types.h>
19 #include <sys/param.h>
20 #include <sys/file.h>
21 #if !defined(_KERNEL) && !defined(__KERNEL__)
22 # include <stdio.h>
23 # include <stdlib.h>
24 # include <string.h>
25 # define _KERNEL
26 # ifdef __OpenBSD__
27 struct file;
28 # endif
29 # include <sys/uio.h>
30 # undef _KERNEL
31 #else
32 # include <sys/systm.h>
33 # if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
34 #  include <sys/proc.h>
35 # endif
36 #endif
37 #include <sys/time.h>
38 #if !defined(linux)
39 # include <sys/protosw.h>
40 #endif
41 #include <sys/socket.h>
42 #if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__))
43 # include <sys/mbuf.h>
44 #endif
45 #if defined(__SVR4) || defined(__svr4__)
46 # include <sys/filio.h>
47 # include <sys/byteorder.h>
48 # ifdef _KERNEL
49 #  include <sys/dditypes.h>
50 # endif
51 # include <sys/stream.h>
52 # include <sys/kmem.h>
53 #endif
54 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
55 # include <sys/malloc.h>
56 #endif
57
58 #if (defined(__osf__) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL)
59 # ifdef __osf__
60 #  include <net/radix.h>
61 # endif
62 # include "radix_ipf_local.h"
63 # define _RADIX_H_
64 #endif
65 #include <net/if.h>
66 #include <netinet/in.h>
67
68 #include "netinet/ip_compat.h"
69 #include "netinet/ip_fil.h"
70 #include "netinet/ip_pool.h"
71
72 #if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \
73       ((BSD >= 198911) && !defined(__osf__) && \
74       !defined(__hpux) && !defined(__sgi))
75 static int rn_freenode __P((struct radix_node *, void *));
76 #endif
77
78 /* END OF INCLUDES */
79
80 #if !defined(lint)
81 static const char sccsid[] = "@(#)ip_fil.c      2.41 6/5/96 (C) 1993-2000 Darren Reed";
82 static const char rcsid[] = "@(#)Id: ip_pool.c,v 2.55.2.12 2005/02/01 04:04:46 darrenr Exp";
83 #endif
84
85 #ifdef IPFILTER_LOOKUP
86
87 # ifndef RADIX_NODE_HEAD_LOCK
88 #  define RADIX_NODE_HEAD_LOCK(x)       ;
89 # endif
90 # ifndef RADIX_NODE_HEAD_UNLOCK
91 #  define RADIX_NODE_HEAD_UNLOCK(x)     ;
92 # endif
93
94 ip_pool_stat_t ipoolstat;
95 ipfrwlock_t ip_poolrw;
96
97 /*
98  * Binary tree routines from Sedgewick and enhanced to do ranges of addresses.
99  * NOTE: Insertion *MUST* be from greatest range to least for it to work!
100  * These should be replaced, eventually, by something else - most notably a
101  * interval searching method.  The important feature is to be able to find
102  * the best match.
103  *
104  * So why not use a radix tree for this?  As the first line implies, it
105  * has been written to work with a _range_ of addresses.  A range is not
106  * necessarily a match with any given netmask so what we end up dealing
107  * with is an interval tree.  Implementations of these are hard to find
108  * and the one herein is far from bug free.
109  *
110  * Sigh, in the end I became convinced that the bugs the code contained did
111  * not make it worthwhile not using radix trees.  For now the radix tree from
112  * 4.4 BSD is used, but this is not viewed as a long term solution.
113  */
114 ip_pool_t *ip_pool_list[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL,
115                                          NULL, NULL, NULL, NULL };
116
117
118 #ifdef TEST_POOL
119 void treeprint __P((ip_pool_t *));
120
121 int
122 main(argc, argv)
123         int argc;
124         char *argv[];
125 {
126         addrfamily_t a, b;
127         iplookupop_t op;
128         ip_pool_t *ipo;
129         i6addr_t ip;
130
131         RWLOCK_INIT(&ip_poolrw, "poolrw");
132         ip_pool_init();
133
134         bzero((char *)&a, sizeof(a));
135         bzero((char *)&b, sizeof(b));
136         bzero((char *)&ip, sizeof(ip));
137         bzero((char *)&op, sizeof(op));
138         strcpy(op.iplo_name, "0");
139
140         if (ip_pool_create(&op) == 0)
141                 ipo = ip_pool_find(0, "0");
142
143         a.adf_addr.in4.s_addr = 0x0a010203;
144         b.adf_addr.in4.s_addr = 0xffffffff;
145         ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
146         ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
147
148         a.adf_addr.in4.s_addr = 0x0a000000;
149         b.adf_addr.in4.s_addr = 0xff000000;
150         ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
151         ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
152
153         a.adf_addr.in4.s_addr = 0x0a010100;
154         b.adf_addr.in4.s_addr = 0xffffff00;
155         ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
156         ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
157
158         a.adf_addr.in4.s_addr = 0x0a010200;
159         b.adf_addr.in4.s_addr = 0xffffff00;
160         ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
161         ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
162
163         a.adf_addr.in4.s_addr = 0x0a010000;
164         b.adf_addr.in4.s_addr = 0xffff0000;
165         ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
166         ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
167
168         a.adf_addr.in4.s_addr = 0x0a01020f;
169         b.adf_addr.in4.s_addr = 0xffffffff;
170         ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
171         ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
172 #ifdef  DEBUG_POOL
173 treeprint(ipo);
174 #endif
175         ip.in4.s_addr = 0x0a00aabb;
176         printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
177                 ip_pool_search(ipo, 4, &ip));
178
179         ip.in4.s_addr = 0x0a000001;
180         printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
181                 ip_pool_search(ipo, 4, &ip));
182
183         ip.in4.s_addr = 0x0a000101;
184         printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
185                 ip_pool_search(ipo, 4, &ip));
186
187         ip.in4.s_addr = 0x0a010001;
188         printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
189                 ip_pool_search(ipo, 4, &ip));
190
191         ip.in4.s_addr = 0x0a010101;
192         printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
193                 ip_pool_search(ipo, 4, &ip));
194
195         ip.in4.s_addr = 0x0a010201;
196         printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
197                 ip_pool_search(ipo, 4, &ip));
198
199         ip.in4.s_addr = 0x0a010203;
200         printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
201                 ip_pool_search(ipo, 4, &ip));
202
203         ip.in4.s_addr = 0x0a01020f;
204         printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
205                 ip_pool_search(ipo, 4, &ip));
206
207         ip.in4.s_addr = 0x0b00aabb;
208         printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
209                 ip_pool_search(ipo, 4, &ip));
210
211 #ifdef  DEBUG_POOL
212 treeprint(ipo);
213 #endif
214
215         ip_pool_fini();
216
217         return 0;
218 }
219
220
221 void
222 treeprint(ipo)
223 ip_pool_t *ipo;
224 {
225         ip_pool_node_t *c;
226
227         for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
228                 printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
229                         c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
230                         c->ipn_mask.adf_addr.in4.s_addr,
231                         c->ipn_info, c->ipn_hits);
232 }
233 #endif /* TEST_POOL */
234
235
236 /* ------------------------------------------------------------------------ */
237 /* Function:    ip_pool_init                                                */
238 /* Returns:     int     - 0 = success, else error                           */
239 /*                                                                          */
240 /* Initialise the routing table data structures where required.             */
241 /* ------------------------------------------------------------------------ */
242 int ip_pool_init()
243 {
244
245         bzero((char *)&ipoolstat, sizeof(ipoolstat));
246
247 #if (!defined(_KERNEL) || (BSD < 199306))
248         rn_init();
249 #endif
250         return 0;
251 }
252
253
254 /* ------------------------------------------------------------------------ */
255 /* Function:    ip_pool_fini                                                */
256 /* Returns:     int     - 0 = success, else error                           */
257 /* Locks:       WRITE(ipf_global)                                           */
258 /*                                                                          */
259 /* Clean up all the pool data structures allocated and call the cleanup     */
260 /* function for the radix tree that supports the pools. ip_pool_destroy() is*/
261 /* used to delete the pools one by one to ensure they're properly freed up. */
262 /* ------------------------------------------------------------------------ */
263 void ip_pool_fini()
264 {
265         ip_pool_t *p, *q;
266         iplookupop_t op;
267         int i;
268
269         ASSERT(rw_read_locked(&ipf_global.ipf_lk) == 0);
270
271         for (i = 0; i <= IPL_LOGMAX; i++) {
272                 for (q = ip_pool_list[i]; (p = q) != NULL; ) {
273                         op.iplo_unit = i;
274                         (void)strncpy(op.iplo_name, p->ipo_name,
275                                 sizeof(op.iplo_name));
276                         q = p->ipo_next;
277                         (void) ip_pool_destroy(&op);
278                 }
279         }
280
281 #if (!defined(_KERNEL) || (BSD < 199306))
282         rn_fini();
283 #endif
284 }
285
286
287 /* ------------------------------------------------------------------------ */
288 /* Function:    ip_pool_statistics                                          */
289 /* Returns:     int     - 0 = success, else error                           */
290 /* Parameters:  op(I)   - pointer to lookup operation arguments             */
291 /*                                                                          */
292 /* Copy the current statistics out into user space, collecting pool list    */
293 /* pointers as appropriate for later use.                                   */
294 /* ------------------------------------------------------------------------ */
295 int ip_pool_statistics(op)
296 iplookupop_t *op;
297 {
298         ip_pool_stat_t stats;
299         int unit, i, err = 0;
300
301         if (op->iplo_size != sizeof(ipoolstat))
302                 return EINVAL;
303
304         bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats));
305         unit = op->iplo_unit;
306         if (unit == IPL_LOGALL) {
307                 for (i = 0; i < IPL_LOGSIZE; i++)
308                         stats.ipls_list[i] = ip_pool_list[i];
309         } else if (unit >= 0 && unit < IPL_LOGSIZE) {
310                 if (op->iplo_name[0] != '\0')
311                         stats.ipls_list[unit] = ip_pool_find(unit,
312                                                              op->iplo_name);
313                 else
314                         stats.ipls_list[unit] = ip_pool_list[unit];
315         } else
316                 err = EINVAL;
317         if (err == 0)
318                 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
319         return err;
320 }
321
322
323
324 /* ------------------------------------------------------------------------ */
325 /* Function:    ip_pool_find                                                */
326 /* Returns:     int     - 0 = success, else error                           */
327 /* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
328 /*                                                                          */
329 /* Find a matching pool inside the collection of pools for a particular     */
330 /* device, indicated by the unit number.                                    */
331 /* ------------------------------------------------------------------------ */
332 void *ip_pool_find(unit, name)
333 int unit;
334 char *name;
335 {
336         ip_pool_t *p;
337
338         for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next)
339                 if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0)
340                         break;
341         return p;
342 }
343
344
345 /* ------------------------------------------------------------------------ */
346 /* Function:    ip_pool_findeq                                              */
347 /* Returns:     int     - 0 = success, else error                           */
348 /* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
349 /*              addr(I) - pointer to address information to delete          */
350 /*              mask(I) -                                                   */
351 /*                                                                          */
352 /* Searches for an exact match of an entry in the pool.                     */
353 /* ------------------------------------------------------------------------ */
354 ip_pool_node_t *ip_pool_findeq(ipo, addr, mask)
355 ip_pool_t *ipo;
356 addrfamily_t *addr, *mask;
357 {
358         struct radix_node *n;
359 #ifdef USE_SPL
360         int s;
361
362         SPL_NET(s);
363 #endif
364         RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
365         n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head);
366         RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
367         SPL_X(s);
368         return (ip_pool_node_t *)n;
369 }
370
371
372 /* ------------------------------------------------------------------------ */
373 /* Function:    ip_pool_search                                              */
374 /* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
375 /* Parameters:  tptr(I)    - pointer to the pool to search                  */
376 /*              version(I) - IP protocol version (4 or 6)                   */
377 /*              dptr(I)    - pointer to address information                 */
378 /*                                                                          */
379 /* Search the pool for a given address and return a search result.          */
380 /* ------------------------------------------------------------------------ */
381 int ip_pool_search(tptr, version, dptr)
382 void *tptr;
383 int version;
384 void *dptr;
385 {
386         struct radix_node *rn;
387         ip_pool_node_t *m;
388         i6addr_t *addr;
389         addrfamily_t v;
390         ip_pool_t *ipo;
391         int rv;
392
393         ipo = tptr;
394         if (ipo == NULL)
395                 return -1;
396
397         rv = 1;
398         m = NULL;
399         addr = (i6addr_t *)dptr;
400         bzero(&v, sizeof(v));
401         v.adf_len = offsetof(addrfamily_t, adf_addr);
402
403         if (version == 4) {
404                 v.adf_len += sizeof(addr->in4);
405                 v.adf_addr.in4 = addr->in4;
406 #ifdef USE_INET6
407         } else if (version == 6) {
408                 v.adf_len += sizeof(addr->in6);
409                 v.adf_addr.in6 = addr->in6;
410 #endif
411         } else
412                 return -1;
413
414         READ_ENTER(&ip_poolrw);
415
416         RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
417         rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head);
418         RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
419
420         if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) {
421                 m = (ip_pool_node_t *)rn;
422                 ipo->ipo_hits++;
423                 m->ipn_hits++;
424                 rv = m->ipn_info;
425         }
426         RWLOCK_EXIT(&ip_poolrw);
427         return rv;
428 }
429
430
431 /* ------------------------------------------------------------------------ */
432 /* Function:    ip_pool_insert                                              */
433 /* Returns:     int     - 0 = success, else error                           */
434 /* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
435 /*              addr(I) - address being added as a node                     */
436 /*              mask(I) - netmask to with the node being added              */
437 /*              info(I) - extra information to store in this node.          */
438 /* Locks:       WRITE(ip_poolrw)                                            */
439 /*                                                                          */
440 /* Add another node to the pool given by ipo.  The three parameters passed  */
441 /* in (addr, mask, info) shold all be stored in the node.                   */
442 /* ------------------------------------------------------------------------ */
443 int ip_pool_insert(ipo, addr, mask, info)
444 ip_pool_t *ipo;
445 i6addr_t *addr, *mask;
446 int info;
447 {
448         struct radix_node *rn;
449         ip_pool_node_t *x;
450
451         ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
452
453         KMALLOC(x, ip_pool_node_t *);
454         if (x == NULL) {
455                 return ENOMEM;
456         }
457
458         bzero(x, sizeof(*x));
459
460         x->ipn_info = info;
461         (void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name));
462
463         bcopy(addr, &x->ipn_addr.adf_addr, sizeof(*addr));
464         x->ipn_addr.adf_len = sizeof(x->ipn_addr);
465         bcopy(mask, &x->ipn_mask.adf_addr, sizeof(*mask));
466         x->ipn_mask.adf_len = sizeof(x->ipn_mask);
467
468         RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
469         rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask,
470                                         ipo->ipo_head, x->ipn_nodes);
471         RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
472 #ifdef  DEBUG_POOL
473         printf("Added %p at %p\n", x, rn);
474 #endif
475
476         if (rn == NULL) {
477                 KFREE(x);
478                 return ENOMEM;
479         }
480
481         x->ipn_next = ipo->ipo_list;
482         x->ipn_pnext = &ipo->ipo_list;
483         if (ipo->ipo_list != NULL)
484                 ipo->ipo_list->ipn_pnext = &x->ipn_next;
485         ipo->ipo_list = x;
486
487         ipoolstat.ipls_nodes++;
488
489         return 0;
490 }
491
492
493 /* ------------------------------------------------------------------------ */
494 /* Function:    ip_pool_create                                              */
495 /* Returns:     int     - 0 = success, else error                           */
496 /* Parameters:  op(I) - pointer to iplookup struct with call details        */
497 /* Locks:       WRITE(ip_poolrw)                                            */
498 /*                                                                          */
499 /* Creates a new group according to the paramters passed in via the         */
500 /* iplookupop structure.  Does not check to see if the group already exists */
501 /* when being inserted - assume this has already been done.  If the pool is */
502 /* marked as being anonymous, give it a new, unique, identifier.  Call any  */
503 /* other functions required to initialise the structure.                    */
504 /* ------------------------------------------------------------------------ */
505 int ip_pool_create(op)
506 iplookupop_t *op;
507 {
508         char name[FR_GROUPLEN];
509         int poolnum, unit;
510         ip_pool_t *h;
511
512         ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
513
514         KMALLOC(h, ip_pool_t *);
515         if (h == NULL)
516                 return ENOMEM;
517         bzero(h, sizeof(*h));
518
519         if (rn_inithead((void **)&h->ipo_head,
520                         offsetof(addrfamily_t, adf_addr) << 3) == 0) {
521                 KFREE(h);
522                 return ENOMEM;
523         }
524
525         unit = op->iplo_unit;
526
527         if ((op->iplo_arg & IPOOL_ANON) != 0) {
528                 ip_pool_t *p;
529
530                 poolnum = IPOOL_ANON;
531
532 #if defined(SNPRINTF) && defined(_KERNEL)
533                 SNPRINTF(name, sizeof(name), "%x", poolnum);
534 #else
535                 (void)sprintf(name, "%x", poolnum);
536 #endif
537
538                 for (p = ip_pool_list[unit]; p != NULL; ) {
539                         if (strncmp(name, p->ipo_name,
540                                     sizeof(p->ipo_name)) == 0) {
541                                 poolnum++;
542 #if defined(SNPRINTF) && defined(_KERNEL)
543                                 SNPRINTF(name, sizeof(name), "%x", poolnum);
544 #else
545                                 (void)sprintf(name, "%x", poolnum);
546 #endif
547                                 p = ip_pool_list[unit];
548                         } else
549                                 p = p->ipo_next;
550                 }
551
552                 (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
553         } else {
554                 (void) strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
555         }
556
557         h->ipo_ref = 1;
558         h->ipo_list = NULL;
559         h->ipo_unit = unit;
560         h->ipo_next = ip_pool_list[unit];
561         if (ip_pool_list[unit] != NULL)
562                 ip_pool_list[unit]->ipo_pnext = &h->ipo_next;
563         h->ipo_pnext = &ip_pool_list[unit];
564         ip_pool_list[unit] = h;
565
566         ipoolstat.ipls_pools++;
567
568         return 0;
569 }
570
571
572 /* ------------------------------------------------------------------------ */
573 /* Function:    ip_pool_remove                                              */
574 /* Returns:     int    - 0 = success, else error                            */
575 /* Parameters:  ipo(I) - pointer to the pool to remove the node from.       */
576 /*              ipe(I) - address being deleted as a node                    */
577 /* Locks:       WRITE(ip_poolrw)                                            */
578 /*                                                                          */
579 /* Add another node to the pool given by ipo.  The three parameters passed  */
580 /* in (addr, mask, info) shold all be stored in the node.                   */
581 /* ------------------------------------------------------------------------ */
582 int ip_pool_remove(ipo, ipe)
583 ip_pool_t *ipo;
584 ip_pool_node_t *ipe;
585 {
586         ip_pool_node_t **ipp, *n;
587
588         ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
589
590         for (ipp = &ipo->ipo_list; (n = *ipp) != NULL; ipp = &n->ipn_next) {
591                 if (ipe == n) {
592                         *n->ipn_pnext = n->ipn_next;
593                         if (n->ipn_next)
594                                 n->ipn_next->ipn_pnext = n->ipn_pnext;
595                         break;
596                 }
597         }
598
599         if (n == NULL)
600                 return ENOENT;
601
602         RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
603         ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
604                                    ipo->ipo_head);
605         RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
606         KFREE(n);
607
608         ipoolstat.ipls_nodes--;
609
610         return 0;
611 }
612
613
614 /* ------------------------------------------------------------------------ */
615 /* Function:    ip_pool_destroy                                             */
616 /* Returns:     int    - 0 = success, else error                            */
617 /* Parameters:  op(I)  -  information about the pool to remove              */
618 /* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
619 /*                                                                          */
620 /* Search for a pool using paramters passed in and if it's not otherwise    */
621 /* busy, free it.                                                           */
622 /*                                                                          */
623 /* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
624 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
625 /* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
626 /* ------------------------------------------------------------------------ */
627 int ip_pool_destroy(op)
628 iplookupop_t *op;
629 {
630         ip_pool_t *ipo;
631
632         ipo = ip_pool_find(op->iplo_unit, op->iplo_name);
633         if (ipo == NULL)
634                 return ESRCH;
635
636         if (ipo->ipo_ref != 1)
637                 return EBUSY;
638
639         ip_pool_free(ipo);
640         return 0;
641 }
642
643
644 /* ------------------------------------------------------------------------ */
645 /* Function:    ip_pool_flush                                               */
646 /* Returns:     int    - number of pools deleted                            */
647 /* Parameters:  fp(I)  - which pool(s) to flush                             */
648 /* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
649 /*                                                                          */
650 /* Free all pools associated with the device that matches the unit number   */
651 /* passed in with operation.                                                */
652 /*                                                                          */
653 /* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
654 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
655 /* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
656 /* ------------------------------------------------------------------------ */
657 int ip_pool_flush(fp)
658 iplookupflush_t *fp;
659 {
660         int i, num = 0, unit, err;
661         ip_pool_t *p, *q;
662         iplookupop_t op;
663
664         unit = fp->iplf_unit;
665
666         for (i = 0; i <= IPL_LOGMAX; i++) {
667                 if (unit != IPLT_ALL && i != unit)
668                         continue;
669                 for (q = ip_pool_list[i]; (p = q) != NULL; ) {
670                         op.iplo_unit = i;
671                         (void)strncpy(op.iplo_name, p->ipo_name,
672                                 sizeof(op.iplo_name));
673                         q = p->ipo_next;
674                         err = ip_pool_destroy(&op);
675                         if (err == 0)
676                                 num++;
677                         else
678                                 break;
679                 }
680         }
681         return num;
682 }
683
684
685 /* ------------------------------------------------------------------------ */
686 /* Function:    ip_pool_free                                                */
687 /* Returns:     void                                                        */
688 /* Parameters:  ipo(I) -  pointer to pool structure                         */
689 /* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
690 /*                                                                          */
691 /* Deletes the pool strucutre passed in from the list of pools and deletes  */
692 /* all of the address information stored in it, including any tree data     */
693 /* structures also allocated.                                               */
694 /*                                                                          */
695 /* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
696 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
697 /* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
698 /* ------------------------------------------------------------------------ */
699 void ip_pool_free(ipo)
700 ip_pool_t *ipo;
701 {
702         ip_pool_node_t *n;
703
704         RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
705         while ((n = ipo->ipo_list) != NULL) {
706                 ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
707                                            ipo->ipo_head);
708
709                 *n->ipn_pnext = n->ipn_next;
710                 if (n->ipn_next)
711                         n->ipn_next->ipn_pnext = n->ipn_pnext;
712
713                 KFREE(n);
714
715                 ipoolstat.ipls_nodes--;
716         }
717         RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
718
719         ipo->ipo_list = NULL;
720         if (ipo->ipo_next != NULL)
721                 ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
722         *ipo->ipo_pnext = ipo->ipo_next;
723         rn_freehead(ipo->ipo_head);
724         KFREE(ipo);
725
726         ipoolstat.ipls_pools--;
727 }
728
729
730 /* ------------------------------------------------------------------------ */
731 /* Function:    ip_pool_deref                                               */
732 /* Returns:     void                                                        */
733 /* Parameters:  ipo(I) -  pointer to pool structure                         */
734 /* Locks:       WRITE(ip_poolrw)                                            */
735 /*                                                                          */
736 /* Drop the number of known references to this pool structure by one and if */
737 /* we arrive at zero known references, free it.                             */
738 /* ------------------------------------------------------------------------ */
739 void ip_pool_deref(ipo)
740 ip_pool_t *ipo;
741 {
742
743         ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
744
745         ipo->ipo_ref--;
746         if (ipo->ipo_ref == 0)
747                 ip_pool_free(ipo);
748 }
749
750
751 # if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \
752       !defined(__hpux) && !defined(__sgi))
753 static int
754 rn_freenode(struct radix_node *n, void *p)
755 {
756         struct radix_node_head *rnh = p;
757         struct radix_node *d;
758
759         d = rnh->rnh_deladdr(n->rn_key, NULL, rnh);
760         if (d != NULL) {
761                 FreeS(d, max_keylen + 2 * sizeof (*d));
762         }
763         return 0;
764 }
765
766
767 void
768 rn_freehead(rnh)
769       struct radix_node_head *rnh;
770 {
771
772         RADIX_NODE_HEAD_LOCK(rnh);
773         (*rnh->rnh_walktree)(rnh, rn_freenode, rnh);
774
775         rnh->rnh_addaddr = NULL;
776         rnh->rnh_deladdr = NULL;
777         rnh->rnh_matchaddr = NULL;
778         rnh->rnh_lookup = NULL;
779         rnh->rnh_walktree = NULL;
780         RADIX_NODE_HEAD_UNLOCK(rnh);
781
782         Free(rnh);
783 }
784 # endif
785
786 #endif /* IPFILTER_LOOKUP */