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