diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/ipv6/Makefile | 2 | ||||
| -rw-r--r-- | net/ipv6/icmp.c | 35 | ||||
| -rw-r--r-- | net/ipv6/ip6_icmp.c | 47 |
3 files changed, 68 insertions, 16 deletions
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 309af19a0a0a..9af088d2cdaa 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile | |||
| @@ -40,7 +40,7 @@ obj-$(CONFIG_IPV6_SIT) += sit.o | |||
| 40 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o | 40 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o |
| 41 | obj-$(CONFIG_IPV6_GRE) += ip6_gre.o | 41 | obj-$(CONFIG_IPV6_GRE) += ip6_gre.o |
| 42 | 42 | ||
| 43 | obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o | 43 | obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o |
| 44 | obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload) | 44 | obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload) |
| 45 | 45 | ||
| 46 | obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o | 46 | obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o |
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 71b900c3f4ff..2a53a790514d 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
| @@ -124,15 +124,6 @@ static __inline__ void icmpv6_xmit_unlock(struct sock *sk) | |||
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | /* | 126 | /* |
| 127 | * Slightly more convenient version of icmpv6_send. | ||
| 128 | */ | ||
| 129 | void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) | ||
| 130 | { | ||
| 131 | icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos); | ||
| 132 | kfree_skb(skb); | ||
| 133 | } | ||
| 134 | |||
| 135 | /* | ||
| 136 | * Figure out, may we reply to this packet with icmp error. | 127 | * Figure out, may we reply to this packet with icmp error. |
| 137 | * | 128 | * |
| 138 | * We do not reply, if: | 129 | * We do not reply, if: |
| @@ -332,7 +323,7 @@ static struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *sk | |||
| 332 | * anycast. | 323 | * anycast. |
| 333 | */ | 324 | */ |
| 334 | if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) { | 325 | if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) { |
| 335 | LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: acast source\n"); | 326 | LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: acast source\n"); |
| 336 | dst_release(dst); | 327 | dst_release(dst); |
| 337 | return ERR_PTR(-EINVAL); | 328 | return ERR_PTR(-EINVAL); |
| 338 | } | 329 | } |
| @@ -381,7 +372,7 @@ relookup_failed: | |||
| 381 | /* | 372 | /* |
| 382 | * Send an ICMP message in response to a packet in error | 373 | * Send an ICMP message in response to a packet in error |
| 383 | */ | 374 | */ |
| 384 | void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | 375 | static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) |
| 385 | { | 376 | { |
| 386 | struct net *net = dev_net(skb->dev); | 377 | struct net *net = dev_net(skb->dev); |
| 387 | struct inet6_dev *idev = NULL; | 378 | struct inet6_dev *idev = NULL; |
| @@ -406,7 +397,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | |||
| 406 | /* | 397 | /* |
| 407 | * Make sure we respect the rules | 398 | * Make sure we respect the rules |
| 408 | * i.e. RFC 1885 2.4(e) | 399 | * i.e. RFC 1885 2.4(e) |
| 409 | * Rule (e.1) is enforced by not using icmpv6_send | 400 | * Rule (e.1) is enforced by not using icmp6_send |
| 410 | * in any code that processes icmp errors. | 401 | * in any code that processes icmp errors. |
| 411 | */ | 402 | */ |
| 412 | addr_type = ipv6_addr_type(&hdr->daddr); | 403 | addr_type = ipv6_addr_type(&hdr->daddr); |
| @@ -444,7 +435,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | |||
| 444 | * and anycast addresses will be checked later. | 435 | * and anycast addresses will be checked later. |
| 445 | */ | 436 | */ |
| 446 | if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) { | 437 | if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) { |
| 447 | LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: addr_any/mcast source\n"); | 438 | LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: addr_any/mcast source\n"); |
| 448 | return; | 439 | return; |
| 449 | } | 440 | } |
| 450 | 441 | ||
| @@ -452,7 +443,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | |||
| 452 | * Never answer to a ICMP packet. | 443 | * Never answer to a ICMP packet. |
| 453 | */ | 444 | */ |
| 454 | if (is_ineligible(skb)) { | 445 | if (is_ineligible(skb)) { |
| 455 | LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: no reply to icmp error\n"); | 446 | LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: no reply to icmp error\n"); |
| 456 | return; | 447 | return; |
| 457 | } | 448 | } |
| 458 | 449 | ||
| @@ -529,7 +520,14 @@ out_dst_release: | |||
| 529 | out: | 520 | out: |
| 530 | icmpv6_xmit_unlock(sk); | 521 | icmpv6_xmit_unlock(sk); |
| 531 | } | 522 | } |
| 532 | EXPORT_SYMBOL(icmpv6_send); | 523 | |
| 524 | /* Slightly more convenient version of icmp6_send. | ||
| 525 | */ | ||
| 526 | void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) | ||
| 527 | { | ||
| 528 | icmp6_send(skb, ICMPV6_PARAMPROB, code, pos); | ||
| 529 | kfree_skb(skb); | ||
| 530 | } | ||
| 533 | 531 | ||
| 534 | static void icmpv6_echo_reply(struct sk_buff *skb) | 532 | static void icmpv6_echo_reply(struct sk_buff *skb) |
| 535 | { | 533 | { |
| @@ -885,8 +883,14 @@ int __init icmpv6_init(void) | |||
| 885 | err = -EAGAIN; | 883 | err = -EAGAIN; |
| 886 | if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0) | 884 | if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0) |
| 887 | goto fail; | 885 | goto fail; |
| 886 | |||
| 887 | err = inet6_register_icmp_sender(icmp6_send); | ||
| 888 | if (err) | ||
| 889 | goto sender_reg_err; | ||
| 888 | return 0; | 890 | return 0; |
| 889 | 891 | ||
| 892 | sender_reg_err: | ||
| 893 | inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); | ||
| 890 | fail: | 894 | fail: |
| 891 | pr_err("Failed to register ICMP6 protocol\n"); | 895 | pr_err("Failed to register ICMP6 protocol\n"); |
| 892 | unregister_pernet_subsys(&icmpv6_sk_ops); | 896 | unregister_pernet_subsys(&icmpv6_sk_ops); |
| @@ -895,6 +899,7 @@ fail: | |||
| 895 | 899 | ||
| 896 | void icmpv6_cleanup(void) | 900 | void icmpv6_cleanup(void) |
| 897 | { | 901 | { |
| 902 | inet6_unregister_icmp_sender(icmp6_send); | ||
| 898 | unregister_pernet_subsys(&icmpv6_sk_ops); | 903 | unregister_pernet_subsys(&icmpv6_sk_ops); |
| 899 | inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); | 904 | inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); |
| 900 | } | 905 | } |
diff --git a/net/ipv6/ip6_icmp.c b/net/ipv6/ip6_icmp.c new file mode 100644 index 000000000000..4578e23834f7 --- /dev/null +++ b/net/ipv6/ip6_icmp.c | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | #include <linux/export.h> | ||
| 2 | #include <linux/icmpv6.h> | ||
| 3 | #include <linux/mutex.h> | ||
| 4 | #include <linux/netdevice.h> | ||
| 5 | #include <linux/spinlock.h> | ||
| 6 | |||
| 7 | #include <net/ipv6.h> | ||
| 8 | |||
| 9 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 10 | |||
| 11 | static ip6_icmp_send_t __rcu *ip6_icmp_send; | ||
| 12 | |||
| 13 | int inet6_register_icmp_sender(ip6_icmp_send_t *fn) | ||
| 14 | { | ||
| 15 | return (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, NULL, fn) == NULL) ? | ||
| 16 | 0 : -EBUSY; | ||
| 17 | } | ||
| 18 | EXPORT_SYMBOL(inet6_register_icmp_sender); | ||
| 19 | |||
| 20 | int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn) | ||
| 21 | { | ||
| 22 | int ret; | ||
| 23 | |||
| 24 | ret = (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, fn, NULL) == fn) ? | ||
| 25 | 0 : -EINVAL; | ||
| 26 | |||
| 27 | synchronize_net(); | ||
| 28 | |||
| 29 | return ret; | ||
| 30 | } | ||
| 31 | EXPORT_SYMBOL(inet6_unregister_icmp_sender); | ||
| 32 | |||
| 33 | void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | ||
| 34 | { | ||
| 35 | ip6_icmp_send_t *send; | ||
| 36 | |||
| 37 | rcu_read_lock(); | ||
| 38 | send = rcu_dereference(ip6_icmp_send); | ||
| 39 | |||
| 40 | if (!send) | ||
| 41 | goto out; | ||
| 42 | send(skb, type, code, info); | ||
| 43 | out: | ||
| 44 | rcu_read_unlock(); | ||
| 45 | } | ||
| 46 | EXPORT_SYMBOL(icmpv6_send); | ||
| 47 | #endif | ||
