~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ipv6/icmp.c

Version: ~ [ linux-6.3-rc3 ] ~ [ linux-6.2.7 ] ~ [ linux-6.1.20 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.103 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.175 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.237 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.278 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.310 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp