summaryrefslogtreecommitdiffstats
path: root/sys/contrib/ipfilter/netinet/ip_htable.c
diff options
context:
space:
mode:
authordarrenr <darrenr@FreeBSD.org>2007-06-04 02:54:36 +0000
committerdarrenr <darrenr@FreeBSD.org>2007-06-04 02:54:36 +0000
commita33069b5324be7fb6d5c0a0d785bb0e10eb0aa36 (patch)
tree28d6fb710df6e0ddec4933e69ec29d2ecd78a134 /sys/contrib/ipfilter/netinet/ip_htable.c
parent1dd4fa592dfed4984b91696b53e64e8c075f63eb (diff)
downloadFreeBSD-src-a33069b5324be7fb6d5c0a0d785bb0e10eb0aa36.zip
FreeBSD-src-a33069b5324be7fb6d5c0a0d785bb0e10eb0aa36.tar.gz
Merge IPFilter 4.1.23 back to HEAD
See src/contrib/ipfilter/HISTORY for details of changes since 4.1.13
Diffstat (limited to 'sys/contrib/ipfilter/netinet/ip_htable.c')
-rw-r--r--sys/contrib/ipfilter/netinet/ip_htable.c406
1 files changed, 303 insertions, 103 deletions
diff --git a/sys/contrib/ipfilter/netinet/ip_htable.c b/sys/contrib/ipfilter/netinet/ip_htable.c
index aaecaa6..3882156 100644
--- a/sys/contrib/ipfilter/netinet/ip_htable.c
+++ b/sys/contrib/ipfilter/netinet/ip_htable.c
@@ -53,7 +53,7 @@ struct file;
/* END OF INCLUDES */
#if !defined(lint)
-static const char rcsid[] = "@(#)$Id: ip_htable.c,v 2.34.2.4 2005/11/13 15:38:37 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id: ip_htable.c,v 2.34.2.9 2007/02/02 23:06:16 darrenr Exp $";
#endif
#ifdef IPFILTER_LOOKUP
@@ -103,30 +103,36 @@ iplookupop_t *op;
char name[FR_GROUPLEN];
int err, i, unit;
- KMALLOC(iph, iphtable_t *);
- if (iph == NULL) {
- ipht_nomem[op->iplo_unit]++;
- return ENOMEM;
- }
+ unit = op->iplo_unit;
+ if ((op->iplo_arg & IPHASH_ANON) == 0)
+ iph = fr_existshtable(unit, op->iplo_name);
+ else
+ iph = NULL;
- err = COPYIN(op->iplo_struct, iph, sizeof(*iph));
- if (err != 0) {
- KFREE(iph);
- return EFAULT;
+ if (iph == NULL) {
+ KMALLOC(iph, iphtable_t *);
+ if (iph == NULL) {
+ ipht_nomem[op->iplo_unit]++;
+ return ENOMEM;
+ }
+ err = COPYIN(op->iplo_struct, iph, sizeof(*iph));
+ if (err != 0) {
+ KFREE(iph);
+ return EFAULT;
+ }
+ } else {
+ if ((iph->iph_flags & IPHASH_DELETE) == 0)
+ return EEXIST;
}
- unit = op->iplo_unit;
if (iph->iph_unit != unit) {
- KFREE(iph);
+ if ((iph->iph_flags & IPHASH_DELETE) == 0) {
+ KFREE(iph);
+ }
return EINVAL;
}
- if ((op->iplo_arg & IPHASH_ANON) == 0) {
- if (fr_findhtable(op->iplo_unit, op->iplo_name) != NULL) {
- KFREE(iph);
- return EEXIST;
- }
- } else {
+ if ((op->iplo_arg & IPHASH_ANON) != 0) {
i = IPHASH_ANON;
do {
i++;
@@ -147,24 +153,33 @@ iplookupop_t *op;
iph->iph_type |= IPHASH_ANON;
}
- KMALLOCS(iph->iph_table, iphtent_t **,
- iph->iph_size * sizeof(*iph->iph_table));
- if (iph->iph_table == NULL) {
- KFREE(iph);
- ipht_nomem[unit]++;
- return ENOMEM;
- }
+ if ((iph->iph_flags & IPHASH_DELETE) == 0) {
+ KMALLOCS(iph->iph_table, iphtent_t **,
+ iph->iph_size * sizeof(*iph->iph_table));
+ if (iph->iph_table == NULL) {
+ if ((iph->iph_flags & IPHASH_DELETE) == 0) {
+ KFREE(iph);
+ }
+ ipht_nomem[unit]++;
+ return ENOMEM;
+ }
- bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
- iph->iph_masks = 0;
+ bzero((char *)iph->iph_table,
+ iph->iph_size * sizeof(*iph->iph_table));
+ iph->iph_masks = 0;
+ iph->iph_list = NULL;
- iph->iph_next = ipf_htables[unit];
- iph->iph_pnext = &ipf_htables[unit];
- if (ipf_htables[unit] != NULL)
- ipf_htables[unit]->iph_pnext = &iph->iph_next;
- ipf_htables[unit] = iph;
+ iph->iph_ref = 1;
+ iph->iph_next = ipf_htables[unit];
+ iph->iph_pnext = &ipf_htables[unit];
+ if (ipf_htables[unit] != NULL)
+ ipf_htables[unit]->iph_pnext = &iph->iph_next;
+ ipf_htables[unit] = iph;
- ipf_nhtables[unit]++;
+ ipf_nhtables[unit]++;
+ }
+
+ iph->iph_flags &= ~IPHASH_DELETE;
return 0;
}
@@ -172,22 +187,24 @@ iplookupop_t *op;
/*
*/
-int fr_removehtable(op)
-iplookupop_t *op;
+int fr_removehtable(unit, name)
+int unit;
+char *name;
{
iphtable_t *iph;
-
- iph = fr_findhtable(op->iplo_unit, op->iplo_name);
+ iph = fr_findhtable(unit, name);
if (iph == NULL)
return ESRCH;
- if (iph->iph_unit != op->iplo_unit) {
+ if (iph->iph_unit != unit) {
return EINVAL;
}
if (iph->iph_ref != 0) {
- return EBUSY;
+ (void) fr_clearhtable(iph);
+ iph->iph_flags |= IPHASH_DELETE;
+ return 0;
}
fr_delhtable(iph);
@@ -196,40 +213,106 @@ iplookupop_t *op;
}
-void fr_delhtable(iph)
+int fr_clearhtable(iph)
iphtable_t *iph;
{
iphtent_t *ipe;
- int i;
- for (i = 0; i < iph->iph_size; i++)
- while ((ipe = iph->iph_table[i]) != NULL)
- if (fr_delhtent(iph, ipe) != 0)
- return;
+ while ((ipe = iph->iph_list) != NULL)
+ if (fr_delhtent(iph, ipe) != 0)
+ return 1;
+ return 0;
+}
+
- *iph->iph_pnext = iph->iph_next;
+int fr_delhtable(iph)
+iphtable_t *iph;
+{
+
+ if (fr_clearhtable(iph) != 0)
+ return 1;
+
+ if (iph->iph_pnext != NULL)
+ *iph->iph_pnext = iph->iph_next;
if (iph->iph_next != NULL)
iph->iph_next->iph_pnext = iph->iph_pnext;
ipf_nhtables[iph->iph_unit]--;
+ return fr_derefhtable(iph);
+}
+
+
+/*
+ * Delete an entry from a hash table.
+ */
+int fr_delhtent(iph, ipe)
+iphtable_t *iph;
+iphtent_t *ipe;
+{
+
+ if (ipe->ipe_phnext != NULL)
+ *ipe->ipe_phnext = ipe->ipe_hnext;
+ if (ipe->ipe_hnext != NULL)
+ ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext;
+
+ if (ipe->ipe_pnext != NULL)
+ *ipe->ipe_pnext = ipe->ipe_next;
+ if (ipe->ipe_next != NULL)
+ ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
+
+ switch (iph->iph_type & ~IPHASH_ANON)
+ {
+ case IPHASH_GROUPMAP :
+ if (ipe->ipe_group != NULL)
+ fr_delgroup(ipe->ipe_group, IPL_LOGIPF, fr_active);
+ break;
+
+ default :
+ ipe->ipe_ptr = NULL;
+ ipe->ipe_value = 0;
+ break;
+ }
+
+ return fr_derefhtent(ipe);
+}
+
+
+int fr_derefhtable(iph)
+iphtable_t *iph;
+{
+ int refs;
+
+ iph->iph_ref--;
+ refs = iph->iph_ref;
+
if (iph->iph_ref == 0) {
KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
KFREE(iph);
}
+
+ return refs;
}
-void fr_derefhtable(iph)
-iphtable_t *iph;
+int fr_derefhtent(ipe)
+iphtent_t *ipe;
{
- iph->iph_ref--;
- if (iph->iph_ref == 0)
- fr_delhtable(iph);
+
+ ipe->ipe_ref--;
+ if (ipe->ipe_ref == 0) {
+ ipf_nhtnodes[ipe->ipe_unit]--;
+
+ KFREE(ipe);
+
+ return 0;
+ }
+
+ return ipe->ipe_ref;
}
-iphtable_t *fr_findhtable(unit, name)
+iphtable_t *fr_existshtable(unit, name)
int unit;
char *name;
{
@@ -242,6 +325,20 @@ char *name;
}
+iphtable_t *fr_findhtable(unit, name)
+int unit;
+char *name;
+{
+ iphtable_t *iph;
+
+ iph = fr_existshtable(unit, name);
+ if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0)
+ return iph;
+
+ return NULL;
+}
+
+
size_t fr_flushhtable(op)
iplookupflush_t *op;
{
@@ -254,8 +351,11 @@ iplookupflush_t *op;
for (i = 0; i <= IPL_LOGMAX; i++) {
if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
while ((iph = ipf_htables[i]) != NULL) {
- fr_delhtable(iph);
- freed++;
+ if (fr_delhtable(iph) == 0) {
+ freed++;
+ } else {
+ iph->iph_flags |= IPHASH_DELETE;
+ }
}
}
}
@@ -287,13 +387,20 @@ iphtent_t *ipeo;
hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr,
iph->iph_size);
- ipe->ipe_ref = 0;
- ipe->ipe_next = iph->iph_table[hv];
- ipe->ipe_pnext = iph->iph_table + hv;
+ ipe->ipe_ref = 1;
+ ipe->ipe_hnext = iph->iph_table[hv];
+ ipe->ipe_phnext = iph->iph_table + hv;
if (iph->iph_table[hv] != NULL)
- iph->iph_table[hv]->ipe_pnext = &ipe->ipe_next;
+ iph->iph_table[hv]->ipe_phnext = &ipe->ipe_hnext;
iph->iph_table[hv] = ipe;
+
+ ipe->ipe_next = iph->iph_list;
+ ipe->ipe_pnext = &iph->iph_list;
+ if (ipe->ipe_next != NULL)
+ ipe->ipe_next->ipe_pnext = &ipe->ipe_next;
+ iph->iph_list = ipe;
+
if ((bits >= 0) && (bits != 32))
iph->iph_masks |= 1 << bits;
@@ -311,44 +418,8 @@ iphtent_t *ipeo;
break;
}
- ipf_nhtnodes[iph->iph_unit]++;
-
- return 0;
-}
-
-
-/*
- * Delete an entry from a hash table.
- */
-int fr_delhtent(iph, ipe)
-iphtable_t *iph;
-iphtent_t *ipe;
-{
-
- if (ipe->ipe_ref != 0)
- return EBUSY;
-
-
- *ipe->ipe_pnext = ipe->ipe_next;
- if (ipe->ipe_next != NULL)
- ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
-
- switch (iph->iph_type & ~IPHASH_ANON)
- {
- case IPHASH_GROUPMAP :
- if (ipe->ipe_group != NULL)
- fr_delgroup(ipe->ipe_group, IPL_LOGIPF, fr_active);
- break;
-
- default :
- ipe->ipe_ptr = NULL;
- ipe->ipe_value = 0;
- break;
- }
-
- KFREE(ipe);
-
- ipf_nhtnodes[iph->iph_unit]--;
+ ipe->ipe_unit = iph->iph_unit;
+ ipf_nhtnodes[ipe->ipe_unit]++;
return 0;
}
@@ -379,22 +450,22 @@ void *tptr, *aptr;
/* ------------------------------------------------------------------------ */
/* Function: fr_iphmfindip */
/* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
-/* Parameters: tptr(I) - pointer to the pool to search */
-/* version(I) - IP protocol version (4 or 6) */
-/* aptr(I) - pointer to address information */
+/* Parameters: tptr(I) - pointer to the pool to search */
+/* ipversion(I) - IP protocol version (4 or 6) */
+/* aptr(I) - pointer to address information */
/* */
/* Search the hash table for a given address and return a search result. */
/* ------------------------------------------------------------------------ */
-int fr_iphmfindip(tptr, version, aptr)
+int fr_iphmfindip(tptr, ipversion, aptr)
void *tptr, *aptr;
-int version;
+int ipversion;
{
struct in_addr *addr;
iphtable_t *iph;
iphtent_t *ipe;
int rval;
- if (version != 4)
+ if (ipversion != 4)
return -1;
if (tptr == NULL || aptr == NULL)
@@ -428,7 +499,7 @@ struct in_addr *addr;
maskloop:
ips = ntohl(addr->s_addr) & msk;
hv = IPE_HASH_FN(ips, msk, iph->iph_size);
- for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
+ for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_hnext) {
if (ipe->ipe_mask.in4_addr != msk ||
ipe->ipe_addr.in4_addr != ips) {
continue;
@@ -451,4 +522,133 @@ maskloop:
return ipe;
}
+
+int fr_htable_getnext(token, ilp)
+ipftoken_t *token;
+ipflookupiter_t *ilp;
+{
+ iphtent_t *node, zn, *nextnode;
+ iphtable_t *iph, zp, *nextiph;
+ int err;
+
+ err = 0;
+ iph = NULL;
+ node = NULL;
+ nextiph = NULL;
+ nextnode = NULL;
+
+ READ_ENTER(&ip_poolrw);
+
+ switch (ilp->ili_otype)
+ {
+ case IPFLOOKUPITER_LIST :
+ iph = token->ipt_data;
+ if (iph == NULL) {
+ nextiph = ipf_htables[(int)ilp->ili_unit];
+ } else {
+ nextiph = iph->iph_next;
+ }
+
+ if (nextiph != NULL) {
+ ATOMIC_INC(nextiph->iph_ref);
+ if (nextiph->iph_next == NULL)
+ token->ipt_alive = 0;
+ } else {
+ bzero((char *)&zp, sizeof(zp));
+ nextiph = &zp;
+ }
+ break;
+
+ case IPFLOOKUPITER_NODE :
+ node = token->ipt_data;
+ if (node == NULL) {
+ iph = fr_findhtable(ilp->ili_unit, ilp->ili_name);
+ if (iph == NULL)
+ err = ESRCH;
+ else {
+ nextnode = iph->iph_list;
+ }
+ } else {
+ nextnode = node->ipe_next;
+ }
+
+ if (nextnode != NULL) {
+ ATOMIC_INC(nextnode->ipe_ref);
+ if (nextnode->ipe_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 (iph != NULL) {
+ WRITE_ENTER(&ip_poolrw);
+ fr_derefhtable(iph);
+ RWLOCK_EXIT(&ip_poolrw);
+ }
+ token->ipt_data = nextiph;
+ err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
+ if (err != 0)
+ err = EFAULT;
+ break;
+
+ case IPFLOOKUPITER_NODE :
+ if (node != NULL) {
+ WRITE_ENTER(&ip_poolrw);
+ fr_derefhtent(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;
+}
+
+
+void fr_htable_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);
+ fr_derefhtable((iphtable_t *)data);
+ RWLOCK_EXIT(&ip_poolrw);
+ break;
+
+ case IPFLOOKUPITER_NODE :
+ WRITE_ENTER(&ip_poolrw);
+ fr_derefhtent((iphtent_t *)data);
+ RWLOCK_EXIT(&ip_poolrw);
+ break;
+ default :
+ break;
+ }
+}
+
#endif /* IPFILTER_LOOKUP */
OpenPOWER on IntegriCloud