Netdev List
 help / color / mirror / Atom feed
* [Patch net-next] net_sched: move the empty tp check from ->destroy() to ->delete()
From: Cong Wang @ 2016-11-24  1:58 UTC (permalink / raw)
  To: netdev; +Cc: roid, jiri, Cong Wang, Daniel Borkmann, John Fastabend

Roi reported we could have a race condition where in ->classify() path
we dereference tp->root and meanwhile a parallel ->destroy() makes it
a NULL.

This is possible because ->destroy() could be called when deleting
a filter to check if we are the last one in tp, this tp is still
linked and visible at that time.

The root cause of this problem is the semantic of ->destroy(), it
does two things (for non-force case):

1) check if tp is empty
2) if tp is empty we could really destroy it

and its caller, if cares, needs to check its return value to see if
it is really destroyed. Therefore we can't unlink tp unless we know
it is empty.

As suggested by Daniel, we could actually move the test logic to ->delete()
so that we can safely unlink tp after ->delete() tells us the last one is
just deleted and before ->destroy().

What's more, even we unlink it before ->destroy(), it could still have
readers since we don't wait for a grace period here, we should not modify
tp->root in ->destroy() either.

Fixes: 1e052be69d04 ("net_sched: destroy proto tp when all filters are gone")
Reported-by: Roi Dayan <roid@mellanox.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: John Fastabend <john.fastabend@gmail.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
---
 include/net/sch_generic.h |  6 ++--
 net/sched/cls_api.c       | 18 +++++++-----
 net/sched/cls_basic.c     | 11 +++-----
 net/sched/cls_bpf.c       | 11 +++-----
 net/sched/cls_cgroup.c    | 12 ++------
 net/sched/cls_flow.c      | 11 +++-----
 net/sched/cls_flower.c    | 10 ++-----
 net/sched/cls_fw.c        | 30 +++++++++++---------
 net/sched/cls_matchall.c  | 10 ++-----
 net/sched/cls_route.c     | 30 ++++++++++----------
 net/sched/cls_rsvp.h      | 34 +++++++++++------------
 net/sched/cls_tcindex.c   | 15 +++++-----
 net/sched/cls_u32.c       | 71 +++++++++++++++++++++++++++--------------------
 net/sched/sch_api.c       | 14 ++++------
 14 files changed, 137 insertions(+), 146 deletions(-)

diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index e6aa0a2..27cd1bd 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -203,14 +203,14 @@ struct tcf_proto_ops {
 					    const struct tcf_proto *,
 					    struct tcf_result *);
 	int			(*init)(struct tcf_proto*);
-	bool			(*destroy)(struct tcf_proto*, bool);
+	void			(*destroy)(struct tcf_proto*);
 
 	unsigned long		(*get)(struct tcf_proto*, u32 handle);
 	int			(*change)(struct net *net, struct sk_buff *,
 					struct tcf_proto*, unsigned long,
 					u32 handle, struct nlattr **,
 					unsigned long *, bool);
-	int			(*delete)(struct tcf_proto*, unsigned long);
+	int			(*delete)(struct tcf_proto*, unsigned long, bool*);
 	void			(*walk)(struct tcf_proto*, struct tcf_walker *arg);
 
 	/* rtnetlink specific */
@@ -405,7 +405,7 @@ struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
 				const struct Qdisc_ops *ops, u32 parentid);
 void __qdisc_calculate_pkt_len(struct sk_buff *skb,
 			       const struct qdisc_size_table *stab);
-bool tcf_destroy(struct tcf_proto *tp, bool force);
+void tcf_destroy(struct tcf_proto *tp);
 void tcf_destroy_chain(struct tcf_proto __rcu **fl);
 int skb_do_redirect(struct sk_buff *);
 
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 8e93d4a..f159aeb 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -321,7 +321,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
 
 			tfilter_notify(net, skb, n, tp, fh,
 				       RTM_DELTFILTER, false);
-			tcf_destroy(tp, true);
+			tcf_destroy(tp);
 			err = 0;
 			goto errout;
 		}
@@ -331,25 +331,29 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
 		    !(n->nlmsg_flags & NLM_F_CREATE))
 			goto errout;
 	} else {
+		bool last;
+
 		switch (n->nlmsg_type) {
 		case RTM_NEWTFILTER:
 			err = -EEXIST;
 			if (n->nlmsg_flags & NLM_F_EXCL) {
 				if (tp_created)
-					tcf_destroy(tp, true);
+					tcf_destroy(tp);
 				goto errout;
 			}
 			break;
 		case RTM_DELTFILTER:
-			err = tp->ops->delete(tp, fh);
+			err = tp->ops->delete(tp, fh, &last);
 			if (err == 0) {
-				struct tcf_proto *next = rtnl_dereference(tp->next);
-
 				tfilter_notify(net, skb, n, tp,
 					       t->tcm_handle,
 					       RTM_DELTFILTER, false);
-				if (tcf_destroy(tp, false))
+				if (last) {
+					struct tcf_proto *next = rtnl_dereference(tp->next);
+
 					RCU_INIT_POINTER(*back, next);
+					tcf_destroy(tp);
+				}
 			}
 			goto errout;
 		case RTM_GETTFILTER:
@@ -372,7 +376,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
 		tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER, false);
 	} else {
 		if (tp_created)
-			tcf_destroy(tp, true);
+			tcf_destroy(tp);
 	}
 
 errout:
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c
index eb219b7..dd63230 100644
--- a/net/sched/cls_basic.c
+++ b/net/sched/cls_basic.c
@@ -96,31 +96,28 @@ static void basic_delete_filter(struct rcu_head *head)
 	kfree(f);
 }
 
-static bool basic_destroy(struct tcf_proto *tp, bool force)
+static void basic_destroy(struct tcf_proto *tp)
 {
 	struct basic_head *head = rtnl_dereference(tp->root);
 	struct basic_filter *f, *n;
 
-	if (!force && !list_empty(&head->flist))
-		return false;
-
 	list_for_each_entry_safe(f, n, &head->flist, link) {
 		list_del_rcu(&f->link);
 		tcf_unbind_filter(tp, &f->res);
 		call_rcu(&f->rcu, basic_delete_filter);
 	}
-	RCU_INIT_POINTER(tp->root, NULL);
 	kfree_rcu(head, rcu);
-	return true;
 }
 
-static int basic_delete(struct tcf_proto *tp, unsigned long arg)
+static int basic_delete(struct tcf_proto *tp, unsigned long arg, bool *last)
 {
+	struct basic_head *head = rtnl_dereference(tp->root);
 	struct basic_filter *f = (struct basic_filter *) arg;
 
 	list_del_rcu(&f->link);
 	tcf_unbind_filter(tp, &f->res);
 	call_rcu(&f->rcu, basic_delete_filter);
+	*last = list_empty(&head->flist);
 	return 0;
 }
 
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c
index 52dc85a..770984c0 100644
--- a/net/sched/cls_bpf.c
+++ b/net/sched/cls_bpf.c
@@ -265,26 +265,25 @@ static void __cls_bpf_delete_prog(struct rcu_head *rcu)
 	cls_bpf_delete_prog(prog->tp, prog);
 }
 
-static int cls_bpf_delete(struct tcf_proto *tp, unsigned long arg)
+static int cls_bpf_delete(struct tcf_proto *tp, unsigned long arg, bool *last)
 {
 	struct cls_bpf_prog *prog = (struct cls_bpf_prog *) arg;
+	struct cls_bpf_head *head = rtnl_dereference(tp->root);
 
 	cls_bpf_stop_offload(tp, prog);
 	list_del_rcu(&prog->link);
 	tcf_unbind_filter(tp, &prog->res);
 	call_rcu(&prog->rcu, __cls_bpf_delete_prog);
+	*last = list_empty(&head->plist);
 
 	return 0;
 }
 
-static bool cls_bpf_destroy(struct tcf_proto *tp, bool force)
+static void cls_bpf_destroy(struct tcf_proto *tp)
 {
 	struct cls_bpf_head *head = rtnl_dereference(tp->root);
 	struct cls_bpf_prog *prog, *tmp;
 
-	if (!force && !list_empty(&head->plist))
-		return false;
-
 	list_for_each_entry_safe(prog, tmp, &head->plist, link) {
 		cls_bpf_stop_offload(tp, prog);
 		list_del_rcu(&prog->link);
@@ -292,9 +291,7 @@ static bool cls_bpf_destroy(struct tcf_proto *tp, bool force)
 		call_rcu(&prog->rcu, __cls_bpf_delete_prog);
 	}
 
-	RCU_INIT_POINTER(tp->root, NULL);
 	kfree_rcu(head, rcu);
-	return true;
 }
 
 static unsigned long cls_bpf_get(struct tcf_proto *tp, u32 handle)
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c
index 85233c47..fa9405e 100644
--- a/net/sched/cls_cgroup.c
+++ b/net/sched/cls_cgroup.c
@@ -131,21 +131,15 @@ static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb,
 	return err;
 }
 
-static bool cls_cgroup_destroy(struct tcf_proto *tp, bool force)
+static void cls_cgroup_destroy(struct tcf_proto *tp)
 {
 	struct cls_cgroup_head *head = rtnl_dereference(tp->root);
 
-	if (!force)
-		return false;
-
-	if (head) {
-		RCU_INIT_POINTER(tp->root, NULL);
+	if (head)
 		call_rcu(&head->rcu, cls_cgroup_destroy_rcu);
-	}
-	return true;
 }
 
-static int cls_cgroup_delete(struct tcf_proto *tp, unsigned long arg)
+static int cls_cgroup_delete(struct tcf_proto *tp, unsigned long arg, bool *last)
 {
 	return -EOPNOTSUPP;
 }
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index e396723..ea2be75 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -563,12 +563,14 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
 	return err;
 }
 
-static int flow_delete(struct tcf_proto *tp, unsigned long arg)
+static int flow_delete(struct tcf_proto *tp, unsigned long arg, bool *last)
 {
+	struct flow_head *head = rtnl_dereference(tp->root);
 	struct flow_filter *f = (struct flow_filter *)arg;
 
 	list_del_rcu(&f->list);
 	call_rcu(&f->rcu, flow_destroy_filter);
+	*last = list_empty(&head->filters);
 	return 0;
 }
 
@@ -584,21 +586,16 @@ static int flow_init(struct tcf_proto *tp)
 	return 0;
 }
 
