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
icmpv6_xmit_lock(void)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
icmpv6_xmit_unlock(void)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
icmpv6_getfrag(const void * data,struct in6_addr * saddr,char * buff,unsigned int offset,unsigned int len)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 */
icmpv6_param_prob(struct sk_buff * skb,int code,int pos)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
is_ineligible(struct sk_buff * skb)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 */
icmpv6_xrlim_allow(struct sock * sk,int type,struct flowi * fl)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
opt_unrec(struct sk_buff * skb,__u32 offset)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
icmpv6_send(struct sk_buff * skb,int type,int code,__u32 info,struct net_device * dev)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
icmpv6_echo_reply(struct sk_buff * skb)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
icmpv6_notify(struct sk_buff * skb,int type,int code,u32 info)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
icmpv6_rcv(struct sk_buff * skb)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
icmpv6_init(struct net_proto_family * ops)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
icmpv6_cleanup(void)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
icmpv6_err_convert(int type,int code,int * err)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