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