diff options
-rw-r--r-- | include/net/if_inet6.h | 1 | ||||
-rw-r--r-- | include/net/ipv6.h | 21 | ||||
-rw-r--r-- | net/ipv6/exthdrs.c | 57 | ||||
-rw-r--r-- | net/ipv6/icmp.c | 3 | ||||
-rw-r--r-- | net/ipv6/ip6_input.c | 40 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 71 | ||||
-rw-r--r-- | net/ipv6/mcast.c | 20 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 8 | ||||
-rw-r--r-- | net/ipv6/netfilter.c | 2 | ||||
-rw-r--r-- | net/ipv6/proc.c | 7 | ||||
-rw-r--r-- | net/ipv6/raw.c | 4 | ||||
-rw-r--r-- | net/ipv6/reassembly.c | 65 | ||||
-rw-r--r-- | net/ipv6/route.c | 4 |
13 files changed, 195 insertions, 108 deletions
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index 34489c13c119..3ec7d07346d6 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h | |||
@@ -152,6 +152,7 @@ struct ifacaddr6 | |||
152 | 152 | ||
153 | struct ipv6_devstat { | 153 | struct ipv6_devstat { |
154 | struct proc_dir_entry *proc_dir_entry; | 154 | struct proc_dir_entry *proc_dir_entry; |
155 | DEFINE_SNMP_STAT(struct ipstats_mib, ipv6); | ||
155 | DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6); | 156 | DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6); |
156 | }; | 157 | }; |
157 | 158 | ||
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 0b8c9b990ac4..3c266ad99a02 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h | |||
@@ -113,9 +113,24 @@ extern int sysctl_mld_max_msf; | |||
113 | 113 | ||
114 | /* MIBs */ | 114 | /* MIBs */ |
115 | DECLARE_SNMP_STAT(struct ipstats_mib, ipv6_statistics); | 115 | DECLARE_SNMP_STAT(struct ipstats_mib, ipv6_statistics); |
116 | #define IP6_INC_STATS(field) SNMP_INC_STATS(ipv6_statistics, field) | 116 | #define IP6_INC_STATS(idev,field) ({ \ |
117 | #define IP6_INC_STATS_BH(field) SNMP_INC_STATS_BH(ipv6_statistics, field) | 117 | struct inet6_dev *_idev = (idev); \ |
118 | #define IP6_INC_STATS_USER(field) SNMP_INC_STATS_USER(ipv6_statistics, field) | 118 | if (likely(_idev != NULL)) \ |
119 | SNMP_INC_STATS(_idev->stats.ipv6, field); \ | ||
120 | SNMP_INC_STATS(ipv6_statistics, field); \ | ||
121 | }) | ||
122 | #define IP6_INC_STATS_BH(idev,field) ({ \ | ||
123 | struct inet6_dev *_idev = (idev); \ | ||
124 | if (likely(_idev != NULL)) \ | ||
125 | SNMP_INC_STATS_BH(_idev->stats.ipv6, field); \ | ||
126 | SNMP_INC_STATS_BH(ipv6_statistics, field); \ | ||
127 | }) | ||
128 | #define IP6_INC_STATS_USER(idev,field) ({ \ | ||
129 | struct inet6_dev *_idev = (idev); \ | ||
130 | if (likely(_idev != NULL)) \ | ||
131 | SNMP_INC_STATS_USER(_idev->stats.ipv6, field); \ | ||
132 | SNMP_INC_STATS_USER(ipv6_statistics, field); \ | ||
133 | }) | ||
119 | DECLARE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics); | 134 | DECLARE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics); |
120 | #define ICMP6_INC_STATS(idev, field) ({ \ | 135 | #define ICMP6_INC_STATS(idev, field) ({ \ |
121 | struct inet6_dev *_idev = (idev); \ | 136 | struct inet6_dev *_idev = (idev); \ |
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 88c96b10684c..27829cc4ce88 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
@@ -284,10 +284,12 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp) | |||
284 | #ifdef CONFIG_IPV6_MIP6 | 284 | #ifdef CONFIG_IPV6_MIP6 |
285 | __u16 dstbuf; | 285 | __u16 dstbuf; |
286 | #endif | 286 | #endif |
287 | struct dst_entry *dst; | ||
287 | 288 | ||
288 | if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || | 289 | if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || |
289 | !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { | 290 | !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { |
290 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 291 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
292 | IPSTATS_MIB_INHDRERRORS); | ||
291 | kfree_skb(skb); | 293 | kfree_skb(skb); |
292 | return -1; | 294 | return -1; |
293 | } | 295 | } |
@@ -298,7 +300,9 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp) | |||
298 | dstbuf = opt->dst1; | 300 | dstbuf = opt->dst1; |
299 | #endif | 301 | #endif |
300 | 302 | ||
303 | dst = dst_clone(skb->dst); | ||
301 | if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) { | 304 | if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) { |
305 | dst_release(dst); | ||
302 | skb = *skbp; | 306 | skb = *skbp; |
303 | skb->h.raw += ((skb->h.raw[1]+1)<<3); | 307 | skb->h.raw += ((skb->h.raw[1]+1)<<3); |
304 | opt = IP6CB(skb); | 308 | opt = IP6CB(skb); |
@@ -310,7 +314,8 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp) | |||
310 | return 1; | 314 | return 1; |
311 | } | 315 | } |
312 | 316 | ||
313 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 317 | IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS); |
318 | dst_release(dst); | ||
314 | return -1; | 319 | return -1; |
315 | } | 320 | } |
316 | 321 | ||
@@ -365,7 +370,8 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp) | |||
365 | 370 | ||
366 | if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || | 371 | if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || |
367 | !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { | 372 | !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { |
368 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 373 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
374 | IPSTATS_MIB_INHDRERRORS); | ||
369 | kfree_skb(skb); | 375 | kfree_skb(skb); |
370 | return -1; | 376 | return -1; |
371 | } | 377 | } |
@@ -374,7 +380,8 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp) | |||
374 | 380 | ||
375 | if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr) || | 381 | if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr) || |
376 | skb->pkt_type != PACKET_HOST) { | 382 | skb->pkt_type != PACKET_HOST) { |
377 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | 383 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
384 | IPSTATS_MIB_INADDRERRORS); | ||
378 | kfree_skb(skb); | 385 | kfree_skb(skb); |
379 | return -1; | 386 | return -1; |
380 | } | 387 | } |
@@ -388,7 +395,8 @@ looped_back: | |||
388 | * processed by own | 395 | * processed by own |
389 | */ | 396 | */ |
390 | if (!addr) { | 397 | if (!addr) { |
391 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | 398 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
399 | IPSTATS_MIB_INADDRERRORS); | ||
392 | kfree_skb(skb); | 400 | kfree_skb(skb); |
393 | return -1; | 401 | return -1; |
394 | } | 402 | } |
@@ -410,7 +418,8 @@ looped_back: | |||
410 | switch (hdr->type) { | 418 | switch (hdr->type) { |
411 | case IPV6_SRCRT_TYPE_0: | 419 | case IPV6_SRCRT_TYPE_0: |
412 | if (hdr->hdrlen & 0x01) { | 420 | if (hdr->hdrlen & 0x01) { |
413 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 421 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
422 | IPSTATS_MIB_INHDRERRORS); | ||
414 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw); | 423 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw); |
415 | return -1; | 424 | return -1; |
416 | } | 425 | } |
@@ -419,14 +428,16 @@ looped_back: | |||
419 | case IPV6_SRCRT_TYPE_2: | 428 | case IPV6_SRCRT_TYPE_2: |
420 | /* Silently discard invalid RTH type 2 */ | 429 | /* Silently discard invalid RTH type 2 */ |
421 | if (hdr->hdrlen != 2 || hdr->segments_left != 1) { | 430 | if (hdr->hdrlen != 2 || hdr->segments_left != 1) { |
422 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 431 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
432 | IPSTATS_MIB_INHDRERRORS); | ||
423 | kfree_skb(skb); | 433 | kfree_skb(skb); |
424 | return -1; | 434 | return -1; |
425 | } | 435 | } |
426 | break; | 436 | break; |
427 | #endif | 437 | #endif |
428 | default: | 438 | default: |
429 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 439 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
440 | IPSTATS_MIB_INHDRERRORS); | ||
430 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw); | 441 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw); |
431 | return -1; | 442 | return -1; |
432 | } | 443 | } |
@@ -439,7 +450,8 @@ looped_back: | |||
439 | n = hdr->hdrlen >> 1; | 450 | n = hdr->hdrlen >> 1; |
440 | 451 | ||
441 | if (hdr->segments_left > n) { | 452 | if (hdr->segments_left > n) { |
442 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 453 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
454 | IPSTATS_MIB_INHDRERRORS); | ||
443 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw); | 455 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw); |
444 | return -1; | 456 | return -1; |
445 | } | 457 | } |
@@ -449,12 +461,14 @@ looped_back: | |||
449 | */ | 461 | */ |
450 | if (skb_cloned(skb)) { | 462 | if (skb_cloned(skb)) { |
451 | struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC); | 463 | struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC); |
452 | kfree_skb(skb); | ||
453 | /* the copy is a forwarded packet */ | 464 | /* the copy is a forwarded packet */ |
454 | if (skb2 == NULL) { | 465 | if (skb2 == NULL) { |
455 | IP6_INC_STATS_BH(IPSTATS_MIB_OUTDISCARDS); | 466 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
467 | IPSTATS_MIB_OUTDISCARDS); | ||
468 | kfree_skb(skb); | ||
456 | return -1; | 469 | return -1; |
457 | } | 470 | } |
471 | kfree_skb(skb); | ||
458 | *skbp = skb = skb2; | 472 | *skbp = skb = skb2; |
459 | opt = IP6CB(skb2); | 473 | opt = IP6CB(skb2); |
460 | hdr = (struct ipv6_rt_hdr *) skb2->h.raw; | 474 | hdr = (struct ipv6_rt_hdr *) skb2->h.raw; |
@@ -475,12 +489,14 @@ looped_back: | |||
475 | if (xfrm6_input_addr(skb, (xfrm_address_t *)addr, | 489 | if (xfrm6_input_addr(skb, (xfrm_address_t *)addr, |
476 | (xfrm_address_t *)&skb->nh.ipv6h->saddr, | 490 | (xfrm_address_t *)&skb->nh.ipv6h->saddr, |
477 | IPPROTO_ROUTING) < 0) { | 491 | IPPROTO_ROUTING) < 0) { |
478 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | 492 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
493 | IPSTATS_MIB_INADDRERRORS); | ||
479 | kfree_skb(skb); | 494 | kfree_skb(skb); |
480 | return -1; | 495 | return -1; |
481 | } | 496 | } |
482 | if (!ipv6_chk_home_addr(addr)) { | 497 | if (!ipv6_chk_home_addr(addr)) { |
483 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | 498 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
499 | IPSTATS_MIB_INADDRERRORS); | ||
484 | kfree_skb(skb); | 500 | kfree_skb(skb); |
485 | return -1; | 501 | return -1; |
486 | } | 502 | } |
@@ -491,7 +507,8 @@ looped_back: | |||
491 | } | 507 | } |
492 | 508 | ||
493 | if (ipv6_addr_is_multicast(addr)) { | 509 | if (ipv6_addr_is_multicast(addr)) { |
494 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | 510 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
511 | IPSTATS_MIB_INADDRERRORS); | ||
495 | kfree_skb(skb); | 512 | kfree_skb(skb); |
496 | return -1; | 513 | return -1; |
497 | } | 514 | } |
@@ -510,7 +527,8 @@ looped_back: | |||
510 | 527 | ||
511 | if (skb->dst->dev->flags&IFF_LOOPBACK) { | 528 | if (skb->dst->dev->flags&IFF_LOOPBACK) { |
512 | if (skb->nh.ipv6h->hop_limit <= 1) { | 529 | if (skb->nh.ipv6h->hop_limit <= 1) { |
513 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 530 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
531 | IPSTATS_MIB_INHDRERRORS); | ||
514 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, | 532 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, |
515 | 0, skb->dev); | 533 | 0, skb->dev); |
516 | kfree_skb(skb); | 534 | kfree_skb(skb); |
@@ -632,24 +650,25 @@ static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff) | |||
632 | if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) { | 650 | if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) { |
633 | LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", | 651 | LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", |
634 | skb->nh.raw[optoff+1]); | 652 | skb->nh.raw[optoff+1]); |
635 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 653 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
654 | IPSTATS_MIB_INHDRERRORS); | ||
636 | goto drop; | 655 | goto drop; |
637 | } | 656 | } |
638 | 657 | ||
639 | pkt_len = ntohl(*(u32*)(skb->nh.raw+optoff+2)); | 658 | pkt_len = ntohl(*(u32*)(skb->nh.raw+optoff+2)); |
640 | if (pkt_len <= IPV6_MAXPLEN) { | 659 | if (pkt_len <= IPV6_MAXPLEN) { |
641 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 660 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); |
642 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2); | 661 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2); |
643 | return 0; | 662 | return 0; |
644 | } | 663 | } |
645 | if (skb->nh.ipv6h->payload_len) { | 664 | if (skb->nh.ipv6h->payload_len) { |
646 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 665 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); |
647 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff); | 666 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff); |
648 | return 0; | 667 | return 0; |
649 | } | 668 | } |
650 | 669 | ||
651 | if (pkt_len > skb->len - sizeof(struct ipv6hdr)) { | 670 | if (pkt_len > skb->len - sizeof(struct ipv6hdr)) { |
652 | IP6_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS); | 671 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INTRUNCATEDPKTS); |
653 | goto drop; | 672 | goto drop; |
654 | } | 673 | } |
655 | 674 | ||
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 81bd45b26c98..52cca93ff2f8 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
@@ -177,7 +177,8 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, int type, | |||
177 | */ | 177 | */ |
178 | dst = ip6_route_output(sk, fl); | 178 | dst = ip6_route_output(sk, fl); |
179 | if (dst->error) { | 179 | if (dst->error) { |
180 | IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES); | 180 | IP6_INC_STATS(ip6_dst_idev(dst), |
181 | IPSTATS_MIB_OUTNOROUTES); | ||
181 | } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) { | 182 | } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) { |
182 | res = 1; | 183 | res = 1; |
183 | } else { | 184 | } else { |
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index ebf54ae90a0c..ad0b8abcdf4b 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
@@ -60,14 +60,22 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
60 | { | 60 | { |
61 | struct ipv6hdr *hdr; | 61 | struct ipv6hdr *hdr; |
62 | u32 pkt_len; | 62 | u32 pkt_len; |
63 | struct inet6_dev *idev; | ||
63 | 64 | ||
64 | if (skb->pkt_type == PACKET_OTHERHOST) | 65 | if (skb->pkt_type == PACKET_OTHERHOST) { |
65 | goto drop; | 66 | kfree_skb(skb); |
67 | return 0; | ||
68 | } | ||
69 | |||
70 | rcu_read_lock(); | ||
66 | 71 | ||
67 | IP6_INC_STATS_BH(IPSTATS_MIB_INRECEIVES); | 72 | idev = __in6_dev_get(skb->dev); |
73 | |||
74 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INRECEIVES); | ||
68 | 75 | ||
69 | if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { | 76 | if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { |
70 | IP6_INC_STATS_BH(IPSTATS_MIB_INDISCARDS); | 77 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS); |
78 | rcu_read_unlock(); | ||
71 | goto out; | 79 | goto out; |
72 | } | 80 | } |
73 | 81 | ||
@@ -104,7 +112,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
104 | if (pkt_len + sizeof(struct ipv6hdr) > skb->len) | 112 | if (pkt_len + sizeof(struct ipv6hdr) > skb->len) |
105 | goto truncated; | 113 | goto truncated; |
106 | if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) { | 114 | if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) { |
107 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 115 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS); |
108 | goto drop; | 116 | goto drop; |
109 | } | 117 | } |
110 | hdr = skb->nh.ipv6h; | 118 | hdr = skb->nh.ipv6h; |
@@ -112,17 +120,21 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
112 | 120 | ||
113 | if (hdr->nexthdr == NEXTHDR_HOP) { | 121 | if (hdr->nexthdr == NEXTHDR_HOP) { |
114 | if (ipv6_parse_hopopts(&skb) < 0) { | 122 | if (ipv6_parse_hopopts(&skb) < 0) { |
115 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 123 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS); |
124 | rcu_read_unlock(); | ||
116 | return 0; | 125 | return 0; |
117 | } | 126 | } |
118 | } | 127 | } |
119 | 128 | ||
129 | rcu_read_unlock(); | ||
130 | |||
120 | return NF_HOOK(PF_INET6,NF_IP6_PRE_ROUTING, skb, dev, NULL, ip6_rcv_finish); | 131 | return NF_HOOK(PF_INET6,NF_IP6_PRE_ROUTING, skb, dev, NULL, ip6_rcv_finish); |
121 | truncated: | 132 | truncated: |
122 | IP6_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS); | 133 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INTRUNCATEDPKTS); |
123 | err: | 134 | err: |
124 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 135 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS); |
125 | drop: | 136 | drop: |
137 | rcu_read_unlock(); | ||
126 | kfree_skb(skb); | 138 | kfree_skb(skb); |
127 | out: | 139 | out: |
128 | return 0; | 140 | return 0; |
@@ -140,6 +152,7 @@ static inline int ip6_input_finish(struct sk_buff *skb) | |||
140 | unsigned int nhoff; | 152 | unsigned int nhoff; |
141 | int nexthdr; | 153 | int nexthdr; |
142 | u8 hash; | 154 | u8 hash; |
155 | struct inet6_dev *idev; | ||
143 | 156 | ||
144 | /* | 157 | /* |
145 | * Parse extension headers | 158 | * Parse extension headers |
@@ -147,6 +160,7 @@ static inline int ip6_input_finish(struct sk_buff *skb) | |||
147 | 160 | ||
148 | rcu_read_lock(); | 161 | rcu_read_lock(); |
149 | resubmit: | 162 | resubmit: |
163 | idev = ip6_dst_idev(skb->dst); | ||
150 | if (!pskb_pull(skb, skb->h.raw - skb->data)) | 164 | if (!pskb_pull(skb, skb->h.raw - skb->data)) |
151 | goto discard; | 165 | goto discard; |
152 | nhoff = IP6CB(skb)->nhoff; | 166 | nhoff = IP6CB(skb)->nhoff; |
@@ -185,24 +199,24 @@ resubmit: | |||
185 | if (ret > 0) | 199 | if (ret > 0) |
186 | goto resubmit; | 200 | goto resubmit; |
187 | else if (ret == 0) | 201 | else if (ret == 0) |
188 | IP6_INC_STATS_BH(IPSTATS_MIB_INDELIVERS); | 202 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDELIVERS); |
189 | } else { | 203 | } else { |
190 | if (!raw_sk) { | 204 | if (!raw_sk) { |
191 | if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { | 205 | if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { |
192 | IP6_INC_STATS_BH(IPSTATS_MIB_INUNKNOWNPROTOS); | 206 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INUNKNOWNPROTOS); |
193 | icmpv6_send(skb, ICMPV6_PARAMPROB, | 207 | icmpv6_send(skb, ICMPV6_PARAMPROB, |
194 | ICMPV6_UNK_NEXTHDR, nhoff, | 208 | ICMPV6_UNK_NEXTHDR, nhoff, |
195 | skb->dev); | 209 | skb->dev); |
196 | } | 210 | } |
197 | } else | 211 | } else |
198 | IP6_INC_STATS_BH(IPSTATS_MIB_INDELIVERS); | 212 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDELIVERS); |
199 | kfree_skb(skb); | 213 | kfree_skb(skb); |
200 | } | 214 | } |
201 | rcu_read_unlock(); | 215 | rcu_read_unlock(); |
202 | return 0; | 216 | return 0; |
203 | 217 | ||
204 | discard: | 218 | discard: |
205 | IP6_INC_STATS_BH(IPSTATS_MIB_INDISCARDS); | 219 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS); |
206 | rcu_read_unlock(); | 220 | rcu_read_unlock(); |
207 | kfree_skb(skb); | 221 | kfree_skb(skb); |
208 | return 0; | 222 | return 0; |
@@ -219,7 +233,7 @@ int ip6_mc_input(struct sk_buff *skb) | |||
219 | struct ipv6hdr *hdr; | 233 | struct ipv6hdr *hdr; |
220 | int deliver; | 234 | int deliver; |
221 | 235 | ||
222 | IP6_INC_STATS_BH(IPSTATS_MIB_INMCASTPKTS); | 236 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INMCASTPKTS); |
223 | 237 | ||
224 | hdr = skb->nh.ipv6h; | 238 | hdr = skb->nh.ipv6h; |
225 | deliver = likely(!(skb->dev->flags & (IFF_PROMISC|IFF_ALLMULTI))) || | 239 | deliver = likely(!(skb->dev->flags & (IFF_PROMISC|IFF_ALLMULTI))) || |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 1bde3aca3466..85f889270492 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -88,7 +88,7 @@ static inline int ip6_output_finish(struct sk_buff *skb) | |||
88 | } else if (dst->neighbour) | 88 | } else if (dst->neighbour) |
89 | return dst->neighbour->output(skb); | 89 | return dst->neighbour->output(skb); |
90 | 90 | ||
91 | IP6_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); | 91 | IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); |
92 | kfree_skb(skb); | 92 | kfree_skb(skb); |
93 | return -EINVAL; | 93 | return -EINVAL; |
94 | 94 | ||
@@ -118,6 +118,7 @@ static int ip6_output2(struct sk_buff *skb) | |||
118 | 118 | ||
119 | if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) { | 119 | if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) { |
120 | struct ipv6_pinfo* np = skb->sk ? inet6_sk(skb->sk) : NULL; | 120 | struct ipv6_pinfo* np = skb->sk ? inet6_sk(skb->sk) : NULL; |
121 | struct inet6_dev *idev = ip6_dst_idev(skb->dst); | ||
121 | 122 | ||
122 | if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) && | 123 | if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) && |
123 | ipv6_chk_mcast_addr(dev, &skb->nh.ipv6h->daddr, | 124 | ipv6_chk_mcast_addr(dev, &skb->nh.ipv6h->daddr, |
@@ -133,13 +134,13 @@ static int ip6_output2(struct sk_buff *skb) | |||
133 | ip6_dev_loopback_xmit); | 134 | ip6_dev_loopback_xmit); |
134 | 135 | ||
135 | if (skb->nh.ipv6h->hop_limit == 0) { | 136 | if (skb->nh.ipv6h->hop_limit == 0) { |
136 | IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); | 137 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS); |
137 | kfree_skb(skb); | 138 | kfree_skb(skb); |
138 | return 0; | 139 | return 0; |
139 | } | 140 | } |
140 | } | 141 | } |
141 | 142 | ||
142 | IP6_INC_STATS(IPSTATS_MIB_OUTMCASTPKTS); | 143 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTMCASTPKTS); |
143 | } | 144 | } |
144 | 145 | ||
145 | return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb,NULL, skb->dev,ip6_output_finish); | 146 | 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, | |||
182 | 183 | ||
183 | if (skb_headroom(skb) < head_room) { | 184 | if (skb_headroom(skb) < head_room) { |
184 | struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room); | 185 | struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room); |
185 | kfree_skb(skb); | 186 | if (skb2 == NULL) { |
186 | skb = skb2; | 187 | IP6_INC_STATS(ip6_dst_idev(skb->dst), |
187 | if (skb == NULL) { | 188 | IPSTATS_MIB_OUTDISCARDS); |
188 | IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); | 189 | kfree_skb(skb); |
189 | return -ENOBUFS; | 190 | return -ENOBUFS; |
190 | } | 191 | } |
192 | kfree_skb(skb); | ||
193 | skb = skb2; | ||
191 | if (sk) | 194 | if (sk) |
192 | skb_set_owner_w(skb, sk); | 195 | skb_set_owner_w(skb, sk); |
193 | } | 196 | } |
@@ -230,7 +233,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
230 | 233 | ||
231 | mtu = dst_mtu(dst); | 234 | mtu = dst_mtu(dst); |
232 | if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) { | 235 | if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) { |
233 | IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); | 236 | IP6_INC_STATS(ip6_dst_idev(skb->dst), |
237 | IPSTATS_MIB_OUTREQUESTS); | ||
234 | return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, | 238 | return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, |
235 | dst_output); | 239 | dst_output); |
236 | } | 240 | } |
@@ -239,7 +243,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
239 | printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n"); | 243 | printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n"); |
240 | skb->dev = dst->dev; | 244 | skb->dev = dst->dev; |
241 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); | 245 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); |
242 | IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); | 246 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS); |
243 | kfree_skb(skb); | 247 | kfree_skb(skb); |
244 | return -EMSGSIZE; | 248 | return -EMSGSIZE; |
245 | } | 249 | } |
@@ -373,7 +377,7 @@ int ip6_forward(struct sk_buff *skb) | |||
373 | goto error; | 377 | goto error; |
374 | 378 | ||
375 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { | 379 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { |
376 | IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); | 380 | IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); |
377 | goto drop; | 381 | goto drop; |
378 | } | 382 | } |
379 | 383 | ||
@@ -406,7 +410,7 @@ int ip6_forward(struct sk_buff *skb) | |||
406 | skb->dev = dst->dev; | 410 | skb->dev = dst->dev; |
407 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, | 411 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, |
408 | 0, skb->dev); | 412 | 0, skb->dev); |
409 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 413 | IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS); |
410 | 414 | ||
411 | kfree_skb(skb); | 415 | kfree_skb(skb); |
412 | return -ETIMEDOUT; | 416 | return -ETIMEDOUT; |
@@ -419,13 +423,13 @@ int ip6_forward(struct sk_buff *skb) | |||
419 | if (proxied > 0) | 423 | if (proxied > 0) |
420 | return ip6_input(skb); | 424 | return ip6_input(skb); |
421 | else if (proxied < 0) { | 425 | else if (proxied < 0) { |
422 | IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); | 426 | IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); |
423 | goto drop; | 427 | goto drop; |
424 | } | 428 | } |
425 | } | 429 | } |
426 | 430 | ||
427 | if (!xfrm6_route_forward(skb)) { | 431 | if (!xfrm6_route_forward(skb)) { |
428 | IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); | 432 | IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); |
429 | goto drop; | 433 | goto drop; |
430 | } | 434 | } |
431 | dst = skb->dst; | 435 | dst = skb->dst; |
@@ -464,14 +468,14 @@ int ip6_forward(struct sk_buff *skb) | |||
464 | /* Again, force OUTPUT device used as source address */ | 468 | /* Again, force OUTPUT device used as source address */ |
465 | skb->dev = dst->dev; | 469 | skb->dev = dst->dev; |
466 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_mtu(dst), skb->dev); | 470 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_mtu(dst), skb->dev); |
467 | IP6_INC_STATS_BH(IPSTATS_MIB_INTOOBIGERRORS); | 471 | IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS); |
468 | IP6_INC_STATS_BH(IPSTATS_MIB_FRAGFAILS); | 472 | IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_FRAGFAILS); |
469 | kfree_skb(skb); | 473 | kfree_skb(skb); |
470 | return -EMSGSIZE; | 474 | return -EMSGSIZE; |
471 | } | 475 | } |
472 | 476 | ||
473 | if (skb_cow(skb, dst->dev->hard_header_len)) { | 477 | if (skb_cow(skb, dst->dev->hard_header_len)) { |
474 | IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); | 478 | IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_OUTDISCARDS); |
475 | goto drop; | 479 | goto drop; |
476 | } | 480 | } |
477 | 481 | ||
@@ -481,11 +485,11 @@ int ip6_forward(struct sk_buff *skb) | |||
481 | 485 | ||
482 | hdr->hop_limit--; | 486 | hdr->hop_limit--; |
483 | 487 | ||
484 | IP6_INC_STATS_BH(IPSTATS_MIB_OUTFORWDATAGRAMS); | 488 | IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS); |
485 | return NF_HOOK(PF_INET6,NF_IP6_FORWARD, skb, skb->dev, dst->dev, ip6_forward_finish); | 489 | return NF_HOOK(PF_INET6,NF_IP6_FORWARD, skb, skb->dev, dst->dev, ip6_forward_finish); |
486 | 490 | ||
487 | error: | 491 | error: |
488 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | 492 | IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS); |
489 | drop: | 493 | drop: |
490 | kfree_skb(skb); | 494 | kfree_skb(skb); |
491 | return -EINVAL; | 495 | return -EINVAL; |
@@ -622,7 +626,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
622 | 626 | ||
623 | tmp_hdr = kmalloc(hlen, GFP_ATOMIC); | 627 | tmp_hdr = kmalloc(hlen, GFP_ATOMIC); |
624 | if (!tmp_hdr) { | 628 | if (!tmp_hdr) { |
625 | IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); | 629 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS); |
626 | return -ENOMEM; | 630 | return -ENOMEM; |
627 | } | 631 | } |
628 | 632 | ||
@@ -643,7 +647,8 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
643 | skb->data_len = first_len - skb_headlen(skb); | 647 | skb->data_len = first_len - skb_headlen(skb); |
644 | skb->len = first_len; | 648 | skb->len = first_len; |
645 | skb->nh.ipv6h->payload_len = htons(first_len - sizeof(struct ipv6hdr)); | 649 | skb->nh.ipv6h->payload_len = htons(first_len - sizeof(struct ipv6hdr)); |
646 | 650 | ||
651 | dst_hold(&rt->u.dst); | ||
647 | 652 | ||
648 | for (;;) { | 653 | for (;;) { |
649 | /* Prepare header of the next frame, | 654 | /* Prepare header of the next frame, |
@@ -667,7 +672,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
667 | 672 | ||
668 | err = output(skb); | 673 | err = output(skb); |
669 | if(!err) | 674 | if(!err) |
670 | IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES); | 675 | IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGCREATES); |
671 | 676 | ||
672 | if (err || !frag) | 677 | if (err || !frag) |
673 | break; | 678 | break; |
@@ -680,7 +685,8 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
680 | kfree(tmp_hdr); | 685 | kfree(tmp_hdr); |
681 | 686 | ||
682 | if (err == 0) { | 687 | if (err == 0) { |
683 | IP6_INC_STATS(IPSTATS_MIB_FRAGOKS); | 688 | IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGOKS); |
689 | dst_release(&rt->u.dst); | ||
684 | return 0; | 690 | return 0; |
685 | } | 691 | } |
686 | 692 | ||
@@ -690,7 +696,8 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
690 | frag = skb; | 696 | frag = skb; |
691 | } | 697 | } |
692 | 698 | ||
693 | IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); | 699 | IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGFAILS); |
700 | dst_release(&rt->u.dst); | ||
694 | return err; | 701 | return err; |
695 | } | 702 | } |
696 | 703 | ||
@@ -723,7 +730,8 @@ slow_path: | |||
723 | 730 | ||
724 | if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) { | 731 | if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) { |
725 | NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n"); | 732 | NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n"); |
726 | IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); | 733 | IP6_INC_STATS(ip6_dst_idev(skb->dst), |
734 | IPSTATS_MIB_FRAGFAILS); | ||
727 | err = -ENOMEM; | 735 | err = -ENOMEM; |
728 | goto fail; | 736 | goto fail; |
729 | } | 737 | } |
@@ -784,15 +792,17 @@ slow_path: | |||
784 | if (err) | 792 | if (err) |
785 | goto fail; | 793 | goto fail; |
786 | 794 | ||
787 | IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES); | 795 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGCREATES); |
788 | } | 796 | } |
797 | IP6_INC_STATS(ip6_dst_idev(skb->dst), | ||
798 | IPSTATS_MIB_FRAGOKS); | ||
789 | kfree_skb(skb); | 799 | kfree_skb(skb); |
790 | IP6_INC_STATS(IPSTATS_MIB_FRAGOKS); | ||
791 | return err; | 800 | return err; |
792 | 801 | ||
793 | fail: | 802 | fail: |
803 | IP6_INC_STATS(ip6_dst_idev(skb->dst), | ||
804 | IPSTATS_MIB_FRAGFAILS); | ||
794 | kfree_skb(skb); | 805 | kfree_skb(skb); |
795 | IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); | ||
796 | return err; | 806 | return err; |
797 | } | 807 | } |
798 | 808 | ||
@@ -1265,7 +1275,7 @@ alloc_new_skb: | |||
1265 | return 0; | 1275 | return 0; |
1266 | error: | 1276 | error: |
1267 | inet->cork.length -= length; | 1277 | inet->cork.length -= length; |
1268 | IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); | 1278 | IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); |
1269 | return err; | 1279 | return err; |
1270 | } | 1280 | } |
1271 | 1281 | ||
@@ -1326,7 +1336,7 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1326 | skb->priority = sk->sk_priority; | 1336 | skb->priority = sk->sk_priority; |
1327 | 1337 | ||
1328 | skb->dst = dst_clone(&rt->u.dst); | 1338 | skb->dst = dst_clone(&rt->u.dst); |
1329 | IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); | 1339 | IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS); |
1330 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output); | 1340 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output); |
1331 | if (err) { | 1341 | if (err) { |
1332 | if (err > 0) | 1342 | if (err > 0) |
@@ -1357,7 +1367,8 @@ void ip6_flush_pending_frames(struct sock *sk) | |||
1357 | struct sk_buff *skb; | 1367 | struct sk_buff *skb; |
1358 | 1368 | ||
1359 | while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) { | 1369 | while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) { |
1360 | IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); | 1370 | IP6_INC_STATS(ip6_dst_idev(skb->dst), |
1371 | IPSTATS_MIB_OUTDISCARDS); | ||
1361 | kfree_skb(skb); | 1372 | kfree_skb(skb); |
1362 | } | 1373 | } |
1363 | 1374 | ||
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 9055979083b6..c006d02be8bc 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -1465,7 +1465,7 @@ static void mld_sendpack(struct sk_buff *skb) | |||
1465 | struct inet6_dev *idev = in6_dev_get(skb->dev); | 1465 | struct inet6_dev *idev = in6_dev_get(skb->dev); |
1466 | int err; | 1466 | int err; |
1467 | 1467 | ||
1468 | IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); | 1468 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS); |
1469 | payload_len = skb->tail - (unsigned char *)skb->nh.ipv6h - | 1469 | payload_len = skb->tail - (unsigned char *)skb->nh.ipv6h - |
1470 | sizeof(struct ipv6hdr); | 1470 | sizeof(struct ipv6hdr); |
1471 | mldlen = skb->tail - skb->h.raw; | 1471 | mldlen = skb->tail - skb->h.raw; |
@@ -1477,9 +1477,9 @@ static void mld_sendpack(struct sk_buff *skb) | |||
1477 | mld_dev_queue_xmit); | 1477 | mld_dev_queue_xmit); |
1478 | if (!err) { | 1478 | if (!err) { |
1479 | ICMP6_INC_STATS(idev,ICMP6_MIB_OUTMSGS); | 1479 | ICMP6_INC_STATS(idev,ICMP6_MIB_OUTMSGS); |
1480 | IP6_INC_STATS(IPSTATS_MIB_OUTMCASTPKTS); | 1480 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTMCASTPKTS); |
1481 | } else | 1481 | } else |
1482 | IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); | 1482 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS); |
1483 | 1483 | ||
1484 | if (likely(idev != NULL)) | 1484 | if (likely(idev != NULL)) |
1485 | in6_dev_put(idev); | 1485 | in6_dev_put(idev); |
@@ -1763,7 +1763,10 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1763 | IPV6_TLV_ROUTERALERT, 2, 0, 0, | 1763 | IPV6_TLV_ROUTERALERT, 2, 0, 0, |
1764 | IPV6_TLV_PADN, 0 }; | 1764 | IPV6_TLV_PADN, 0 }; |
1765 | 1765 | ||
1766 | IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); | 1766 | rcu_read_lock(); |
1767 | IP6_INC_STATS(__in6_dev_get(dev), | ||
1768 | IPSTATS_MIB_OUTREQUESTS); | ||
1769 | rcu_read_unlock(); | ||
1767 | snd_addr = addr; | 1770 | snd_addr = addr; |
1768 | if (type == ICMPV6_MGM_REDUCTION) { | 1771 | if (type == ICMPV6_MGM_REDUCTION) { |
1769 | snd_addr = &all_routers; | 1772 | snd_addr = &all_routers; |
@@ -1777,7 +1780,10 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1777 | skb = sock_alloc_send_skb(sk, LL_RESERVED_SPACE(dev) + full_len, 1, &err); | 1780 | skb = sock_alloc_send_skb(sk, LL_RESERVED_SPACE(dev) + full_len, 1, &err); |
1778 | 1781 | ||
1779 | if (skb == NULL) { | 1782 | if (skb == NULL) { |
1780 | IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); | 1783 | rcu_read_lock(); |
1784 | IP6_INC_STATS(__in6_dev_get(dev), | ||
1785 | IPSTATS_MIB_OUTDISCARDS); | ||
1786 | rcu_read_unlock(); | ||
1781 | return; | 1787 | return; |
1782 | } | 1788 | } |
1783 | 1789 | ||
@@ -1816,9 +1822,9 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1816 | else | 1822 | else |
1817 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTGROUPMEMBRESPONSES); | 1823 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTGROUPMEMBRESPONSES); |
1818 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS); | 1824 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS); |
1819 | IP6_INC_STATS(IPSTATS_MIB_OUTMCASTPKTS); | 1825 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTMCASTPKTS); |
1820 | } else | 1826 | } else |
1821 | IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); | 1827 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS); |
1822 | 1828 | ||
1823 | if (likely(idev != NULL)) | 1829 | if (likely(idev != NULL)) |
1824 | in6_dev_put(idev); | 1830 | in6_dev_put(idev); |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 89d527ebd7f6..1342be8b4cdc 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -515,7 +515,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
515 | 515 | ||
516 | skb->dst = dst; | 516 | skb->dst = dst; |
517 | idev = in6_dev_get(dst->dev); | 517 | idev = in6_dev_get(dst->dev); |
518 | IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); | 518 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS); |
519 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output); | 519 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output); |
520 | if (!err) { | 520 | if (!err) { |
521 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTNEIGHBORADVERTISEMENTS); | 521 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTNEIGHBORADVERTISEMENTS); |
@@ -601,7 +601,7 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, | |||
601 | /* send it! */ | 601 | /* send it! */ |
602 | skb->dst = dst; | 602 | skb->dst = dst; |
603 | idev = in6_dev_get(dst->dev); | 603 | idev = in6_dev_get(dst->dev); |
604 | IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); | 604 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS); |
605 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output); | 605 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output); |
606 | if (!err) { | 606 | if (!err) { |
607 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTNEIGHBORSOLICITS); | 607 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTNEIGHBORSOLICITS); |
@@ -676,7 +676,7 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, | |||
676 | /* send it! */ | 676 | /* send it! */ |
677 | skb->dst = dst; | 677 | skb->dst = dst; |
678 | idev = in6_dev_get(dst->dev); | 678 | idev = in6_dev_get(dst->dev); |
679 | IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); | 679 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS); |
680 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output); | 680 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output); |
681 | if (!err) { | 681 | if (!err) { |
682 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTROUTERSOLICITS); | 682 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTROUTERSOLICITS); |
@@ -1512,7 +1512,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1512 | 1512 | ||
1513 | buff->dst = dst; | 1513 | buff->dst = dst; |
1514 | idev = in6_dev_get(dst->dev); | 1514 | idev = in6_dev_get(dst->dev); |
1515 | IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); | 1515 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS); |
1516 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, buff, NULL, dst->dev, dst_output); | 1516 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, buff, NULL, dst->dev, dst_output); |
1517 | if (!err) { | 1517 | if (!err) { |
1518 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTREDIRECTS); | 1518 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTREDIRECTS); |
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 580b1aba6722..646a47456fd4 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c | |||
@@ -31,7 +31,7 @@ int ip6_route_me_harder(struct sk_buff *skb) | |||
31 | #endif | 31 | #endif |
32 | 32 | ||
33 | if (dst->error) { | 33 | if (dst->error) { |
34 | IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES); | 34 | IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); |
35 | LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n"); | 35 | LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n"); |
36 | dst_release(dst); | 36 | dst_release(dst); |
37 | return -EINVAL; | 37 | return -EINVAL; |
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index efee7a6301a8..4158d386b0aa 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c | |||
@@ -161,6 +161,7 @@ static int snmp6_seq_show(struct seq_file *seq, void *v) | |||
161 | 161 | ||
162 | if (idev) { | 162 | if (idev) { |
163 | seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex); | 163 | seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex); |
164 | snmp6_seq_show_item(seq, (void **)idev->stats.ipv6, snmp6_ipstats_list); | ||
164 | snmp6_seq_show_item(seq, (void **)idev->stats.icmpv6, snmp6_icmp6_list); | 165 | snmp6_seq_show_item(seq, (void **)idev->stats.icmpv6, snmp6_icmp6_list); |
165 | } else { | 166 | } else { |
166 | snmp6_seq_show_item(seq, (void **)ipv6_statistics, snmp6_ipstats_list); | 167 | snmp6_seq_show_item(seq, (void **)ipv6_statistics, snmp6_ipstats_list); |
@@ -281,6 +282,9 @@ int snmp6_alloc_dev(struct inet6_dev *idev) | |||
281 | if (!idev || !idev->dev) | 282 | if (!idev || !idev->dev) |
282 | return -EINVAL; | 283 | return -EINVAL; |
283 | 284 | ||
285 | if (snmp6_mib_init((void **)idev->stats.ipv6, sizeof(struct ipstats_mib), | ||
286 | __alignof__(struct ipstats_mib)) < 0) | ||
287 | goto err_ip; | ||
284 | if (snmp6_mib_init((void **)idev->stats.icmpv6, sizeof(struct icmpv6_mib), | 288 | if (snmp6_mib_init((void **)idev->stats.icmpv6, sizeof(struct icmpv6_mib), |
285 | __alignof__(struct icmpv6_mib)) < 0) | 289 | __alignof__(struct icmpv6_mib)) < 0) |
286 | goto err_icmp; | 290 | goto err_icmp; |
@@ -288,12 +292,15 @@ int snmp6_alloc_dev(struct inet6_dev *idev) | |||
288 | return 0; | 292 | return 0; |
289 | 293 | ||
290 | err_icmp: | 294 | err_icmp: |
295 | snmp6_mib_free((void **)idev->stats.ipv6); | ||
296 | err_ip: | ||
291 | return err; | 297 | return err; |
292 | } | 298 | } |
293 | 299 | ||
294 | int snmp6_free_dev(struct inet6_dev *idev) | 300 | int snmp6_free_dev(struct inet6_dev *idev) |
295 | { | 301 | { |
296 | snmp6_mib_free((void **)idev->stats.icmpv6); | 302 | snmp6_mib_free((void **)idev->stats.icmpv6); |
303 | snmp6_mib_free((void **)idev->stats.ipv6); | ||
297 | return 0; | 304 | return 0; |
298 | } | 305 | } |
299 | 306 | ||
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 6bc66552442c..18a90075f942 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -586,7 +586,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, | |||
586 | if (err) | 586 | if (err) |
587 | goto error_fault; | 587 | goto error_fault; |
588 | 588 | ||
589 | IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); | 589 | IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS); |
590 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, rt->u.dst.dev, | 590 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, rt->u.dst.dev, |
591 | dst_output); | 591 | dst_output); |
592 | if (err > 0) | 592 | if (err > 0) |
@@ -600,7 +600,7 @@ error_fault: | |||
600 | err = -EFAULT; | 600 | err = -EFAULT; |
601 | kfree_skb(skb); | 601 | kfree_skb(skb); |
602 | error: | 602 | error: |
603 | IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); | 603 | IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); |
604 | return err; | 604 | return err; |
605 | } | 605 | } |
606 | 606 | ||
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index f39bbedd1327..3af0d5a6ceeb 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <net/snmp.h> | 47 | #include <net/snmp.h> |
48 | 48 | ||
49 | #include <net/ipv6.h> | 49 | #include <net/ipv6.h> |
50 | #include <net/ip6_route.h> | ||
50 | #include <net/protocol.h> | 51 | #include <net/protocol.h> |
51 | #include <net/transp_v6.h> | 52 | #include <net/transp_v6.h> |
52 | #include <net/rawv6.h> | 53 | #include <net/rawv6.h> |
@@ -257,7 +258,7 @@ static __inline__ void fq_kill(struct frag_queue *fq) | |||
257 | } | 258 | } |
258 | } | 259 | } |
259 | 260 | ||
260 | static void ip6_evictor(void) | 261 | static void ip6_evictor(struct inet6_dev *idev) |
261 | { | 262 | { |
262 | struct frag_queue *fq; | 263 | struct frag_queue *fq; |
263 | struct list_head *tmp; | 264 | struct list_head *tmp; |
@@ -284,14 +285,14 @@ static void ip6_evictor(void) | |||
284 | spin_unlock(&fq->lock); | 285 | spin_unlock(&fq->lock); |
285 | 286 | ||
286 | fq_put(fq, &work); | 287 | fq_put(fq, &work); |
287 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); | 288 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMFAILS); |
288 | } | 289 | } |
289 | } | 290 | } |
290 | 291 | ||
291 | static void ip6_frag_expire(unsigned long data) | 292 | static void ip6_frag_expire(unsigned long data) |
292 | { | 293 | { |
293 | struct frag_queue *fq = (struct frag_queue *) data; | 294 | struct frag_queue *fq = (struct frag_queue *) data; |
294 | struct net_device *dev; | 295 | struct net_device *dev = NULL; |
295 | 296 | ||
296 | spin_lock(&fq->lock); | 297 | spin_lock(&fq->lock); |
297 | 298 | ||
@@ -300,17 +301,19 @@ static void ip6_frag_expire(unsigned long data) | |||
300 | 301 | ||
301 | fq_kill(fq); | 302 | fq_kill(fq); |
302 | 303 | ||
303 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT); | 304 | dev = dev_get_by_index(fq->iif); |
304 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); | 305 | if (!dev) |
306 | goto out; | ||
307 | |||
308 | rcu_read_lock(); | ||
309 | IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); | ||
310 | IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); | ||
311 | rcu_read_unlock(); | ||
305 | 312 | ||
306 | /* Don't send error if the first segment did not arrive. */ | 313 | /* Don't send error if the first segment did not arrive. */ |
307 | if (!(fq->last_in&FIRST_IN) || !fq->fragments) | 314 | if (!(fq->last_in&FIRST_IN) || !fq->fragments) |
308 | goto out; | 315 | goto out; |
309 | 316 | ||
310 | dev = dev_get_by_index(fq->iif); | ||
311 | if (!dev) | ||
312 | goto out; | ||
313 | |||
314 | /* | 317 | /* |
315 | But use as source device on which LAST ARRIVED | 318 | But use as source device on which LAST ARRIVED |
316 | segment was received. And do not use fq->dev | 319 | segment was received. And do not use fq->dev |
@@ -318,8 +321,9 @@ static void ip6_frag_expire(unsigned long data) | |||
318 | */ | 321 | */ |
319 | fq->fragments->dev = dev; | 322 | fq->fragments->dev = dev; |
320 | icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev); | 323 | icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev); |
321 | dev_put(dev); | ||
322 | out: | 324 | out: |
325 | if (dev) | ||
326 | dev_put(dev); | ||
323 | spin_unlock(&fq->lock); | 327 | spin_unlock(&fq->lock); |
324 | fq_put(fq, NULL); | 328 | fq_put(fq, NULL); |
325 | } | 329 | } |
@@ -366,7 +370,8 @@ static struct frag_queue *ip6_frag_intern(struct frag_queue *fq_in) | |||
366 | 370 | ||
367 | 371 | ||
368 | static struct frag_queue * | 372 | static struct frag_queue * |
369 | ip6_frag_create(u32 id, struct in6_addr *src, struct in6_addr *dst) | 373 | ip6_frag_create(u32 id, struct in6_addr *src, struct in6_addr *dst, |
374 | struct inet6_dev *idev) | ||
370 | { | 375 | { |
371 | struct frag_queue *fq; | 376 | struct frag_queue *fq; |
372 | 377 | ||
@@ -386,12 +391,13 @@ ip6_frag_create(u32 id, struct in6_addr *src, struct in6_addr *dst) | |||
386 | return ip6_frag_intern(fq); | 391 | return ip6_frag_intern(fq); |
387 | 392 | ||
388 | oom: | 393 | oom: |
389 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); | 394 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMFAILS); |
390 | return NULL; | 395 | return NULL; |
391 | } | 396 | } |
392 | 397 | ||
393 | static __inline__ struct frag_queue * | 398 | static __inline__ struct frag_queue * |
394 | fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst) | 399 | fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst, |
400 | struct inet6_dev *idev) | ||
395 | { | 401 | { |
396 | struct frag_queue *fq; | 402 | struct frag_queue *fq; |
397 | struct hlist_node *n; | 403 | struct hlist_node *n; |
@@ -410,7 +416,7 @@ fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst) | |||
410 | } | 416 | } |
411 | read_unlock(&ip6_frag_lock); | 417 | read_unlock(&ip6_frag_lock); |
412 | 418 | ||
413 | return ip6_frag_create(id, src, dst); | 419 | return ip6_frag_create(id, src, dst, idev); |
414 | } | 420 | } |
415 | 421 | ||
416 | 422 | ||
@@ -428,7 +434,8 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
428 | ((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1))); | 434 | ((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1))); |
429 | 435 | ||
430 | if ((unsigned int)end > IPV6_MAXPLEN) { | 436 | if ((unsigned int)end > IPV6_MAXPLEN) { |
431 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 437 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
438 | IPSTATS_MIB_INHDRERRORS); | ||
432 | icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off - skb->nh.raw); | 439 | icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off - skb->nh.raw); |
433 | return; | 440 | return; |
434 | } | 441 | } |
@@ -455,7 +462,8 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
455 | /* RFC2460 says always send parameter problem in | 462 | /* RFC2460 says always send parameter problem in |
456 | * this case. -DaveM | 463 | * this case. -DaveM |
457 | */ | 464 | */ |
458 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 465 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
466 | IPSTATS_MIB_INHDRERRORS); | ||
459 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, | 467 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, |
460 | offsetof(struct ipv6hdr, payload_len)); | 468 | offsetof(struct ipv6hdr, payload_len)); |
461 | return; | 469 | return; |
@@ -571,7 +579,7 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
571 | return; | 579 | return; |
572 | 580 | ||
573 | err: | 581 | err: |
574 | IP6_INC_STATS(IPSTATS_MIB_REASMFAILS); | 582 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMFAILS); |
575 | kfree_skb(skb); | 583 | kfree_skb(skb); |
576 | } | 584 | } |
577 | 585 | ||
@@ -665,7 +673,9 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, | |||
665 | if (head->ip_summed == CHECKSUM_COMPLETE) | 673 | if (head->ip_summed == CHECKSUM_COMPLETE) |
666 | head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum); | 674 | head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum); |
667 | 675 | ||
668 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS); | 676 | rcu_read_lock(); |
677 | IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMOKS); | ||
678 | rcu_read_unlock(); | ||
669 | fq->fragments = NULL; | 679 | fq->fragments = NULL; |
670 | return 1; | 680 | return 1; |
671 | 681 | ||
@@ -677,7 +687,9 @@ out_oom: | |||
677 | if (net_ratelimit()) | 687 | if (net_ratelimit()) |
678 | printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n"); | 688 | printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n"); |
679 | out_fail: | 689 | out_fail: |
680 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); | 690 | rcu_read_lock(); |
691 | IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); | ||
692 | rcu_read_unlock(); | ||
681 | return -1; | 693 | return -1; |
682 | } | 694 | } |
683 | 695 | ||
@@ -691,16 +703,16 @@ static int ipv6_frag_rcv(struct sk_buff **skbp) | |||
691 | 703 | ||
692 | hdr = skb->nh.ipv6h; | 704 | hdr = skb->nh.ipv6h; |
693 | 705 | ||
694 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMREQDS); | 706 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMREQDS); |
695 | 707 | ||
696 | /* Jumbo payload inhibits frag. header */ | 708 | /* Jumbo payload inhibits frag. header */ |
697 | if (hdr->payload_len==0) { | 709 | if (hdr->payload_len==0) { |
698 | IP6_INC_STATS(IPSTATS_MIB_INHDRERRORS); | 710 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); |
699 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw); | 711 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw); |
700 | return -1; | 712 | return -1; |
701 | } | 713 | } |
702 | if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+sizeof(struct frag_hdr))) { | 714 | if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+sizeof(struct frag_hdr))) { |
703 | IP6_INC_STATS(IPSTATS_MIB_INHDRERRORS); | 715 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); |
704 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw); | 716 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw); |
705 | return -1; | 717 | return -1; |
706 | } | 718 | } |
@@ -711,16 +723,17 @@ static int ipv6_frag_rcv(struct sk_buff **skbp) | |||
711 | if (!(fhdr->frag_off & htons(0xFFF9))) { | 723 | if (!(fhdr->frag_off & htons(0xFFF9))) { |
712 | /* It is not a fragmented frame */ | 724 | /* It is not a fragmented frame */ |
713 | skb->h.raw += sizeof(struct frag_hdr); | 725 | skb->h.raw += sizeof(struct frag_hdr); |
714 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS); | 726 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMOKS); |
715 | 727 | ||
716 | IP6CB(skb)->nhoff = (u8*)fhdr - skb->nh.raw; | 728 | IP6CB(skb)->nhoff = (u8*)fhdr - skb->nh.raw; |
717 | return 1; | 729 | return 1; |
718 | } | 730 | } |
719 | 731 | ||
720 | if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh) | 732 | if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh) |
721 | ip6_evictor(); | 733 | ip6_evictor(ip6_dst_idev(skb->dst)); |
722 | 734 | ||
723 | if ((fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr)) != NULL) { | 735 | if ((fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr, |
736 | ip6_dst_idev(skb->dst))) != NULL) { | ||
724 | int ret = -1; | 737 | int ret = -1; |
725 | 738 | ||
726 | spin_lock(&fq->lock); | 739 | spin_lock(&fq->lock); |
@@ -736,7 +749,7 @@ static int ipv6_frag_rcv(struct sk_buff **skbp) | |||
736 | return ret; | 749 | return ret; |
737 | } | 750 | } |
738 | 751 | ||
739 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); | 752 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMFAILS); |
740 | kfree_skb(skb); | 753 | kfree_skb(skb); |
741 | return -1; | 754 | return -1; |
742 | } | 755 | } |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index eb78b5252248..0ad07c9087a7 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -1749,9 +1749,9 @@ static inline int ip6_pkt_drop(struct sk_buff *skb, int code) | |||
1749 | { | 1749 | { |
1750 | int type = ipv6_addr_type(&skb->nh.ipv6h->daddr); | 1750 | int type = ipv6_addr_type(&skb->nh.ipv6h->daddr); |
1751 | if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED) | 1751 | if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED) |
1752 | IP6_INC_STATS(IPSTATS_MIB_INADDRERRORS); | 1752 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INADDRERRORS); |
1753 | 1753 | ||
1754 | IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES); | 1754 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_OUTNOROUTES); |
1755 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0, skb->dev); | 1755 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0, skb->dev); |
1756 | kfree_skb(skb); | 1756 | kfree_skb(skb); |
1757 | return 0; | 1757 | return 0; |