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