-static bool flow_destroy(struct tcf_proto *tp, bool force)
+static void flow_destroy(struct tcf_proto *tp)
 {
 	struct flow_head *head = rtnl_dereference(tp->root);
 	struct flow_filter *f, *next;
 
-	if (!force && !list_empty(&head->filters))
-		return false;
-
 	list_for_each_entry_safe(f, next, &head->filters, list) {
 		list_del_rcu(&f->list);
 		call_rcu(&f->rcu, flow_destroy_filter);
 	}
-	RCU_INIT_POINTER(tp->root, NULL);
 	kfree_rcu(head, rcu);
-	return true;
 }
 
 static unsigned long flow_get(struct tcf_proto *tp, u32 handle)
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index e8dd09a..495d63224 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -280,21 +280,16 @@ static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f)
 	call_rcu(&f->rcu, fl_destroy_filter);
 }
 
-static bool fl_destroy(struct tcf_proto *tp, bool force)
+static void fl_destroy(struct tcf_proto *tp)
 {
 	struct cls_fl_head *head = rtnl_dereference(tp->root);
 	struct cls_fl_filter *f, *next;
 
-	if (!force && !list_empty(&head->filters))
-		return false;
-
 	list_for_each_entry_safe(f, next, &head->filters, list)
 		__fl_delete(tp, f);
-	RCU_INIT_POINTER(tp->root, NULL);
 	if (head->mask_assigned)
 		rhashtable_destroy(&head->ht);
 	kfree_rcu(head, rcu);
-	return true;
 }
 
 static unsigned long fl_get(struct tcf_proto *tp, u32 handle)
@@ -777,7 +772,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
 	return err;
 }
 
-static int fl_delete(struct tcf_proto *tp, unsigned long arg)
+static int fl_delete(struct tcf_proto *tp, unsigned long arg, bool *last)
 {
 	struct cls_fl_head *head = rtnl_dereference(tp->root);
 	struct cls_fl_filter *f = (struct cls_fl_filter *) arg;
@@ -785,6 +780,7 @@ static int fl_delete(struct tcf_proto *tp, unsigned long arg)
 	rhashtable_remove_fast(&head->ht, &f->ht_node,
 			       head->ht_params);
 	__fl_delete(tp, f);
+	*last = list_empty(&head->filters);
 	return 0;
 }
 
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index 9dc63d5..bc8ceb7 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -127,20 +127,14 @@ static void fw_delete_filter(struct rcu_head *head)
 	kfree(f);
 }
 
-static bool fw_destroy(struct tcf_proto *tp, bool force)
+static void fw_destroy(struct tcf_proto *tp)
 {
 	struct fw_head *head = rtnl_dereference(tp->root);
 	struct fw_filter *f;
 	int h;
 
 	if (head == NULL)
-		return true;
-
-	if (!force) {
-		for (h = 0; h < HTSIZE; h++)
-			if (rcu_access_pointer(head->ht[h]))
-				return false;
-	}
+		return;
 
 	for (h = 0; h < HTSIZE; h++) {
 		while ((f = rtnl_dereference(head->ht[h])) != NULL) {
@@ -150,17 +144,17 @@ static bool fw_destroy(struct tcf_proto *tp, bool force)
 			call_rcu(&f->rcu, fw_delete_filter);
 		}
 	}
-	RCU_INIT_POINTER(tp->root, NULL);
 	kfree_rcu(head, rcu);
-	return true;
 }
 
-static int fw_delete(struct tcf_proto *tp, unsigned long arg)
+static int fw_delete(struct tcf_proto *tp, unsigned long arg, bool *last)
 {
 	struct fw_head *head = rtnl_dereference(tp->root);
 	struct fw_filter *f = (struct fw_filter *)arg;
 	struct fw_filter __rcu **fp;
 	struct fw_filter *pfp;
+	int ret = -EINVAL;
+	int h;
 
 	if (head == NULL || f == NULL)
 		goto out;
@@ -173,11 +167,21 @@ static int fw_delete(struct tcf_proto *tp, unsigned long arg)
 			RCU_INIT_POINTER(*fp, rtnl_dereference(f->next));
 			tcf_unbind_filter(tp, &f->res);
 			call_rcu(&f->rcu, fw_delete_filter);
-			return 0;
+			ret = 0;
+			break;
 		}
 	}
+
+	*last = true;
+	for (h = 0; h < HTSIZE; h++) {
+		if (rcu_access_pointer(head->ht[h])) {
+			*last = false;
+			break;
+		}
+	}
+
 out:
-	return -EINVAL;
+	return ret;
 }
 
 static const struct nla_policy fw_policy[TCA_FW_MAX + 1] = {
diff --git a/net/sched/cls_matchall.c b/net/sched/cls_matchall.c
index 25927b6..7d54805 100644
--- a/net/sched/cls_matchall.c
+++ b/net/sched/cls_matchall.c
@@ -99,24 +99,19 @@ static void mall_destroy_hw_filter(struct tcf_proto *tp,
 					     &offload);
 }
 
-static bool mall_destroy(struct tcf_proto *tp, bool force)
+static void mall_destroy(struct tcf_proto *tp)
 {
 	struct cls_mall_head *head = rtnl_dereference(tp->root);
 	struct net_device *dev = tp->q->dev_queue->dev;
 	struct cls_mall_filter *f = head->filter;
 
-	if (!force && f)
-		return false;
-
 	if (f) {
 		if (tc_should_offload(dev, tp, f->flags))
 			mall_destroy_hw_filter(tp, f, (unsigned long) f);
 
 		call_rcu(&f->rcu, mall_destroy_filter);
 	}
-	RCU_INIT_POINTER(tp->root, NULL);
 	kfree_rcu(head, rcu);
-	return true;
 }
 
 static unsigned long mall_get(struct tcf_proto *tp, u32 handle)
@@ -225,7 +220,7 @@ static int mall_change(struct net *net, struct sk_buff *in_skb,
 	return err;
 }
 
-static int mall_delete(struct tcf_proto *tp, unsigned long arg)
+static int mall_delete(struct tcf_proto *tp, unsigned long arg, bool *last)
 {
 	struct cls_mall_head *head = rtnl_dereference(tp->root);
 	struct cls_mall_filter *f = (struct cls_mall_filter *) arg;
@@ -237,6 +232,7 @@ static int mall_delete(struct tcf_proto *tp, unsigned long arg)
 	RCU_INIT_POINTER(head->filter, NULL);
 	tcf_unbind_filter(tp, &f->res);
 	call_rcu(&f->rcu, mall_destroy_filter);
+	*last = true;
 	return 0;
 }
 
diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
index 455fc8f..1a38e41 100644
--- a/net/sched/cls_route.c
+++ b/net/sched/cls_route.c
@@ -276,20 +276,13 @@ static void route4_delete_filter(struct rcu_head *head)
 	kfree(f);
 }
 
-static bool route4_destroy(struct tcf_proto *tp, bool force)
+static void route4_destroy(struct tcf_proto *tp)
 {
 	struct route4_head *head = rtnl_dereference(tp->root);
 	int h1, h2;
 
 	if (head == NULL)
-		return true;
-
-	if (!force) {
-		for (h1 = 0; h1 <= 256; h1++) {
-			if (rcu_access_pointer(head->table[h1]))
-				return false;
-		}
-	}
+		return;
 
 	for (h1 = 0; h1 <= 256; h1++) {
 		struct route4_bucket *b;
@@ -312,12 +305,10 @@ static bool route4_destroy(struct tcf_proto *tp, bool force)
 			kfree_rcu(b, rcu);
 		}
 	}
-	RCU_INIT_POINTER(tp->root, NULL);
 	kfree_rcu(head, rcu);
-	return true;
 }
 
-static int route4_delete(struct tcf_proto *tp, unsigned long arg)
+static int route4_delete(struct tcf_proto *tp, unsigned long arg, bool *last)
 {
 	struct route4_head *head = rtnl_dereference(tp->root);
 	struct route4_filter *f = (struct route4_filter *)arg;
@@ -325,7 +316,7 @@ static int route4_delete(struct tcf_proto *tp, unsigned long arg)
 	struct route4_filter *nf;
 	struct route4_bucket *b;
 	unsigned int h = 0;
-	int i;
+	int i, h1;
 
 	if (!head || !f)
 		return -EINVAL;
@@ -356,16 +347,25 @@ static int route4_delete(struct tcf_proto *tp, unsigned long arg)
 
 				rt = rtnl_dereference(b->ht[i]);
 				if (rt)
-					return 0;
+					goto out;
 			}
 
 			/* OK, session has no flows */
 			RCU_INIT_POINTER(head->table[to_hash(h)], NULL);
 			kfree_rcu(b, rcu);
+			break;
+		}
+	}
 
-			return 0;
+out:
+	*last = true;
+	for (h1 = 0; h1 <= 256; h1++) {
+		if (rcu_access_pointer(head->table[h1])) {
+			*last = false;
+			break;
 		}
 	}
+
 	return 0;
 }
 
diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h
index 4f05a19..e8ba81a 100644
--- a/net/sched/cls_rsvp.h
+++ b/net/sched/cls_rsvp.h
@@ -301,22 +301,13 @@ static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f)
 	call_rcu(&f->rcu, rsvp_delete_filter_rcu);
 }
 
-static bool rsvp_destroy(struct tcf_proto *tp, bool force)
+static void rsvp_destroy(struct tcf_proto *tp)
 {
 	struct rsvp_head *data = rtnl_dereference(tp->root);
 	int h1, h2;
 
 	if (data == NULL)
-		return true;
-
-	if (!force) {
-		for (h1 = 0; h1 < 256; h1++) {
-			if (rcu_access_pointer(data->ht[h1]))
-				return false;
-		}
-	}
-
-	RCU_INIT_POINTER(tp->root, NULL);
+		return;
 
 	for (h1 = 0; h1 < 256; h1++) {
 		struct rsvp_session *s;
@@ -336,10 +327,9 @@ static bool rsvp_destroy(struct tcf_proto *tp, bool force)
 		}
 	}
 	kfree_rcu(data, rcu);
-	return true;
 }
 
