|
@@ -88,7 +88,7 @@ static inline int ip6_output_finish(struct sk_buff *skb)
|
|
} else if (dst->neighbour)
|
|
} else if (dst->neighbour)
|
|
return dst->neighbour->output(skb);
|
|
return dst->neighbour->output(skb);
|
|
|
|
|
|
- IP6_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
|
|
|
|
|
|
+ IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
|
|
kfree_skb(skb);
|
|
kfree_skb(skb);
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
@@ -118,6 +118,7 @@ static int ip6_output2(struct sk_buff *skb)
|
|
|
|
|
|
if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) {
|
|
if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) {
|
|
struct ipv6_pinfo* np = skb->sk ? inet6_sk(skb->sk) : NULL;
|
|
struct ipv6_pinfo* np = skb->sk ? inet6_sk(skb->sk) : NULL;
|
|
|
|
+ struct inet6_dev *idev = ip6_dst_idev(skb->dst);
|
|
|
|
|
|
if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) &&
|
|
if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) &&
|
|
ipv6_chk_mcast_addr(dev, &skb->nh.ipv6h->daddr,
|
|
ipv6_chk_mcast_addr(dev, &skb->nh.ipv6h->daddr,
|
|
@@ -133,13 +134,13 @@ static int ip6_output2(struct sk_buff *skb)
|
|
ip6_dev_loopback_xmit);
|
|
ip6_dev_loopback_xmit);
|
|
|
|
|
|
if (skb->nh.ipv6h->hop_limit == 0) {
|
|
if (skb->nh.ipv6h->hop_limit == 0) {
|
|
- IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
|
|
|
|
|
|
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
|
|
kfree_skb(skb);
|
|
kfree_skb(skb);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- IP6_INC_STATS(IPSTATS_MIB_OUTMCASTPKTS);
|
|
|
|
|
|
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTMCASTPKTS);
|
|
}
|
|
}
|
|
|
|
|
|
return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb,NULL, skb->dev,ip6_output_finish);
|
|
return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb,NULL, skb->dev,ip6_output_finish);
|
|
@@ -182,12 +183,14 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
|
|
|
|
|
|
if (skb_headroom(skb) < head_room) {
|
|
if (skb_headroom(skb) < head_room) {
|
|
struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
|
|
struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
|
|
- kfree_skb(skb);
|
|
|
|
- skb = skb2;
|
|
|
|
- if (skb == NULL) {
|
|
|
|
- IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
|
|
|
|
|
|
+ if (skb2 == NULL) {
|
|
|
|
+ IP6_INC_STATS(ip6_dst_idev(skb->dst),
|
|
|
|
+ IPSTATS_MIB_OUTDISCARDS);
|
|
|
|
+ kfree_skb(skb);
|
|
return -ENOBUFS;
|
|
return -ENOBUFS;
|
|
}
|
|
}
|
|
|
|
+ kfree_skb(skb);
|
|
|
|
+ skb = skb2;
|
|
if (sk)
|
|
if (sk)
|
|
skb_set_owner_w(skb, sk);
|
|
skb_set_owner_w(skb, sk);
|
|
}
|
|
}
|
|
@@ -230,7 +233,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
|
|
|
|
|
|
mtu = dst_mtu(dst);
|
|
mtu = dst_mtu(dst);
|
|
if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) {
|
|
if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) {
|
|
- IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
|
|
|
|
|
|
+ IP6_INC_STATS(ip6_dst_idev(skb->dst),
|
|
|
|
+ IPSTATS_MIB_OUTREQUESTS);
|
|
return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev,
|
|
return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev,
|
|
dst_output);
|
|
dst_output);
|
|
}
|
|
}
|
|
@@ -239,7 +243,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
|
|
printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n");
|
|
printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n");
|
|
skb->dev = dst->dev;
|
|
skb->dev = dst->dev;
|
|
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
|
|
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
|
|
- IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS);
|
|
|
|
|
|
+ IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS);
|
|
kfree_skb(skb);
|
|
kfree_skb(skb);
|
|
return -EMSGSIZE;
|
|
return -EMSGSIZE;
|
|
}
|
|
}
|
|
@@ -373,7 +377,7 @@ int ip6_forward(struct sk_buff *skb)
|
|
goto error;
|
|
goto error;
|
|
|
|
|
|
if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) {
|
|
if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) {
|
|
- IP6_INC_STATS(IPSTATS_MIB_INDISCARDS);
|
|
|
|
|
|
+ IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
|
|
goto drop;
|
|
goto drop;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -406,7 +410,7 @@ int ip6_forward(struct sk_buff *skb)
|
|
skb->dev = dst->dev;
|
|
skb->dev = dst->dev;
|
|
icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
|
|
icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
|
|
0, skb->dev);
|
|
0, skb->dev);
|
|
- IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
|
|
|
|
|
|
+ IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
|
|
|
|
|
|
kfree_skb(skb);
|
|
kfree_skb(skb);
|
|
return -ETIMEDOUT;
|
|
return -ETIMEDOUT;
|
|
@@ -419,13 +423,13 @@ int ip6_forward(struct sk_buff *skb)
|
|
if (proxied > 0)
|
|
if (proxied > 0)
|
|
return ip6_input(skb);
|
|
return ip6_input(skb);
|
|
else if (proxied < 0) {
|
|
else if (proxied < 0) {
|
|
- IP6_INC_STATS(IPSTATS_MIB_INDISCARDS);
|
|
|
|
|
|
+ IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
|
|
goto drop;
|
|
goto drop;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (!xfrm6_route_forward(skb)) {
|
|
if (!xfrm6_route_forward(skb)) {
|
|
- IP6_INC_STATS(IPSTATS_MIB_INDISCARDS);
|
|
|
|
|
|
+ IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
|
|
goto drop;
|
|
goto drop;
|
|
}
|
|
}
|
|
dst = skb->dst;
|
|
dst = skb->dst;
|
|
@@ -464,14 +468,14 @@ int ip6_forward(struct sk_buff *skb)
|
|
/* Again, force OUTPUT device used as source address */
|
|
/* Again, force OUTPUT device used as source address */
|
|
skb->dev = dst->dev;
|
|
skb->dev = dst->dev;
|
|
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_mtu(dst), skb->dev);
|
|
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_mtu(dst), skb->dev);
|
|
- IP6_INC_STATS_BH(IPSTATS_MIB_INTOOBIGERRORS);
|
|
|
|
- IP6_INC_STATS_BH(IPSTATS_MIB_FRAGFAILS);
|
|
|
|
|
|
+ IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS);
|
|
|
|
+ IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_FRAGFAILS);
|
|
kfree_skb(skb);
|
|
kfree_skb(skb);
|
|
return -EMSGSIZE;
|
|
return -EMSGSIZE;
|
|
}
|
|
}
|
|
|
|
|
|
if (skb_cow(skb, dst->dev->hard_header_len)) {
|
|
if (skb_cow(skb, dst->dev->hard_header_len)) {
|
|
- IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
|
|
|
|
|
|
+ IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_OUTDISCARDS);
|
|
goto drop;
|
|
goto drop;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -481,11 +485,11 @@ int ip6_forward(struct sk_buff *skb)
|
|
|
|
|
|
hdr->hop_limit--;
|
|
hdr->hop_limit--;
|
|
|
|
|
|
- IP6_INC_STATS_BH(IPSTATS_MIB_OUTFORWDATAGRAMS);
|
|
|
|
|
|
+ IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
|
|
return NF_HOOK(PF_INET6,NF_IP6_FORWARD, skb, skb->dev, dst->dev, ip6_forward_finish);
|
|
return NF_HOOK(PF_INET6,NF_IP6_FORWARD, skb, skb->dev, dst->dev, ip6_forward_finish);
|
|
|
|
|
|
error:
|
|
error:
|
|
- IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
|
|
|
|
|
|
+ IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS);
|
|
drop:
|
|
drop:
|
|
kfree_skb(skb);
|
|
kfree_skb(skb);
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
@@ -622,7 +626,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
|
|
|
|
|
|
tmp_hdr = kmalloc(hlen, GFP_ATOMIC);
|
|
tmp_hdr = kmalloc(hlen, GFP_ATOMIC);
|
|
if (!tmp_hdr) {
|
|
if (!tmp_hdr) {
|
|
- IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS);
|
|
|
|
|
|
+ IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS);
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -643,7 +647,8 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
|
|
skb->data_len = first_len - skb_headlen(skb);
|
|
skb->data_len = first_len - skb_headlen(skb);
|
|
skb->len = first_len;
|
|
skb->len = first_len;
|
|
skb->nh.ipv6h->payload_len = htons(first_len - sizeof(struct ipv6hdr));
|
|
skb->nh.ipv6h->payload_len = htons(first_len - sizeof(struct ipv6hdr));
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+ dst_hold(&rt->u.dst);
|
|
|
|
|
|
for (;;) {
|
|
for (;;) {
|
|
/* Prepare header of the next frame,
|
|
/* Prepare header of the next frame,
|
|
@@ -667,7 +672,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
|
|
|
|
|
|
err = output(skb);
|
|
err = output(skb);
|
|
if(!err)
|
|
if(!err)
|
|
- IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES);
|
|
|
|
|
|
+ IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGCREATES);
|
|
|
|
|
|
if (err || !frag)
|
|
if (err || !frag)
|
|
break;
|
|
break;
|
|
@@ -680,7 +685,8 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
|
|
kfree(tmp_hdr);
|
|
kfree(tmp_hdr);
|
|
|
|
|
|
if (err == 0) {
|
|
if (err == 0) {
|
|
- IP6_INC_STATS(IPSTATS_MIB_FRAGOKS);
|
|
|
|
|
|
+ IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGOKS);
|
|
|
|
+ dst_release(&rt->u.dst);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -690,7 +696,8 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
|
|
frag = skb;
|
|
frag = skb;
|
|
}
|
|
}
|
|
|
|
|
|
- IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS);
|
|
|
|
|
|
+ IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGFAILS);
|
|
|
|
+ dst_release(&rt->u.dst);
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -723,7 +730,8 @@ slow_path:
|
|
|
|
|
|
if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
|
|
if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
|
|
NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n");
|
|
NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n");
|
|
- IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS);
|
|
|
|
|
|
+ IP6_INC_STATS(ip6_dst_idev(skb->dst),
|
|
|
|
+ IPSTATS_MIB_FRAGFAILS);
|
|
err = -ENOMEM;
|
|
err = -ENOMEM;
|
|
goto fail;
|
|
goto fail;
|
|
}
|
|
}
|
|
@@ -784,15 +792,17 @@ slow_path:
|
|
if (err)
|
|
if (err)
|
|
goto fail;
|
|
goto fail;
|
|
|
|
|
|
- IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES);
|
|
|
|
|
|
+ IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGCREATES);
|
|
}
|
|
}
|
|
|
|
+ IP6_INC_STATS(ip6_dst_idev(skb->dst),
|
|
|
|
+ IPSTATS_MIB_FRAGOKS);
|
|
kfree_skb(skb);
|
|
kfree_skb(skb);
|
|
- IP6_INC_STATS(IPSTATS_MIB_FRAGOKS);
|
|
|
|
return err;
|
|
return err;
|
|
|
|
|
|
fail:
|
|
fail:
|
|
|
|
+ IP6_INC_STATS(ip6_dst_idev(skb->dst),
|
|
|
|
+ IPSTATS_MIB_FRAGFAILS);
|
|
kfree_skb(skb);
|
|
kfree_skb(skb);
|
|
- IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS);
|
|
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1265,7 +1275,7 @@ alloc_new_skb:
|
|
return 0;
|
|
return 0;
|
|
error:
|
|
error:
|
|
inet->cork.length -= length;
|
|
inet->cork.length -= length;
|
|
- IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
|
|
|
|
|
|
+ IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1326,7 +1336,7 @@ int ip6_push_pending_frames(struct sock *sk)
|
|
skb->priority = sk->sk_priority;
|
|
skb->priority = sk->sk_priority;
|
|
|
|
|
|
skb->dst = dst_clone(&rt->u.dst);
|
|
skb->dst = dst_clone(&rt->u.dst);
|
|
- IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
|
|
|
|
|
|
+ IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS);
|
|
err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output);
|
|
err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output);
|
|
if (err) {
|
|
if (err) {
|
|
if (err > 0)
|
|
if (err > 0)
|
|
@@ -1357,7 +1367,8 @@ void ip6_flush_pending_frames(struct sock *sk)
|
|
struct sk_buff *skb;
|
|
struct sk_buff *skb;
|
|
|
|
|
|
while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) {
|
|
while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) {
|
|
- IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
|
|
|
|
|
|
+ IP6_INC_STATS(ip6_dst_idev(skb->dst),
|
|
|
|
+ IPSTATS_MIB_OUTDISCARDS);
|
|
kfree_skb(skb);
|
|
kfree_skb(skb);
|
|
}
|
|
}
|
|
|
|
|