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