diff options
author | Stephen Hemminger <shemminger@vyatta.com> | 2008-01-21 02:23:49 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 15:08:40 -0800 |
commit | 4c30719f4f550d9b3034d9c00da9cb7fb99e6c0b (patch) | |
tree | db487b4ae184e7e6b90e2623c371f8a09edec830 | |
parent | 5b0ac72bc5fdda9634fb07db4cb0237fa9b6df68 (diff) |
[PKT_SCHED] dsmark: handle cloned and non-linear skb's
Make dsmark work properly with non-linear and cloned skb's
Before modifying the header, it needs to check that skb header is
writeable.
Note: this makes the assumption, that if it queues a good skb
then a good skb will come out of the embedded qdisc.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/sched/sch_dsmark.c | 19 |
1 files changed, 15 insertions, 4 deletions
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index d96eaf0aa6b..ad30b7b4769 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -187,13 +187,19 @@ static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch) pr_debug("dsmark_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); if (p->set_tc_index) { - /* FIXME: Safe with non-linear skbs? --RR */ switch (skb->protocol) { case __constant_htons(ETH_P_IP): + if (skb_cow_head(skb, sizeof(struct iphdr))) + goto drop; + skb->tc_index = ipv4_get_dsfield(ip_hdr(skb)) & ~INET_ECN_MASK; break; + case __constant_htons(ETH_P_IPV6): + if (skb_cow_head(skb, sizeof(struct ipv6hdr))) + goto drop; + skb->tc_index = ipv6_get_dsfield(ipv6_hdr(skb)) & ~INET_ECN_MASK; break; @@ -217,14 +223,14 @@ static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch) case TC_ACT_STOLEN: kfree_skb(skb); return NET_XMIT_SUCCESS; + case TC_ACT_SHOT: - kfree_skb(skb); - sch->qstats.drops++; - return NET_XMIT_BYPASS; + goto drop; #endif case TC_ACT_OK: skb->tc_index = TC_H_MIN(res.classid); break; + default: if (p->default_index != NO_DEFAULT_INDEX) skb->tc_index = p->default_index; @@ -243,6 +249,11 @@ static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch) sch->q.qlen++; return NET_XMIT_SUCCESS; + +drop: + kfree_skb(skb); + sch->qstats.drops++; + return NET_XMIT_BYPASS; } static struct sk_buff *dsmark_dequeue(struct Qdisc *sch) |