1 /* 2 * Internet Control Message Protocol (ICMPv6) 3 * Linux INET6 implementation 4 * 5 * Authors: 6 * Pedro Roque <pedro_m@yahoo.com> 7 * 8 * $Id: icmp.c,v 1.37 2001/09/18 22:29:10 davem Exp $ 9 * 10 * Based on net/ipv4/icmp.c 11 * 12 * RFC 1885 13 * 14 * This program is free software; you can redistribute it and/or 15 * modify it under the terms of the GNU General Public License 16 * as published by the Free Software Foundation; either version 17 * 2 of the License, or (at your option) any later version. 18 */ 19 20 /* 21 * Changes: 22 * 23 * Andi Kleen : exception handling 24 * Andi Kleen add rate limits. never reply to a icmp. 25 * add more length checks and other fixes. 26 * yoshfuji : ensure to sent parameter problem for 27 * fragments. 28 * YOSHIFUJI Hideaki @USAGI: added sysctl for icmp rate limit. 29 */ 30 31 #include <linux/module.h> 32 #include <linux/errno.h> 33 #include <linux/types.h> 34 #include <linux/socket.h> 35 #include <linux/in.h> 36 #include <linux/kernel.h> 37 #include <linux/sched.h> 38 #include <linux/sockios.h> 39 #include <linux/net.h> 40 #include <linux/skbuff.h> 41 #include <linux/init.h> 42 43 #ifdef CONFIG_SYSCTL 44 #include <linux/sysctl.h> 45 #endif 46 47 #include <linux/inet.h> 48 #include <linux/netdevice.h> 49 #include <linux/icmpv6.h> 50 51 #include <net/ip.h> 52 #include <net/sock.h> 53 54 #include <net/ipv6.h> 55 #include <net/checksum.h> 56 #include <net/protocol.h> 57 #include <net/raw.h> 58 #include <net/rawv6.h> 59 #include <net/transp_v6.h> 60 #include <net/ip6_route.h> 61 #include <net/addrconf.h> 62 #include <net/icmp.h> 63 64 #include <asm/uaccess.h> 65 #include <asm/system.h> 66 67 struct icmpv6_mib icmpv6_statistics[NR_CPUS*2]; 68 69 /* 70 * ICMP socket(s) for flow control. 71 */ 72 73 static struct socket *__icmpv6_socket[NR_CPUS]; 74 #define icmpv6_socket __icmpv6_socket[smp_processor_id()] 75 #define icmpv6_socket_cpu(X) __icmpv6_socket[(X)] 76 77 int icmpv6_rcv(struct sk_buff *skb); 78 79 static struct inet6_protocol icmpv6_protocol = 80 { 81 icmpv6_rcv, /* handler */ 82 NULL, /* error control */ 83 NULL, /* next */ 84 IPPROTO_ICMPV6, /* protocol ID */ 85 0, /* copy */ 86 NULL, /* data */ 87 "ICMPv6" /* name */ 88 }; 89 90 struct icmpv6_msg { 91 struct icmp6hdr icmph; 92 struct sk_buff *skb; 93 int offset; 94 struct in6_addr *daddr; 95 int len; 96 __u32 csum; 97 }; 98 99 100 static int icmpv6_xmit_lock(void) 101 { 102 local_bh_disable(); 103 if (unlikely(!spin_trylock(&icmpv6_socket->sk->lock.slock))) { 104 /* This can happen if the output path (f.e. SIT or 105 * ip6ip6 tunnel) signals dst_link_failure() for an 106 * outgoing ICMP6 packet. 107 */ 108 local_bh_enable(); 109 return 1; 110 } 111 return 0; 112 } 113 114 static void icmpv6_xmit_unlock(void) 115 { 116 spin_unlock_bh(&icmpv6_socket->sk->lock.slock); 117 } 118 119 /* 120 * getfrag callback 121 */ 122 123 static int icmpv6_getfrag(const void *data, struct in6_addr *saddr, 124 char *buff, unsigned int offset, unsigned int len) 125 { 126 struct icmpv6_msg *msg = (struct icmpv6_msg *) data; 127 struct icmp6hdr *icmph; 128 __u32 csum; 129 130 if (offset) { 131 csum = skb_copy_and_csum_bits(msg->skb, msg->offset + 132 (offset - sizeof(struct icmp6hdr)), 133 buff, len, msg->csum); 134 msg->csum = csum; 135 return 0; 136 } 137 138 csum = csum_partial_copy_nocheck((void *) &msg->icmph, buff, 139 sizeof(struct icmp6hdr), msg->csum); 140 141 csum = skb_copy_and_csum_bits(msg->skb, msg->offset, 142 buff + sizeof(struct icmp6hdr), 143 len - sizeof(struct icmp6hdr), csum); 144 145 icmph = (struct icmp6hdr *) buff; 146 147 icmph->icmp6_cksum = csum_ipv6_magic(saddr, msg->daddr, msg->len, 148 IPPROTO_ICMPV6, csum); 149 return 0; 150 } 151 152 153 /* 154 * Slightly more convenient version of icmpv6_send. 155 */ 156 void icmpv6_param_prob(struct sk_buff *skb, int code, int pos) 157 { 158 icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev); 159 kfree_skb(skb); 160 } 161 162 /* 163 * Figure out, may we reply to this packet with icmp error. 164 * 165 * We do not reply, if: 166 * - it was icmp error message. 167 * - it is truncated, so that it is known, that protocol is ICMPV6 168 * (i.e. in the middle of some exthdr) 169 * 170 * --ANK (980726) 171 */ 172 173 static int is_ineligible(struct sk_buff *skb) 174 { 175 int ptr = (u8*)(skb->nh.ipv6h+1) - skb->data; 176 int len = skb->len - ptr; 177 __u8 nexthdr = skb->nh.ipv6h->nexthdr; 178 179 if (len < 0) 180 return 1; 181 182 ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, len); 183 if (ptr < 0) 184 return 0; 185 if (nexthdr == IPPROTO_ICMPV6) { 186 u8 type; 187 if (skb_copy_bits(skb, ptr+offsetof(struct icmp6hdr, icmp6_type), 188 &type, 1) 189 || !(type & ICMPV6_INFOMSG_MASK)) 190 return 1; 191 } 192 return 0; 193 } 194 195 int sysctl_icmpv6_time = 1*HZ; 196 197 /* 198 * Check the ICMP output rate limit 199 */ 200 static inline int icmpv6_xrlim_allow(struct sock *sk, int type, 201 struct flowi *fl) 202 { 203 struct dst_entry *dst; 204 int res = 0; 205 206 /* Informational messages are not limited. */ 207 if (type & ICMPV6_INFOMSG_MASK) 208 return 1; 209 210 /* Do not limit pmtu discovery, it would break it. */ 211 if (type == ICMPV6_PKT_TOOBIG) 212 return 1; 213 214 /* 215 * Look up the output route. 216 * XXX: perhaps the expire for routing entries cloned by 217 * this lookup should be more aggressive (not longer than timeout). 218 */ 219 dst = ip6_route_output(sk, fl); 220 if (dst->error) { 221 IP6_INC_STATS(Ip6OutNoRoutes); 222 } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) { 223 res = 1; 224 } else { 225 struct rt6_info *rt = (struct rt6_info *)dst; 226 int tmo = sysctl_icmpv6_time; 227 228 /* Give more bandwidth to wider prefixes. */ 229 if (rt->rt6i_dst.plen < 128) 230 tmo >>= ((128 - rt->rt6i_dst.plen)>>5); 231 232 res = xrlim_allow(dst, tmo); 233 } 234 dst_release(dst); 235 return res; 236 } 237 238 /* 239 * an inline helper for the "simple" if statement below 240 * checks if parameter problem report is caused by an 241 * unrecognized IPv6 option that has the Option Type 242 * highest-order two bits set to 10 243 */ 244 245 static __inline__ int opt_unrec(struct sk_buff *skb, __u32 offset) 246 { 247 u8 optval; 248 249 offset += skb->nh.raw - skb->data; 250 if (skb_copy_bits(skb, offset, &optval, 1)) 251 return 1; 252 return (optval&0xC0) == 0x80; 253 } 254 255 /* 256 * Send an ICMP message in response to a packet in error 257 */ 258 259 void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, 260 struct net_device *dev) 261 { 262 struct ipv6hdr *hdr = skb->nh.ipv6h; 263 struct sock *sk = icmpv6_socket->sk; 264 struct in6_addr *saddr = NULL; 265 int iif = 0; 266 struct icmpv6_msg msg; 267 struct flowi fl; 268 int addr_type = 0; 269 int len; 270 271 if ((u8*)hdr < skb->head || (u8*)(hdr+1) > skb->tail) 272 return; 273 274 /* 275 * Make sure we respect the rules 276 * i.e. RFC 1885 2.4(e) 277 * Rule (e.1) is enforced by not using icmpv6_send 278 * in any code that processes icmp errors. 279 */ 280 addr_type = ipv6_addr_type(&hdr->daddr); 281 282 if (ipv6_chk_addr(&hdr->daddr, skb->dev)) 283 saddr = &hdr->daddr; 284 285 /* 286 * Dest addr check 287 */ 288 289 if ((addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST)) { 290 if (type != ICMPV6_PKT_TOOBIG && 291 !(type == ICMPV6_PARAMPROB && 292 code == ICMPV6_UNK_OPTION && 293 (opt_unrec(skb, info)))) 294 return; 295 296 saddr = NULL; 297 } 298 299 addr_type = ipv6_addr_type(&hdr->saddr); 300 301 /* 302 * Source addr check 303 */ 304 305 if (addr_type & IPV6_ADDR_LINKLOCAL) 306 iif = skb->dev->ifindex; 307 308 /* 309 * Must not send if we know that source is Anycast also. 310 * for now we don't know that. 311 */ 312 if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) { 313 if (net_ratelimit()) 314 printk(KERN_DEBUG "icmpv6_send: addr_any/mcast source\n"); 315 return; 316 } 317 318 /* 319 * Never answer to a ICMP packet. 320 */ 321 if (is_ineligible(skb)) { 322 if (net_ratelimit()) 323 printk(KERN_DEBUG "icmpv6_send: no reply to icmp error\n"); 324 return; 325 } 326 327 fl.proto = IPPROTO_ICMPV6; 328 fl.nl_u.ip6_u.daddr = &hdr->saddr; 329 fl.nl_u.ip6_u.saddr = saddr; 330 fl.oif = iif; 331 fl.fl6_flowlabel = 0; 332 fl.uli_u.icmpt.type = type; 333 fl.uli_u.icmpt.code = code; 334 335 if (icmpv6_xmit_lock()) 336 return; 337 338 if (!icmpv6_xrlim_allow(sk, type, &fl)) 339 goto out; 340 341 /* 342 * ok. kick it. checksum will be provided by the 343 * getfrag_t callback. 344 */ 345 346 msg.icmph.icmp6_type = type; 347 msg.icmph.icmp6_code = code; 348 msg.icmph.icmp6_cksum = 0; 349 msg.icmph.icmp6_pointer = htonl(info); 350 351 msg.skb = skb; 352 msg.offset = skb->nh.raw - skb->data; 353 msg.csum = 0; 354 msg.daddr = &hdr->saddr; 355 356 len = skb->len - msg.offset + sizeof(struct icmp6hdr); 357 len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr)); 358 359 if (len < 0) { 360 if (net_ratelimit()) 361 printk(KERN_DEBUG "icmp: len problem\n"); 362 goto out; 363 } 364 365 msg.len = len; 366 367 ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1, 368 MSG_DONTWAIT); 369 if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB) 370 (&(icmpv6_statistics[smp_processor_id()*2].Icmp6OutDestUnreachs))[type-1]++; 371 ICMP6_INC_STATS_BH(Icmp6OutMsgs); 372 out: 373 icmpv6_xmit_unlock(); 374 } 375 376 static void icmpv6_echo_reply(struct sk_buff *skb) 377 { 378 struct sock *sk = icmpv6_socket->sk; 379 struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw; 380 struct in6_addr *saddr; 381 struct icmpv6_msg msg; 382 struct flowi fl; 383 384 saddr = &skb->nh.ipv6h->daddr; 385 386 if (ipv6_addr_type(saddr) & IPV6_ADDR_MULTICAST || 387 ipv6_chk_acast_addr(0, saddr)) 388 saddr = NULL; 389 390 msg.icmph.icmp6_type = ICMPV6_ECHO_REPLY; 391 msg.icmph.icmp6_code = 0; 392 msg.icmph.icmp6_cksum = 0; 393 msg.icmph.icmp6_identifier = icmph->icmp6_identifier; 394 msg.icmph.icmp6_sequence = icmph->icmp6_sequence; 395 396 msg.skb = skb; 397 msg.offset = 0; 398 msg.csum = 0; 399 msg.len = skb->len + sizeof(struct icmp6hdr); 400 msg.daddr = &skb->nh.ipv6h->saddr; 401 402 fl.proto = IPPROTO_ICMPV6; 403 fl.nl_u.ip6_u.daddr = msg.daddr; 404 fl.nl_u.ip6_u.saddr = saddr; 405 fl.oif = skb->dev->ifindex; 406 fl.fl6_flowlabel = 0; 407 fl.uli_u.icmpt.type = ICMPV6_ECHO_REPLY; 408 fl.uli_u.icmpt.code = 0; 409 410 if (icmpv6_xmit_lock()) 411 return; 412 413 ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, msg.len, NULL, -1, 414 MSG_DONTWAIT); 415 ICMP6_INC_STATS_BH(Icmp6OutEchoReplies); 416 ICMP6_INC_STATS_BH(Icmp6OutMsgs); 417 418 icmpv6_xmit_unlock(); 419 } 420 421 static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info) 422 { 423 struct in6_addr *saddr, *daddr; 424 struct inet6_protocol *ipprot; 425 struct sock *sk; 426 int inner_offset; 427 int hash; 428 u8 nexthdr; 429 430 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 431 return; 432 433 nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr; 434 if (ipv6_ext_hdr(nexthdr)) { 435 /* now skip over extension headers */ 436 inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, skb->len - sizeof(struct ipv6hdr)); 437 if (inner_offset<0) 438 return; 439 } else { 440 inner_offset = sizeof(struct ipv6hdr); 441 } 442 443 /* Checkin header including 8 bytes of inner protocol header. */ 444 if (!pskb_may_pull(skb, inner_offset+8)) 445 return; 446 447 saddr = &skb->nh.ipv6h->saddr; 448 daddr = &skb->nh.ipv6h->daddr; 449 450 /* BUGGG_FUTURE: we should try to parse exthdrs in this packet. 451 Without this we will not able f.e. to make source routed 452 pmtu discovery. 453 Corresponding argument (opt) to notifiers is already added. 454 --ANK (980726) 455 */ 456 457 hash = nexthdr & (MAX_INET_PROTOS - 1); 458 459 for (ipprot = (struct inet6_protocol *) inet6_protos[hash]; 460 ipprot != NULL; 461 ipprot=(struct inet6_protocol *)ipprot->next) { 462 if (ipprot->protocol != nexthdr) 463 continue; 464 465 if (ipprot->err_handler) 466 ipprot->err_handler(skb, NULL, type, code, inner_offset, info); 467 } 468 469 read_lock(&raw_v6_lock); 470 if ((sk = raw_v6_htable[hash]) != NULL) { 471 while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr))) { 472 rawv6_err(sk, skb, NULL, type, code, inner_offset, info); 473 sk = sk->next; 474 } 475 } 476 read_unlock(&raw_v6_lock); 477 } 478 479 /* 480 * Handle icmp messages 481 */ 482 483 int icmpv6_rcv(struct sk_buff *skb) 484 { 485 struct net_device *dev = skb->dev; 486 struct in6_addr *saddr, *daddr; 487 struct ipv6hdr *orig_hdr; 488 struct icmp6hdr *hdr; 489 int type; 490 491 ICMP6_INC_STATS_BH(Icmp6InMsgs); 492 493 saddr = &skb->nh.ipv6h->saddr; 494 daddr = &skb->nh.ipv6h->daddr; 495 496 /* Perform checksum. */ 497 if (skb->ip_summed == CHECKSUM_HW) { 498 skb->ip_summed = CHECKSUM_UNNECESSARY; 499 if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, 500 skb->csum)) { 501 if (net_ratelimit()) 502 printk(KERN_DEBUG "ICMPv6 hw checksum failed\n"); 503 skb->ip_summed = CHECKSUM_NONE; 504 } 505 } 506 if (skb->ip_summed == CHECKSUM_NONE) { 507 if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, 508 skb_checksum(skb, 0, skb->len, 0))) { 509 if (net_ratelimit()) 510 printk(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n", 511 ntohs(saddr->s6_addr16[0]), 512 ntohs(saddr->s6_addr16[1]), 513 ntohs(saddr->s6_addr16[2]), 514 ntohs(saddr->s6_addr16[3]), 515 ntohs(saddr->s6_addr16[4]), 516 ntohs(saddr->s6_addr16[5]), 517 ntohs(saddr->s6_addr16[6]), 518 ntohs(saddr->s6_addr16[7]), 519 ntohs(daddr->s6_addr16[0]), 520 ntohs(daddr->s6_addr16[1]), 521 ntohs(daddr->s6_addr16[2]), 522 ntohs(daddr->s6_addr16[3]), 523 ntohs(daddr->s6_addr16[4]), 524 ntohs(daddr->s6_addr16[5]), 525 ntohs(daddr->s6_addr16[6]), 526 ntohs(daddr->s6_addr16[7])); 527 goto discard_it; 528 } 529 } 530 531 if (!pskb_pull(skb, sizeof(struct icmp6hdr))) 532 goto discard_it; 533 534 hdr = (struct icmp6hdr *) skb->h.raw; 535 536 type = hdr->icmp6_type; 537 538 if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB) 539 (&icmpv6_statistics[smp_processor_id()*2].Icmp6InDestUnreachs)[type-ICMPV6_DEST_UNREACH]++; 540 else if (type >= ICMPV6_ECHO_REQUEST && type <= NDISC_REDIRECT) 541 (&icmpv6_statistics[smp_processor_id()*2].Icmp6InEchos)[type-ICMPV6_ECHO_REQUEST]++; 542 543 switch (type) { 544 case ICMPV6_ECHO_REQUEST: 545 icmpv6_echo_reply(skb); 546 break; 547 548 case ICMPV6_ECHO_REPLY: 549 /* we coulnd't care less */ 550 break; 551 552 case ICMPV6_PKT_TOOBIG: 553 /* BUGGG_FUTURE: if packet contains rthdr, we cannot update 554 standard destination cache. Seems, only "advanced" 555 destination cache will allow to solve this problem 556 --ANK (980726) 557 */ 558 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 559 goto discard_it; 560 hdr = (struct icmp6hdr *) skb->h.raw; 561 orig_hdr = (struct ipv6hdr *) (hdr + 1); 562 rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev, 563 ntohl(hdr->icmp6_mtu)); 564 565 /* 566 * Drop through to notify 567 */ 568 569 case ICMPV6_DEST_UNREACH: 570 case ICMPV6_TIME_EXCEED: 571 case ICMPV6_PARAMPROB: 572 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu); 573 break; 574 575 case NDISC_ROUTER_SOLICITATION: 576 case NDISC_ROUTER_ADVERTISEMENT: 577 case NDISC_NEIGHBOUR_SOLICITATION: 578 case NDISC_NEIGHBOUR_ADVERTISEMENT: 579 case NDISC_REDIRECT: 580 if (skb_is_nonlinear(skb) && 581 skb_linearize(skb, GFP_ATOMIC) != 0) { 582 kfree_skb(skb); 583 return 0; 584 } 585 586 ndisc_rcv(skb); 587 break; 588 589 case ICMPV6_MGM_QUERY: 590 igmp6_event_query(skb); 591 break; 592 593 case ICMPV6_MGM_REPORT: 594 igmp6_event_report(skb); 595 break; 596 597 case ICMPV6_MGM_REDUCTION: 598 case ICMPV6_MLD2_REPORT: 599 break; 600 601 default: 602 if (net_ratelimit()) 603 printk(KERN_DEBUG "icmpv6: msg of unkown type\n"); 604 605 /* informational */ 606 if (type & ICMPV6_INFOMSG_MASK) 607 break; 608 609 /* 610 * error of unkown type. 611 * must pass to upper level 612 */ 613 614 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu); 615 }; 616 kfree_skb(skb); 617 return 0; 618 619 discard_it: 620 ICMP6_INC_STATS_BH(Icmp6InErrors); 621 kfree_skb(skb); 622 return 0; 623 } 624 625 int __init icmpv6_init(struct net_proto_family *ops) 626 { 627 struct sock *sk; 628 int err, i, j; 629 630 for (i = 0; i < NR_CPUS; i++) { 631 icmpv6_socket_cpu(i) = sock_alloc(); 632 if (icmpv6_socket_cpu(i) == NULL) { 633 printk(KERN_ERR 634 "Failed to create the ICMP6 control socket.\n"); 635 err = -1; 636 goto fail; 637 } 638 icmpv6_socket_cpu(i)->inode->i_uid = 0; 639 icmpv6_socket_cpu(i)->inode->i_gid = 0; 640 icmpv6_socket_cpu(i)->type = SOCK_RAW; 641 642 if ((err = ops->create(icmpv6_socket_cpu(i), IPPROTO_ICMPV6)) < 0) { 643 printk(KERN_ERR 644 "Failed to initialize the ICMP6 control socket " 645 "(err %d).\n", 646 err); 647 goto fail; 648 } 649 650 sk = icmpv6_socket_cpu(i)->sk; 651 sk->allocation = GFP_ATOMIC; 652 653 /* Enough space for 2 64K ICMP packets, including 654 * sk_buff struct overhead. 655 */ 656 sk->sndbuf = 657 (2 * ((64 * 1024) + sizeof(struct sk_buff))); 658 659 sk->prot->unhash(sk); 660 } 661 662 inet6_add_protocol(&icmpv6_protocol); 663 664 return 0; 665 fail: 666 for (j = 0; j < i; j++) { 667 sock_release(icmpv6_socket_cpu(j)); 668 icmpv6_socket_cpu(j) = NULL; 669 } 670 return err; 671 } 672 673 void icmpv6_cleanup(void) 674 { 675 int i; 676 677 for (i = 0; i < NR_CPUS; i++) { 678 sock_release(icmpv6_socket_cpu(i)); 679 icmpv6_socket_cpu(i) = NULL; 680 } 681 inet6_del_protocol(&icmpv6_protocol); 682 } 683 684 static struct icmp6_err { 685 int err; 686 int fatal; 687 } tab_unreach[] = { 688 { ENETUNREACH, 0}, /* NOROUTE */ 689 { EACCES, 1}, /* ADM_PROHIBITED */ 690 { EHOSTUNREACH, 0}, /* Was NOT_NEIGHBOUR, now reserved */ 691 { EHOSTUNREACH, 0}, /* ADDR_UNREACH */ 692 { ECONNREFUSED, 1}, /* PORT_UNREACH */ 693 }; 694 695 int icmpv6_err_convert(int type, int code, int *err) 696 { 697 int fatal = 0; 698 699 *err = EPROTO; 700 701 switch (type) { 702 case ICMPV6_DEST_UNREACH: 703 fatal = 1; 704 if (code <= ICMPV6_PORT_UNREACH) { 705 *err = tab_unreach[code].err; 706 fatal = tab_unreach[code].fatal; 707 } 708 break; 709 710 case ICMPV6_PKT_TOOBIG: 711 *err = EMSGSIZE; 712 break; 713 714 case ICMPV6_PARAMPROB: 715 *err = EPROTO; 716 fatal = 1; 717 break; 718 719 case ICMPV6_TIME_EXCEED: 720 *err = EHOSTUNREACH; 721 break; 722 }; 723 724 return fatal; 725 } 726 727 #ifdef CONFIG_SYSCTL 728 ctl_table ipv6_icmp_table[] = { 729 {NET_IPV6_ICMP_RATELIMIT, "ratelimit", 730 &sysctl_icmpv6_time, sizeof(int), 0644, NULL, &proc_dointvec}, 731 {0}, 732 }; 733 #endif 734 735
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.