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