-static int rsvp_delete(struct tcf_proto *tp, unsigned long arg)
+static int rsvp_delete(struct tcf_proto *tp, unsigned long arg, bool *last)
 {
 	struct rsvp_head *head = rtnl_dereference(tp->root);
 	struct rsvp_filter *nfp, *f = (struct rsvp_filter *)arg;
@@ -347,7 +337,7 @@ static int rsvp_delete(struct tcf_proto *tp, unsigned long arg)
 	unsigned int h = f->handle;
 	struct rsvp_session __rcu **sp;
 	struct rsvp_session *nsp, *s = f->sess;
-	int i;
+	int i, h1;
 
 	fp = &s->ht[(h >> 8) & 0xFF];
 	for (nfp = rtnl_dereference(*fp); nfp;
@@ -360,7 +350,7 @@ static int rsvp_delete(struct tcf_proto *tp, unsigned long arg)
 
 			for (i = 0; i <= 16; i++)
 				if (s->ht[i])
-					return 0;
+					goto out;
 
 			/* OK, session has no flows */
 			sp = &head->ht[h & 0xFF];
@@ -369,13 +359,23 @@ static int rsvp_delete(struct tcf_proto *tp, unsigned long arg)
 				if (nsp == s) {
 					RCU_INIT_POINTER(*sp, s->next);
 					kfree_rcu(s, rcu);
-					return 0;
+					goto out;
 				}
 			}
 
-			return 0;
+			break;
 		}
 	}
+
+out:
+	*last = true;
+	for (h1 = 0; h1 < 256; h1++) {
+		if (rcu_access_pointer(head->ht[h1])) {
+			*last = false;
+			break;
+		}
+	}
+
 	return 0;
 }
 
diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c
index 96144bd..9149a03 100644
--- a/net/sched/cls_tcindex.c
+++ b/net/sched/cls_tcindex.c
@@ -150,7 +150,7 @@ static void tcindex_destroy_fexts(struct rcu_head *head)
 	kfree(f);
 }
 
-static int tcindex_delete(struct tcf_proto *tp, unsigned long arg)
+static int tcindex_delete(struct tcf_proto *tp, unsigned long arg, bool *last)
 {
 	struct tcindex_data *p = rtnl_dereference(tp->root);
 	struct tcindex_filter_result *r = (struct tcindex_filter_result *) arg;
@@ -186,6 +186,8 @@ static int tcindex_delete(struct tcf_proto *tp, unsigned long arg)
 		call_rcu(&f->rcu, tcindex_destroy_fexts);
 	else
 		call_rcu(&r->rcu, tcindex_destroy_rexts);
+
+	*last = false;
 	return 0;
 }
 
@@ -193,7 +195,9 @@ static int tcindex_destroy_element(struct tcf_proto *tp,
 				   unsigned long arg,
 				   struct tcf_walker *walker)
 {
-	return tcindex_delete(tp, arg);
+	bool last;
+
+	return tcindex_delete(tp, arg, &last);
 }
 
 static void __tcindex_destroy(struct rcu_head *head)
@@ -529,23 +533,18 @@ static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker)
 	}
 }
 
-static bool tcindex_destroy(struct tcf_proto *tp, bool force)
+static void tcindex_destroy(struct tcf_proto *tp)
 {
 	struct tcindex_data *p = rtnl_dereference(tp->root);
 	struct tcf_walker walker;
 
-	if (!force)
-		return false;
-
 	pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p);
 	walker.count = 0;
 	walker.skip = 0;
 	walker.fn = tcindex_destroy_element;
 	tcindex_walk(tp, &walker);
 
-	RCU_INIT_POINTER(tp->root, NULL);
 	call_rcu(&p->rcu, __tcindex_destroy);
-	return true;
 }
 
 
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index ae83c3ae..787573b 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -582,37 +582,13 @@ static bool ht_empty(struct tc_u_hnode *ht)
 	return true;
 }
 
-static bool u32_destroy(struct tcf_proto *tp, bool force)
+static void u32_destroy(struct tcf_proto *tp)
 {
 	struct tc_u_common *tp_c = tp->data;
 	struct tc_u_hnode *root_ht = rtnl_dereference(tp->root);
 
 	WARN_ON(root_ht == NULL);
 
-	if (!force) {
-		if (root_ht) {
-			if (root_ht->refcnt > 1)
-				return false;
-			if (root_ht->refcnt == 1) {
-				if (!ht_empty(root_ht))
-					return false;
-			}
-		}
-
-		if (tp_c->refcnt > 1)
-			return false;
-
-		if (tp_c->refcnt == 1) {
-			struct tc_u_hnode *ht;
-
-			for (ht = rtnl_dereference(tp_c->hlist);
-			     ht;
-			     ht = rtnl_dereference(ht->next))
-				if (!ht_empty(ht))
-					return false;
-		}
-	}
-
 	if (root_ht && --root_ht->refcnt == 0)
 		u32_destroy_hnode(tp, root_ht);
 
@@ -637,20 +613,22 @@ static bool u32_destroy(struct tcf_proto *tp, bool force)
 	}
 
 	tp->data = NULL;
-	return true;
 }
 
-static int u32_delete(struct tcf_proto *tp, unsigned long arg)
+static int u32_delete(struct tcf_proto *tp, unsigned long arg, bool *last)
 {
 	struct tc_u_hnode *ht = (struct tc_u_hnode *)arg;
 	struct tc_u_hnode *root_ht = rtnl_dereference(tp->root);
+	struct tc_u_common *tp_c = tp->data;
+	int ret = 0;
 
 	if (ht == NULL)
-		return 0;
+		goto out;
 
 	if (TC_U32_KEY(ht->handle)) {
 		u32_remove_hw_knode(tp, ht->handle);
-		return u32_delete_key(tp, (struct tc_u_knode *)ht);
+		ret = u32_delete_key(tp, (struct tc_u_knode *)ht);
+		goto out;
 	}
 
 	if (root_ht == ht)
@@ -663,7 +641,40 @@ static int u32_delete(struct tcf_proto *tp, unsigned long arg)
 		return -EBUSY;
 	}
 
-	return 0;
+out:
+	*last = true;
+	if (root_ht) {
+		if (root_ht->refcnt > 1) {
+			*last = false;
+			goto ret;
+		}
+		if (root_ht->refcnt == 1) {
+			if (!ht_empty(root_ht)) {
+				*last = false;
+				goto ret;
+			}
+		}
+	}
+
+	if (tp_c->refcnt > 1) {
+		*last = false;
+		goto ret;
+	}
+
+	if (tp_c->refcnt == 1) {
+		struct tc_u_hnode *ht;
+
+		for (ht = rtnl_dereference(tp_c->hlist);
+		     ht;
+		     ht = rtnl_dereference(ht->next))
+			if (!ht_empty(ht)) {
+				*last = false;
+				break;
+			}
+	}
+
+ret:
+	return ret;
 }
 
 #define NR_U32_NODE (1<<12)
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index f337f1b..7fc48b3 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1899,15 +1899,11 @@ int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
 }
 EXPORT_SYMBOL(tc_classify);
 
-bool tcf_destroy(struct tcf_proto *tp, bool force)
+void tcf_destroy(struct tcf_proto *tp)
 {
-	if (tp->ops->destroy(tp, force)) {
-		module_put(tp->ops->owner);
-		kfree_rcu(tp, rcu);
-		return true;
-	}
-
-	return false;
+	tp->ops->destroy(tp);
+	module_put(tp->ops->owner);
+	kfree_rcu(tp, rcu);
 }
 
 void tcf_destroy_chain(struct tcf_proto __rcu **fl)
@@ -1916,7 +1912,7 @@ void tcf_destroy_chain(struct tcf_proto __rcu **fl)
 
 	while ((tp = rtnl_dereference(*fl)) != NULL) {
 		RCU_INIT_POINTER(*fl, tp->next);
-		tcf_destroy(tp, true);
+		tcf_destroy(tp);
 	}
 }
 EXPORT_SYMBOL(tcf_destroy_chain);
-- 
2.1.0

^ permalink raw reply related

* [PATCH net 1/1] tipc: fix compatibility bug in link monitoring
From: Jon Maloy @ 2016-11-24  2:05 UTC (permalink / raw)
  To: davem; +Cc: Jon Maloy, netdev, tipc-discussion

commit 817298102b0b ("tipc: fix link priority propagation") introduced a
compatibility problem between TIPC versions newer than Linux 4.6 and
those older than Linux 4.4. In versions later than 4.4, link STATE
messages only contain a non-zero link priority value when the sender
wants the receiver to change its priority. This has the effect that the
receiver resets itself in order to apply the new priority. This works
well, and is consistent with the said commit.

However, in versions older than 4.4 a valid link priority is present in
all sent link STATE messages, leading to cyclic link establishment and
reset on the 4.6+ node.

We fix this by adding a test that the received value should not only
be valid, but also differ from the current value in order to cause the
receiving link endpoint to reset.

Reported-by: Amar Nv <amar.nv005@gmail.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
---
 net/tipc/link.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/net/tipc/link.c b/net/tipc/link.c
index 1055164..ecc12411 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -1492,8 +1492,9 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
 		if (in_range(peers_tol, TIPC_MIN_LINK_TOL, TIPC_MAX_LINK_TOL))
 			l->tolerance = peers_tol;
 
