diff options
Diffstat (limited to 'net/ipv6/icmp.c')
| -rw-r--r-- | net/ipv6/icmp.c | 48 |
1 files changed, 44 insertions, 4 deletions
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 1044b6fce0d5..4ec876066b3f 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
| @@ -151,7 +151,7 @@ static int is_ineligible(struct sk_buff *skb) | |||
| 151 | return 0; | 151 | return 0; |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | static int sysctl_icmpv6_time = 1*HZ; | 154 | static int sysctl_icmpv6_time __read_mostly = 1*HZ; |
| 155 | 155 | ||
| 156 | /* | 156 | /* |
| 157 | * Check the ICMP output rate limit | 157 | * Check the ICMP output rate limit |
| @@ -273,6 +273,29 @@ static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, st | |||
| 273 | return 0; | 273 | return 0; |
| 274 | } | 274 | } |
| 275 | 275 | ||
| 276 | #ifdef CONFIG_IPV6_MIP6 | ||
| 277 | static void mip6_addr_swap(struct sk_buff *skb) | ||
| 278 | { | ||
| 279 | struct ipv6hdr *iph = skb->nh.ipv6h; | ||
| 280 | struct inet6_skb_parm *opt = IP6CB(skb); | ||
| 281 | struct ipv6_destopt_hao *hao; | ||
| 282 | struct in6_addr tmp; | ||
| 283 | int off; | ||
| 284 | |||
| 285 | if (opt->dsthao) { | ||
| 286 | off = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO); | ||
| 287 | if (likely(off >= 0)) { | ||
| 288 | hao = (struct ipv6_destopt_hao *)(skb->nh.raw + off); | ||
| 289 | ipv6_addr_copy(&tmp, &iph->saddr); | ||
| 290 | ipv6_addr_copy(&iph->saddr, &hao->addr); | ||
| 291 | ipv6_addr_copy(&hao->addr, &tmp); | ||
| 292 | } | ||
| 293 | } | ||
| 294 | } | ||
| 295 | #else | ||
| 296 | static inline void mip6_addr_swap(struct sk_buff *skb) {} | ||
| 297 | #endif | ||
| 298 | |||
| 276 | /* | 299 | /* |
| 277 | * Send an ICMP message in response to a packet in error | 300 | * Send an ICMP message in response to a packet in error |
| 278 | */ | 301 | */ |
| @@ -350,6 +373,8 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, | |||
| 350 | return; | 373 | return; |
| 351 | } | 374 | } |
| 352 | 375 | ||
| 376 | mip6_addr_swap(skb); | ||
| 377 | |||
| 353 | memset(&fl, 0, sizeof(fl)); | 378 | memset(&fl, 0, sizeof(fl)); |
| 354 | fl.proto = IPPROTO_ICMPV6; | 379 | fl.proto = IPPROTO_ICMPV6; |
| 355 | ipv6_addr_copy(&fl.fl6_dst, &hdr->saddr); | 380 | ipv6_addr_copy(&fl.fl6_dst, &hdr->saddr); |
| @@ -358,6 +383,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, | |||
| 358 | fl.oif = iif; | 383 | fl.oif = iif; |
| 359 | fl.fl_icmp_type = type; | 384 | fl.fl_icmp_type = type; |
| 360 | fl.fl_icmp_code = code; | 385 | fl.fl_icmp_code = code; |
| 386 | security_skb_classify_flow(skb, &fl); | ||
| 361 | 387 | ||
| 362 | if (icmpv6_xmit_lock()) | 388 | if (icmpv6_xmit_lock()) |
| 363 | return; | 389 | return; |
| @@ -401,7 +427,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, | |||
| 401 | if (hlimit < 0) | 427 | if (hlimit < 0) |
| 402 | hlimit = ipv6_get_hoplimit(dst->dev); | 428 | hlimit = ipv6_get_hoplimit(dst->dev); |
| 403 | 429 | ||
| 404 | tclass = np->cork.tclass; | 430 | tclass = np->tclass; |
| 405 | if (tclass < 0) | 431 | if (tclass < 0) |
| 406 | tclass = 0; | 432 | tclass = 0; |
| 407 | 433 | ||
| @@ -472,6 +498,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
| 472 | ipv6_addr_copy(&fl.fl6_src, saddr); | 498 | ipv6_addr_copy(&fl.fl6_src, saddr); |
| 473 | fl.oif = skb->dev->ifindex; | 499 | fl.oif = skb->dev->ifindex; |
| 474 | fl.fl_icmp_type = ICMPV6_ECHO_REPLY; | 500 | fl.fl_icmp_type = ICMPV6_ECHO_REPLY; |
| 501 | security_skb_classify_flow(skb, &fl); | ||
| 475 | 502 | ||
| 476 | if (icmpv6_xmit_lock()) | 503 | if (icmpv6_xmit_lock()) |
| 477 | return; | 504 | return; |
| @@ -497,7 +524,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
| 497 | if (hlimit < 0) | 524 | if (hlimit < 0) |
| 498 | hlimit = ipv6_get_hoplimit(dst->dev); | 525 | hlimit = ipv6_get_hoplimit(dst->dev); |
| 499 | 526 | ||
| 500 | tclass = np->cork.tclass; | 527 | tclass = np->tclass; |
| 501 | if (tclass < 0) | 528 | if (tclass < 0) |
| 502 | tclass = 0; | 529 | tclass = 0; |
| 503 | 530 | ||
| @@ -604,7 +631,7 @@ static int icmpv6_rcv(struct sk_buff **pskb) | |||
| 604 | 631 | ||
| 605 | /* Perform checksum. */ | 632 | /* Perform checksum. */ |
| 606 | switch (skb->ip_summed) { | 633 | switch (skb->ip_summed) { |
| 607 | case CHECKSUM_HW: | 634 | case CHECKSUM_COMPLETE: |
| 608 | if (!csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, | 635 | if (!csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, |
| 609 | skb->csum)) | 636 | skb->csum)) |
| 610 | break; | 637 | break; |
| @@ -712,6 +739,11 @@ discard_it: | |||
| 712 | return 0; | 739 | return 0; |
| 713 | } | 740 | } |
| 714 | 741 | ||
| 742 | /* | ||
| 743 | * Special lock-class for __icmpv6_socket: | ||
| 744 | */ | ||
| 745 | static struct lock_class_key icmpv6_socket_sk_dst_lock_key; | ||
| 746 | |||
| 715 | int __init icmpv6_init(struct net_proto_family *ops) | 747 | int __init icmpv6_init(struct net_proto_family *ops) |
| 716 | { | 748 | { |
| 717 | struct sock *sk; | 749 | struct sock *sk; |
| @@ -730,6 +762,14 @@ int __init icmpv6_init(struct net_proto_family *ops) | |||
| 730 | 762 | ||
| 731 | sk = per_cpu(__icmpv6_socket, i)->sk; | 763 | sk = per_cpu(__icmpv6_socket, i)->sk; |
| 732 | sk->sk_allocation = GFP_ATOMIC; | 764 | sk->sk_allocation = GFP_ATOMIC; |
| 765 | /* | ||
| 766 | * Split off their lock-class, because sk->sk_dst_lock | ||
| 767 | * gets used from softirqs, which is safe for | ||
| 768 | * __icmpv6_socket (because those never get directly used | ||
| 769 | * via userspace syscalls), but unsafe for normal sockets. | ||
| 770 | */ | ||
| 771 | lockdep_set_class(&sk->sk_dst_lock, | ||
| 772 | &icmpv6_socket_sk_dst_lock_key); | ||
| 733 | 773 | ||
| 734 | /* Enough space for 2 64K ICMP packets, including | 774 | /* Enough space for 2 64K ICMP packets, including |
| 735 | * sk_buff struct overhead. | 775 | * sk_buff struct overhead. |
