aboutsummaryrefslogtreecommitdiff
path: root/sys/contrib/ipfilter/netinet/ip_pool.c
diff options
context:
space:
mode:
authorDarren Reed <darrenr@FreeBSD.org>2007-06-04 02:50:28 +0000
committerDarren Reed <darrenr@FreeBSD.org>2007-06-04 02:50:28 +0000
commit103b406762fd9664783670aae8479f3a8ec71c61 (patch)
tree4a85b8476e1218a7ef6991f70ee02ffe60e6ec9b /sys/contrib/ipfilter/netinet/ip_pool.c
parent0be1832174307c242b42db3dac9d7e762f0c693b (diff)
downloadsrc-103b406762fd9664783670aae8479f3a8ec71c61.tar.gz
src-103b406762fd9664783670aae8479f3a8ec71c61.zip
Import IPFilter 4.1.23 to vendor branch.
See src/contrib/ipfilter/HISTORY for details of changes since 4.1.13
Notes
Notes: svn path=/vendor-sys/ipfilter/dist/; revision=170263
Diffstat (limited to 'sys/contrib/ipfilter/netinet/ip_pool.c')
-rw-r--r--sys/contrib/ipfilter/netinet/ip_pool.c375
1 files changed, 298 insertions, 77 deletions
diff --git a/sys/contrib/ipfilter/netinet/ip_pool.c b/sys/contrib/ipfilter/netinet/ip_pool.c
index 3d19afbf06ba..b7e994604adf 100644
--- a/sys/contrib/ipfilter/netinet/ip_pool.c
+++ b/sys/contrib/ipfilter/netinet/ip_pool.c
@@ -55,9 +55,6 @@ struct file;
#if defined(_KERNEL) && (defined(__osf__) || defined(AIX) || \
defined(__hpux) || defined(__sgi))
-# ifdef __osf__
-# include <net/radix.h>
-# endif
# include "radix_ipf_local.h"
# define _RADIX_H_
#endif
@@ -78,7 +75,7 @@ static int rn_freenode __P((struct radix_node *, void *));
#if !defined(lint)
static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
-static const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.15 2005/11/13 15:38:37 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.20 2007/05/31 12:27:35 darrenr Exp $";
#endif
#ifdef IPFILTER_LOOKUP
@@ -90,6 +87,9 @@ static const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.15 2005/11/13 15:38:37
# define RADIX_NODE_HEAD_UNLOCK(x) ;
# endif
+static void ip_pool_clearnodes __P((ip_pool_t *));
+static void *ip_pool_exists __P((int, char *));
+
ip_pool_stat_t ipoolstat;
ipfrwlock_t ip_poolrw;
@@ -137,7 +137,7 @@ main(argc, argv)
strcpy(op.iplo_name, "0");
if (ip_pool_create(&op) == 0)
- ipo = ip_pool_find(0, "0");
+ ipo = ip_pool_exists(0, "0");
a.adf_addr.in4.s_addr = 0x0a010203;
b.adf_addr.in4.s_addr = 0xffffffff;
@@ -262,18 +262,14 @@ int ip_pool_init()
void ip_pool_fini()
{
ip_pool_t *p, *q;
- iplookupop_t op;
int i;
ASSERT(rw_read_locked(&ipf_global.ipf_lk) == 0);
for (i = 0; i <= IPL_LOGMAX; i++) {
for (q = ip_pool_list[i]; (p = q) != NULL; ) {
- op.iplo_unit = i;
- (void)strncpy(op.iplo_name, p->ipo_name,
- sizeof(op.iplo_name));
q = p->ipo_next;
- (void) ip_pool_destroy(&op);
+ (void) ip_pool_destroy(i, p->ipo_name);
}
}
@@ -307,8 +303,8 @@ iplookupop_t *op;
stats.ipls_list[i] = ip_pool_list[i];
} else if (unit >= 0 && unit < IPL_LOGSIZE) {
if (op->iplo_name[0] != '\0')
- stats.ipls_list[unit] = ip_pool_find(unit,
- op->iplo_name);
+ stats.ipls_list[unit] = ip_pool_exists(unit,
+ op->iplo_name);
else
stats.ipls_list[unit] = ip_pool_list[unit];
} else
@@ -319,16 +315,15 @@ iplookupop_t *op;
}
-
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_find */
+/* Function: ip_pool_exists */
/* Returns: int - 0 = success, else error */
/* Parameters: ipo(I) - pointer to the pool getting the new node. */
/* */
/* Find a matching pool inside the collection of pools for a particular */
/* device, indicated by the unit number. */
/* ------------------------------------------------------------------------ */
-void *ip_pool_find(unit, name)
+static void *ip_pool_exists(unit, name)
int unit;
char *name;
{
@@ -342,6 +337,29 @@ char *name;
/* ------------------------------------------------------------------------ */
+/* Function: ip_pool_find */
+/* Returns: int - 0 = success, else error */
+/* Parameters: ipo(I) - pointer to the pool getting the new node. */
+/* */
+/* Find a matching pool inside the collection of pools for a particular */
+/* device, indicated by the unit number. If it is marked for deletion then */
+/* pretend it does not exist. */
+/* ------------------------------------------------------------------------ */
+void *ip_pool_find(unit, name)
+int unit;
+char *name;
+{
+ ip_pool_t *p;
+
+ p = ip_pool_exists(unit, name);
+ if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
+ return NULL;
+
+ return p;
+}
+
+
+/* ------------------------------------------------------------------------ */
/* Function: ip_pool_findeq */
/* Returns: int - 0 = success, else error */
/* Parameters: ipo(I) - pointer to the pool getting the new node. */
@@ -375,9 +393,9 @@ addrfamily_t *addr, *mask;
/* */
/* Search the pool for a given address and return a search result. */
/* ------------------------------------------------------------------------ */
-int ip_pool_search(tptr, version, dptr)
+int ip_pool_search(tptr, ipversion, dptr)
void *tptr;
-int version;
+int ipversion;
void *dptr;
{
struct radix_node *rn;
@@ -397,11 +415,11 @@ void *dptr;
bzero(&v, sizeof(v));
v.adf_len = offsetof(addrfamily_t, adf_addr);
- if (version == 4) {
+ if (ipversion == 4) {
v.adf_len += sizeof(addr->in4);
v.adf_addr.in4 = addr->in4;
#ifdef USE_INET6
- } else if (version == 6) {
+ } else if (ipversion == 6) {
v.adf_len += sizeof(addr->in6);
v.adf_addr.in6 = addr->in6;
#endif
@@ -475,6 +493,7 @@ int info;
return ENOMEM;
}
+ x->ipn_ref = 1;
x->ipn_next = ipo->ipo_list;
x->ipn_pnext = &ipo->ipo_list;
if (ipo->ipo_list != NULL)
@@ -498,6 +517,10 @@ int info;
/* when being inserted - assume this has already been done. If the pool is */
/* marked as being anonymous, give it a new, unique, identifier. Call any */
/* other functions required to initialise the structure. */
+/* */
+/* If the structure is flagged for deletion then reset the flag and return, */
+/* as this likely means we've tried to free a pool that is in use (flush) */
+/* and now want to repopulate it with "new" data. */
/* ------------------------------------------------------------------------ */
int ip_pool_create(op)
iplookupop_t *op;
@@ -508,23 +531,37 @@ iplookupop_t *op;
ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
- KMALLOC(h, ip_pool_t *);
- if (h == NULL)
- return ENOMEM;
- bzero(h, sizeof(*h));
+ unit = op->iplo_unit;
- if (rn_inithead((void **)&h->ipo_head,
- offsetof(addrfamily_t, adf_addr) << 3) == 0) {
- KFREE(h);
- return ENOMEM;
- }
+ if ((op->iplo_arg & LOOKUP_ANON) == 0)
+ h = ip_pool_exists(unit, op->iplo_name);
+ else
+ h = NULL;
- unit = op->iplo_unit;
+ if (h != NULL) {
+ if ((h->ipo_flags & IPOOL_DELETE) != 0) {
+ h->ipo_flags &= ~IPOOL_DELETE;
+ return 0;
+ }
+ return EEXIST;
+ } else {
+ KMALLOC(h, ip_pool_t *);
+ if (h == NULL)
+ return ENOMEM;
+ bzero(h, sizeof(*h));
+
+ if (rn_inithead((void **)&h->ipo_head,
+ offsetof(addrfamily_t, adf_addr) << 3) == 0) {
+ KFREE(h);
+ return ENOMEM;
+ }
+ }
- if ((op->iplo_arg & IPOOL_ANON) != 0) {
+ if ((op->iplo_arg & LOOKUP_ANON) != 0) {
ip_pool_t *p;
- poolnum = IPOOL_ANON;
+ h->ipo_flags |= IPOOL_ANON;
+ poolnum = LOOKUP_ANON;
#if defined(SNPRINTF) && defined(_KERNEL)
SNPRINTF(name, sizeof(name), "%x", poolnum);
@@ -549,19 +586,21 @@ iplookupop_t *op;
(void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
(void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
} else {
- (void) strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
+ (void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
}
- h->ipo_ref = 1;
- h->ipo_list = NULL;
- h->ipo_unit = unit;
- h->ipo_next = ip_pool_list[unit];
- if (ip_pool_list[unit] != NULL)
- ip_pool_list[unit]->ipo_pnext = &h->ipo_next;
- h->ipo_pnext = &ip_pool_list[unit];
- ip_pool_list[unit] = h;
-
- ipoolstat.ipls_pools++;
+ if ((h->ipo_flags & IPOOL_DELETE) == 0) {
+ h->ipo_ref = 1;
+ h->ipo_list = NULL;
+ h->ipo_unit = unit;
+ h->ipo_next = ip_pool_list[unit];
+ if (ip_pool_list[unit] != NULL)
+ ip_pool_list[unit]->ipo_pnext = &h->ipo_next;
+ h->ipo_pnext = &ip_pool_list[unit];
+ ip_pool_list[unit] = h;
+
+ ipoolstat.ipls_pools++;
+ }
return 0;
}
@@ -574,36 +613,26 @@ iplookupop_t *op;
/* ipe(I) - address being deleted as a node */
/* Locks: WRITE(ip_poolrw) */
/* */
-/* Add another node to the pool given by ipo. The three parameters passed */
-/* in (addr, mask, info) shold all be stored in the node. */
+/* Remove a node from the pool given by ipo. */
/* ------------------------------------------------------------------------ */
int ip_pool_remove(ipo, ipe)
ip_pool_t *ipo;
ip_pool_node_t *ipe;
{
- ip_pool_node_t **ipp, *n;
ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
- for (ipp = &ipo->ipo_list; (n = *ipp) != NULL; ipp = &n->ipn_next) {
- if (ipe == n) {
- *n->ipn_pnext = n->ipn_next;
- if (n->ipn_next)
- n->ipn_next->ipn_pnext = n->ipn_pnext;
- break;
- }
- }
-
- if (n == NULL)
- return ENOENT;
+ if (ipe->ipn_pnext != NULL)
+ *ipe->ipn_pnext = ipe->ipn_next;
+ if (ipe->ipn_next != NULL)
+ ipe->ipn_next->ipn_pnext = ipe->ipn_pnext;
RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
- ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
+ ipo->ipo_head->rnh_deladdr(&ipe->ipn_addr, &ipe->ipn_mask,
ipo->ipo_head);
RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
- KFREE(n);
- ipoolstat.ipls_nodes--;
+ ip_pool_node_deref(ipe);
return 0;
}
@@ -616,23 +645,28 @@ ip_pool_node_t *ipe;
/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
/* */
/* Search for a pool using paramters passed in and if it's not otherwise */
-/* busy, free it. */
+/* busy, free it. If it is busy, clear all of its nodes, mark it for being */
+/* deleted and return an error saying it is busy. */
/* */
-/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
+/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
/* may not be initialised, we can't use an ASSERT to enforce the locking */
/* assertion that one of the two (ip_poolrw,ipf_global) is held. */
/* ------------------------------------------------------------------------ */
-int ip_pool_destroy(op)
-iplookupop_t *op;
+int ip_pool_destroy(unit, name)
+int unit;
+char *name;
{
ip_pool_t *ipo;
- ipo = ip_pool_find(op->iplo_unit, op->iplo_name);
+ ipo = ip_pool_exists(unit, name);
if (ipo == NULL)
return ESRCH;
- if (ipo->ipo_ref != 1)
- return EBUSY;
+ if (ipo->ipo_ref != 1) {
+ ip_pool_clearnodes(ipo);
+ ipo->ipo_flags |= IPOOL_DELETE;
+ return 0;
+ }
ip_pool_free(ipo);
return 0;
@@ -648,7 +682,7 @@ iplookupop_t *op;
/* Free all pools associated with the device that matches the unit number */
/* passed in with operation. */
/* */
-/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
+/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
/* may not be initialised, we can't use an ASSERT to enforce the locking */
/* assertion that one of the two (ip_poolrw,ipf_global) is held. */
/* ------------------------------------------------------------------------ */
@@ -669,7 +703,7 @@ iplookupflush_t *fp;
(void)strncpy(op.iplo_name, p->ipo_name,
sizeof(op.iplo_name));
q = p->ipo_next;
- err = ip_pool_destroy(&op);
+ err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
if (err == 0)
num++;
else
@@ -690,13 +724,37 @@ iplookupflush_t *fp;
/* all of the address information stored in it, including any tree data */
/* structures also allocated. */
/* */
-/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
+/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
/* may not be initialised, we can't use an ASSERT to enforce the locking */
/* assertion that one of the two (ip_poolrw,ipf_global) is held. */
/* ------------------------------------------------------------------------ */
void ip_pool_free(ipo)
ip_pool_t *ipo;
{
+
+ ip_pool_clearnodes(ipo);
+
+ if (ipo->ipo_next != NULL)
+ ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
+ *ipo->ipo_pnext = ipo->ipo_next;
+ rn_freehead(ipo->ipo_head);
+ KFREE(ipo);
+
+ ipoolstat.ipls_pools--;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ip_pool_clearnodes */
+/* Returns: void */
+/* Parameters: ipo(I) - pointer to pool structure */
+/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
+/* */
+/* Deletes all nodes stored in a pool structure. */
+/* ------------------------------------------------------------------------ */
+static void ip_pool_clearnodes(ipo)
+ip_pool_t *ipo;
+{
ip_pool_node_t *n;
RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
@@ -715,13 +773,6 @@ ip_pool_t *ipo;
RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
ipo->ipo_list = NULL;
- if (ipo->ipo_next != NULL)
- ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
- *ipo->ipo_pnext = ipo->ipo_next;
- rn_freehead(ipo->ipo_head);
- KFREE(ipo);
-
- ipoolstat.ipls_pools--;
}
@@ -741,8 +792,179 @@ ip_pool_t *ipo;
ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
ipo->ipo_ref--;
+
if (ipo->ipo_ref == 0)
ip_pool_free(ipo);
+
+ else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
+ ip_pool_destroy(ipo->ipo_unit, ipo->ipo_name);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ip_pool_node_deref */
+/* Returns: void */
+/* Parameters: ipn(I) - pointer to pool structure */
+/* Locks: WRITE(ip_poolrw) */
+/* */
+/* Drop a reference to the pool node passed in and if we're the last, free */
+/* it all up and adjust the stats accordingly. */
+/* ------------------------------------------------------------------------ */
+void ip_pool_node_deref(ipn)
+ip_pool_node_t *ipn;
+{
+
+ ipn->ipn_ref--;
+
+ if (ipn->ipn_ref == 0) {
+ KFREE(ipn);
+ ipoolstat.ipls_nodes--;
+ }
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ip_pool_getnext */
+/* Returns: void */
+/* Parameters: token(I) - pointer to pool structure */
+/* Parameters: ilp(IO) - pointer to pool iterating structure */
+/* */
+/* ------------------------------------------------------------------------ */
+int ip_pool_getnext(token, ilp)
+ipftoken_t *token;
+ipflookupiter_t *ilp;
+{
+ ip_pool_node_t *node, zn, *nextnode;
+ ip_pool_t *ipo, zp, *nextipo;
+ int err;
+
+ err = 0;
+ node = NULL;
+ nextnode = NULL;
+ ipo = NULL;
+ nextipo = NULL;
+
+ READ_ENTER(&ip_poolrw);
+
+ switch (ilp->ili_otype)
+ {
+ case IPFLOOKUPITER_LIST :
+ ipo = token->ipt_data;
+ if (ipo == NULL) {
+ nextipo = ip_pool_list[(int)ilp->ili_unit];
+ } else {
+ nextipo = ipo->ipo_next;
+ }
+
+ if (nextipo != NULL) {
+ ATOMIC_INC(nextipo->ipo_ref);
+ if (nextipo->ipo_next == NULL)
+ token->ipt_alive = 0;
+ } else {
+ bzero((char *)&zp, sizeof(zp));
+ nextipo = &zp;
+ }
+ break;
+
+ case IPFLOOKUPITER_NODE :
+ node = token->ipt_data;
+ if (node == NULL) {
+ ipo = ip_pool_exists(ilp->ili_unit, ilp->ili_name);
+ if (ipo == NULL)
+ err = ESRCH;
+ else {
+ nextnode = ipo->ipo_list;
+ ipo = NULL;
+ }
+ } else {
+ nextnode = node->ipn_next;
+ }
+
+ if (nextnode != NULL) {
+ ATOMIC_INC(nextnode->ipn_ref);
+ if (nextnode->ipn_next == NULL)
+ token->ipt_alive = 0;
+ } else {
+ bzero((char *)&zn, sizeof(zn));
+ nextnode = &zn;
+ }
+ break;
+ default :
+ err = EINVAL;
+ break;
+ }
+
+ RWLOCK_EXIT(&ip_poolrw);
+
+ if (err != 0)
+ return err;
+
+ switch (ilp->ili_otype)
+ {
+ case IPFLOOKUPITER_LIST :
+ if (ipo != NULL) {
+ WRITE_ENTER(&ip_poolrw);
+ ip_pool_deref(ipo);
+ RWLOCK_EXIT(&ip_poolrw);
+ }
+ token->ipt_data = nextipo;
+ err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
+ if (err != 0)
+ err = EFAULT;
+ break;
+
+ case IPFLOOKUPITER_NODE :
+ if (node != NULL) {
+ WRITE_ENTER(&ip_poolrw);
+ ip_pool_node_deref(node);
+ RWLOCK_EXIT(&ip_poolrw);
+ }
+ token->ipt_data = nextnode;
+ err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
+ if (err != 0)
+ err = EFAULT;
+ break;
+ }
+
+ return err;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ip_pool_iterderef */
+/* Returns: void */
+/* Parameters: ipn(I) - pointer to pool structure */
+/* Locks: WRITE(ip_poolrw) */
+/* */
+/* ------------------------------------------------------------------------ */
+void ip_pool_iterderef(otype, unit, data)
+u_int otype;
+int unit;
+void *data;
+{
+
+ if (data == NULL)
+ return;
+
+ if (unit < 0 || unit > IPL_LOGMAX)
+ return;
+
+ switch (otype)
+ {
+ case IPFLOOKUPITER_LIST :
+ WRITE_ENTER(&ip_poolrw);
+ ip_pool_deref((ip_pool_t *)data);
+ RWLOCK_EXIT(&ip_poolrw);
+ break;
+
+ case IPFLOOKUPITER_NODE :
+ WRITE_ENTER(&ip_poolrw);
+ ip_pool_node_deref((ip_pool_node_t *)data);
+ RWLOCK_EXIT(&ip_poolrw);
+ break;
+ default :
+ break;
+ }
}
@@ -780,5 +1002,4 @@ rn_freehead(rnh)
Free(rnh);
}
# endif
-
#endif /* IPFILTER_LOOKUP */