diff options
author | darrenr <darrenr@FreeBSD.org> | 2007-06-04 02:54:36 +0000 |
---|---|---|
committer | darrenr <darrenr@FreeBSD.org> | 2007-06-04 02:54:36 +0000 |
commit | a33069b5324be7fb6d5c0a0d785bb0e10eb0aa36 (patch) | |
tree | 28d6fb710df6e0ddec4933e69ec29d2ecd78a134 /sys/contrib/ipfilter/netinet/ip_frag.c | |
parent | 1dd4fa592dfed4984b91696b53e64e8c075f63eb (diff) | |
download | FreeBSD-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_frag.c')
-rw-r--r-- | sys/contrib/ipfilter/netinet/ip_frag.c | 194 |
1 files changed, 162 insertions, 32 deletions
diff --git a/sys/contrib/ipfilter/netinet/ip_frag.c b/sys/contrib/ipfilter/netinet/ip_frag.c index 5a93295..02e7bd1 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.c +++ b/sys/contrib/ipfilter/netinet/ip_frag.c @@ -107,16 +107,17 @@ static const char rcsid[] = "@(#)$FreeBSD$"; #endif -static ipfr_t *ipfr_list = NULL; -static ipfr_t **ipfr_tail = &ipfr_list; -static ipfr_t **ipfr_heads; +ipfr_t *ipfr_list = NULL; +ipfr_t **ipfr_tail = &ipfr_list; -static ipfr_t *ipfr_natlist = NULL; -static ipfr_t **ipfr_nattail = &ipfr_natlist; -static ipfr_t **ipfr_nattab; +ipfr_t *ipfr_natlist = NULL; +ipfr_t **ipfr_nattail = &ipfr_natlist; -static ipfr_t *ipfr_ipidlist = NULL; -static ipfr_t **ipfr_ipidtail = &ipfr_ipidlist; +ipfr_t *ipfr_ipidlist = NULL; +ipfr_t **ipfr_ipidtail = &ipfr_ipidlist; + +static ipfr_t **ipfr_heads; +static ipfr_t **ipfr_nattab; static ipfr_t **ipfr_ipidtab; static ipfrstat_t ipfr_stats; @@ -132,6 +133,7 @@ u_long fr_ticks = 0; static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **)); static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **)); static void fr_fragdelete __P((ipfr_t *, ipfr_t ***)); +static void fr_fragfree __P((ipfr_t *)); /* ------------------------------------------------------------------------ */ @@ -308,6 +310,7 @@ ipfr_t *table[]; fra->ipfr_seen0 = 1; fra->ipfr_off = off + (fin->fin_dlen >> 3); fra->ipfr_pass = pass; + fra->ipfr_ref = 1; ipfr_stats.ifs_new++; ipfr_inuse++; return fra; @@ -688,11 +691,6 @@ void *ptr; static void fr_fragdelete(fra, tail) ipfr_t *fra, ***tail; { - frentry_t *fr; - - fr = fra->ipfr_rule; - if (fr != NULL) - (void)fr_derefrule(&fr); if (fra->ipfr_next) fra->ipfr_next->ipfr_prev = fra->ipfr_prev; @@ -703,7 +701,30 @@ ipfr_t *fra, ***tail; if (fra->ipfr_hnext) fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev; *fra->ipfr_hprev = fra->ipfr_hnext; + + if (fra->ipfr_rule != NULL) { + (void) fr_derefrule(&fra->ipfr_rule); + } + + if (fra->ipfr_ref <= 0) + fr_fragfree(fra); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_fragfree */ +/* Returns: Nil */ +/* Parameters: fra - pointer to frag structure to free */ +/* */ +/* Take care of the details associated with deleting an entry from the frag */ +/* cache. Currently this just means bumping stats correctly after freeing */ +/* ------------------------------------------------------------------------ */ +static void fr_fragfree(fra) +ipfr_t *fra; +{ KFREE(fra); + ipfr_stats.ifs_expire++; + ipfr_inuse--; } @@ -721,8 +742,10 @@ void fr_fragclear() nat_t *nat; WRITE_ENTER(&ipf_frag); - while ((fra = ipfr_list) != NULL) + while ((fra = ipfr_list) != NULL) { + fra->ipfr_ref--; fr_fragdelete(fra, &ipfr_tail); + } ipfr_tail = &ipfr_list; RWLOCK_EXIT(&ipf_frag); @@ -734,6 +757,7 @@ void fr_fragclear() if (nat->nat_data == fra) nat->nat_data = NULL; } + fra->ipfr_ref--; fr_fragdelete(fra, &ipfr_nattail); } ipfr_nattail = &ipfr_natlist; @@ -767,9 +791,8 @@ void fr_fragexpire() for (fp = &ipfr_list; ((fra = *fp) != NULL); ) { if (fra->ipfr_ttl > fr_ticks) break; + fra->ipfr_ref--; fr_fragdelete(fra, &ipfr_tail); - ipfr_stats.ifs_expire++; - ipfr_inuse--; } RWLOCK_EXIT(&ipf_frag); @@ -777,9 +800,8 @@ void fr_fragexpire() for (fp = &ipfr_ipidlist; ((fra = *fp) != NULL); ) { if (fra->ipfr_ttl > fr_ticks) break; + fra->ipfr_ref--; fr_fragdelete(fra, &ipfr_ipidtail); - ipfr_stats.ifs_expire++; - ipfr_inuse--; } RWLOCK_EXIT(&ipf_ipidfrag); @@ -789,23 +811,27 @@ void fr_fragexpire() * at the one to be free'd, NULL the reference from the NAT struct. * NOTE: We need to grab both mutex's early, and in this order so as * to prevent a deadlock if both try to expire at the same time. + * The extra if() statement here is because it locks out all NAT + * operations - no need to do that if there are no entries in this + * list, right? */ - WRITE_ENTER(&ipf_nat); - WRITE_ENTER(&ipf_natfrag); - for (fp = &ipfr_natlist; ((fra = *fp) != NULL); ) { - if (fra->ipfr_ttl > fr_ticks) - break; - nat = fra->ipfr_data; - if (nat != NULL) { - if (nat->nat_data == fra) - nat->nat_data = NULL; + if (ipfr_natlist != NULL) { + WRITE_ENTER(&ipf_nat); + WRITE_ENTER(&ipf_natfrag); + for (fp = &ipfr_natlist; ((fra = *fp) != NULL); ) { + if (fra->ipfr_ttl > fr_ticks) + break; + nat = fra->ipfr_data; + if (nat != NULL) { + if (nat->nat_data == fra) + nat->nat_data = NULL; + } + fra->ipfr_ref--; + fr_fragdelete(fra, &ipfr_nattail); } - fr_fragdelete(fra, &ipfr_nattail); - ipfr_stats.ifs_expire++; - ipfr_inuse--; + RWLOCK_EXIT(&ipf_natfrag); + RWLOCK_EXIT(&ipf_nat); } - RWLOCK_EXIT(&ipf_natfrag); - RWLOCK_EXIT(&ipf_nat); SPL_X(s); } @@ -828,6 +854,7 @@ int fr_slowtimer() { READ_ENTER(&ipf_global); + ipf_expiretokens(); fr_fragexpire(); fr_timeoutstate(); fr_natexpire(); @@ -861,3 +888,106 @@ done: # endif } #endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */ + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_nextfrag */ +/* Returns: int - 0 == success, else error */ +/* Parameters: token(I) - pointer to token information for this caller */ +/* itp(I) - pointer to generic iterator from caller */ +/* top(I) - top of the fragment list */ +/* tail(I) - tail of the fragment list */ +/* lock(I) - fragment cache lock */ +/* */ +/* This function is used to interate through the list of entries in the */ +/* fragment cache. It increases the reference count on the one currently */ +/* being returned so that the caller can come back and resume from it later.*/ +/* */ +/* This function is used for both the NAT fragment cache as well as the ipf */ +/* fragment cache - hence the reason for passing in top, tail and lock. */ +/* ------------------------------------------------------------------------ */ +int fr_nextfrag(token, itp, top, tail +#ifdef USE_MUTEXES +, lock +#endif +) +ipftoken_t *token; +ipfgeniter_t *itp; +ipfr_t **top, ***tail; +#ifdef USE_MUTEXES +ipfrwlock_t *lock; +#endif +{ + ipfr_t *frag, *next, zero; + int error = 0; + + frag = token->ipt_data; + if (frag == (ipfr_t *)-1) { + ipf_freetoken(token); + return ESRCH; + } + + READ_ENTER(lock); + if (frag == NULL) + next = *top; + else + next = frag->ipfr_next; + + if (next != NULL) { + ATOMIC_INC(next->ipfr_ref); + token->ipt_data = next; + } else { + bzero(&zero, sizeof(zero)); + next = &zero; + token->ipt_data = (void *)-1; + } + RWLOCK_EXIT(lock); + + if (frag != NULL) { + WRITE_ENTER(lock); + frag->ipfr_ref--; + if (frag->ipfr_ref <= 0) + fr_fragfree(frag); + RWLOCK_EXIT(lock); + } + + error = COPYOUT(next, itp->igi_data, sizeof(*next)); + if (error != 0) + error = EFAULT; + + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_fragderef */ +/* Returns: Nil */ +/* Parameters: frp(IO) - pointer to fragment structure to deference */ +/* lock(I) - lock associated with the fragment */ +/* */ +/* This function dereferences a fragment structure (ipfr_t). The pointer */ +/* passed in will always be reset back to NULL, even if the structure is */ +/* not freed, to enforce the notion that the caller is no longer entitled */ +/* to use the pointer it is dropping the reference to. */ +/* ------------------------------------------------------------------------ */ +void fr_fragderef(frp +#ifdef USE_MUTEXES +, lock +#endif +) +ipfr_t **frp; +#ifdef USE_MUTEXES +ipfrwlock_t *lock; +#endif +{ + ipfr_t *fra; + + fra = *frp; + *frp = NULL; + + WRITE_ENTER(lock); + fra->ipfr_ref--; + if (fra->ipfr_ref <= 0) + fr_fragfree(fra); + RWLOCK_EXIT(lock); +} |