[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

cls_tcindex, combined patch (tcicomb)



Since the number of cls_tcindex patches is getting a bit confusing, I've
made a combined patch of tcinext, tcihsh2, and tcinull. tcihsh2 is an
update of tcihash, which fixes overly restrictive range checks introduced
in tcihash.

This patch is for 2.4.2-pre1 and similar.

- Werner

------------------------------------ patch ------------------------------------

--- linux.orig/net/sched/cls_tcindex.c	Fri Aug 18 19:26:25 2000
+++ linux/net/sched/cls_tcindex.c	Sat Feb 17 09:57:12 2001
@@ -76,7 +76,7 @@
 	struct tcindex_filter *f;
 
 	if (p->perfect)
-		return p->perfect[key].res.classid ? p->perfect+key : NULL;
+		return p->perfect[key].res.class ? p->perfect+key : NULL;
 	if (!p->h)
 		return NULL;
 	for (f = p->h[key % p->hash]; f; f = f->next) {
@@ -122,8 +122,14 @@
 
 static unsigned long tcindex_get(struct tcf_proto *tp, u32 handle)
 {
+	struct tcindex_data *p = PRIV(tp);
+	struct tcindex_filter_result *r;
+
 	DPRINTK("tcindex_get(tp %p,handle 0x%08x)\n",tp,handle);
-	return (unsigned long) lookup(PRIV(tp),handle);
+	if (p->perfect && handle >= p->alloc_hash)
+		return 0;
+	r = lookup(PRIV(tp),handle);
+	return r && r->res.class ? (unsigned long) r : 0;
 }
 
 
@@ -164,7 +170,7 @@
 
 	DPRINTK("tcindex_delete(tp %p,arg 0x%lx),p %p,f %p\n",tp,arg,p,f);
 	if (p->perfect) {
-		if (!r->res.classid)
+		if (!r->res.class)
 			return -ENOENT;
 	} else {
 		int i;
@@ -212,7 +218,7 @@
 	struct tcindex_filter *f;
 	struct tcindex_filter_result *r = (struct tcindex_filter_result *) *arg;
 	struct tcindex_filter **walk;
-	int hash;
+	int hash,shift;
 	__u16 mask;
 
 	DPRINTK("tcindex_change(tp %p,handle 0x%08x,tca %p,arg %p),opt %p,"
@@ -237,17 +243,22 @@
 			return -EINVAL;
 		mask = *(__u16 *) RTA_DATA(tb[TCA_TCINDEX_MASK-1]);
 	}
-	if (p->perfect && hash <= mask)
+	if (!tb[TCA_TCINDEX_SHIFT-1])
+		shift = p->shift;
+	else {
+		if (RTA_PAYLOAD(tb[TCA_TCINDEX_SHIFT-1]) < sizeof(__u16))
+			return -EINVAL;
+		shift = *(int *) RTA_DATA(tb[TCA_TCINDEX_SHIFT-1]);
+	}
+	if (p->perfect && hash <= (mask >> shift))
 		return -EBUSY;
-	if ((p->perfect || p->h) && hash > p->alloc_hash)
+	if (p->perfect && hash > p->alloc_hash)
+		return -EBUSY;
+	if (p->h && hash != p->alloc_hash)
 		return -EBUSY;
 	p->hash = hash;
 	p->mask = mask;
-	if (tb[TCA_TCINDEX_SHIFT-1]) {
-		if (RTA_PAYLOAD(tb[TCA_TCINDEX_SHIFT-1]) < sizeof(__u16))
-			return -EINVAL;
-		p->shift = *(int *) RTA_DATA(tb[TCA_TCINDEX_SHIFT-1]);
-	}
+	p->shift = shift;
 	if (tb[TCA_TCINDEX_FALL_THROUGH-1]) {
 		if (RTA_PAYLOAD(tb[TCA_TCINDEX_FALL_THROUGH-1]) < sizeof(int))
 			return -EINVAL;
@@ -258,9 +269,9 @@
 	    tb[TCA_TCINDEX_POLICE-1]);
 	if (!tb[TCA_TCINDEX_CLASSID-1] && !tb[TCA_TCINDEX_POLICE-1])
 		return 0;
-	if (!p->hash) {
-		if (p->mask < PERFECT_HASH_THRESHOLD) {
-			p->hash = p->mask+1;
+	if (!hash) {
+		if ((mask >> shift) < PERFECT_HASH_THRESHOLD) {
+			p->hash = (mask >> shift)+1;
 		} else {
 			p->hash = DEFAULT_HASH_SIZE;
 		}
@@ -268,7 +279,7 @@
 	if (!p->perfect && !p->h) {
 		p->alloc_hash = p->hash;
 		DPRINTK("hash %d mask %d\n",p->hash,p->mask);
-		if (p->hash > p->mask) {
+		if (p->hash > (mask >> shift)) {
 			p->perfect = kmalloc(p->hash*
 			    sizeof(struct tcindex_filter_result),GFP_KERNEL);
 			if (!p->perfect)
@@ -283,7 +294,15 @@
 			memset(p->h, 0, p->hash*sizeof(struct tcindex_filter *));
 		}
 	}
-	if (handle > p->mask)
+	/*
+	 * Note: this could be as restrictive as
+	 * if (handle & ~(mask >> shift))
+	 * but then, we'd fail handles that may become valid after some
+	 * future mask change. While this is extremely unlikely to ever
+	 * matter, the check below is safer (and also more
+	 * backwards-compatible).
+	 */
+	if (p->perfect && handle >= p->alloc_hash)
 		return -EINVAL;
 	if (p->perfect) {
 		r = p->perfect+handle;
@@ -339,13 +358,13 @@
 static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker)
 {
 	struct tcindex_data *p = PRIV(tp);
-	struct tcindex_filter *f;
+	struct tcindex_filter *f,*next;
 	int i;
 
 	DPRINTK("tcindex_walk(tp %p,walker %p),p %p\n",tp,walker,p);
 	if (p->perfect) {
 		for (i = 0; i < p->hash; i++) {
-			if (!p->perfect[i].res.classid)
+			if (!p->perfect[i].res.class)
 				continue;
 			if (walker->count >= walker->skip) {
 				if (walker->fn(tp,
@@ -361,7 +380,8 @@
 	if (!p->h)
 		return;
 	for (i = 0; i < p->hash; i++) {
-		for (f = p->h[i]; f; f = f->next) {
+		for (f = p->h[i]; f; f = next) {
+			next = f->next;
 			if (walker->count >= walker->skip) {
 				if (walker->fn(tp,(unsigned long) &f->result,
 				    walker) < 0) {

-- 
  _________________________________________________________________________
 / Werner Almesberger, ICA, EPFL, CH           Werner.Almesberger@epfl.ch /
/_IN_N_032__Tel_+41_21_693_6621__Fax_+41_21_693_6610_____________________/