diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index d96eaf0aa6b8b6bb8809c682b5338732e84017ff..ad30b7b4769f8c47d328f6492db0d35dbd7a6159 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)