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