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