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