Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ip6: move ipip6_err_gen_icmpv6_unreach()

We want to use this helper from GRE as well, so this is
the time to move it in net/ipv6/icmp.c

Also add a @nhs parameter, since SIT and GRE have different
values for the header(s) to skip.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Eric Dumazet and committed by
David S. Miller
5fbba8ac b1cadc1a

+41 -37
+1
include/linux/icmpv6.h
··· 18 18 const struct in6_addr *force_saddr); 19 19 extern int inet6_register_icmp_sender(ip6_icmp_send_t *fn); 20 20 extern int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn); 21 + int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs); 21 22 22 23 #else 23 24
+39
net/ipv6/icmp.c
··· 558 558 kfree_skb(skb); 559 559 } 560 560 561 + /* Generate icmpv6 with type/code ICMPV6_DEST_UNREACH/ICMPV6_ADDR_UNREACH 562 + * if sufficient data bytes are available 563 + * @nhs is the size of the tunnel header(s) : 564 + * Either an IPv4 header for SIT encap 565 + * an IPv4 header + GRE header for GRE encap 566 + */ 567 + int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs) 568 + { 569 + struct rt6_info *rt; 570 + struct sk_buff *skb2; 571 + 572 + if (!pskb_may_pull(skb, nhs + sizeof(struct ipv6hdr) + 8)) 573 + return 1; 574 + 575 + skb2 = skb_clone(skb, GFP_ATOMIC); 576 + 577 + if (!skb2) 578 + return 1; 579 + 580 + skb_dst_drop(skb2); 581 + skb_pull(skb2, nhs); 582 + skb_reset_network_header(skb2); 583 + 584 + rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, NULL, 0, 0); 585 + 586 + if (rt && rt->dst.dev) 587 + skb2->dev = rt->dst.dev; 588 + 589 + icmpv6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); 590 + 591 + if (rt) 592 + ip6_rt_put(rt); 593 + 594 + kfree_skb(skb2); 595 + 596 + return 0; 597 + } 598 + EXPORT_SYMBOL(ip6_err_gen_icmpv6_unreach); 599 + 561 600 static void icmpv6_echo_reply(struct sk_buff *skb) 562 601 { 563 602 struct net *net = dev_net(skb->dev);
+1 -37
net/ipv6/sit.c
··· 479 479 dev_put(dev); 480 480 } 481 481 482 - /* Generate icmpv6 with type/code ICMPV6_DEST_UNREACH/ICMPV6_ADDR_UNREACH 483 - * if sufficient data bytes are available 484 - */ 485 - static int ipip6_err_gen_icmpv6_unreach(struct sk_buff *skb) 486 - { 487 - int ihl = ((const struct iphdr *)skb->data)->ihl*4; 488 - struct rt6_info *rt; 489 - struct sk_buff *skb2; 490 - 491 - if (!pskb_may_pull(skb, ihl + sizeof(struct ipv6hdr) + 8)) 492 - return 1; 493 - 494 - skb2 = skb_clone(skb, GFP_ATOMIC); 495 - 496 - if (!skb2) 497 - return 1; 498 - 499 - skb_dst_drop(skb2); 500 - skb_pull(skb2, ihl); 501 - skb_reset_network_header(skb2); 502 - 503 - rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, NULL, 0, 0); 504 - 505 - if (rt && rt->dst.dev) 506 - skb2->dev = rt->dst.dev; 507 - 508 - icmpv6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); 509 - 510 - if (rt) 511 - ip6_rt_put(rt); 512 - 513 - kfree_skb(skb2); 514 - 515 - return 0; 516 - } 517 - 518 482 static int ipip6_err(struct sk_buff *skb, u32 info) 519 483 { 520 484 const struct iphdr *iph = (const struct iphdr *)skb->data; ··· 539 575 goto out; 540 576 541 577 err = 0; 542 - if (!ipip6_err_gen_icmpv6_unreach(skb)) 578 + if (!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4)) 543 579 goto out; 544 580 545 581 if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)