import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / net / ipv6 / icmp.c
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