Deleted Added
full compact
ip_pool.c (170263) ip_pool.c (172771)
1/*
2 * Copyright (C) 1993-2001, 2003 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#if defined(__osf__)
13# define _PROTO_NET_H_
14#endif
15#include <sys/errno.h>
16#include <sys/types.h>
17#include <sys/param.h>
18#include <sys/file.h>
19#if !defined(_KERNEL) && !defined(__KERNEL__)
20# include <stdio.h>
21# include <stdlib.h>
22# include <string.h>
23# define _KERNEL
24# ifdef __OpenBSD__
25struct file;
26# endif
27# include <sys/uio.h>
28# undef _KERNEL
29#else
30# include <sys/systm.h>
31# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
32# include <sys/proc.h>
33# endif
34#endif
35#include <sys/time.h>
36#if !defined(linux)
37# include <sys/protosw.h>
38#endif
39#include <sys/socket.h>
40#if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__))
41# include <sys/mbuf.h>
42#endif
43#if defined(__SVR4) || defined(__svr4__)
44# include <sys/filio.h>
45# include <sys/byteorder.h>
46# ifdef _KERNEL
47# include <sys/dditypes.h>
48# endif
49# include <sys/stream.h>
50# include <sys/kmem.h>
51#endif
52#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
53# include <sys/malloc.h>
54#endif
55
1/*
2 * Copyright (C) 1993-2001, 2003 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#if defined(__osf__)
13# define _PROTO_NET_H_
14#endif
15#include <sys/errno.h>
16#include <sys/types.h>
17#include <sys/param.h>
18#include <sys/file.h>
19#if !defined(_KERNEL) && !defined(__KERNEL__)
20# include <stdio.h>
21# include <stdlib.h>
22# include <string.h>
23# define _KERNEL
24# ifdef __OpenBSD__
25struct file;
26# endif
27# include <sys/uio.h>
28# undef _KERNEL
29#else
30# include <sys/systm.h>
31# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
32# include <sys/proc.h>
33# endif
34#endif
35#include <sys/time.h>
36#if !defined(linux)
37# include <sys/protosw.h>
38#endif
39#include <sys/socket.h>
40#if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__))
41# include <sys/mbuf.h>
42#endif
43#if defined(__SVR4) || defined(__svr4__)
44# include <sys/filio.h>
45# include <sys/byteorder.h>
46# ifdef _KERNEL
47# include <sys/dditypes.h>
48# endif
49# include <sys/stream.h>
50# include <sys/kmem.h>
51#endif
52#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
53# include <sys/malloc.h>
54#endif
55
56#if defined(SOLARIS2) && !defined(_KERNEL)
57# include "radix_ipf.h"
58#endif
56#if defined(_KERNEL) && (defined(__osf__) || defined(AIX) || \
57 defined(__hpux) || defined(__sgi))
58# include "radix_ipf_local.h"
59# define _RADIX_H_
60#endif
61#include <net/if.h>
62#include <netinet/in.h>
63
64#include "netinet/ip_compat.h"
65#include "netinet/ip_fil.h"
66#include "netinet/ip_pool.h"
67
68#if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \
69 ((BSD >= 198911) && !defined(__osf__) && \
70 !defined(__hpux) && !defined(__sgi))
71static int rn_freenode __P((struct radix_node *, void *));
72#endif
73
74/* END OF INCLUDES */
75
76#if !defined(lint)
77static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
59#if defined(_KERNEL) && (defined(__osf__) || defined(AIX) || \
60 defined(__hpux) || defined(__sgi))
61# include "radix_ipf_local.h"
62# define _RADIX_H_
63#endif
64#include <net/if.h>
65#include <netinet/in.h>
66
67#include "netinet/ip_compat.h"
68#include "netinet/ip_fil.h"
69#include "netinet/ip_pool.h"
70
71#if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \
72 ((BSD >= 198911) && !defined(__osf__) && \
73 !defined(__hpux) && !defined(__sgi))
74static int rn_freenode __P((struct radix_node *, void *));
75#endif
76
77/* END OF INCLUDES */
78
79#if !defined(lint)
80static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
78static const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.20 2007/05/31 12:27:35 darrenr Exp $";
81static const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.24 2007/10/10 09:45:37 darrenr Exp $";
79#endif
80
81#ifdef IPFILTER_LOOKUP
82
82#endif
83
84#ifdef IPFILTER_LOOKUP
85
83# ifndef RADIX_NODE_HEAD_LOCK
86# if !defined(RADIX_NODE_HEAD_LOCK) || !defined(RADIX_NODE_HEAD_UNLOCK) || \
87 !defined(_KERNEL)
88# undef RADIX_NODE_HEAD_LOCK
89# undef RADIX_NODE_HEAD_UNLOCK
84# define RADIX_NODE_HEAD_LOCK(x) ;
90# define RADIX_NODE_HEAD_LOCK(x) ;
85# endif
86# ifndef RADIX_NODE_HEAD_UNLOCK
87# define RADIX_NODE_HEAD_UNLOCK(x) ;
88# endif
89
90static void ip_pool_clearnodes __P((ip_pool_t *));
91static void *ip_pool_exists __P((int, char *));
92
93ip_pool_stat_t ipoolstat;
94ipfrwlock_t ip_poolrw;
95
96/*
97 * Binary tree routines from Sedgewick and enhanced to do ranges of addresses.
98 * NOTE: Insertion *MUST* be from greatest range to least for it to work!
99 * These should be replaced, eventually, by something else - most notably a
100 * interval searching method. The important feature is to be able to find
101 * the best match.
102 *
103 * So why not use a radix tree for this? As the first line implies, it
104 * has been written to work with a _range_ of addresses. A range is not
105 * necessarily a match with any given netmask so what we end up dealing
106 * with is an interval tree. Implementations of these are hard to find
107 * and the one herein is far from bug free.
108 *
109 * Sigh, in the end I became convinced that the bugs the code contained did
110 * not make it worthwhile not using radix trees. For now the radix tree from
111 * 4.4 BSD is used, but this is not viewed as a long term solution.
112 */
113ip_pool_t *ip_pool_list[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL,
114 NULL, NULL, NULL, NULL };
115
116
117#ifdef TEST_POOL
118void treeprint __P((ip_pool_t *));
119
120int
121main(argc, argv)
122 int argc;
123 char *argv[];
124{
125 addrfamily_t a, b;
126 iplookupop_t op;
127 ip_pool_t *ipo;
128 i6addr_t ip;
129
130 RWLOCK_INIT(&ip_poolrw, "poolrw");
131 ip_pool_init();
132
133 bzero((char *)&a, sizeof(a));
134 bzero((char *)&b, sizeof(b));
135 bzero((char *)&ip, sizeof(ip));
136 bzero((char *)&op, sizeof(op));
137 strcpy(op.iplo_name, "0");
138
139 if (ip_pool_create(&op) == 0)
140 ipo = ip_pool_exists(0, "0");
141
142 a.adf_addr.in4.s_addr = 0x0a010203;
143 b.adf_addr.in4.s_addr = 0xffffffff;
144 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
145 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
146
147 a.adf_addr.in4.s_addr = 0x0a000000;
148 b.adf_addr.in4.s_addr = 0xff000000;
149 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
150 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
151
152 a.adf_addr.in4.s_addr = 0x0a010100;
153 b.adf_addr.in4.s_addr = 0xffffff00;
154 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
155 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
156
157 a.adf_addr.in4.s_addr = 0x0a010200;
158 b.adf_addr.in4.s_addr = 0xffffff00;
159 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
160 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
161
162 a.adf_addr.in4.s_addr = 0x0a010000;
163 b.adf_addr.in4.s_addr = 0xffff0000;
164 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
165 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
166
167 a.adf_addr.in4.s_addr = 0x0a01020f;
168 b.adf_addr.in4.s_addr = 0xffffffff;
169 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
170 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
171#ifdef DEBUG_POOL
172treeprint(ipo);
173#endif
174 ip.in4.s_addr = 0x0a00aabb;
175 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
176 ip_pool_search(ipo, 4, &ip));
177
178 ip.in4.s_addr = 0x0a000001;
179 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
180 ip_pool_search(ipo, 4, &ip));
181
182 ip.in4.s_addr = 0x0a000101;
183 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
184 ip_pool_search(ipo, 4, &ip));
185
186 ip.in4.s_addr = 0x0a010001;
187 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
188 ip_pool_search(ipo, 4, &ip));
189
190 ip.in4.s_addr = 0x0a010101;
191 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
192 ip_pool_search(ipo, 4, &ip));
193
194 ip.in4.s_addr = 0x0a010201;
195 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
196 ip_pool_search(ipo, 4, &ip));
197
198 ip.in4.s_addr = 0x0a010203;
199 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
200 ip_pool_search(ipo, 4, &ip));
201
202 ip.in4.s_addr = 0x0a01020f;
203 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
204 ip_pool_search(ipo, 4, &ip));
205
206 ip.in4.s_addr = 0x0b00aabb;
207 printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
208 ip_pool_search(ipo, 4, &ip));
209
210#ifdef DEBUG_POOL
211treeprint(ipo);
212#endif
213
214 ip_pool_fini();
215
216 return 0;
217}
218
219
220void
221treeprint(ipo)
222ip_pool_t *ipo;
223{
224 ip_pool_node_t *c;
225
226 for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
227 printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
228 c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
229 c->ipn_mask.adf_addr.in4.s_addr,
230 c->ipn_info, c->ipn_hits);
231}
232#endif /* TEST_POOL */
233
234
235/* ------------------------------------------------------------------------ */
236/* Function: ip_pool_init */
237/* Returns: int - 0 = success, else error */
238/* */
239/* Initialise the routing table data structures where required. */
240/* ------------------------------------------------------------------------ */
241int ip_pool_init()
242{
243
244 bzero((char *)&ipoolstat, sizeof(ipoolstat));
245
246#if (!defined(_KERNEL) || (BSD < 199306))
247 rn_init();
248#endif
249 return 0;
250}
251
252
253/* ------------------------------------------------------------------------ */
254/* Function: ip_pool_fini */
255/* Returns: int - 0 = success, else error */
256/* Locks: WRITE(ipf_global) */
257/* */
258/* Clean up all the pool data structures allocated and call the cleanup */
259/* function for the radix tree that supports the pools. ip_pool_destroy() is*/
260/* used to delete the pools one by one to ensure they're properly freed up. */
261/* ------------------------------------------------------------------------ */
262void ip_pool_fini()
263{
264 ip_pool_t *p, *q;
265 int i;
266
91# define RADIX_NODE_HEAD_UNLOCK(x) ;
92# endif
93
94static void ip_pool_clearnodes __P((ip_pool_t *));
95static void *ip_pool_exists __P((int, char *));
96
97ip_pool_stat_t ipoolstat;
98ipfrwlock_t ip_poolrw;
99
100/*
101 * Binary tree routines from Sedgewick and enhanced to do ranges of addresses.
102 * NOTE: Insertion *MUST* be from greatest range to least for it to work!
103 * These should be replaced, eventually, by something else - most notably a
104 * interval searching method. The important feature is to be able to find
105 * the best match.
106 *
107 * So why not use a radix tree for this? As the first line implies, it
108 * has been written to work with a _range_ of addresses. A range is not
109 * necessarily a match with any given netmask so what we end up dealing
110 * with is an interval tree. Implementations of these are hard to find
111 * and the one herein is far from bug free.
112 *
113 * Sigh, in the end I became convinced that the bugs the code contained did
114 * not make it worthwhile not using radix trees. For now the radix tree from
115 * 4.4 BSD is used, but this is not viewed as a long term solution.
116 */
117ip_pool_t *ip_pool_list[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL,
118 NULL, NULL, NULL, NULL };
119
120
121#ifdef TEST_POOL
122void treeprint __P((ip_pool_t *));
123
124int
125main(argc, argv)
126 int argc;
127 char *argv[];
128{
129 addrfamily_t a, b;
130 iplookupop_t op;
131 ip_pool_t *ipo;
132 i6addr_t ip;
133
134 RWLOCK_INIT(&ip_poolrw, "poolrw");
135 ip_pool_init();
136
137 bzero((char *)&a, sizeof(a));
138 bzero((char *)&b, sizeof(b));
139 bzero((char *)&ip, sizeof(ip));
140 bzero((char *)&op, sizeof(op));
141 strcpy(op.iplo_name, "0");
142
143 if (ip_pool_create(&op) == 0)
144 ipo = ip_pool_exists(0, "0");
145
146 a.adf_addr.in4.s_addr = 0x0a010203;
147 b.adf_addr.in4.s_addr = 0xffffffff;
148 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
149 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
150
151 a.adf_addr.in4.s_addr = 0x0a000000;
152 b.adf_addr.in4.s_addr = 0xff000000;
153 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
154 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
155
156 a.adf_addr.in4.s_addr = 0x0a010100;
157 b.adf_addr.in4.s_addr = 0xffffff00;
158 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
159 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
160
161 a.adf_addr.in4.s_addr = 0x0a010200;
162 b.adf_addr.in4.s_addr = 0xffffff00;
163 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
164 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
165
166 a.adf_addr.in4.s_addr = 0x0a010000;
167 b.adf_addr.in4.s_addr = 0xffff0000;
168 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
169 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
170
171 a.adf_addr.in4.s_addr = 0x0a01020f;
172 b.adf_addr.in4.s_addr = 0xffffffff;
173 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
174 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
175#ifdef DEBUG_POOL
176treeprint(ipo);
177#endif
178 ip.in4.s_addr = 0x0a00aabb;
179 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
180 ip_pool_search(ipo, 4, &ip));
181
182 ip.in4.s_addr = 0x0a000001;
183 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
184 ip_pool_search(ipo, 4, &ip));
185
186 ip.in4.s_addr = 0x0a000101;
187 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
188 ip_pool_search(ipo, 4, &ip));
189
190 ip.in4.s_addr = 0x0a010001;
191 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
192 ip_pool_search(ipo, 4, &ip));
193
194 ip.in4.s_addr = 0x0a010101;
195 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
196 ip_pool_search(ipo, 4, &ip));
197
198 ip.in4.s_addr = 0x0a010201;
199 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
200 ip_pool_search(ipo, 4, &ip));
201
202 ip.in4.s_addr = 0x0a010203;
203 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
204 ip_pool_search(ipo, 4, &ip));
205
206 ip.in4.s_addr = 0x0a01020f;
207 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
208 ip_pool_search(ipo, 4, &ip));
209
210 ip.in4.s_addr = 0x0b00aabb;
211 printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
212 ip_pool_search(ipo, 4, &ip));
213
214#ifdef DEBUG_POOL
215treeprint(ipo);
216#endif
217
218 ip_pool_fini();
219
220 return 0;
221}
222
223
224void
225treeprint(ipo)
226ip_pool_t *ipo;
227{
228 ip_pool_node_t *c;
229
230 for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
231 printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
232 c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
233 c->ipn_mask.adf_addr.in4.s_addr,
234 c->ipn_info, c->ipn_hits);
235}
236#endif /* TEST_POOL */
237
238
239/* ------------------------------------------------------------------------ */
240/* Function: ip_pool_init */
241/* Returns: int - 0 = success, else error */
242/* */
243/* Initialise the routing table data structures where required. */
244/* ------------------------------------------------------------------------ */
245int ip_pool_init()
246{
247
248 bzero((char *)&ipoolstat, sizeof(ipoolstat));
249
250#if (!defined(_KERNEL) || (BSD < 199306))
251 rn_init();
252#endif
253 return 0;
254}
255
256
257/* ------------------------------------------------------------------------ */
258/* Function: ip_pool_fini */
259/* Returns: int - 0 = success, else error */
260/* Locks: WRITE(ipf_global) */
261/* */
262/* Clean up all the pool data structures allocated and call the cleanup */
263/* function for the radix tree that supports the pools. ip_pool_destroy() is*/
264/* used to delete the pools one by one to ensure they're properly freed up. */
265/* ------------------------------------------------------------------------ */
266void ip_pool_fini()
267{
268 ip_pool_t *p, *q;
269 int i;
270
267 ASSERT(rw_read_locked(&ipf_global.ipf_lk) == 0);
268
269 for (i = 0; i <= IPL_LOGMAX; i++) {
270 for (q = ip_pool_list[i]; (p = q) != NULL; ) {
271 q = p->ipo_next;
272 (void) ip_pool_destroy(i, p->ipo_name);
273 }
274 }
275
276#if (!defined(_KERNEL) || (BSD < 199306))
277 rn_fini();
278#endif
279}
280
281
282/* ------------------------------------------------------------------------ */
283/* Function: ip_pool_statistics */
284/* Returns: int - 0 = success, else error */
285/* Parameters: op(I) - pointer to lookup operation arguments */
286/* */
287/* Copy the current statistics out into user space, collecting pool list */
288/* pointers as appropriate for later use. */
289/* ------------------------------------------------------------------------ */
290int ip_pool_statistics(op)
291iplookupop_t *op;
292{
293 ip_pool_stat_t stats;
294 int unit, i, err = 0;
295
296 if (op->iplo_size != sizeof(ipoolstat))
297 return EINVAL;
298
299 bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats));
300 unit = op->iplo_unit;
301 if (unit == IPL_LOGALL) {
302 for (i = 0; i < IPL_LOGSIZE; i++)
303 stats.ipls_list[i] = ip_pool_list[i];
304 } else if (unit >= 0 && unit < IPL_LOGSIZE) {
305 if (op->iplo_name[0] != '\0')
306 stats.ipls_list[unit] = ip_pool_exists(unit,
307 op->iplo_name);
308 else
309 stats.ipls_list[unit] = ip_pool_list[unit];
310 } else
311 err = EINVAL;
312 if (err == 0)
313 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
314 return err;
315}
316
317
318/* ------------------------------------------------------------------------ */
319/* Function: ip_pool_exists */
320/* Returns: int - 0 = success, else error */
321/* Parameters: ipo(I) - pointer to the pool getting the new node. */
322/* */
323/* Find a matching pool inside the collection of pools for a particular */
324/* device, indicated by the unit number. */
325/* ------------------------------------------------------------------------ */
326static void *ip_pool_exists(unit, name)
327int unit;
328char *name;
329{
330 ip_pool_t *p;
331
332 for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next)
333 if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0)
334 break;
335 return p;
336}
337
338
339/* ------------------------------------------------------------------------ */
340/* Function: ip_pool_find */
341/* Returns: int - 0 = success, else error */
342/* Parameters: ipo(I) - pointer to the pool getting the new node. */
343/* */
344/* Find a matching pool inside the collection of pools for a particular */
345/* device, indicated by the unit number. If it is marked for deletion then */
346/* pretend it does not exist. */
347/* ------------------------------------------------------------------------ */
348void *ip_pool_find(unit, name)
349int unit;
350char *name;
351{
352 ip_pool_t *p;
353
354 p = ip_pool_exists(unit, name);
355 if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
356 return NULL;
357
358 return p;
359}
360
361
362/* ------------------------------------------------------------------------ */
363/* Function: ip_pool_findeq */
364/* Returns: int - 0 = success, else error */
365/* Parameters: ipo(I) - pointer to the pool getting the new node. */
366/* addr(I) - pointer to address information to delete */
367/* mask(I) - */
368/* */
369/* Searches for an exact match of an entry in the pool. */
370/* ------------------------------------------------------------------------ */
371ip_pool_node_t *ip_pool_findeq(ipo, addr, mask)
372ip_pool_t *ipo;
373addrfamily_t *addr, *mask;
374{
375 struct radix_node *n;
376 SPL_INT(s);
377
378 SPL_NET(s);
379 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
380 n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head);
381 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
382 SPL_X(s);
383 return (ip_pool_node_t *)n;
384}
385
386
387/* ------------------------------------------------------------------------ */
388/* Function: ip_pool_search */
389/* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
390/* Parameters: tptr(I) - pointer to the pool to search */
391/* version(I) - IP protocol version (4 or 6) */
392/* dptr(I) - pointer to address information */
393/* */
394/* Search the pool for a given address and return a search result. */
395/* ------------------------------------------------------------------------ */
396int ip_pool_search(tptr, ipversion, dptr)
397void *tptr;
398int ipversion;
399void *dptr;
400{
401 struct radix_node *rn;
402 ip_pool_node_t *m;
403 i6addr_t *addr;
404 addrfamily_t v;
405 ip_pool_t *ipo;
406 int rv;
407
408 ipo = tptr;
409 if (ipo == NULL)
410 return -1;
411
412 rv = 1;
413 m = NULL;
414 addr = (i6addr_t *)dptr;
415 bzero(&v, sizeof(v));
416 v.adf_len = offsetof(addrfamily_t, adf_addr);
417
418 if (ipversion == 4) {
419 v.adf_len += sizeof(addr->in4);
420 v.adf_addr.in4 = addr->in4;
421#ifdef USE_INET6
422 } else if (ipversion == 6) {
423 v.adf_len += sizeof(addr->in6);
424 v.adf_addr.in6 = addr->in6;
425#endif
426 } else
427 return -1;
428
429 READ_ENTER(&ip_poolrw);
430
431 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
432 rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head);
433 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
434
435 if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) {
436 m = (ip_pool_node_t *)rn;
437 ipo->ipo_hits++;
438 m->ipn_hits++;
439 rv = m->ipn_info;
440 }
441 RWLOCK_EXIT(&ip_poolrw);
442 return rv;
443}
444
445
446/* ------------------------------------------------------------------------ */
447/* Function: ip_pool_insert */
448/* Returns: int - 0 = success, else error */
449/* Parameters: ipo(I) - pointer to the pool getting the new node. */
450/* addr(I) - address being added as a node */
451/* mask(I) - netmask to with the node being added */
452/* info(I) - extra information to store in this node. */
453/* Locks: WRITE(ip_poolrw) */
454/* */
455/* Add another node to the pool given by ipo. The three parameters passed */
456/* in (addr, mask, info) shold all be stored in the node. */
457/* ------------------------------------------------------------------------ */
458int ip_pool_insert(ipo, addr, mask, info)
459ip_pool_t *ipo;
460i6addr_t *addr, *mask;
461int info;
462{
463 struct radix_node *rn;
464 ip_pool_node_t *x;
465
271 for (i = 0; i <= IPL_LOGMAX; i++) {
272 for (q = ip_pool_list[i]; (p = q) != NULL; ) {
273 q = p->ipo_next;
274 (void) ip_pool_destroy(i, p->ipo_name);
275 }
276 }
277
278#if (!defined(_KERNEL) || (BSD < 199306))
279 rn_fini();
280#endif
281}
282
283
284/* ------------------------------------------------------------------------ */
285/* Function: ip_pool_statistics */
286/* Returns: int - 0 = success, else error */
287/* Parameters: op(I) - pointer to lookup operation arguments */
288/* */
289/* Copy the current statistics out into user space, collecting pool list */
290/* pointers as appropriate for later use. */
291/* ------------------------------------------------------------------------ */
292int ip_pool_statistics(op)
293iplookupop_t *op;
294{
295 ip_pool_stat_t stats;
296 int unit, i, err = 0;
297
298 if (op->iplo_size != sizeof(ipoolstat))
299 return EINVAL;
300
301 bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats));
302 unit = op->iplo_unit;
303 if (unit == IPL_LOGALL) {
304 for (i = 0; i < IPL_LOGSIZE; i++)
305 stats.ipls_list[i] = ip_pool_list[i];
306 } else if (unit >= 0 && unit < IPL_LOGSIZE) {
307 if (op->iplo_name[0] != '\0')
308 stats.ipls_list[unit] = ip_pool_exists(unit,
309 op->iplo_name);
310 else
311 stats.ipls_list[unit] = ip_pool_list[unit];
312 } else
313 err = EINVAL;
314 if (err == 0)
315 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
316 return err;
317}
318
319
320/* ------------------------------------------------------------------------ */
321/* Function: ip_pool_exists */
322/* Returns: int - 0 = success, else error */
323/* Parameters: ipo(I) - pointer to the pool getting the new node. */
324/* */
325/* Find a matching pool inside the collection of pools for a particular */
326/* device, indicated by the unit number. */
327/* ------------------------------------------------------------------------ */
328static void *ip_pool_exists(unit, name)
329int unit;
330char *name;
331{
332 ip_pool_t *p;
333
334 for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next)
335 if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0)
336 break;
337 return p;
338}
339
340
341/* ------------------------------------------------------------------------ */
342/* Function: ip_pool_find */
343/* Returns: int - 0 = success, else error */
344/* Parameters: ipo(I) - pointer to the pool getting the new node. */
345/* */
346/* Find a matching pool inside the collection of pools for a particular */
347/* device, indicated by the unit number. If it is marked for deletion then */
348/* pretend it does not exist. */
349/* ------------------------------------------------------------------------ */
350void *ip_pool_find(unit, name)
351int unit;
352char *name;
353{
354 ip_pool_t *p;
355
356 p = ip_pool_exists(unit, name);
357 if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
358 return NULL;
359
360 return p;
361}
362
363
364/* ------------------------------------------------------------------------ */
365/* Function: ip_pool_findeq */
366/* Returns: int - 0 = success, else error */
367/* Parameters: ipo(I) - pointer to the pool getting the new node. */
368/* addr(I) - pointer to address information to delete */
369/* mask(I) - */
370/* */
371/* Searches for an exact match of an entry in the pool. */
372/* ------------------------------------------------------------------------ */
373ip_pool_node_t *ip_pool_findeq(ipo, addr, mask)
374ip_pool_t *ipo;
375addrfamily_t *addr, *mask;
376{
377 struct radix_node *n;
378 SPL_INT(s);
379
380 SPL_NET(s);
381 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
382 n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head);
383 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
384 SPL_X(s);
385 return (ip_pool_node_t *)n;
386}
387
388
389/* ------------------------------------------------------------------------ */
390/* Function: ip_pool_search */
391/* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
392/* Parameters: tptr(I) - pointer to the pool to search */
393/* version(I) - IP protocol version (4 or 6) */
394/* dptr(I) - pointer to address information */
395/* */
396/* Search the pool for a given address and return a search result. */
397/* ------------------------------------------------------------------------ */
398int ip_pool_search(tptr, ipversion, dptr)
399void *tptr;
400int ipversion;
401void *dptr;
402{
403 struct radix_node *rn;
404 ip_pool_node_t *m;
405 i6addr_t *addr;
406 addrfamily_t v;
407 ip_pool_t *ipo;
408 int rv;
409
410 ipo = tptr;
411 if (ipo == NULL)
412 return -1;
413
414 rv = 1;
415 m = NULL;
416 addr = (i6addr_t *)dptr;
417 bzero(&v, sizeof(v));
418 v.adf_len = offsetof(addrfamily_t, adf_addr);
419
420 if (ipversion == 4) {
421 v.adf_len += sizeof(addr->in4);
422 v.adf_addr.in4 = addr->in4;
423#ifdef USE_INET6
424 } else if (ipversion == 6) {
425 v.adf_len += sizeof(addr->in6);
426 v.adf_addr.in6 = addr->in6;
427#endif
428 } else
429 return -1;
430
431 READ_ENTER(&ip_poolrw);
432
433 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
434 rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head);
435 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
436
437 if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) {
438 m = (ip_pool_node_t *)rn;
439 ipo->ipo_hits++;
440 m->ipn_hits++;
441 rv = m->ipn_info;
442 }
443 RWLOCK_EXIT(&ip_poolrw);
444 return rv;
445}
446
447
448/* ------------------------------------------------------------------------ */
449/* Function: ip_pool_insert */
450/* Returns: int - 0 = success, else error */
451/* Parameters: ipo(I) - pointer to the pool getting the new node. */
452/* addr(I) - address being added as a node */
453/* mask(I) - netmask to with the node being added */
454/* info(I) - extra information to store in this node. */
455/* Locks: WRITE(ip_poolrw) */
456/* */
457/* Add another node to the pool given by ipo. The three parameters passed */
458/* in (addr, mask, info) shold all be stored in the node. */
459/* ------------------------------------------------------------------------ */
460int ip_pool_insert(ipo, addr, mask, info)
461ip_pool_t *ipo;
462i6addr_t *addr, *mask;
463int info;
464{
465 struct radix_node *rn;
466 ip_pool_node_t *x;
467
466 ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
467
468 KMALLOC(x, ip_pool_node_t *);
469 if (x == NULL) {
470 return ENOMEM;
471 }
472
473 bzero(x, sizeof(*x));
474
475 x->ipn_info = info;
476 (void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name));
477
478 bcopy(addr, &x->ipn_addr.adf_addr, sizeof(*addr));
479 x->ipn_addr.adf_len = sizeof(x->ipn_addr);
480 bcopy(mask, &x->ipn_mask.adf_addr, sizeof(*mask));
481 x->ipn_mask.adf_len = sizeof(x->ipn_mask);
482
483 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
484 rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask,
485 ipo->ipo_head, x->ipn_nodes);
486 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
487#ifdef DEBUG_POOL
488 printf("Added %p at %p\n", x, rn);
489#endif
490
491 if (rn == NULL) {
492 KFREE(x);
493 return ENOMEM;
494 }
495
496 x->ipn_ref = 1;
497 x->ipn_next = ipo->ipo_list;
498 x->ipn_pnext = &ipo->ipo_list;
499 if (ipo->ipo_list != NULL)
500 ipo->ipo_list->ipn_pnext = &x->ipn_next;
501 ipo->ipo_list = x;
502
503 ipoolstat.ipls_nodes++;
504
505 return 0;
506}
507
508
509/* ------------------------------------------------------------------------ */
510/* Function: ip_pool_create */
511/* Returns: int - 0 = success, else error */
512/* Parameters: op(I) - pointer to iplookup struct with call details */
513/* Locks: WRITE(ip_poolrw) */
514/* */
515/* Creates a new group according to the paramters passed in via the */
516/* iplookupop structure. Does not check to see if the group already exists */
517/* when being inserted - assume this has already been done. If the pool is */
518/* marked as being anonymous, give it a new, unique, identifier. Call any */
519/* other functions required to initialise the structure. */
520/* */
521/* If the structure is flagged for deletion then reset the flag and return, */
522/* as this likely means we've tried to free a pool that is in use (flush) */
523/* and now want to repopulate it with "new" data. */
524/* ------------------------------------------------------------------------ */
525int ip_pool_create(op)
526iplookupop_t *op;
527{
528 char name[FR_GROUPLEN];
529 int poolnum, unit;
530 ip_pool_t *h;
531
468 KMALLOC(x, ip_pool_node_t *);
469 if (x == NULL) {
470 return ENOMEM;
471 }
472
473 bzero(x, sizeof(*x));
474
475 x->ipn_info = info;
476 (void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name));
477
478 bcopy(addr, &x->ipn_addr.adf_addr, sizeof(*addr));
479 x->ipn_addr.adf_len = sizeof(x->ipn_addr);
480 bcopy(mask, &x->ipn_mask.adf_addr, sizeof(*mask));
481 x->ipn_mask.adf_len = sizeof(x->ipn_mask);
482
483 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
484 rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask,
485 ipo->ipo_head, x->ipn_nodes);
486 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
487#ifdef DEBUG_POOL
488 printf("Added %p at %p\n", x, rn);
489#endif
490
491 if (rn == NULL) {
492 KFREE(x);
493 return ENOMEM;
494 }
495
496 x->ipn_ref = 1;
497 x->ipn_next = ipo->ipo_list;
498 x->ipn_pnext = &ipo->ipo_list;
499 if (ipo->ipo_list != NULL)
500 ipo->ipo_list->ipn_pnext = &x->ipn_next;
501 ipo->ipo_list = x;
502
503 ipoolstat.ipls_nodes++;
504
505 return 0;
506}
507
508
509/* ------------------------------------------------------------------------ */
510/* Function: ip_pool_create */
511/* Returns: int - 0 = success, else error */
512/* Parameters: op(I) - pointer to iplookup struct with call details */
513/* Locks: WRITE(ip_poolrw) */
514/* */
515/* Creates a new group according to the paramters passed in via the */
516/* iplookupop structure. Does not check to see if the group already exists */
517/* when being inserted - assume this has already been done. If the pool is */
518/* marked as being anonymous, give it a new, unique, identifier. Call any */
519/* other functions required to initialise the structure. */
520/* */
521/* If the structure is flagged for deletion then reset the flag and return, */
522/* as this likely means we've tried to free a pool that is in use (flush) */
523/* and now want to repopulate it with "new" data. */
524/* ------------------------------------------------------------------------ */
525int ip_pool_create(op)
526iplookupop_t *op;
527{
528 char name[FR_GROUPLEN];
529 int poolnum, unit;
530 ip_pool_t *h;
531
532 ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
533
534 unit = op->iplo_unit;
535
532 unit = op->iplo_unit;
533
536 if ((op->iplo_arg & LOOKUP_ANON) == 0)
534 if ((op->iplo_arg & LOOKUP_ANON) == 0) {
537 h = ip_pool_exists(unit, op->iplo_name);
535 h = ip_pool_exists(unit, op->iplo_name);
538 else
539 h = NULL;
540
541 if (h != NULL) {
542 if ((h->ipo_flags & IPOOL_DELETE) != 0) {
536 if (h != NULL) {
537 if ((h->ipo_flags & IPOOL_DELETE) == 0)
538 return EEXIST;
543 h->ipo_flags &= ~IPOOL_DELETE;
544 return 0;
545 }
539 h->ipo_flags &= ~IPOOL_DELETE;
540 return 0;
541 }
546 return EEXIST;
547 } else {
548 KMALLOC(h, ip_pool_t *);
549 if (h == NULL)
550 return ENOMEM;
551 bzero(h, sizeof(*h));
542 }
552
543
553 if (rn_inithead((void **)&h->ipo_head,
554 offsetof(addrfamily_t, adf_addr) << 3) == 0) {
555 KFREE(h);
556 return ENOMEM;
557 }
544 KMALLOC(h, ip_pool_t *);
545 if (h == NULL)
546 return ENOMEM;
547 bzero(h, sizeof(*h));
548
549 if (rn_inithead((void **)&h->ipo_head,
550 offsetof(addrfamily_t, adf_addr) << 3) == 0) {
551 KFREE(h);
552 return ENOMEM;
558 }
559
560 if ((op->iplo_arg & LOOKUP_ANON) != 0) {
561 ip_pool_t *p;
562
563 h->ipo_flags |= IPOOL_ANON;
564 poolnum = LOOKUP_ANON;
565
566#if defined(SNPRINTF) && defined(_KERNEL)
567 SNPRINTF(name, sizeof(name), "%x", poolnum);
568#else
569 (void)sprintf(name, "%x", poolnum);
570#endif
571
572 for (p = ip_pool_list[unit]; p != NULL; ) {
573 if (strncmp(name, p->ipo_name,
574 sizeof(p->ipo_name)) == 0) {
575 poolnum++;
576#if defined(SNPRINTF) && defined(_KERNEL)
577 SNPRINTF(name, sizeof(name), "%x", poolnum);
578#else
579 (void)sprintf(name, "%x", poolnum);
580#endif
581 p = ip_pool_list[unit];
582 } else
583 p = p->ipo_next;
584 }
585
586 (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
587 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
588 } else {
589 (void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
590 }
591
553 }
554
555 if ((op->iplo_arg & LOOKUP_ANON) != 0) {
556 ip_pool_t *p;
557
558 h->ipo_flags |= IPOOL_ANON;
559 poolnum = LOOKUP_ANON;
560
561#if defined(SNPRINTF) && defined(_KERNEL)
562 SNPRINTF(name, sizeof(name), "%x", poolnum);
563#else
564 (void)sprintf(name, "%x", poolnum);
565#endif
566
567 for (p = ip_pool_list[unit]; p != NULL; ) {
568 if (strncmp(name, p->ipo_name,
569 sizeof(p->ipo_name)) == 0) {
570 poolnum++;
571#if defined(SNPRINTF) && defined(_KERNEL)
572 SNPRINTF(name, sizeof(name), "%x", poolnum);
573#else
574 (void)sprintf(name, "%x", poolnum);
575#endif
576 p = ip_pool_list[unit];
577 } else
578 p = p->ipo_next;
579 }
580
581 (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
582 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
583 } else {
584 (void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
585 }
586
592 if ((h->ipo_flags & IPOOL_DELETE) == 0) {
593 h->ipo_ref = 1;
594 h->ipo_list = NULL;
595 h->ipo_unit = unit;
596 h->ipo_next = ip_pool_list[unit];
597 if (ip_pool_list[unit] != NULL)
598 ip_pool_list[unit]->ipo_pnext = &h->ipo_next;
599 h->ipo_pnext = &ip_pool_list[unit];
600 ip_pool_list[unit] = h;
587 h->ipo_ref = 1;
588 h->ipo_list = NULL;
589 h->ipo_unit = unit;
590 h->ipo_next = ip_pool_list[unit];
591 if (ip_pool_list[unit] != NULL)
592 ip_pool_list[unit]->ipo_pnext = &h->ipo_next;
593 h->ipo_pnext = &ip_pool_list[unit];
594 ip_pool_list[unit] = h;
601
595
602 ipoolstat.ipls_pools++;
603 }
596 ipoolstat.ipls_pools++;
604
605 return 0;
606}
607
608
609/* ------------------------------------------------------------------------ */
610/* Function: ip_pool_remove */
611/* Returns: int - 0 = success, else error */
612/* Parameters: ipo(I) - pointer to the pool to remove the node from. */
613/* ipe(I) - address being deleted as a node */
614/* Locks: WRITE(ip_poolrw) */
615/* */
616/* Remove a node from the pool given by ipo. */
617/* ------------------------------------------------------------------------ */
618int ip_pool_remove(ipo, ipe)
619ip_pool_t *ipo;
620ip_pool_node_t *ipe;
621{
622
597
598 return 0;
599}
600
601
602/* ------------------------------------------------------------------------ */
603/* Function: ip_pool_remove */
604/* Returns: int - 0 = success, else error */
605/* Parameters: ipo(I) - pointer to the pool to remove the node from. */
606/* ipe(I) - address being deleted as a node */
607/* Locks: WRITE(ip_poolrw) */
608/* */
609/* Remove a node from the pool given by ipo. */
610/* ------------------------------------------------------------------------ */
611int ip_pool_remove(ipo, ipe)
612ip_pool_t *ipo;
613ip_pool_node_t *ipe;
614{
615
623 ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
624
625 if (ipe->ipn_pnext != NULL)
626 *ipe->ipn_pnext = ipe->ipn_next;
627 if (ipe->ipn_next != NULL)
628 ipe->ipn_next->ipn_pnext = ipe->ipn_pnext;
629
630 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
631 ipo->ipo_head->rnh_deladdr(&ipe->ipn_addr, &ipe->ipn_mask,
632 ipo->ipo_head);
633 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
634
635 ip_pool_node_deref(ipe);
636
637 return 0;
638}
639
640
641/* ------------------------------------------------------------------------ */
642/* Function: ip_pool_destroy */
643/* Returns: int - 0 = success, else error */
644/* Parameters: op(I) - information about the pool to remove */
645/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
646/* */
647/* Search for a pool using paramters passed in and if it's not otherwise */
648/* busy, free it. If it is busy, clear all of its nodes, mark it for being */
649/* deleted and return an error saying it is busy. */
650/* */
651/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
652/* may not be initialised, we can't use an ASSERT to enforce the locking */
653/* assertion that one of the two (ip_poolrw,ipf_global) is held. */
654/* ------------------------------------------------------------------------ */
655int ip_pool_destroy(unit, name)
656int unit;
657char *name;
658{
659 ip_pool_t *ipo;
660
661 ipo = ip_pool_exists(unit, name);
662 if (ipo == NULL)
663 return ESRCH;
664
665 if (ipo->ipo_ref != 1) {
666 ip_pool_clearnodes(ipo);
667 ipo->ipo_flags |= IPOOL_DELETE;
668 return 0;
669 }
670
671 ip_pool_free(ipo);
672 return 0;
673}
674
675
676/* ------------------------------------------------------------------------ */
677/* Function: ip_pool_flush */
678/* Returns: int - number of pools deleted */
679/* Parameters: fp(I) - which pool(s) to flush */
680/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
681/* */
682/* Free all pools associated with the device that matches the unit number */
683/* passed in with operation. */
684/* */
685/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
686/* may not be initialised, we can't use an ASSERT to enforce the locking */
687/* assertion that one of the two (ip_poolrw,ipf_global) is held. */
688/* ------------------------------------------------------------------------ */
689int ip_pool_flush(fp)
690iplookupflush_t *fp;
691{
692 int i, num = 0, unit, err;
693 ip_pool_t *p, *q;
694 iplookupop_t op;
695
696 unit = fp->iplf_unit;
697
698 for (i = 0; i <= IPL_LOGMAX; i++) {
699 if (unit != IPLT_ALL && i != unit)
700 continue;
701 for (q = ip_pool_list[i]; (p = q) != NULL; ) {
702 op.iplo_unit = i;
703 (void)strncpy(op.iplo_name, p->ipo_name,
704 sizeof(op.iplo_name));
705 q = p->ipo_next;
706 err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
707 if (err == 0)
708 num++;
709 else
710 break;
711 }
712 }
713 return num;
714}
715
716
717/* ------------------------------------------------------------------------ */
718/* Function: ip_pool_free */
719/* Returns: void */
720/* Parameters: ipo(I) - pointer to pool structure */
721/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
722/* */
723/* Deletes the pool strucutre passed in from the list of pools and deletes */
724/* all of the address information stored in it, including any tree data */
725/* structures also allocated. */
726/* */
727/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
728/* may not be initialised, we can't use an ASSERT to enforce the locking */
729/* assertion that one of the two (ip_poolrw,ipf_global) is held. */
730/* ------------------------------------------------------------------------ */
731void ip_pool_free(ipo)
732ip_pool_t *ipo;
733{
734
735 ip_pool_clearnodes(ipo);
736
737 if (ipo->ipo_next != NULL)
738 ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
739 *ipo->ipo_pnext = ipo->ipo_next;
740 rn_freehead(ipo->ipo_head);
741 KFREE(ipo);
742
743 ipoolstat.ipls_pools--;
744}
745
746
747/* ------------------------------------------------------------------------ */
748/* Function: ip_pool_clearnodes */
749/* Returns: void */
750/* Parameters: ipo(I) - pointer to pool structure */
751/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
752/* */
753/* Deletes all nodes stored in a pool structure. */
754/* ------------------------------------------------------------------------ */
755static void ip_pool_clearnodes(ipo)
756ip_pool_t *ipo;
757{
758 ip_pool_node_t *n;
759
760 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
761 while ((n = ipo->ipo_list) != NULL) {
762 ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
763 ipo->ipo_head);
764
765 *n->ipn_pnext = n->ipn_next;
766 if (n->ipn_next)
767 n->ipn_next->ipn_pnext = n->ipn_pnext;
768
769 KFREE(n);
770
771 ipoolstat.ipls_nodes--;
772 }
773 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
774
775 ipo->ipo_list = NULL;
776}
777
778
779/* ------------------------------------------------------------------------ */
780/* Function: ip_pool_deref */
781/* Returns: void */
782/* Parameters: ipo(I) - pointer to pool structure */
783/* Locks: WRITE(ip_poolrw) */
784/* */
785/* Drop the number of known references to this pool structure by one and if */
786/* we arrive at zero known references, free it. */
787/* ------------------------------------------------------------------------ */
788void ip_pool_deref(ipo)
789ip_pool_t *ipo;
790{
791
616 if (ipe->ipn_pnext != NULL)
617 *ipe->ipn_pnext = ipe->ipn_next;
618 if (ipe->ipn_next != NULL)
619 ipe->ipn_next->ipn_pnext = ipe->ipn_pnext;
620
621 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
622 ipo->ipo_head->rnh_deladdr(&ipe->ipn_addr, &ipe->ipn_mask,
623 ipo->ipo_head);
624 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
625
626 ip_pool_node_deref(ipe);
627
628 return 0;
629}
630
631
632/* ------------------------------------------------------------------------ */
633/* Function: ip_pool_destroy */
634/* Returns: int - 0 = success, else error */
635/* Parameters: op(I) - information about the pool to remove */
636/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
637/* */
638/* Search for a pool using paramters passed in and if it's not otherwise */
639/* busy, free it. If it is busy, clear all of its nodes, mark it for being */
640/* deleted and return an error saying it is busy. */
641/* */
642/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
643/* may not be initialised, we can't use an ASSERT to enforce the locking */
644/* assertion that one of the two (ip_poolrw,ipf_global) is held. */
645/* ------------------------------------------------------------------------ */
646int ip_pool_destroy(unit, name)
647int unit;
648char *name;
649{
650 ip_pool_t *ipo;
651
652 ipo = ip_pool_exists(unit, name);
653 if (ipo == NULL)
654 return ESRCH;
655
656 if (ipo->ipo_ref != 1) {
657 ip_pool_clearnodes(ipo);
658 ipo->ipo_flags |= IPOOL_DELETE;
659 return 0;
660 }
661
662 ip_pool_free(ipo);
663 return 0;
664}
665
666
667/* ------------------------------------------------------------------------ */
668/* Function: ip_pool_flush */
669/* Returns: int - number of pools deleted */
670/* Parameters: fp(I) - which pool(s) to flush */
671/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
672/* */
673/* Free all pools associated with the device that matches the unit number */
674/* passed in with operation. */
675/* */
676/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
677/* may not be initialised, we can't use an ASSERT to enforce the locking */
678/* assertion that one of the two (ip_poolrw,ipf_global) is held. */
679/* ------------------------------------------------------------------------ */
680int ip_pool_flush(fp)
681iplookupflush_t *fp;
682{
683 int i, num = 0, unit, err;
684 ip_pool_t *p, *q;
685 iplookupop_t op;
686
687 unit = fp->iplf_unit;
688
689 for (i = 0; i <= IPL_LOGMAX; i++) {
690 if (unit != IPLT_ALL && i != unit)
691 continue;
692 for (q = ip_pool_list[i]; (p = q) != NULL; ) {
693 op.iplo_unit = i;
694 (void)strncpy(op.iplo_name, p->ipo_name,
695 sizeof(op.iplo_name));
696 q = p->ipo_next;
697 err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
698 if (err == 0)
699 num++;
700 else
701 break;
702 }
703 }
704 return num;
705}
706
707
708/* ------------------------------------------------------------------------ */
709/* Function: ip_pool_free */
710/* Returns: void */
711/* Parameters: ipo(I) - pointer to pool structure */
712/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
713/* */
714/* Deletes the pool strucutre passed in from the list of pools and deletes */
715/* all of the address information stored in it, including any tree data */
716/* structures also allocated. */
717/* */
718/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
719/* may not be initialised, we can't use an ASSERT to enforce the locking */
720/* assertion that one of the two (ip_poolrw,ipf_global) is held. */
721/* ------------------------------------------------------------------------ */
722void ip_pool_free(ipo)
723ip_pool_t *ipo;
724{
725
726 ip_pool_clearnodes(ipo);
727
728 if (ipo->ipo_next != NULL)
729 ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
730 *ipo->ipo_pnext = ipo->ipo_next;
731 rn_freehead(ipo->ipo_head);
732 KFREE(ipo);
733
734 ipoolstat.ipls_pools--;
735}
736
737
738/* ------------------------------------------------------------------------ */
739/* Function: ip_pool_clearnodes */
740/* Returns: void */
741/* Parameters: ipo(I) - pointer to pool structure */
742/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
743/* */
744/* Deletes all nodes stored in a pool structure. */
745/* ------------------------------------------------------------------------ */
746static void ip_pool_clearnodes(ipo)
747ip_pool_t *ipo;
748{
749 ip_pool_node_t *n;
750
751 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
752 while ((n = ipo->ipo_list) != NULL) {
753 ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
754 ipo->ipo_head);
755
756 *n->ipn_pnext = n->ipn_next;
757 if (n->ipn_next)
758 n->ipn_next->ipn_pnext = n->ipn_pnext;
759
760 KFREE(n);
761
762 ipoolstat.ipls_nodes--;
763 }
764 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
765
766 ipo->ipo_list = NULL;
767}
768
769
770/* ------------------------------------------------------------------------ */
771/* Function: ip_pool_deref */
772/* Returns: void */
773/* Parameters: ipo(I) - pointer to pool structure */
774/* Locks: WRITE(ip_poolrw) */
775/* */
776/* Drop the number of known references to this pool structure by one and if */
777/* we arrive at zero known references, free it. */
778/* ------------------------------------------------------------------------ */
779void ip_pool_deref(ipo)
780ip_pool_t *ipo;
781{
782
792 ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
793
794 ipo->ipo_ref--;
795
796 if (ipo->ipo_ref == 0)
797 ip_pool_free(ipo);
798
799 else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
800 ip_pool_destroy(ipo->ipo_unit, ipo->ipo_name);
801}
802
803
804/* ------------------------------------------------------------------------ */
805/* Function: ip_pool_node_deref */
806/* Returns: void */
807/* Parameters: ipn(I) - pointer to pool structure */
808/* Locks: WRITE(ip_poolrw) */
809/* */
810/* Drop a reference to the pool node passed in and if we're the last, free */
811/* it all up and adjust the stats accordingly. */
812/* ------------------------------------------------------------------------ */
813void ip_pool_node_deref(ipn)
814ip_pool_node_t *ipn;
815{
816
817 ipn->ipn_ref--;
818
819 if (ipn->ipn_ref == 0) {
820 KFREE(ipn);
821 ipoolstat.ipls_nodes--;
822 }
823}
824
825
826/* ------------------------------------------------------------------------ */
827/* Function: ip_pool_getnext */
828/* Returns: void */
829/* Parameters: token(I) - pointer to pool structure */
830/* Parameters: ilp(IO) - pointer to pool iterating structure */
831/* */
832/* ------------------------------------------------------------------------ */
833int ip_pool_getnext(token, ilp)
834ipftoken_t *token;
835ipflookupiter_t *ilp;
836{
837 ip_pool_node_t *node, zn, *nextnode;
838 ip_pool_t *ipo, zp, *nextipo;
839 int err;
840
841 err = 0;
842 node = NULL;
843 nextnode = NULL;
844 ipo = NULL;
845 nextipo = NULL;
846
847 READ_ENTER(&ip_poolrw);
848
849 switch (ilp->ili_otype)
850 {
851 case IPFLOOKUPITER_LIST :
852 ipo = token->ipt_data;
853 if (ipo == NULL) {
854 nextipo = ip_pool_list[(int)ilp->ili_unit];
855 } else {
856 nextipo = ipo->ipo_next;
857 }
858
859 if (nextipo != NULL) {
860 ATOMIC_INC(nextipo->ipo_ref);
783 ipo->ipo_ref--;
784
785 if (ipo->ipo_ref == 0)
786 ip_pool_free(ipo);
787
788 else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
789 ip_pool_destroy(ipo->ipo_unit, ipo->ipo_name);
790}
791
792
793/* ------------------------------------------------------------------------ */
794/* Function: ip_pool_node_deref */
795/* Returns: void */
796/* Parameters: ipn(I) - pointer to pool structure */
797/* Locks: WRITE(ip_poolrw) */
798/* */
799/* Drop a reference to the pool node passed in and if we're the last, free */
800/* it all up and adjust the stats accordingly. */
801/* ------------------------------------------------------------------------ */
802void ip_pool_node_deref(ipn)
803ip_pool_node_t *ipn;
804{
805
806 ipn->ipn_ref--;
807
808 if (ipn->ipn_ref == 0) {
809 KFREE(ipn);
810 ipoolstat.ipls_nodes--;
811 }
812}
813
814
815/* ------------------------------------------------------------------------ */
816/* Function: ip_pool_getnext */
817/* Returns: void */
818/* Parameters: token(I) - pointer to pool structure */
819/* Parameters: ilp(IO) - pointer to pool iterating structure */
820/* */
821/* ------------------------------------------------------------------------ */
822int ip_pool_getnext(token, ilp)
823ipftoken_t *token;
824ipflookupiter_t *ilp;
825{
826 ip_pool_node_t *node, zn, *nextnode;
827 ip_pool_t *ipo, zp, *nextipo;
828 int err;
829
830 err = 0;
831 node = NULL;
832 nextnode = NULL;
833 ipo = NULL;
834 nextipo = NULL;
835
836 READ_ENTER(&ip_poolrw);
837
838 switch (ilp->ili_otype)
839 {
840 case IPFLOOKUPITER_LIST :
841 ipo = token->ipt_data;
842 if (ipo == NULL) {
843 nextipo = ip_pool_list[(int)ilp->ili_unit];
844 } else {
845 nextipo = ipo->ipo_next;
846 }
847
848 if (nextipo != NULL) {
849 ATOMIC_INC(nextipo->ipo_ref);
861 if (nextipo->ipo_next == NULL)
862 token->ipt_alive = 0;
850 token->ipt_data = nextipo;
863 } else {
864 bzero((char *)&zp, sizeof(zp));
865 nextipo = &zp;
851 } else {
852 bzero((char *)&zp, sizeof(zp));
853 nextipo = &zp;
854 token->ipt_data = NULL;
866 }
867 break;
868
869 case IPFLOOKUPITER_NODE :
870 node = token->ipt_data;
871 if (node == NULL) {
872 ipo = ip_pool_exists(ilp->ili_unit, ilp->ili_name);
873 if (ipo == NULL)
874 err = ESRCH;
875 else {
876 nextnode = ipo->ipo_list;
877 ipo = NULL;
878 }
879 } else {
880 nextnode = node->ipn_next;
881 }
882
883 if (nextnode != NULL) {
884 ATOMIC_INC(nextnode->ipn_ref);
855 }
856 break;
857
858 case IPFLOOKUPITER_NODE :
859 node = token->ipt_data;
860 if (node == NULL) {
861 ipo = ip_pool_exists(ilp->ili_unit, ilp->ili_name);
862 if (ipo == NULL)
863 err = ESRCH;
864 else {
865 nextnode = ipo->ipo_list;
866 ipo = NULL;
867 }
868 } else {
869 nextnode = node->ipn_next;
870 }
871
872 if (nextnode != NULL) {
873 ATOMIC_INC(nextnode->ipn_ref);
885 if (nextnode->ipn_next == NULL)
886 token->ipt_alive = 0;
874 token->ipt_data = nextnode;
887 } else {
888 bzero((char *)&zn, sizeof(zn));
889 nextnode = &zn;
875 } else {
876 bzero((char *)&zn, sizeof(zn));
877 nextnode = &zn;
878 token->ipt_data = NULL;
890 }
891 break;
892 default :
893 err = EINVAL;
894 break;
895 }
896
897 RWLOCK_EXIT(&ip_poolrw);
898
899 if (err != 0)
900 return err;
901
902 switch (ilp->ili_otype)
903 {
904 case IPFLOOKUPITER_LIST :
905 if (ipo != NULL) {
906 WRITE_ENTER(&ip_poolrw);
907 ip_pool_deref(ipo);
908 RWLOCK_EXIT(&ip_poolrw);
909 }
879 }
880 break;
881 default :
882 err = EINVAL;
883 break;
884 }
885
886 RWLOCK_EXIT(&ip_poolrw);
887
888 if (err != 0)
889 return err;
890
891 switch (ilp->ili_otype)
892 {
893 case IPFLOOKUPITER_LIST :
894 if (ipo != NULL) {
895 WRITE_ENTER(&ip_poolrw);
896 ip_pool_deref(ipo);
897 RWLOCK_EXIT(&ip_poolrw);
898 }
910 token->ipt_data = nextipo;
911 err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
912 if (err != 0)
913 err = EFAULT;
914 break;
915
916 case IPFLOOKUPITER_NODE :
917 if (node != NULL) {
918 WRITE_ENTER(&ip_poolrw);
919 ip_pool_node_deref(node);
920 RWLOCK_EXIT(&ip_poolrw);
921 }
899 err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
900 if (err != 0)
901 err = EFAULT;
902 break;
903
904 case IPFLOOKUPITER_NODE :
905 if (node != NULL) {
906 WRITE_ENTER(&ip_poolrw);
907 ip_pool_node_deref(node);
908 RWLOCK_EXIT(&ip_poolrw);
909 }
922 token->ipt_data = nextnode;
923 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
924 if (err != 0)
925 err = EFAULT;
926 break;
927 }
928
929 return err;
930}
931
932
933/* ------------------------------------------------------------------------ */
934/* Function: ip_pool_iterderef */
935/* Returns: void */
936/* Parameters: ipn(I) - pointer to pool structure */
937/* Locks: WRITE(ip_poolrw) */
938/* */
939/* ------------------------------------------------------------------------ */
940void ip_pool_iterderef(otype, unit, data)
941u_int otype;
942int unit;
943void *data;
944{
945
946 if (data == NULL)
947 return;
948
949 if (unit < 0 || unit > IPL_LOGMAX)
950 return;
951
952 switch (otype)
953 {
954 case IPFLOOKUPITER_LIST :
955 WRITE_ENTER(&ip_poolrw);
956 ip_pool_deref((ip_pool_t *)data);
957 RWLOCK_EXIT(&ip_poolrw);
958 break;
959
960 case IPFLOOKUPITER_NODE :
961 WRITE_ENTER(&ip_poolrw);
962 ip_pool_node_deref((ip_pool_node_t *)data);
963 RWLOCK_EXIT(&ip_poolrw);
964 break;
965 default :
966 break;
967 }
968}
969
970
971# if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \
972 !defined(__hpux) && !defined(__sgi))
973static int
974rn_freenode(struct radix_node *n, void *p)
975{
976 struct radix_node_head *rnh = p;
977 struct radix_node *d;
978
979 d = rnh->rnh_deladdr(n->rn_key, NULL, rnh);
980 if (d != NULL) {
981 FreeS(d, max_keylen + 2 * sizeof (*d));
982 }
983 return 0;
984}
985
986
987void
988rn_freehead(rnh)
989 struct radix_node_head *rnh;
990{
991
992 RADIX_NODE_HEAD_LOCK(rnh);
993 (*rnh->rnh_walktree)(rnh, rn_freenode, rnh);
994
995 rnh->rnh_addaddr = NULL;
996 rnh->rnh_deladdr = NULL;
997 rnh->rnh_matchaddr = NULL;
998 rnh->rnh_lookup = NULL;
999 rnh->rnh_walktree = NULL;
1000 RADIX_NODE_HEAD_UNLOCK(rnh);
1001
1002 Free(rnh);
1003}
1004# endif
1005#endif /* IPFILTER_LOOKUP */
910 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
911 if (err != 0)
912 err = EFAULT;
913 break;
914 }
915
916 return err;
917}
918
919
920/* ------------------------------------------------------------------------ */
921/* Function: ip_pool_iterderef */
922/* Returns: void */
923/* Parameters: ipn(I) - pointer to pool structure */
924/* Locks: WRITE(ip_poolrw) */
925/* */
926/* ------------------------------------------------------------------------ */
927void ip_pool_iterderef(otype, unit, data)
928u_int otype;
929int unit;
930void *data;
931{
932
933 if (data == NULL)
934 return;
935
936 if (unit < 0 || unit > IPL_LOGMAX)
937 return;
938
939 switch (otype)
940 {
941 case IPFLOOKUPITER_LIST :
942 WRITE_ENTER(&ip_poolrw);
943 ip_pool_deref((ip_pool_t *)data);
944 RWLOCK_EXIT(&ip_poolrw);
945 break;
946
947 case IPFLOOKUPITER_NODE :
948 WRITE_ENTER(&ip_poolrw);
949 ip_pool_node_deref((ip_pool_node_t *)data);
950 RWLOCK_EXIT(&ip_poolrw);
951 break;
952 default :
953 break;
954 }
955}
956
957
958# if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \
959 !defined(__hpux) && !defined(__sgi))
960static int
961rn_freenode(struct radix_node *n, void *p)
962{
963 struct radix_node_head *rnh = p;
964 struct radix_node *d;
965
966 d = rnh->rnh_deladdr(n->rn_key, NULL, rnh);
967 if (d != NULL) {
968 FreeS(d, max_keylen + 2 * sizeof (*d));
969 }
970 return 0;
971}
972
973
974void
975rn_freehead(rnh)
976 struct radix_node_head *rnh;
977{
978
979 RADIX_NODE_HEAD_LOCK(rnh);
980 (*rnh->rnh_walktree)(rnh, rn_freenode, rnh);
981
982 rnh->rnh_addaddr = NULL;
983 rnh->rnh_deladdr = NULL;
984 rnh->rnh_matchaddr = NULL;
985 rnh->rnh_lookup = NULL;
986 rnh->rnh_walktree = NULL;
987 RADIX_NODE_HEAD_UNLOCK(rnh);
988
989 Free(rnh);
990}
991# endif
992#endif /* IPFILTER_LOOKUP */