summaryrefslogtreecommitdiffstats
path: root/sys/contrib/ipfilter/netinet/ip_frag.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_frag.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_frag.c')
-rw-r--r--sys/contrib/ipfilter/netinet/ip_frag.c194
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);
+}
OpenPOWER on IntegriCloud