1 /*
2 * Copyright (C) 1993-2001, 2003 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(linux)
37 # include <sys/protosw.h>
38 #endif
39 #include <sys/socket.h>
40 #if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__))
41 # include <sys/mbuf.h>
42 #endif
43 #if defined(__SVR4) || defined(__svr4__)
44 # include <sys/filio.h>
45 # include <sys/byteorder.h>
46 # ifdef _KERNEL
47 # include <sys/dditypes.h>
48 # endif
49 # include <sys/stream.h>
50 # include <sys/kmem.h>
51 #endif
52 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
53 # include <sys/malloc.h>
54 #endif
55
56 #if defined(SOLARIS2) && !defined(_KERNEL)
57 # include "radix_ipf.h"
58 #endif
59 #if defined(_KERNEL) && (defined(__osf__) || defined(AIX) || \
60 defined(__hpux) || defined(__sgi))
61 # include "radix_ipf_local.h"
62 # define _RADIX_H_
63 #endif
64 #include <net/if.h>
65 #include <netinet/in.h>
66
67 #include "netinet/ip_compat.h"
68 #include "netinet/ip_fil.h"
69 #include "netinet/ip_pool.h"
70
71 #if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \
72 ((BSD >= 198911) && !defined(__osf__) && \
73 !defined(__hpux) && !defined(__sgi))
74 static int rn_freenode __P((struct radix_node *, void *));
75 #endif
76
77 /* END OF INCLUDES */
78
79 #if !defined(lint)
80 static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
81 static const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.24 2007/10/10 09:45:37 darrenr Exp $";
82 #endif
83
84 #ifdef IPFILTER_LOOKUP
85
86 # if !defined(RADIX_NODE_HEAD_LOCK) || !defined(RADIX_NODE_HEAD_UNLOCK) || \
87 !defined(_KERNEL)
88 # undef RADIX_NODE_HEAD_LOCK
89 # undef RADIX_NODE_HEAD_UNLOCK
90 # define RADIX_NODE_HEAD_LOCK(x) ;
91 # define RADIX_NODE_HEAD_UNLOCK(x) ;
92 # endif
93
94 static void ip_pool_clearnodes __P((ip_pool_t *));
95 static void *ip_pool_exists __P((int, char *));
96
97 ip_pool_stat_t ipoolstat;
98 ipfrwlock_t ip_poolrw;
99
100 /*
101 * Binary tree routines from Sedgewick and enhanced to do ranges of addresses.
102 * NOTE: Insertion *MUST* be from greatest range to least for it to work!
103 * These should be replaced, eventually, by something else - most notably a
104 * interval searching method. The important feature is to be able to find
105 * the best match.
106 *
107 * So why not use a radix tree for this? As the first line implies, it
108 * has been written to work with a _range_ of addresses. A range is not
109 * necessarily a match with any given netmask so what we end up dealing
110 * with is an interval tree. Implementations of these are hard to find
111 * and the one herein is far from bug free.
112 *
113 * Sigh, in the end I became convinced that the bugs the code contained did
114 * not make it worthwhile not using radix trees. For now the radix tree from
115 * 4.4 BSD is used, but this is not viewed as a long term solution.
116 */
117 ip_pool_t *ip_pool_list[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL,
118 NULL, NULL, NULL, NULL };
119
120
121 #ifdef TEST_POOL
122 void treeprint __P((ip_pool_t *));
123
124 int
main(argc,argv)125 main(argc, argv)
126 int argc;
127 char *argv[];
128 {
129 addrfamily_t a, b;
130 iplookupop_t op;
131 ip_pool_t *ipo;
132 i6addr_t ip;
133
134 RWLOCK_INIT(&ip_poolrw, "poolrw");
135 ip_pool_init();
136
137 bzero((char *)&a, sizeof(a));
138 bzero((char *)&b, sizeof(b));
139 bzero((char *)&ip, sizeof(ip));
140 bzero((char *)&op, sizeof(op));
141 strcpy(op.iplo_name, "0");
142
143 if (ip_pool_create(&op) == 0)
144 ipo = ip_pool_exists(0, "0");
145
146 a.adf_addr.in4.s_addr = 0x0a010203;
147 b.adf_addr.in4.s_addr = 0xffffffff;
148 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
149 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
150
151 a.adf_addr.in4.s_addr = 0x0a000000;
152 b.adf_addr.in4.s_addr = 0xff000000;
153 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
154 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
155
156 a.adf_addr.in4.s_addr = 0x0a010100;
157 b.adf_addr.in4.s_addr = 0xffffff00;
158 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
159 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
160
161 a.adf_addr.in4.s_addr = 0x0a010200;
162 b.adf_addr.in4.s_addr = 0xffffff00;
163 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
164 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
165
166 a.adf_addr.in4.s_addr = 0x0a010000;
167 b.adf_addr.in4.s_addr = 0xffff0000;
168 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
169 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
170
171 a.adf_addr.in4.s_addr = 0x0a01020f;
172 b.adf_addr.in4.s_addr = 0xffffffff;
173 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
174 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
175 #ifdef DEBUG_POOL
176 treeprint(ipo);
177 #endif
178 ip.in4.s_addr = 0x0a00aabb;
179 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
180 ip_pool_search(ipo, 4, &ip));
181
182 ip.in4.s_addr = 0x0a000001;
183 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
184 ip_pool_search(ipo, 4, &ip));
185
186 ip.in4.s_addr = 0x0a000101;
187 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
188 ip_pool_search(ipo, 4, &ip));
189
190 ip.in4.s_addr = 0x0a010001;
191 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
192 ip_pool_search(ipo, 4, &ip));
193
194 ip.in4.s_addr = 0x0a010101;
195 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
196 ip_pool_search(ipo, 4, &ip));
197
198 ip.in4.s_addr = 0x0a010201;
199 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
200 ip_pool_search(ipo, 4, &ip));
201
202 ip.in4.s_addr = 0x0a010203;
203 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
204 ip_pool_search(ipo, 4, &ip));
205
206 ip.in4.s_addr = 0x0a01020f;
207 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
208 ip_pool_search(ipo, 4, &ip));
209
210 ip.in4.s_addr = 0x0b00aabb;
211 printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
212 ip_pool_search(ipo, 4, &ip));
213
214 #ifdef DEBUG_POOL
215 treeprint(ipo);
216 #endif
217
218 ip_pool_fini();
219
220 return 0;
221 }
222
223
224 void
treeprint(ipo)225 treeprint(ipo)
226 ip_pool_t *ipo;
227 {
228 ip_pool_node_t *c;
229
230 for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
231 printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
232 c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
233 c->ipn_mask.adf_addr.in4.s_addr,
234 c->ipn_info, c->ipn_hits);
235 }
236 #endif /* TEST_POOL */
237
238
239 /* ------------------------------------------------------------------------ */
240 /* Function: ip_pool_init */
241 /* Returns: int - 0 = success, else error */
242 /* */
243 /* Initialise the routing table data structures where required. */
244 /* ------------------------------------------------------------------------ */
ip_pool_init()245 int ip_pool_init()
246 {
247
248 bzero((char *)&ipoolstat, sizeof(ipoolstat));
249
250 #if (!defined(_KERNEL) || (BSD < 199306))
251 rn_init();
252 #endif
253 return 0;
254 }
255
256
257 /* ------------------------------------------------------------------------ */
258 /* Function: ip_pool_fini */
259 /* Returns: int - 0 = success, else error */
260 /* Locks: WRITE(ipf_global) */
261 /* */
262 /* Clean up all the pool data structures allocated and call the cleanup */
263 /* function for the radix tree that supports the pools. ip_pool_destroy() is*/
264 /* used to delete the pools one by one to ensure they're properly freed up. */
265 /* ------------------------------------------------------------------------ */
ip_pool_fini()266 void ip_pool_fini()
267 {
268 ip_pool_t *p, *q;
269 int i;
270
271 for (i = 0; i <= IPL_LOGMAX; i++) {
272 for (q = ip_pool_list[i]; (p = q) != NULL; ) {
273 q = p->ipo_next;
274 (void) ip_pool_destroy(i, p->ipo_name);
275 }
276 }
277
278 #if (!defined(_KERNEL) || (BSD < 199306))
279 rn_fini();
280 #endif
281 }
282
283
284 /* ------------------------------------------------------------------------ */
285 /* Function: ip_pool_statistics */
286 /* Returns: int - 0 = success, else error */
287 /* Parameters: op(I) - pointer to lookup operation arguments */
288 /* */
289 /* Copy the current statistics out into user space, collecting pool list */
290 /* pointers as appropriate for later use. */
291 /* ------------------------------------------------------------------------ */
ip_pool_statistics(op)292 int ip_pool_statistics(op)
293 iplookupop_t *op;
294 {
295 ip_pool_stat_t stats;
296 int unit, i, err = 0;
297
298 if (op->iplo_size != sizeof(ipoolstat))
299 return EINVAL;
300
301 bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats));
302 unit = op->iplo_unit;
303 if (unit == IPL_LOGALL) {
304 for (i = 0; i < IPL_LOGSIZE; i++)
305 stats.ipls_list[i] = ip_pool_list[i];
306 } else if (unit >= 0 && unit < IPL_LOGSIZE) {
307 if (op->iplo_name[0] != '\0')
308 stats.ipls_list[unit] = ip_pool_exists(unit,
309 op->iplo_name);
310 else
311 stats.ipls_list[unit] = ip_pool_list[unit];
312 } else
313 err = EINVAL;
314 if (err == 0)
315 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
316 return err;
317 }
318
319
320 /* ------------------------------------------------------------------------ */
321 /* Function: ip_pool_exists */
322 /* Returns: int - 0 = success, else error */
323 /* Parameters: ipo(I) - pointer to the pool getting the new node. */
324 /* */
325 /* Find a matching pool inside the collection of pools for a particular */
326 /* device, indicated by the unit number. */
327 /* ------------------------------------------------------------------------ */
ip_pool_exists(unit,name)328 static void *ip_pool_exists(unit, name)
329 int unit;
330 char *name;
331 {
332 ip_pool_t *p;
333
334 for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next)
335 if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0)
336 break;
337 return p;
338 }
339
340
341 /* ------------------------------------------------------------------------ */
342 /* Function: ip_pool_find */
343 /* Returns: int - 0 = success, else error */
344 /* Parameters: ipo(I) - pointer to the pool getting the new node. */
345 /* */
346 /* Find a matching pool inside the collection of pools for a particular */
347 /* device, indicated by the unit number. If it is marked for deletion then */
348 /* pretend it does not exist. */
349 /* ------------------------------------------------------------------------ */
ip_pool_find(unit,name)350 void *ip_pool_find(unit, name)
351 int unit;
352 char *name;
353 {
354 ip_pool_t *p;
355
356 p = ip_pool_exists(unit, name);
357 if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
358 return NULL;
359
360 return p;
361 }
362
363
364 /* ------------------------------------------------------------------------ */
365 /* Function: ip_pool_findeq */
366 /* Returns: int - 0 = success, else error */
367 /* Parameters: ipo(I) - pointer to the pool getting the new node. */
368 /* addr(I) - pointer to address information to delete */
369 /* mask(I) - */
370 /* */
371 /* Searches for an exact match of an entry in the pool. */
372 /* ------------------------------------------------------------------------ */
ip_pool_findeq(ipo,addr,mask)373 ip_pool_node_t *ip_pool_findeq(ipo, addr, mask)
374 ip_pool_t *ipo;
375 addrfamily_t *addr, *mask;
376 {
377 struct radix_node *n;
378 SPL_INT(s);
379
380 SPL_NET(s);
381 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
382 n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head);
383 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
384 SPL_X(s);
385 return (ip_pool_node_t *)n;
386 }
387
388
389 /* ------------------------------------------------------------------------ */
390 /* Function: ip_pool_search */
391 /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
392 /* Parameters: tptr(I) - pointer to the pool to search */
393 /* version(I) - IP protocol version (4 or 6) */
394 /* dptr(I) - pointer to address information */
395 /* */
396 /* Search the pool for a given address and return a search result. */
397 /* ------------------------------------------------------------------------ */
ip_pool_search(tptr,ipversion,dptr)398 int ip_pool_search(tptr, ipversion, dptr)
399 void *tptr;
400 int ipversion;
401 void *dptr;
402 {
403 struct radix_node *rn;
404 ip_pool_node_t *m;
405 i6addr_t *addr;
406 addrfamily_t v;
407 ip_pool_t *ipo;
408 int rv;
409
410 ipo = tptr;
411 if (ipo == NULL)
412 return -1;
413
414 rv = 1;
415 m = NULL;
416 addr = (i6addr_t *)dptr;
417 bzero(&v, sizeof(v));
418 v.adf_len = offsetof(addrfamily_t, adf_addr);
419
420 if (ipversion == 4) {
421 v.adf_len += sizeof(addr->in4);
422 v.adf_addr.in4 = addr->in4;
423 #ifdef USE_INET6
424 } else if (ipversion == 6) {
425 v.adf_len += sizeof(addr->in6);
426 v.adf_addr.in6 = addr->in6;
427 #endif
428 } else
429 return -1;
430
431 READ_ENTER(&ip_poolrw);
432
433 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
434 rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head);
435 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
436
437 if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) {
438 m = (ip_pool_node_t *)rn;
439 ipo->ipo_hits++;
440 m->ipn_hits++;
441 rv = m->ipn_info;
442 }
443 RWLOCK_EXIT(&ip_poolrw);
444 return rv;
445 }
446
447
448 /* ------------------------------------------------------------------------ */
449 /* Function: ip_pool_insert */
450 /* Returns: int - 0 = success, else error */
451 /* Parameters: ipo(I) - pointer to the pool getting the new node. */
452 /* addr(I) - address being added as a node */
453 /* mask(I) - netmask to with the node being added */
454 /* info(I) - extra information to store in this node. */
455 /* Locks: WRITE(ip_poolrw) */
456 /* */
457 /* Add another node to the pool given by ipo. The three parameters passed */
458 /* in (addr, mask, info) shold all be stored in the node. */
459 /* ------------------------------------------------------------------------ */
ip_pool_insert(ipo,addr,mask,info)460 int ip_pool_insert(ipo, addr, mask, info)
461 ip_pool_t *ipo;
462 i6addr_t *addr, *mask;
463 int info;
464 {
465 struct radix_node *rn;
466 ip_pool_node_t *x;
467
468 KMALLOC(x, ip_pool_node_t *);
469 if (x == NULL) {
470 return ENOMEM;
471 }
472
473 bzero(x, sizeof(*x));
474
475 x->ipn_info = info;
476 (void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name));
477
478 bcopy(addr, &x->ipn_addr.adf_addr, sizeof(*addr));
479 x->ipn_addr.adf_len = sizeof(x->ipn_addr);
480 bcopy(mask, &x->ipn_mask.adf_addr, sizeof(*mask));
481 x->ipn_mask.adf_len = sizeof(x->ipn_mask);
482
483 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
484 rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask,
485 ipo->ipo_head, x->ipn_nodes);
486 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
487 #ifdef DEBUG_POOL
488 printf("Added %p at %p\n", x, rn);
489 #endif
490
491 if (rn == NULL) {
492 KFREE(x);
493 return ENOMEM;
494 }
495
496 x->ipn_ref = 1;
497 x->ipn_next = ipo->ipo_list;
498 x->ipn_pnext = &ipo->ipo_list;
499 if (ipo->ipo_list != NULL)
500 ipo->ipo_list->ipn_pnext = &x->ipn_next;
501 ipo->ipo_list = x;
502
503 ipoolstat.ipls_nodes++;
504
505 return 0;
506 }
507
508
509 /* ------------------------------------------------------------------------ */
510 /* Function: ip_pool_create */
511 /* Returns: int - 0 = success, else error */
512 /* Parameters: op(I) - pointer to iplookup struct with call details */
513 /* Locks: WRITE(ip_poolrw) */
514 /* */
515 /* Creates a new group according to the paramters passed in via the */
516 /* iplookupop structure. Does not check to see if the group already exists */
517 /* when being inserted - assume this has already been done. If the pool is */
518 /* marked as being anonymous, give it a new, unique, identifier. Call any */
519 /* other functions required to initialise the structure. */
520 /* */
521 /* If the structure is flagged for deletion then reset the flag and return, */
522 /* as this likely means we've tried to free a pool that is in use (flush) */
523 /* and now want to repopulate it with "new" data. */
524 /* ------------------------------------------------------------------------ */
ip_pool_create(op)525 int ip_pool_create(op)
526 iplookupop_t *op;
527 {
528 char name[FR_GROUPLEN];
529 int poolnum, unit;
530 ip_pool_t *h;
531
532 unit = op->iplo_unit;
533
534 if ((op->iplo_arg & LOOKUP_ANON) == 0) {
535 h = ip_pool_exists(unit, op->iplo_name);
536 if (h != NULL) {
537 if ((h->ipo_flags & IPOOL_DELETE) == 0)
538 return EEXIST;
539 h->ipo_flags &= ~IPOOL_DELETE;
540 return 0;
541 }
542 }
543
544 KMALLOC(h, ip_pool_t *);
545 if (h == NULL)
546 return ENOMEM;
547 bzero(h, sizeof(*h));
548
549 if (rn_inithead((void **)&h->ipo_head,
550 offsetof(addrfamily_t, adf_addr) << 3) == 0) {
551 KFREE(h);
552 return ENOMEM;
553 }
554
555 if ((op->iplo_arg & LOOKUP_ANON) != 0) {
556 ip_pool_t *p;
557
558 h->ipo_flags |= IPOOL_ANON;
559 poolnum = LOOKUP_ANON;
560
561 #if defined(SNPRINTF) && defined(_KERNEL)
562 SNPRINTF(name, sizeof(name), "%x", poolnum);
563 #else
564 (void)sprintf(name, "%x", poolnum);
565 #endif
566
567 for (p = ip_pool_list[unit]; p != NULL; ) {
568 if (strncmp(name, p->ipo_name,
569 sizeof(p->ipo_name)) == 0) {
570 poolnum++;
571 #if defined(SNPRINTF) && defined(_KERNEL)
572 SNPRINTF(name, sizeof(name), "%x", poolnum);
573 #else
574 (void)sprintf(name, "%x", poolnum);
575 #endif
576 p = ip_pool_list[unit];
577 } else
578 p = p->ipo_next;
579 }
580
581 (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
582 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
583 } else {
584 (void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
585 }
586
587 h->ipo_ref = 1;
588 h->ipo_list = NULL;
589 h->ipo_unit = unit;
590 h->ipo_next = ip_pool_list[unit];
591 if (ip_pool_list[unit] != NULL)
592 ip_pool_list[unit]->ipo_pnext = &h->ipo_next;
593 h->ipo_pnext = &ip_pool_list[unit];
594 ip_pool_list[unit] = h;
595
596 ipoolstat.ipls_pools++;
597
598 return 0;
599 }
600
601
602 /* ------------------------------------------------------------------------ */
603 /* Function: ip_pool_remove */
604 /* Returns: int - 0 = success, else error */
605 /* Parameters: ipo(I) - pointer to the pool to remove the node from. */
606 /* ipe(I) - address being deleted as a node */
607 /* Locks: WRITE(ip_poolrw) */
608 /* */
609 /* Remove a node from the pool given by ipo. */
610 /* ------------------------------------------------------------------------ */
ip_pool_remove(ipo,ipe)611 int ip_pool_remove(ipo, ipe)
612 ip_pool_t *ipo;
613 ip_pool_node_t *ipe;
614 {
615
616 if (ipe->ipn_pnext != NULL)
617 *ipe->ipn_pnext = ipe->ipn_next;
618 if (ipe->ipn_next != NULL)
619 ipe->ipn_next->ipn_pnext = ipe->ipn_pnext;
620
621 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
622 ipo->ipo_head->rnh_deladdr(&ipe->ipn_addr, &ipe->ipn_mask,
623 ipo->ipo_head);
624 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
625
626 ip_pool_node_deref(ipe);
627
628 return 0;
629 }
630
631
632 /* ------------------------------------------------------------------------ */
633 /* Function: ip_pool_destroy */
634 /* Returns: int - 0 = success, else error */
635 /* Parameters: op(I) - information about the pool to remove */
636 /* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
637 /* */
638 /* Search for a pool using paramters passed in and if it's not otherwise */
639 /* busy, free it. If it is busy, clear all of its nodes, mark it for being */
640 /* deleted and return an error saying it is busy. */
641 /* */
642 /* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
643 /* may not be initialised, we can't use an ASSERT to enforce the locking */
644 /* assertion that one of the two (ip_poolrw,ipf_global) is held. */
645 /* ------------------------------------------------------------------------ */
ip_pool_destroy(unit,name)646 int ip_pool_destroy(unit, name)
647 int unit;
648 char *name;
649 {
650 ip_pool_t *ipo;
651
652 ipo = ip_pool_exists(unit, name);
653 if (ipo == NULL)
654 return ESRCH;
655
656 if (ipo->ipo_ref != 1) {
657 ip_pool_clearnodes(ipo);
658 ipo->ipo_flags |= IPOOL_DELETE;
659 return 0;
660 }
661
662 ip_pool_free(ipo);
663 return 0;
664 }
665
666
667 /* ------------------------------------------------------------------------ */
668 /* Function: ip_pool_flush */
669 /* Returns: int - number of pools deleted */
670 /* Parameters: fp(I) - which pool(s) to flush */
671 /* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
672 /* */
673 /* Free all pools associated with the device that matches the unit number */
674 /* passed in with operation. */
675 /* */
676 /* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
677 /* may not be initialised, we can't use an ASSERT to enforce the locking */
678 /* assertion that one of the two (ip_poolrw,ipf_global) is held. */
679 /* ------------------------------------------------------------------------ */
ip_pool_flush(fp)680 int ip_pool_flush(fp)
681 iplookupflush_t *fp;
682 {
683 int i, num = 0, unit, err;
684 ip_pool_t *p, *q;
685 iplookupop_t op;
686
687 unit = fp->iplf_unit;
688
689 for (i = 0; i <= IPL_LOGMAX; i++) {
690 if (unit != IPLT_ALL && i != unit)
691 continue;
692 for (q = ip_pool_list[i]; (p = q) != NULL; ) {
693 op.iplo_unit = i;
694 (void)strncpy(op.iplo_name, p->ipo_name,
695 sizeof(op.iplo_name));
696 q = p->ipo_next;
697 err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
698 if (err == 0)
699 num++;
700 else
701 break;
702 }
703 }
704 return num;
705 }
706
707
708 /* ------------------------------------------------------------------------ */
709 /* Function: ip_pool_free */
710 /* Returns: void */
711 /* Parameters: ipo(I) - pointer to pool structure */
712 /* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
713 /* */
714 /* Deletes the pool strucutre passed in from the list of pools and deletes */
715 /* all of the address information stored in it, including any tree data */
716 /* structures also allocated. */
717 /* */
718 /* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
719 /* may not be initialised, we can't use an ASSERT to enforce the locking */
720 /* assertion that one of the two (ip_poolrw,ipf_global) is held. */
721 /* ------------------------------------------------------------------------ */
ip_pool_free(ipo)722 void ip_pool_free(ipo)
723 ip_pool_t *ipo;
724 {
725
726 ip_pool_clearnodes(ipo);
727
728 if (ipo->ipo_next != NULL)
729 ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
730 *ipo->ipo_pnext = ipo->ipo_next;
731 rn_freehead(ipo->ipo_head);
732 KFREE(ipo);
733
734 ipoolstat.ipls_pools--;
735 }
736
737
738 /* ------------------------------------------------------------------------ */
739 /* Function: ip_pool_clearnodes */
740 /* Returns: void */
741 /* Parameters: ipo(I) - pointer to pool structure */
742 /* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
743 /* */
744 /* Deletes all nodes stored in a pool structure. */
745 /* ------------------------------------------------------------------------ */
ip_pool_clearnodes(ipo)746 static void ip_pool_clearnodes(ipo)
747 ip_pool_t *ipo;
748 {
749 ip_pool_node_t *n;
750
751 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
752 while ((n = ipo->ipo_list) != NULL) {
753 ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
754 ipo->ipo_head);
755
756 *n->ipn_pnext = n->ipn_next;
757 if (n->ipn_next)
758 n->ipn_next->ipn_pnext = n->ipn_pnext;
759
760 KFREE(n);
761
762 ipoolstat.ipls_nodes--;
763 }
764 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
765
766 ipo->ipo_list = NULL;
767 }
768
769
770 /* ------------------------------------------------------------------------ */
771 /* Function: ip_pool_deref */
772 /* Returns: void */
773 /* Parameters: ipo(I) - pointer to pool structure */
774 /* Locks: WRITE(ip_poolrw) */
775 /* */
776 /* Drop the number of known references to this pool structure by one and if */
777 /* we arrive at zero known references, free it. */
778 /* ------------------------------------------------------------------------ */
ip_pool_deref(ipo)779 void ip_pool_deref(ipo)
780 ip_pool_t *ipo;
781 {
782
783 ipo->ipo_ref--;
784
785 if (ipo->ipo_ref == 0)
786 ip_pool_free(ipo);
787
788 else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
789 ip_pool_destroy(ipo->ipo_unit, ipo->ipo_name);
790 }
791
792
793 /* ------------------------------------------------------------------------ */
794 /* Function: ip_pool_node_deref */
795 /* Returns: void */
796 /* Parameters: ipn(I) - pointer to pool structure */
797 /* Locks: WRITE(ip_poolrw) */
798 /* */
799 /* Drop a reference to the pool node passed in and if we're the last, free */
800 /* it all up and adjust the stats accordingly. */
801 /* ------------------------------------------------------------------------ */
ip_pool_node_deref(ipn)802 void ip_pool_node_deref(ipn)
803 ip_pool_node_t *ipn;
804 {
805
806 ipn->ipn_ref--;
807
808 if (ipn->ipn_ref == 0) {
809 KFREE(ipn);
810 ipoolstat.ipls_nodes--;
811 }
812 }
813
814
815 /* ------------------------------------------------------------------------ */
816 /* Function: ip_pool_getnext */
817 /* Returns: void */
818 /* Parameters: token(I) - pointer to pool structure */
819 /* Parameters: ilp(IO) - pointer to pool iterating structure */
820 /* */
821 /* ------------------------------------------------------------------------ */
ip_pool_getnext(token,ilp)822 int ip_pool_getnext(token, ilp)
823 ipftoken_t *token;
824 ipflookupiter_t *ilp;
825 {
826 ip_pool_node_t *node, zn, *nextnode;
827 ip_pool_t *ipo, zp, *nextipo;
828 int err;
829
830 err = 0;
831 node = NULL;
832 nextnode = NULL;
833 ipo = NULL;
834 nextipo = NULL;
835
836 READ_ENTER(&ip_poolrw);
837
838 switch (ilp->ili_otype)
839 {
840 case IPFLOOKUPITER_LIST :
841 ipo = token->ipt_data;
842 if (ipo == NULL) {
843 nextipo = ip_pool_list[(int)ilp->ili_unit];
844 } else {
845 nextipo = ipo->ipo_next;
846 }
847
848 if (nextipo != NULL) {
849 ATOMIC_INC(nextipo->ipo_ref);
850 token->ipt_data = nextipo;
851 } else {
852 bzero((char *)&zp, sizeof(zp));
853 nextipo = &zp;
854 token->ipt_data = NULL;
855 }
856 break;
857
858 case IPFLOOKUPITER_NODE :
859 node = token->ipt_data;
860 if (node == NULL) {
861 ipo = ip_pool_exists(ilp->ili_unit, ilp->ili_name);
862 if (ipo == NULL)
863 err = ESRCH;
864 else {
865 nextnode = ipo->ipo_list;
866 ipo = NULL;
867 }
868 } else {
869 nextnode = node->ipn_next;
870 }
871
872 if (nextnode != NULL) {
873 ATOMIC_INC(nextnode->ipn_ref);
874 token->ipt_data = nextnode;
875 } else {
876 bzero((char *)&zn, sizeof(zn));
877 nextnode = &zn;
878 token->ipt_data = NULL;
879 }
880 break;
881 default :
882 err = EINVAL;
883 break;
884 }
885
886 RWLOCK_EXIT(&ip_poolrw);
887
888 if (err != 0)
889 return err;
890
891 switch (ilp->ili_otype)
892 {
893 case IPFLOOKUPITER_LIST :
894 if (ipo != NULL) {
895 WRITE_ENTER(&ip_poolrw);
896 ip_pool_deref(ipo);
897 RWLOCK_EXIT(&ip_poolrw);
898 }
899 err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
900 if (err != 0)
901 err = EFAULT;
902 break;
903
904 case IPFLOOKUPITER_NODE :
905 if (node != NULL) {
906 WRITE_ENTER(&ip_poolrw);
907 ip_pool_node_deref(node);
908 RWLOCK_EXIT(&ip_poolrw);
909 }
910 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
911 if (err != 0)
912 err = EFAULT;
913 break;
914 }
915
916 return err;
917 }
918
919
920 /* ------------------------------------------------------------------------ */
921 /* Function: ip_pool_iterderef */
922 /* Returns: void */
923 /* Parameters: ipn(I) - pointer to pool structure */
924 /* Locks: WRITE(ip_poolrw) */
925 /* */
926 /* ------------------------------------------------------------------------ */
ip_pool_iterderef(otype,unit,data)927 void ip_pool_iterderef(otype, unit, data)
928 u_int otype;
929 int unit;
930 void *data;
931 {
932
933 if (data == NULL)
934 return;
935
936 if (unit < 0 || unit > IPL_LOGMAX)
937 return;
938
939 switch (otype)
940 {
941 case IPFLOOKUPITER_LIST :
942 WRITE_ENTER(&ip_poolrw);
943 ip_pool_deref((ip_pool_t *)data);
944 RWLOCK_EXIT(&ip_poolrw);
945 break;
946
947 case IPFLOOKUPITER_NODE :
948 WRITE_ENTER(&ip_poolrw);
949 ip_pool_node_deref((ip_pool_node_t *)data);
950 RWLOCK_EXIT(&ip_poolrw);
951 break;
952 default :
953 break;
954 }
955 }
956
957
958 # if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \
959 !defined(__hpux) && !defined(__sgi))
960 static int
rn_freenode(struct radix_node * n,void * p)961 rn_freenode(struct radix_node *n, void *p)
962 {
963 struct radix_node_head *rnh = p;
964 struct radix_node *d;
965
966 d = rnh->rnh_deladdr(n->rn_key, NULL, rnh);
967 if (d != NULL) {
968 FreeS(d, max_keylen + 2 * sizeof (*d));
969 }
970 return 0;
971 }
972
973
974 void
rn_freehead(rnh)975 rn_freehead(rnh)
976 struct radix_node_head *rnh;
977 {
978
979 RADIX_NODE_HEAD_LOCK(rnh);
980 (*rnh->rnh_walktree)(rnh, rn_freenode, rnh);
981
982 rnh->rnh_addaddr = NULL;
983 rnh->rnh_deladdr = NULL;
984 rnh->rnh_matchaddr = NULL;
985 rnh->rnh_lookup = NULL;
986 rnh->rnh_walktree = NULL;
987 RADIX_NODE_HEAD_UNLOCK(rnh);
988
989 Free(rnh);
990 }
991 # endif
992 #endif /* IPFILTER_LOOKUP */
993