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