-		if (peers_prio && in_range(peers_prio, TIPC_MIN_LINK_PRI,
-					   TIPC_MAX_LINK_PRI)) {
+		/* Update own prio if peer indicates a different value */
+		if ((peers_prio != l->priority) &&
+		    in_range(peers_prio, 1, TIPC_MAX_LINK_PRI)) {
 			l->priority = peers_prio;
 			rc = tipc_link_fsm_evt(l, LINK_FAILURE_EVT);
 		}
-- 
2.7.4


------------------------------------------------------------------------------

^ permalink raw reply related

* Re: [PATCH net-next 1/1] ipv6: sr: add option to control lwtunnel support
From: Alexei Starovoitov @ 2016-11-24  2:31 UTC (permalink / raw)
  To: David Lebrun
  Cc: Roopa Prabhu, David Miller, netdev@vger.kernel.org,
	Lorenzo Colitti, Eric Dumazet
In-Reply-To: <5835613D.8070104@uclouvain.be>

On Wed, Nov 23, 2016 at 10:28:29AM +0100, David Lebrun wrote:
> On 11/23/2016 08:34 AM, Roopa Prabhu wrote:
> > I can't seem to reproduce the problem you are seeing. still trying..
> > I don't have CONFIG_LWTUNNEL set nor any of the other SEG6 configs.
> > My CONFIG_IPV6 is on and compiled as a module. I have also tried disabling it.
> > If you can send me the config, I can try again. Looking back at the patches,
> > I do see a few things below ..but they may not fix your problem directly.
> > 
> > Though I had none of the ipv6 segment routing configs turned on,
> > I do see the "Segment Routing with IPv6" msg at bootup.
> > Was looking at david's patches again, and a few things (I had missed seeing the last version):
> > 
> > In my review comment I was hinting at CONFIG_IPV6_SEG6 to cover all of ipv6 segment routing,
> > including the lwtunnel bits.
> > 
> > something like below:
> > 
> > config IPV6_SEG6
> >         bool "IPv6: Segment Routing Header encapsulation support"
> >         depends on LWTUNNEL && IPV6
> > 
> > DavidL, do you see a problem doing it this way ?. with this 'seg6.o' will be part of CONFIG_IPV6_SEG6 and not
> > get initialized unless it is enabled..which seems like the right thing to do.
> 
> Can't reproduce the bug either, with CONFIG_IPV6=y, LWTUNNEL=n and all
> SEG6 disabled. Alexei, your .config and dmesg log could help.

I didn't save that .config and did bisect of the other bug that
messed up my .confg. Now I cannot reproduce it. Sorry for the noise.
Still weird though that ping prefers ipv6 address now.
$ ping localhost
PING localhost(localhost.localdomain (::1)) 56 data bytes
64 bytes from localhost.localdomain (::1): icmp_seq=1 ttl=64 time=0.043 ms

^ permalink raw reply

* [scr265482] ip_tunnel.c
From: Liyang Yu (于立洋1) @ 2016-11-24  2:47 UTC (permalink / raw)
  To: security@kernel.org, netdev@vger.kernel.org; +Cc: cve-request@mitre.org
In-Reply-To: <860a2905e7f7467f864e13839eb05222@imshyb02.MITRE.ORG>

Hi: 
	I found that the GRE tunnel in same case can cause integer overflow in ip_tunnel.c:397
   
Cause of the problem:
  	When tpi->seq less than tunnel->i_seqno, the packet will be droped. 

How to recurrence problem
	1. Create an tunnel use kernel GRE module.
    2. Use the tunnel to send packets for awile.
    3.Reboot one site of the tunnel. 
    4. Communication interrupted 


		if (tunnel->parms.i_flags&TUNNEL_SEQ) {
		if (!(tpi->flags&TUNNEL_SEQ) ||
		    (tunnel->i_seqno && (s32)(ntohl(tpi->seq) - tunnel->i_seqno) < 0)) {    /**Here is the trouble code* /
			tunnel->dev->stats.rx_fifo_errors++;
			tunnel->dev->stats.rx_errors++;
			goto drop;
		}
		tunnel->i_seqno = ntohl(tpi->seq) + 1;
	}
    
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

> Integer Overflow in ip_tunnel.c in Ubuntu Linux kernel GRE ALL kernel 
> version allows attacker to Denial of Service via reboot one end of the 
> tunnel

Could you please clarify whether this affects only Ubuntu, or potentially affects other Linux distributions? ip_tunnel.c is present in the Linux kernel in all distributions and is maintained at:

  http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/log/net/ipv4/ip_tunnel.c

You should provide your evidence of an integer overflow, such as source code or crash tracing.

If you are reporting an Ubuntu issue, please see:

  https://wiki.ubuntu.com/SecurityTeam/FAQ#Contact

about how to file a Private Security bug in Launchpad.

If you are reporting an issue affecting the Linux kernel in general, please contact:

  security@kernel.org

You can also include:

  netdev@vger.kernel.org

if the report is public. If you need to subscribe, see:

  http://vger.kernel.org/vger-lists.html#netdev

- --
CVE Assignment Team
M/S M300, 202 Burlington Road, Bedford, MA 01730 USA [ A PGP key is available for encrypted communications at
  http://cve.mitre.org/cve/request_id.html ] -----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQIcBAEBCAAGBQJYNeETAAoJEHb/MwWLVhi26RcP/R38S6V0LFGPHOTFNjTapcnV
RPKycC/lOCGjQehDAUkhxxTwolJpJF3RWeI+KL/hOvxA+LP3B3YeYdoYnQyZ6SqI
8J+zz5vV5mCP3olKYynO4S32bBn8rZiwoWsFWPaC4ILmoQFTLZiDbH6ji3DrHewm
OwrTysyC1a7clOuIM3BaPl3Ra0qMHsgR2b16gYMEdi/B1Ya3oLY7MVLTB2AixA9F
BB/aQjFMICfchEF39uQslU3jJd+SPuayLvceiKIvqFqBt1D8Kt2rBamzMmI5MC3M
ZbVBNfXde1MxqlV2WjUzl8KFj2l1zG7IlH1rcRes+6ZI3VaJnbv9Jyi6oc9QzMQc
nFRg9sH/DzD3g40bh2zRBtLqkQeTxxkg3JvaFc2OC2MaxMiobQCso926d4pFxTmd
+x8wP7E/nKvd4+E09/bep/v0+mEOxfSDICNGO/7gBOU4wKZ6IyaNftfe5Q1zDaxv
M3vWI6VqTFx32wY7TE69AHIH7X7WvzsBi7BLj2RHGFg2hwS7n80A1t4BcdYjPdSh
feFxfVH5gGAaG3Bm4jJOCKe5+vRwuJGjnox2+vQvUrD9v+vx0z1D5ooO8Ms2MLnT
kKL7BKhcntcoLJ3TUI09I2HZBSh7R3homgFhgrpbDHd0YjaW6XgqHjAr8piKEToK
V6jChR0YzXTkTlw1jYlE
=z0ta
-----END PGP SIGNATURE-----

^ permalink raw reply

* RE: [PATCH net 1/2] r8152: fix the sw rx checksum is unavailable
From: Hayes Wang @ 2016-11-24  3:24 UTC (permalink / raw)
  To: Mark Lord, netdev@vger.kernel.org
  Cc: nic_swsd, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org
In-Reply-To: <95fa9f67-3af6-6749-0e2b-c95406486f7d@pobox.com>

Mark Lord [mailto:mlord@pobox.com]
> Sent: Thursday, November 24, 2016 3:30 AM
[...]
> Worth repeating: other dongles we have tried, eg. those using the asix driver,
> do not cause us any troubles here.  Only the r8152 dongles do.

I couldn't tell you why you would see the problem. I have tested the
RTL8152 on raspberry pi platform with iperf more than 17 hours. And
I don't see any invalid rx descriptor. I don't think it really is the
issue about our hw.

Best Regards,
Hayes

^ permalink raw reply

* linux-next: manual merge of the staging tree with the net-next tree
From: Stephen Rothwell @ 2016-11-24  3:42 UTC (permalink / raw)
  To: Greg KH, David Miller, Networking
  Cc: linux-next, linux-kernel, Jarod Wilson, Erik Arfvidson,
	David Kershner

Hi Greg,

Today's linux-next merge of the staging tree got a conflict in:

  drivers/staging/unisys/include/iochannel.h

between commit:

  d0c2c9973ecd ("net: use core MTU range checking in virt drivers")

from the net-next tree and commit:

  b18f9c676f93 ("staging: unisys: include: fix pound defines")

from the staging tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

-- 
Cheers,
Stephen Rothwell

diff --cc drivers/staging/unisys/include/iochannel.h
index 9081b3f8779c,c43da782f37e..000000000000
--- a/drivers/staging/unisys/include/iochannel.h
+++ b/drivers/staging/unisys/include/iochannel.h
@@@ -113,10 -117,12 +117,10 @@@ enum net_types 
  
  };
  
- #define		ETH_MIN_DATA_SIZE 46	/* minimum eth data size */
- #define		ETH_MIN_PACKET_SIZE (ETH_HLEN + ETH_MIN_DATA_SIZE)
 -#define ETH_HEADER_SIZE 14	/* size of ethernet header */
 -
+ #define ETH_MIN_DATA_SIZE 46	/* minimum eth data size */
 -#define ETH_MIN_PACKET_SIZE (ETH_HEADER_SIZE + ETH_MIN_DATA_SIZE)
++#define ETH_MIN_PACKET_SIZE (ETH_HLEN + ETH_MIN_DATA_SIZE)
  
- #define		VISOR_ETH_MAX_MTU 16384	/* maximum data size */
 -#define ETH_MAX_MTU 16384	/* maximum data size */
++#define VISOR_ETH_MAX_MTU 16384	/* maximum data size */
  
  #ifndef MAX_MACADDR_LEN
  #define MAX_MACADDR_LEN 6	/* number of bytes in MAC address */
@@@ -286,9 -304,9 +302,9 @@@ struct net_pkt_xmt 
  	int len;	/* full length of data in the packet */
  	int num_frags;	/* number of fragments in frags containing data */
  	struct phys_info frags[MAX_PHYS_INFO];	/* physical page information */
 -	char ethhdr[ETH_HEADER_SIZE];	/* the ethernet header  */
 +	char ethhdr[ETH_HLEN];	/* the ethernet header  */
  	struct {
- 		/* these are needed for csum at uisnic end */
+ 		/* These are needed for csum at uisnic end */
  		u8 valid;	/* 1 = struct is valid - else ignore */
  		u8 hrawoffv;	/* 1 = hwrafoff is valid */
  		u8 nhrawoffv;	/* 1 = nhwrafoff is valid */
@@@ -321,29 -341,41 +339,41 @@@ struct net_pkt_xmtdone 
   */
  #define RCVPOST_BUF_SIZE 4032
  #define MAX_NET_RCV_CHAIN \
 -	((ETH_MAX_MTU + ETH_HEADER_SIZE + RCVPOST_BUF_SIZE - 1) \
 +	((VISOR_ETH_MAX_MTU + ETH_HLEN + RCVPOST_BUF_SIZE - 1) \
  	/ RCVPOST_BUF_SIZE)
  
+ /*
+  * rcv buf size must be large enough to include ethernet data len + ethernet
+  * header len - we are choosing 2K because it is guaranteed to be describable.
+  */
  struct net_pkt_rcvpost {
- 	    /* rcv buf size must be large enough to include ethernet data len +
- 	     * ethernet header len - we are choosing 2K because it is guaranteed
- 	     * to be describable
- 	     */
- 	    struct phys_info frag;	/* physical page information for the */
- 					/* single fragment 2K rcv buf */
- 	    u64 unique_num;
- 	    /* unique_num ensure that receive posts are returned to */
- 	    /* the Adapter which we sent them originally. */
+ 	/* Physical page information for the single fragment 2K rcv buf */
+ 	struct phys_info frag;
+ 
+ 	/*
+ 	 * Ensures that receive posts are returned to the adapter which we sent
+ 	 * them from originally.
+ 	 */
+ 	u64 unique_num;
+ 
  } __packed;
  
+ /*
+  * The number of rcvbuf that can be chained is based on max mtu and size of each
+  * rcvbuf.
+  */
  struct net_pkt_rcv {
- 	/* the number of receive buffers that can be chained  */
- 	/* is based on max mtu and size of each rcv buf */
- 	u32 rcv_done_len;	/* length of received data */
- 	u8 numrcvbufs;		/* number of receive buffers that contain the */
- 	/* incoming data; guest end MUST chain these together. */
- 	void *rcvbuf[MAX_NET_RCV_CHAIN];	/* list of chained rcvbufs */
- 	/* each entry is a receive buffer provided by NET_RCV_POST. */
+ 	u32 rcv_done_len; /* length of received data */
+ 
+ 	/*
+ 	 * numrcvbufs: contain the incoming data; guest side MUST chain these
+ 	 * together.
+ 	 */
+ 	u8 numrcvbufs;
+ 
+ 	void *rcvbuf[MAX_NET_RCV_CHAIN]; /* list of chained rcvbufs */
+ 
+ 	/* Each entry is a receive buffer provided by NET_RCV_POST. */
  	/* NOTE: first rcvbuf in the chain will also be provided in net.buf. */
  	u64 unique_num;
  	u32 rcvs_dropped_delta;

^ permalink raw reply

* [PATCH 0/4] Fix -Wunused-but-set-variable in net/mac80211/
From: Kirtika Ruchandani @ 2016-11-24  4:45 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Arnd Bergmann, netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA, Marek Kwaczynski,
	David Spinadel, Alexander Bondar, Michal Kazior

This patchset is part of the effort led by Arnd Bergmann to clean up
warnings in the kernel. This and following patchsets will focus on
"-Wunused-but-set-variable" as it among the noisier ones. These were
found compiling with W=1.

Kirtika Ruchandani (4):
  mac80211: Removed unused 'i' variable
  mac80211: Remove unused 'len' variable
  mac80211: Removed unused 'struct ieee80211_supported_band*' variable
  mac80211: Remove unused 'beaconint_us' variable

 net/mac80211/chan.c | 4 +---
 net/mac80211/mlme.c | 4 ----
 net/mac80211/scan.c | 8 +++-----
 net/mac80211/vht.c  | 4 ----
 4 files changed, 4 insertions(+), 16 deletions(-)

-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply

* [PATCH 1/4] mac80211: Removed unused 'i' variable
From: Kirtika Ruchandani @ 2016-11-24  4:45 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Arnd Bergmann, netdev, linux-wireless, Marek Kwaczynski,
	David Spinadel, Alexander Bondar, Michal Kazior
In-Reply-To: <cover.1479962513.git.kirtika@chromium.org>

Commit 5bcae31d9 (mac80211: implement multi-vif in-place reservations)
introduced ieee80211_vif_use_reserved_switch() with a counter variable
'i' that is set but not used. Compiling with W=1 gives the following
warning, fix it.
net/mac80211/chan.c: In function ‘ieee80211_vif_use_reserved_switch’:
net/mac80211/chan.c:1273:6: warning: variable ‘i’ set but not used [-Wunused-but-set-variable]

This is a harmless warning, and is only being fixed to reduce the
noise obtained with W=1 in the kernel.

Fixes: 5bcae31d9 ("mac80211: implement multi-vif in-place reservations")
Cc: Michal Kazior <michal.kazior@tieto.com>
Cc: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Kirtika Ruchandani <kirtika@chromium.org>
---
 net/mac80211/chan.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index e75cbf6..7550fd2 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -1270,7 +1270,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
 	struct ieee80211_sub_if_data *sdata, *sdata_tmp;
 	struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx;
 	struct ieee80211_chanctx *new_ctx = NULL;
-	int i, err, n_assigned, n_reserved, n_ready;
+	int err, n_assigned, n_reserved, n_ready;
 	int n_ctx = 0, n_vifs_switch = 0, n_vifs_assign = 0, n_vifs_ctxless = 0;
 
 	lockdep_assert_held(&local->mtx);
@@ -1391,8 +1391,6 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
 	 * Update all structures, values and pointers to point to new channel
 	 * context(s).
 	 */
-
-	i = 0;
 	list_for_each_entry(ctx, &local->chanctx_list, list) {
 		if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
 			continue;
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related

* [PATCH 2/4] mac80211: Remove unused 'len' variable
From: Kirtika Ruchandani @ 2016-11-24  4:45 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Arnd Bergmann, netdev, linux-wireless, Marek Kwaczynski,
	David Spinadel, Alexander Bondar, Michal Kazior
In-Reply-To: <cover.1479962513.git.kirtika@chromium.org>

Commit 633e27132625 (mac80211: split sched scan IEs) introduced the
len variable to keep track of the return value of
ieee80211_build_preq_ies() but did not use it. Compiling with W=1
gives the following warning, fix it.

net/mac80211/scan.c: In function ‘__ieee80211_request_sched_scan_start’:
net/mac80211/scan.c:1123:9: warning: variable ‘len’ set but not used [-Wunused-but-set-variable]

This is a harmless warning and is only being fixed to reduce the noise
with W=1 in the kernel.

Fixes: 633e27132625 ("mac80211: split sched scan IEs")
Cc: David Spinadel <david.spinadel@intel.com>
Cc: Alexander Bondar <alexander.bondar@intel.com>
Cc: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Kirtika Ruchandani <kirtika@chromium.org>
---
 net/mac80211/scan.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 23d8ac8..faab3c4 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -1120,7 +1120,6 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
 	u32 rate_masks[NUM_NL80211_BANDS] = {};
 	u8 bands_used = 0;
 	u8 *ie;
-	size_t len;
 
 	iebufsz = local->scan_ies_len + req->ie_len;
 
@@ -1145,10 +1144,9 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
 
 	ieee80211_prepare_scan_chandef(&chandef, req->scan_width);
 
-	len = ieee80211_build_preq_ies(local, ie, num_bands * iebufsz,
-				       &sched_scan_ies, req->ie,
-				       req->ie_len, bands_used,
-				       rate_masks, &chandef);
+	ieee80211_build_preq_ies(local, ie, num_bands * iebufsz,
+				 &sched_scan_ies, req->ie,
+				 req->ie_len, bands_used, rate_masks, &chandef);
 
 	ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
 	if (ret == 0) {
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related

* [PATCH net 1/1] tipc: improve sanity check for received domain records
From: Jon Maloy @ 2016-11-24  4:46 UTC (permalink / raw)
  To: davem; +Cc: Jon Maloy, netdev, tipc-discussion

In commit 35c55c9877f8 ("tipc: add neighbor monitoring framework") we
added a data area to the link monitor STATE messages under the
assumption that previous versions did not use any such data area.

For versions older than Linux 4.3 this assumption is not correct. In
those version, all STATE messages sent out from a node inadvertently
contain a 16 byte data area containing a string; -a leftover from
previous RESET messages which were using this during the setup phase.
This string serves no purpose in STATE messages, and should no be there.

Unfortunately, this data area is delivered to the link monitor
framework, where a sanity check catches that it is not a correct domain
record, and drops it. It also issues a rate limited warning about the
event.

Since such events occur much more frequently than anticipated, we now
choose to remove the warning in order to not fill the kernel log with
useless contents. We also make the sanity check stricter, to further
reduce the risk that such data is inavertently admitted.

Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
---
 net/tipc/monitor.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/net/tipc/monitor.c b/net/tipc/monitor.c
index ed97a58..9e109bb 100644
--- a/net/tipc/monitor.c
+++ b/net/tipc/monitor.c
@@ -455,14 +455,14 @@ void tipc_mon_rcv(struct net *net, void *data, u16 dlen, u32 addr,
 	int i, applied_bef;
 
 	state->probing = false;
-	if (!dlen)
-		return;
 
 	/* Sanity check received domain record */
-	if ((dlen < new_dlen) || ntohs(arrv_dom->len) != new_dlen) {
-		pr_warn_ratelimited("Received illegal domain record\n");
+	if (dlen < dom_rec_len(arrv_dom, 0))
+		return;
+	if (dlen != dom_rec_len(arrv_dom, new_member_cnt))
+		return;
+	if ((dlen < new_dlen) || ntohs(arrv_dom->len) != new_dlen)
 		return;
-	}
 
 	/* Synch generation numbers with peer if link just came up */
 	if (!state->synched) {
-- 
2.7.4


------------------------------------------------------------------------------

^ permalink raw reply related

* [PATCH 3/4] mac80211: Removed unused 'struct ieee80211_supported_band*' variable
From: Kirtika Ruchandani @ 2016-11-24  4:46 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Arnd Bergmann, netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA, Marek Kwaczynski,
	David Spinadel, Alexander Bondar, Michal Kazior
In-Reply-To: <cover.1479962513.git.kirtika-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>

Commit b1bce14a7954 (mac80211: update opmode when adding new station)
refactored ieee80211_vht_handle_opmode into __ieee80211_vht_handle_opmode
and ieee80211_vht_handle_opmode leaving a set but unused variable
(sband) in the former. Compiling with W=1 gives the following warning,
fix it.

net/mac80211/vht.c: In function ‘__ieee80211_vht_handle_opmode’:
net/mac80211/vht.c:424:35: warning: variable ‘sband’ set but not used [-Wunused-but-set-variable]

Remove 'struct ieee80211_local* local' as well, it was only used to
set sband.

This is a harmless warning, and is only being fixed to reduce the
noise with W=1 in the kernel.

Fixes: b1bce14a7954 ("mac80211: update opmode when adding new station")
Cc: Marek Kwaczynski <marek.kwaczynski-++hxYGjEMp0AvxtiuMwx3w@public.gmane.org>
Cc: Johannes Berg <johannes.berg-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
Signed-off-by: Kirtika Ruchandani <kirtika-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
---
 net/mac80211/vht.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index ee71576..14920e3 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -420,14 +420,10 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
 				  struct sta_info *sta, u8 opmode,
 				  enum nl80211_band band)
 {
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_supported_band *sband;
 	enum ieee80211_sta_rx_bandwidth new_bw;
 	u32 changed = 0;
 	u8 nss;
 
-	sband = local->hw.wiphy->bands[band];

^ permalink raw reply related

* [PATCH 4/4] mac80211: Remove unused 'beaconint_us' variable
From: Kirtika Ruchandani @ 2016-11-24  4:46 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Arnd Bergmann, netdev, linux-wireless, Marek Kwaczynski,
	David Spinadel, Alexander Bondar, Michal Kazior
In-Reply-To: <cover.1479962513.git.kirtika@chromium.org>

Commit 4a733ef1bea7 (mac80211: remove PM-QoS listener) removed all use
of 'beaconint_us' from ieee80211_recalc_ps() but left the variable
intact. Compiling with W=1 gives the following warning, fix it.
net/mac80211/mlme.c: In function ‘ieee80211_recalc_ps’:
net/mac80211/mlme.c:1481:7: warning: variable ‘beaconint_us’ set but not used [-Wunused-but-set-variable]

iee80211_tu_to_usec has no side-effects and is safe to remove.

Fixes: 4a733ef1bea7 ("mac80211: remove PM-QoS listener")
Cc: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Kirtika Ruchandani <kirtika@chromium.org>
---
 net/mac80211/mlme.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 7486f2d..e883345 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1478,10 +1478,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local)
 
 	if (count == 1 && ieee80211_powersave_allowed(found)) {
 		u8 dtimper = found->u.mgd.dtim_period;
-		s32 beaconint_us;
-
-		beaconint_us = ieee80211_tu_to_usec(
-					found->vif.bss_conf.beacon_int);
 
 		timeout = local->dynamic_ps_forced_timeout;
 		if (timeout < 0)
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related

* [PATCH] netdevice: fix sparse warning for HARD_TX_LOCK
From: Michael S. Tsirkin @ 2016-11-24  5:04 UTC (permalink / raw)
  To: linux-kernel; +Cc: David S. Miller, netdev

sparse warns about context imbalance in any code
that uses HARD_TX_LOCK/UNLOCK - this is because it's
unable to determine that flags don't change so
lock and unlock are paired.

Seems easy enough to fix by adding __acquire/__release
calls.

With this patch af_packet.c is now sparse-clean,

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---

compile-tested only.

 include/linux/netdevice.h | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 91ee364..0a58a50 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3539,6 +3539,17 @@ static inline void __netif_tx_lock(struct netdev_queue *txq, int cpu)
 	txq->xmit_lock_owner = cpu;
 }
 
+static inline bool __netif_tx_acquire(struct netdev_queue *txq)
+{
+	__acquire(&txq->_xmit_lock);
+	return true;
+}
+
+static inline void __netif_tx_release(struct netdev_queue *txq)
+{
+	__release(&txq->_xmit_lock);
+}
+
 static inline void __netif_tx_lock_bh(struct netdev_queue *txq)
 {
 	spin_lock_bh(&txq->_xmit_lock);
@@ -3640,17 +3651,21 @@ static inline void netif_tx_unlock_bh(struct net_device *dev)
 #define HARD_TX_LOCK(dev, txq, cpu) {			\
 	if ((dev->features & NETIF_F_LLTX) == 0) {	\
 		__netif_tx_lock(txq, cpu);		\
+	} else {					\
+		__netif_tx_acquire(txq);		\
 	}						\
 }
 
 #define HARD_TX_TRYLOCK(dev, txq)			\
 	(((dev->features & NETIF_F_LLTX) == 0) ?	\
 		__netif_tx_trylock(txq) :		\
-		true )
+		__netif_tx_acquire(txq))
 
 #define HARD_TX_UNLOCK(dev, txq) {			\
 	if ((dev->features & NETIF_F_LLTX) == 0) {	\
 		__netif_tx_unlock(txq);			\
+	} else {					\
+		__netif_tx_release(txq);		\
 	}						\
 }
 
-- 
MST

^ permalink raw reply related

* [net-next] neigh: fix the loop index error in neigh dump
From: Zhang Shengju @ 2016-11-24  5:25 UTC (permalink / raw)
  To: netdev, dsa

Loop index in neigh dump function is not updated correctly under some
circumstances, this patch will fix it.

Signed-off-by: Zhang Shengju <zhangshengju@cmss.chinamobile.com>
---
 net/core/neighbour.c | 39 ++++++++++++++++++---------------------
 1 file changed, 18 insertions(+), 21 deletions(-)

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 2ae929f..ce32e9c 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -2256,6 +2256,16 @@ static bool neigh_ifindex_filtered(struct net_device *dev, int filter_idx)
 	return false;
 }
 
+static bool neigh_dump_filtered(struct net_device *dev, int filter_idx,
+		int filter_master_idx)
+{
+	if (neigh_ifindex_filtered(dev, filter_idx) ||
+	    neigh_master_filtered(dev, filter_master_idx))
+		return true;
+
+	return false;
+}
+
 static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
 			    struct netlink_callback *cb)
 {
@@ -2285,20 +2295,15 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
 	rcu_read_lock_bh();
 	nht = rcu_dereference_bh(tbl->nht);
 
-	for (h = s_h; h < (1 << nht->hash_shift); h++) {
-		if (h > s_h)
-			s_idx = 0;
+	for (h = s_h; h < (1 << nht->hash_shift); h++, s_idx = 0) {
 		for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
 		     n != NULL;
-		     n = rcu_dereference_bh(n->next)) {
-			if (!net_eq(dev_net(n->dev), net))
-				continue;
-			if (neigh_ifindex_filtered(n->dev, filter_idx))
+		     n = rcu_dereference_bh(n->next), idx++) {
+			if (idx < s_idx || !net_eq(dev_net(n->dev), net))
 				continue;
-			if (neigh_master_filtered(n->dev, filter_master_idx))
+			if (neigh_dump_filtered(n->dev, filter_idx,
+						filter_master_idx))
 				continue;
-			if (idx < s_idx)
-				goto next;
 			if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
 					    cb->nlh->nlmsg_seq,
 					    RTM_NEWNEIGH,
@@ -2306,8 +2311,6 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
 				rc = -1;
 				goto out;
 			}
-next:
-			idx++;
 		}
 	}
 	rc = skb->len;
@@ -2328,14 +2331,10 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
 
 	read_lock_bh(&tbl->lock);
 
-	for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
-		if (h > s_h)
-			s_idx = 0;
-		for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
-			if (pneigh_net(n) != net)
+	for (h = s_h; h <= PNEIGH_HASHMASK; h++, s_idx = 0) {
+		for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next, idx++) {
+			if (idx < s_idx || pneigh_net(n) != net)
 				continue;
-			if (idx < s_idx)
-				goto next;
 			if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
 					    cb->nlh->nlmsg_seq,
 					    RTM_NEWNEIGH,
@@ -2344,8 +2343,6 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
 				rc = -1;
 				goto out;
 			}
-		next:
-			idx++;
 		}
 	}
 
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH] adm80211: Removed unused 'io_addr' 'mem_addr' variables
From: Kirtika Ruchandani @ 2016-11-24  6:40 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Arnd Bergmann, Johannes Berg, linux-wireless, netdev

Initial commit cc0b88cf5ecf ([PATCH] Add adm8211 802.11b wireless driver)
introduced variables mem_addr and io_addr in adm80211_probe() that are
set but not used. Compiling with W=1 gives the following warnings,
fix them.

drivers/net/wireless/admtek/adm8211.c: In function ‘adm8211_probe’:
drivers/net/wireless/admtek/adm8211.c:1769:15: warning: variable ‘io_addr’ set but not used [-Wunused-but-set-variable]
  unsigned int io_addr, io_len;
               ^
drivers/net/wireless/admtek/adm8211.c:1768:16: warning: variable ‘mem_addr’ set but not used [-Wunused-but-set-variable]
  unsigned long mem_addr, mem_len;
                ^

These are harmless warnings and are only being fixed to reduce the
noise with W=1 in the kernel. The calls to pci_resource_start do not
have any side-effects and are safe to remove.

Fixes: cc0b88cf5ecf ("[PATCH] Add adm8211 802.11b wireless driver")
Cc: Michael Wu <flamingice@sourmilk.net>
Cc: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Kirtika Ruchandani <kirtika@chromium.org>
---
 drivers/net/wireless/admtek/adm8211.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/admtek/adm8211.c b/drivers/net/wireless/admtek/adm8211.c
index 70ecd82..70b4da0 100644
--- a/drivers/net/wireless/admtek/adm8211.c
+++ b/drivers/net/wireless/admtek/adm8211.c
@@ -1765,8 +1765,8 @@ static int adm8211_probe(struct pci_dev *pdev,
 {
	struct ieee80211_hw *dev;
	struct adm8211_priv *priv;
-	unsigned long mem_addr, mem_len;
-	unsigned int io_addr, io_len;
+	unsigned long mem_len;
+	unsigned int io_len;
	int err;
	u32 reg;
	u8 perm_addr[ETH_ALEN];
@@ -1778,9 +1778,7 @@ static int adm8211_probe(struct pci_dev *pdev,
		return err;
	}

-	io_addr = pci_resource_start(pdev, 0);
	io_len = pci_resource_len(pdev, 0);
-	mem_addr = pci_resource_start(pdev, 1);
	mem_len = pci_resource_len(pdev, 1);
	if (io_len < 256 || mem_len < 1024) {
		printk(KERN_ERR "%s (adm8211): Too short PCI resources\n",

^ permalink raw reply related

* Re: [scr265482] ip_tunnel.c
From: Cong Wang @ 2016-11-24  7:19 UTC (permalink / raw)
  To: Liyang Yu (于立洋1)
  Cc: security@kernel.org, netdev@vger.kernel.org,
	cve-request@mitre.org
In-Reply-To: <F41877A268BCDE49BAEE2286FA8C269F6FECFB15@LETV-MBX-IDC09.letv.local>

On Wed, Nov 23, 2016 at 6:47 PM, Liyang Yu (于立洋1) <yuliyang1@le.com> wrote:
> Hi:
>         I found that the GRE tunnel in same case can cause integer overflow in ip_tunnel.c:397
>
> Cause of the problem:
>         When tpi->seq less than tunnel->i_seqno, the packet will be droped.
>
> How to recurrence problem
>         1. Create an tunnel use kernel GRE module.
>     2. Use the tunnel to send packets for awile.
>     3.Reboot one site of the tunnel.
>     4. Communication interrupted

What do you mean by "reboot one site of the tunnel"?

If you mean something like delete and create it again,
it has nothing related to integer overflow, the tunnel->o_seqno
will restart from 0 and the tunnel->i_seqno will remain as it is
since we can't detect the interruption of the tunnel traffic.
If so, the following patch could help?


diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index 5719d6b..2738ff2 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -277,6 +277,7 @@ static struct net_device
*__ip_tunnel_create(struct net *net,
        tunnel = netdev_priv(dev);
        tunnel->parms = *parms;
        tunnel->net = net;
+       tunnel->o_seqno = UINT_MAX;

        err = register_netdevice(dev);
        if (err)

^ permalink raw reply related

* 答复: [scr265482] ip_tunnel.c
From: Liyang Yu (于立洋1) @ 2016-11-24  7:45 UTC (permalink / raw)
  To: Cong Wang
  Cc: security@kernel.org, netdev@vger.kernel.org,
	cve-request@mitre.org
In-Reply-To: <CAM_iQpX7mU7gogGx1peYMoOQbp0CZgYmTZJt=uGFm0c0gviY5A@mail.gmail.com>

Yeah,I means that recreate the tunnel again, 
But I don’t think the patch can fix the bug. It only can make the first packet received successed. And the follow packet will droped also.
In function __gre_xmit  line 366 
  tunnel->o_seqno++;

If you restart from UINT_MAX, the 'o_seqno' of second packet will return to 0 again. 

BTW:
   Can you read Chinese? :)

On Wed, Nov 23, 2016 at 6:47 PM, Liyang Yu (于立洋1) <yuliyang1@le.com> wrote:
> Hi:
>         I found that the GRE tunnel in same case can cause integer 
> overflow in ip_tunnel.c:397
>
> Cause of the problem:
>         When tpi->seq less than tunnel->i_seqno, the packet will be droped.
>
> How to recurrence problem
>         1. Create an tunnel use kernel GRE module.
>     2. Use the tunnel to send packets for awile.
>     3.Reboot one site of the tunnel.
>     4. Communication interrupted

What do you mean by "reboot one site of the tunnel"?

If you mean something like delete and create it again, it has nothing related to integer overflow, the tunnel->o_seqno will restart from 0 and the tunnel->i_seqno will remain as it is since we can't detect the interruption of the tunnel traffic.
If so, the following patch could help?


diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 5719d6b..2738ff2 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -277,6 +277,7 @@ static struct net_device *__ip_tunnel_create(struct net *net,
        tunnel = netdev_priv(dev);
        tunnel->parms = *parms;
        tunnel->net = net;
+       tunnel->o_seqno = UINT_MAX;

        err = register_netdevice(dev);
        if (err)

^ permalink raw reply

* Re: wl1251 & mac address & calibration data
From: Pavel Machek @ 2016-11-24  7:51 UTC (permalink / raw)
  To: Pali Rohár
  Cc: Michal Kazior, Kalle Valo, Ivaylo Dimitrov, Sebastian Reichel,
	Aaro Koskinen, Tony Lindgren, linux-wireless, Network Development,
	linux-kernel
In-Reply-To: <201611232339.59411@pali>

[-- Attachment #1: Type: text/plain, Size: 728 bytes --]

Hi!

> > "ifconfig hw ether XX" normally sets the address. I guess that's
> > ioctl?
> 
> This sets temporary address and it is ioctl. IIRC same as what ethtool 
> uses. (ifconfig is already deprecated).
> 
> > And I guess we should use similar mechanism for permanent
> > address.
> 
> I'm not sure here... Above ioctl ↑↑↑ is for changing temporary mac 
> address. But here we do not want to change permanent mac address. We 
> want to tell kernel driver current permanent mac address which is
> stored

Well... I'd still use similar mechanism :-).
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply

* Re: net/arp: ARP cache aging failed.
From: Julian Anastasov @ 2016-11-24  7:51 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Hannes Frederic Sowa, yuehaibing, davem, netdev
In-Reply-To: <1479944967.8455.516.camel@edumazet-glaptop3.roam.corp.google.com>


	Hello,

On Wed, 23 Nov 2016, Eric Dumazet wrote:

> On Wed, 2016-11-23 at 15:37 +0100, Hannes Frederic Sowa wrote:
> 
> > Irregardless about the question if bonding should keep the MAC address
> > alive, a MAC address can certainly change below a TCP connection.
> 
> Of course ;)
> 
> > 
> > dst_entry is 1:n to neigh_entry and as such we can end up confirming an
> > aging neighbor while sending a reply with dst->pending_confirm set while
> > the confirming packet actually came from a different neighbor.
> > 
> > I agree with Julian, pending_confirm became useless in this way.
> 
> Let's kill it then ;)

	It works for traffic via gateway. I now see that
we can even avoid write in dst_confirm:

	if (!dst->pending_confirm)
		dst->pending_confirm = 1;

	because it is called by non-dup TCP ACKs.

	But for traffic to hosts on LAN we need different solution,
i.e. for cached dsts with rt_gateway = 0 (last entry below).

rt_uses_gateway rt_gateway DST_NOCACHE Description
====================================================================
1               nh_gw      ANY         Traffic via gateway
0               LAN_host   1           FLOWI_FLAG_KNOWN_NH (nexthop
                                       set by IPVS, hdrincl, xt_TEE)
0               0          0           1 dst for many subnet hosts

Regards

^ permalink raw reply

* [PATCH 2/5] ath10k: Remove unused 'num_vdev_stats' variable
From: Kirtika Ruchandani @ 2016-11-24  8:01 UTC (permalink / raw)
  To: Kalle Valo
  Cc: Arnd Bergmann, netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA, Raja Mani, Michal Kazior
In-Reply-To: <cover.1479974100.git.kirtika-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>

Several functions for wmi stats parsing define and set num_vdev_stats
but do not use it. Compiling with W=1 gives the following warnings,
fix them.

drivers/net/wireless/ath/ath10k/wmi.c: In function ‘ath10k_wmi_main_op_pull_fw_stats’:
drivers/net/wireless/ath/ath10k/wmi.c:2680:22: warning: variable ‘num_vdev_stats’ set but not used [-Wunused-but-set-variable]
  u32 num_pdev_stats, num_vdev_stats, num_peer_stats;
                      ^
drivers/net/wireless/ath/ath10k/wmi.c: In function ‘ath10k_wmi_10x_op_pull_fw_stats’:
drivers/net/wireless/ath/ath10k/wmi.c:2735:22: warning: variable ‘num_vdev_stats’ set but not used [-Wunused-but-set-variable]
  u32 num_pdev_stats, num_vdev_stats, num_peer_stats;
                      ^
drivers/net/wireless/ath/ath10k/wmi.c: In function ‘ath10k_wmi_10_2_op_pull_fw_stats’:
drivers/net/wireless/ath/ath10k/wmi.c:2796:6: warning: variable ‘num_vdev_stats’ set but not used [-Wunused-but-set-variable]
  u32 num_vdev_stats;
      ^
drivers/net/wireless/ath/ath10k/wmi.c: In function ‘ath10k_wmi_10_2_4_op_pull_fw_stats’:
drivers/net/wireless/ath/ath10k/wmi.c:2875:6: warning: variable ‘num_vdev_stats’ set but not used [-Wunused-but-set-variable]
  u32 num_vdev_stats;
      ^
drivers/net/wireless/ath/ath10k/wmi.c: In function ‘ath10k_wmi_10_4_op_pull_fw_stats’:
drivers/net/wireless/ath/ath10k/wmi.c:2963:6: warning: variable ‘num_vdev_stats’ set but not used [-Wunused-but-set-variable]
  u32 num_vdev_stats;
      ^

These are harmless warnings and are only being fixed to reduce the
noise with W=1 in the kernel.

Fixes: d15fb5200664 ("ath10k: split wmi stats parsing")
Fixes: 20de2229c634 ("ath10k: fix 10.2 fw stats parsing")
Cc: Michal Kazior <michal.kazior-++hxYGjEMp0AvxtiuMwx3w@public.gmane.org>
Cc: Kalle Valo <kvalo-A+ZNKFmMK5xy9aJCnZT0Uw@public.gmane.org>
Signed-off-by: Kirtika Ruchandani <kirtika-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
---
 drivers/net/wireless/ath/ath10k/wmi.c | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 1f28187..10ec5a5 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2675,14 +2675,13 @@ static int ath10k_wmi_main_op_pull_fw_stats(struct ath10k *ar,
					    struct ath10k_fw_stats *stats)
 {
	const struct wmi_stats_event *ev = (void *)skb->data;
-	u32 num_pdev_stats, num_vdev_stats, num_peer_stats;
+	u32 num_pdev_stats, num_peer_stats;
	int i;

	if (!skb_pull(skb, sizeof(*ev)))
		return -EPROTO;

	num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
-	num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
	num_peer_stats = __le32_to_cpu(ev->num_peer_stats);

	for (i = 0; i < num_pdev_stats; i++) {
@@ -2730,14 +2729,13 @@ static int ath10k_wmi_10x_op_pull_fw_stats(struct ath10k *ar,
					   struct ath10k_fw_stats *stats)
 {
	const struct wmi_stats_event *ev = (void *)skb->data;
-	u32 num_pdev_stats, num_vdev_stats, num_peer_stats;
+	u32 num_pdev_stats, num_peer_stats;
	int i;

	if (!skb_pull(skb, sizeof(*ev)))
		return -EPROTO;

	num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
-	num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
	num_peer_stats = __le32_to_cpu(ev->num_peer_stats);

	for (i = 0; i < num_pdev_stats; i++) {
@@ -2791,7 +2789,6 @@ static int ath10k_wmi_10_2_op_pull_fw_stats(struct ath10k *ar,
	const struct wmi_10_2_stats_event *ev = (void *)skb->data;
	u32 num_pdev_stats;
	u32 num_pdev_ext_stats;
-	u32 num_vdev_stats;
	u32 num_peer_stats;
	int i;

@@ -2800,7 +2797,6 @@ static int ath10k_wmi_10_2_op_pull_fw_stats(struct ath10k *ar,

	num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
	num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats);
-	num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
	num_peer_stats = __le32_to_cpu(ev->num_peer_stats);

	for (i = 0; i < num_pdev_stats; i++) {
@@ -2870,7 +2866,6 @@ static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar,
	const struct wmi_10_2_stats_event *ev = (void *)skb->data;
	u32 num_pdev_stats;
	u32 num_pdev_ext_stats;
-	u32 num_vdev_stats;
	u32 num_peer_stats;
	int i;

@@ -2879,7 +2874,6 @@ static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar,

	num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
	num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats);
-	num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
	num_peer_stats = __le32_to_cpu(ev->num_peer_stats);

	for (i = 0; i < num_pdev_stats; i++) {
@@ -2958,7 +2952,6 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar,
	const struct wmi_10_2_stats_event *ev = (void *)skb->data;
	u32 num_pdev_stats;
	u32 num_pdev_ext_stats;
-	u32 num_vdev_stats;
	u32 num_peer_stats;
	u32 num_bcnflt_stats;
	u32 stats_id;
@@ -2969,7 +2962,6 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar,

	num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
	num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats);
-	num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
	num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
	num_bcnflt_stats = __le32_to_cpu(ev->num_bcnflt_stats);
	stats_id = __le32_to_cpu(ev->stats_id);
--
2.8.0.rc3.226.g39d4020

^ permalink raw reply related

* [PATCH 3/5] ath10k: Remove unused wmi_p2p_noa_descriptor 'noa' in wmi-tlv
From: Kirtika Ruchandani @ 2016-11-24  8:01 UTC (permalink / raw)
  To: Kalle Valo
  Cc: Arnd Bergmann, netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA, Raja Mani, Michal Kazior
In-Reply-To: <cover.1479974100.git.kirtika-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>

Commit ca996ec56608 (ath10k: implement wmi-tlv backend)
introduced ath10k_wmi_tlv_op_gen_vdev_start() where
'struct wmi_p2p_noa_descriptor *noa' is defined and set but not used.
Compiling with W=1 gives the following warning, fix it.
drivers/net/wireless/ath/ath10k/wmi-tlv.c: In function ‘ath10k_wmi_tlv_op_gen_vdev_start’:
drivers/net/wireless/ath/ath10k/wmi-tlv.c:1647:33: warning: variable ‘noa’ set but not used [-Wunused-but-set-variable]

Fixes: ca996ec56608 ("ath10k: implement wmi-tlv backend")
Cc: Michal Kazior <michal.kazior-++hxYGjEMp0AvxtiuMwx3w@public.gmane.org>
Cc: Kalle Valo <kvalo-A+ZNKFmMK5xy9aJCnZT0Uw@public.gmane.org>
Signed-off-by: Kirtika Ruchandani <kirtika-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
---
 drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index e64f593..0e4bd29 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -1644,7 +1644,6 @@ ath10k_wmi_tlv_op_gen_vdev_start(struct ath10k *ar,
 {
	struct wmi_tlv_vdev_start_cmd *cmd;
	struct wmi_channel *ch;
-	struct wmi_p2p_noa_descriptor *noa;
	struct wmi_tlv *tlv;
	struct sk_buff *skb;
	size_t len;
@@ -1702,7 +1701,6 @@ ath10k_wmi_tlv_op_gen_vdev_start(struct ath10k *ar,
	tlv = ptr;
	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
	tlv->len = 0;
-	noa = (void *)tlv->value;

	/* Note: This is a nested TLV containing:
	 * [wmi_tlv][wmi_p2p_noa_descriptor][wmi_tlv]..
--
2.8.0.rc3.226.g39d4020

^ permalink raw reply related

* [PATCH 5/5] ath10k: Removed unused 'dev' in ath10k_ahb_resource_init
From: Kirtika Ruchandani @ 2016-11-24  8:02 UTC (permalink / raw)
  To: Kalle Valo
  Cc: Arnd Bergmann, netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA, Raja Mani, Michal Kazior
In-Reply-To: <cover.1479974100.git.kirtika-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>

Commit 704dc4e36769 introduced ath10k_ahb_resource_init() which
defines and sets 'struct device* dev' but does not use it.
Compiling with W=1 gives the following warning, fix it.

drivers/net/wireless/ath/ath10k/ahb.c: In function ‘ath10k_ahb_resource_init’:
drivers/net/wireless/ath/ath10k/ahb.c:449:17: warning: variable ‘dev’ set but not used [-Wunused-but-set-variable]

This is a harmless warning, and is only being fixed to reduce the
noise with W=1 in the kernel.

Fixes: 704dc4e36769 ("ath10k: add resource init and deinit in ahb")
Cc: Raja Mani <rmani-Rm6X0d1/PG5y9aJCnZT0Uw@public.gmane.org>
Cc: Kalle Valo <kvalo-A+ZNKFmMK5xy9aJCnZT0Uw@public.gmane.org>
Signed-off-by: Kirtika Ruchandani <kirtika-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
---
 drivers/net/wireless/ath/ath10k/ahb.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c
index 8078d64..19507fe 100644
--- a/drivers/net/wireless/ath/ath10k/ahb.c
+++ b/drivers/net/wireless/ath/ath10k/ahb.c
@@ -443,12 +443,10 @@ static int ath10k_ahb_resource_init(struct ath10k *ar)
 {
	struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
	struct platform_device *pdev;
-	struct device *dev;
	struct resource *res;
	int ret;

	pdev = ar_ahb->pdev;
-	dev = &pdev->dev;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
--
2.8.0.rc3.226.g39d4020

^ permalink raw reply related

* [PATCH 1/5] ath10k: Remove unused 'buf_len' variable
From: Kirtika Ruchandani @ 2016-11-24  8:01 UTC (permalink / raw)
  To: Kalle Valo
  Cc: Arnd Bergmann, netdev, linux-wireless, Raja Mani, Michal Kazior
In-Reply-To: <cover.1479974100.git.kirtika@chromium.org>

Commit 32653cf19554 removed the call to 'skb_trim(skb, buf_len)'
in ath10k_wmi_event_mgmt_rx(), leaving the buf_len variable set but
unused. Compiling with W=1 gives the following warning, fix it.
drivers/net/wireless/ath/ath10k/wmi.c: In function ‘ath10k_wmi_event_mgmt_rx’:
drivers/net/wireless/ath/ath10k/wmi.c:2280:6: warning: variable ‘buf_len’ set but not used [-Wunused-but-set-variable]

This is a harmless warning, and is only being fixed to reduce the
noise with W=1 in the kernel.

Fixes: 32653cf19554 ("ath10k: implement intermediate event args")
Cc: Michal Kazior <michal.kazior@tieto.com>
Cc: Kalle Valo <kvalo@qca.qualcomm.com>
Signed-off-by: Kirtika Ruchandani <kirtika@chromium.org>
---
 drivers/net/wireless/ath/ath10k/wmi.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 387c4ee..1f28187 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2277,7 +2277,6 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
	u32 phy_mode;
	u32 snr;
	u32 rate;
-	u32 buf_len;
	u16 fc;
	int ret;

@@ -2289,7 +2288,6 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
	}

	channel = __le32_to_cpu(arg.channel);
-	buf_len = __le32_to_cpu(arg.buf_len);
	rx_status = __le32_to_cpu(arg.status);
	snr = __le32_to_cpu(arg.snr);
	phy_mode = __le32_to_cpu(arg.phy_mode);

^ permalink raw reply related

* [PATCH 0/5] Fix -Wunused-but-set-variable in ath10k/
From: Kirtika Ruchandani @ 2016-11-24  8:01 UTC (permalink / raw)
  To: Kalle Valo
  Cc: Arnd Bergmann, netdev, linux-wireless, Raja Mani, Michal Kazior

This patchset is part of the effort led by Arnd Bergmann to clean up
warnings in the kernel. This and following patchsets will focus on
"-Wunused-but-set-variable" as it among the noisier ones. These were
found compiling with W=1.

Kirtika Ruchandani (5):
  ath10k: Remove unused 'buf_len' variable
  ath10k: Remove unused 'num_vdev_stats' variable
  ath10k: Remove unused wmi_p2p_noa_descriptor 'noa' in wmi-tlv
  ath10k: Removed unused 'dev' in ath10k_ahb_clock_enable()
  ath10k: Removed unused 'dev' in ath10k_ahb_resource_init

 drivers/net/wireless/ath/ath10k/ahb.c     |  5 -----
 drivers/net/wireless/ath/ath10k/wmi-tlv.c |  2 --
 drivers/net/wireless/ath/ath10k/wmi.c     | 14 ++------------
 3 files changed, 2 insertions(+), 19 deletions(-)

^ permalink raw reply

* [PATCH 4/5] ath10k: Removed unused 'dev' in ath10k_ahb_clock_enable()
From: Kirtika Ruchandani @ 2016-11-24  8:02 UTC (permalink / raw)
  To: Kalle Valo
  Cc: Arnd Bergmann, netdev, linux-wireless, Raja Mani, Michal Kazior
In-Reply-To: <cover.1479974100.git.kirtika@chromium.org>

Commit 8beff219c528 introduced ath10k_ahb_clock_enable() which
defines and sets 'struct device* dev' but does not use it.
Compiling with W=1 gives the following warning, fix it.
drivers/net/wireless/ath/ath10k/ahb.c: In function ‘ath10k_ahb_clock_enable’:
drivers/net/wireless/ath/ath10k/ahb.c:133:17: warning: variable ‘dev’ set but not used [-Wunused-but-set-variable]

This is a harmless warning, and is only being fixed to reduce the
noise with W=1 in the kernel.

Fixes: 8beff219c528("ath10k: add clock ctrl related functions in ahb")
Cc: Raja Mani <rmani@qti.qualcomm.com>
Cc: Kalle Valo <kvalo@qca.qualcomm.com>
Signed-off-by: Kirtika Ruchandani <kirtika@chromium.org>
---
 drivers/net/wireless/ath/ath10k/ahb.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c
index 766c63b..8078d64 100644
--- a/drivers/net/wireless/ath/ath10k/ahb.c
+++ b/drivers/net/wireless/ath/ath10k/ahb.c
@@ -130,11 +130,8 @@ static void ath10k_ahb_clock_deinit(struct ath10k *ar)
 static int ath10k_ahb_clock_enable(struct ath10k *ar)
 {
	struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
-	struct device *dev;
	int ret;

-	dev = &ar_ahb->pdev->dev;
-
	if (IS_ERR_OR_NULL(ar_ahb->cmd_clk) ||
	    IS_ERR_OR_NULL(ar_ahb->ref_clk) ||
	    IS_ERR_OR_NULL(ar_ahb->rtc_clk)) {

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox