Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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.38 2002/02/08 03:57:19 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  *      Randy Dunlap and
 30  *      YOSHIFUJI Hideaki @USAGI:       Per-interface statistics support
 31  *      Kazunori MIYAZAWA @USAGI:       change output process to use ip6_append_data
 32  */
 33 
 34 #include <linux/module.h>
 35 #include <linux/errno.h>
 36 #include <linux/types.h>
 37 #include <linux/socket.h>
 38 #include <linux/in.h>
 39 #include <linux/kernel.h>
 40 #include <linux/sched.h>
 41 #include <linux/sockios.h>
 42 #include <linux/net.h>
 43 #include <linux/skbuff.h>
 44 #include <linux/init.h>
 45 
 46 #ifdef CONFIG_SYSCTL
 47 #include <linux/sysctl.h>
 48 #endif
 49 
 50 #include <linux/inet.h>
 51 #include <linux/netdevice.h>
 52 #include <linux/icmpv6.h>
 53 
 54 #include <net/ip.h>
 55 #include <net/sock.h>
 56 
 57 #include <net/ipv6.h>
 58 #include <net/ip6_checksum.h>
 59 #include <net/protocol.h>
 60 #include <net/raw.h>
 61 #include <net/rawv6.h>
 62 #include <net/transp_v6.h>
 63 #include <net/ip6_route.h>
 64 #include <net/addrconf.h>
 65 #include <net/icmp.h>
 66 
 67 #include <asm/uaccess.h>
 68 #include <asm/system.h>
 69 
 70 DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics);
 71 
 72 /*
 73  *      The ICMP socket(s). This is the most convenient way to flow control
 74  *      our ICMP output as well as maintain a clean interface throughout
 75  *      all layers. All Socketless IP sends will soon be gone.
 76  *
 77  *      On SMP we have one ICMP socket per-cpu.
 78  */
 79 static DEFINE_PER_CPU(struct socket *, __icmpv6_socket) = NULL;
 80 #define icmpv6_socket   __get_cpu_var(__icmpv6_socket)
 81 
 82 static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp);
 83 
 84 static struct inet6_protocol icmpv6_protocol = {
 85         .handler        =       icmpv6_rcv,
 86         .flags          =       INET6_PROTO_FINAL,
 87 };
 88 
 89 static __inline__ int icmpv6_xmit_lock(void)
 90 {
 91         local_bh_disable();
 92 
 93         if (unlikely(!spin_trylock(&icmpv6_socket->sk->sk_lock.slock))) {
 94                 /* This can happen if the output path (f.e. SIT or
 95                  * ip6ip6 tunnel) signals dst_link_failure() for an
 96                  * outgoing ICMP6 packet.
 97                  */
 98                 local_bh_enable();
 99                 return 1;
100         }
101         return 0;
102 }
103 
104 static __inline__ void icmpv6_xmit_unlock(void)
105 {
106         spin_unlock_bh(&icmpv6_socket->sk->sk_lock.slock);
107 }
108 
109 /* 
110  * Slightly more convenient version of icmpv6_send.
111  */
112 void icmpv6_param_prob(struct sk_buff *skb, int code, int pos)
113 {
114         icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev);
115         kfree_skb(skb);
116 }
117 
118 /*
119  * Figure out, may we reply to this packet with icmp error.
120  *
121  * We do not reply, if:
122  *      - it was icmp error message.
123  *      - it is truncated, so that it is known, that protocol is ICMPV6
124  *        (i.e. in the middle of some exthdr)
125  *
126  *      --ANK (980726)
127  */
128 
129 static int is_ineligible(struct sk_buff *skb)
130 {
131         int ptr = (u8*)(skb->nh.ipv6h+1) - skb->data;
132         int len = skb->len - ptr;
133         __u8 nexthdr = skb->nh.ipv6h->nexthdr;
134 
135         if (len < 0)
136                 return 1;
137 
138         ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, len);
139         if (ptr < 0)
140                 return 0;
141         if (nexthdr == IPPROTO_ICMPV6) {
142                 u8 _type, *tp;
143                 tp = skb_header_pointer(skb,
144                         ptr+offsetof(struct icmp6hdr, icmp6_type),
145                         sizeof(_type), &_type);
146                 if (tp == NULL ||
147                     !(*tp & ICMPV6_INFOMSG_MASK))
148                         return 1;
149         }
150         return 0;
151 }
152 
153 static int sysctl_icmpv6_time = 1*HZ; 
154 
155 /* 
156  * Check the ICMP output rate limit 
157  */
158 static inline int icmpv6_xrlim_allow(struct sock *sk, int type,
159                                      struct flowi *fl)
160 {
161         struct dst_entry *dst;
162         int res = 0;
163 
164         /* Informational messages are not limited. */
165         if (type & ICMPV6_INFOMSG_MASK)
166                 return 1;
167 
168         /* Do not limit pmtu discovery, it would break it. */
169         if (type == ICMPV6_PKT_TOOBIG)
170                 return 1;
171 
172         /* 
173          * Look up the output route.
174          * XXX: perhaps the expire for routing entries cloned by
175          * this lookup should be more aggressive (not longer than timeout).
176          */
177         dst = ip6_route_output(sk, fl);
178         if (dst->error) {
179                 IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
180         } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {
181                 res = 1;
182         } else {
183                 struct rt6_info *rt = (struct rt6_info *)dst;
184                 int tmo = sysctl_icmpv6_time;
185 
186                 /* Give more bandwidth to wider prefixes. */
187                 if (rt->rt6i_dst.plen < 128)
188                         tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
189 
190                 res = xrlim_allow(dst, tmo);
191         }
192         dst_release(dst);
193         return res;
194 }
195 
196 /*
197  *      an inline helper for the "simple" if statement below
198  *      checks if parameter problem report is caused by an
199  *      unrecognized IPv6 option that has the Option Type 
200  *      highest-order two bits set to 10
201  */
202 
203 static __inline__ int opt_unrec(struct sk_buff *skb, __u32 offset)
204 {
205         u8 _optval, *op;
206 
207         offset += skb->nh.raw - skb->data;
208         op = skb_header_pointer(skb, offset, sizeof(_optval), &_optval);
209         if (op == NULL)
210                 return 1;
211         return (*op & 0xC0) == 0x80;
212 }
213 
214 static int icmpv6_push_pending_frames(struct sock *sk, struct flowi *fl, struct icmp6hdr *thdr, int len)
215 {
216         struct sk_buff *skb;
217         struct icmp6hdr *icmp6h;
218         int err = 0;
219 
220         if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
221                 goto out;
222 
223         icmp6h = (struct icmp6hdr*) skb->h.raw;
224         memcpy(icmp6h, thdr, sizeof(struct icmp6hdr));
225         icmp6h->icmp6_cksum = 0;
226 
227         if (skb_queue_len(&sk->sk_write_queue) == 1) {
228                 skb->csum = csum_partial((char *)icmp6h,
229                                         sizeof(struct icmp6hdr), skb->csum);
230                 icmp6h->icmp6_cksum = csum_ipv6_magic(&fl->fl6_src,
231                                                       &fl->fl6_dst,
232                                                       len, fl->proto,
233                                                       skb->csum);
234         } else {
235                 u32 tmp_csum = 0;
236 
237                 skb_queue_walk(&sk->sk_write_queue, skb) {
238                         tmp_csum = csum_add(tmp_csum, skb->csum);
239                 }
240 
241                 tmp_csum = csum_partial((char *)icmp6h,
242                                         sizeof(struct icmp6hdr), tmp_csum);
243                 tmp_csum = csum_ipv6_magic(&fl->fl6_src,
244                                            &fl->fl6_dst,
245                                            len, fl->proto, tmp_csum);
246                 icmp6h->icmp6_cksum = tmp_csum;
247         }
248         if (icmp6h->icmp6_cksum == 0)
249                 icmp6h->icmp6_cksum = -1;
250         ip6_push_pending_frames(sk);
251 out:
252         return err;
253 }
254 
255 struct icmpv6_msg {
256         struct sk_buff  *skb;
257         int             offset;
258 };
259 
260 static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
261 {
262         struct icmpv6_msg *msg = (struct icmpv6_msg *) from;
263         struct sk_buff *org_skb = msg->skb;
264         __u32 csum = 0;
265 
266         csum = skb_copy_and_csum_bits(org_skb, msg->offset + offset,
267                                       to, len, csum);
268         skb->csum = csum_block_add(skb->csum, csum, odd);
269         return 0;
270 }
271 
272 /*
273  *      Send an ICMP message in response to a packet in error
274  */
275 void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, 
276                  struct net_device *dev)
277 {
278         struct inet6_dev *idev = NULL;
279         struct ipv6hdr *hdr = skb->nh.ipv6h;
280         struct sock *sk = icmpv6_socket->sk;
281         struct ipv6_pinfo *np = inet6_sk(sk);
282         struct in6_addr *saddr = NULL;
283         struct dst_entry *dst;
284         struct icmp6hdr tmp_hdr;
285         struct flowi fl;
286         struct icmpv6_msg msg;
287         int iif = 0;
288         int addr_type = 0;
289         int len;
290         int hlimit;
291         int err = 0;
292 
293         if ((u8*)hdr < skb->head || (u8*)(hdr+1) > skb->tail)
294                 return;
295 
296         /*
297          *      Make sure we respect the rules 
298          *      i.e. RFC 1885 2.4(e)
299          *      Rule (e.1) is enforced by not using icmpv6_send
300          *      in any code that processes icmp errors.
301          */
302         addr_type = ipv6_addr_type(&hdr->daddr);
303 
304         if (ipv6_chk_addr(&hdr->daddr, skb->dev, 0))
305                 saddr = &hdr->daddr;
306 
307         /*
308          *      Dest addr check
309          */
310 
311         if ((addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST)) {
312                 if (type != ICMPV6_PKT_TOOBIG &&
313                     !(type == ICMPV6_PARAMPROB && 
314                       code == ICMPV6_UNK_OPTION && 
315                       (opt_unrec(skb, info))))
316                         return;
317 
318                 saddr = NULL;
319         }
320 
321         addr_type = ipv6_addr_type(&hdr->saddr);
322 
323         /*
324          *      Source addr check
325          */
326 
327         if (addr_type & IPV6_ADDR_LINKLOCAL)
328                 iif = skb->dev->ifindex;
329 
330         /*
331          *      Must not send if we know that source is Anycast also.
332          *      for now we don't know that.
333          */
334         if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
335                 LIMIT_NETDEBUG(
336                         printk(KERN_DEBUG "icmpv6_send: addr_any/mcast source\n"));
337                 return;
338         }
339 
340         /* 
341          *      Never answer to a ICMP packet.
342          */
343         if (is_ineligible(skb)) {
344                 LIMIT_NETDEBUG(
345                         printk(KERN_DEBUG "icmpv6_send: no reply to icmp error\n")); 
346                 return;
347         }
348 
349         memset(&fl, 0, sizeof(fl));
350         fl.proto = IPPROTO_ICMPV6;
351         ipv6_addr_copy(&fl.fl6_dst, &hdr->saddr);
352         if (saddr)
353                 ipv6_addr_copy(&fl.fl6_src, saddr);
354         fl.oif = iif;
355         fl.fl_icmp_type = type;
356         fl.fl_icmp_code = code;
357 
358         if (icmpv6_xmit_lock())
359                 return;
360 
361         if (!icmpv6_xrlim_allow(sk, type, &fl))
362                 goto out;
363 
364         tmp_hdr.icmp6_type = type;
365         tmp_hdr.icmp6_code = code;
366         tmp_hdr.icmp6_cksum = 0;
367         tmp_hdr.icmp6_pointer = htonl(info);
368 
369         if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
370                 fl.oif = np->mcast_oif;
371 
372         err = ip6_dst_lookup(sk, &dst, &fl);
373         if (err)
374                 goto out;
375         if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
376                 goto out_dst_release;
377 
378         if (ipv6_addr_is_multicast(&fl.fl6_dst))
379                 hlimit = np->mcast_hops;
380         else
381                 hlimit = np->hop_limit;
382         if (hlimit < 0)
383                 hlimit = dst_metric(dst, RTAX_HOPLIMIT);
384 
385         msg.skb = skb;
386         msg.offset = skb->nh.raw - skb->data;
387 
388         len = skb->len - msg.offset;
389         len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) -sizeof(struct icmp6hdr));
390         if (len < 0) {
391                 LIMIT_NETDEBUG(
392                         printk(KERN_DEBUG "icmp: len problem\n"));
393                 goto out_dst_release;
394         }
395 
396         idev = in6_dev_get(skb->dev);
397 
398         err = ip6_append_data(sk, icmpv6_getfrag, &msg,
399                               len + sizeof(struct icmp6hdr),
400                               sizeof(struct icmp6hdr),
401                               hlimit, NULL, &fl, (struct rt6_info*)dst,
402                               MSG_DONTWAIT);
403         if (err) {
404                 ip6_flush_pending_frames(sk);
405                 goto out_put;
406         }
407         err = icmpv6_push_pending_frames(sk, &fl, &tmp_hdr, len + sizeof(struct icmp6hdr));
408 
409         if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB)
410                 ICMP6_INC_STATS_OFFSET_BH(idev, ICMP6_MIB_OUTDESTUNREACHS, type - ICMPV6_DEST_UNREACH);
411         ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS);
412 
413 out_put:
414         if (likely(idev != NULL))
415                 in6_dev_put(idev);
416 out_dst_release:
417         dst_release(dst);
418 out:
419         icmpv6_xmit_unlock();
420 }
421 
422 static void icmpv6_echo_reply(struct sk_buff *skb)
423 {
424         struct sock *sk = icmpv6_socket->sk;
425         struct inet6_dev *idev;
426         struct ipv6_pinfo *np = inet6_sk(sk);
427         struct in6_addr *saddr = NULL;
428         struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw;
429         struct icmp6hdr tmp_hdr;
430         struct flowi fl;
431         struct icmpv6_msg msg;
432         struct dst_entry *dst;
433         int err = 0;
434         int hlimit;
435 
436         saddr = &skb->nh.ipv6h->daddr;
437 
438         if (!ipv6_unicast_destination(skb))
439                 saddr = NULL;
440 
441         memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr));
442         tmp_hdr.icmp6_type = ICMPV6_ECHO_REPLY;
443 
444         memset(&fl, 0, sizeof(fl));
445         fl.proto = IPPROTO_ICMPV6;
446         ipv6_addr_copy(&fl.fl6_dst, &skb->nh.ipv6h->saddr);
447         if (saddr)
448                 ipv6_addr_copy(&fl.fl6_src, saddr);
449         fl.oif = skb->dev->ifindex;
450         fl.fl_icmp_type = ICMPV6_ECHO_REPLY;
451 
452         if (icmpv6_xmit_lock())
453                 return;
454 
455         if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
456                 fl.oif = np->mcast_oif;
457 
458         err = ip6_dst_lookup(sk, &dst, &fl);
459         if (err)
460                 goto out;
461         if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
462                 goto out_dst_release;
463 
464         if (ipv6_addr_is_multicast(&fl.fl6_dst))
465                 hlimit = np->mcast_hops;
466         else
467                 hlimit = np->hop_limit;
468         if (hlimit < 0)
469                 hlimit = dst_metric(dst, RTAX_HOPLIMIT);
470 
471         idev = in6_dev_get(skb->dev);
472 
473         msg.skb = skb;
474         msg.offset = 0;
475 
476         err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr),
477                                 sizeof(struct icmp6hdr), hlimit, NULL, &fl,
478                                 (struct rt6_info*)dst, MSG_DONTWAIT);
479 
480         if (err) {
481                 ip6_flush_pending_frames(sk);
482                 goto out_put;
483         }
484         err = icmpv6_push_pending_frames(sk, &fl, &tmp_hdr, skb->len + sizeof(struct icmp6hdr));
485 
486         ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTECHOREPLIES);
487         ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS);
488 
489 out_put: 
490         if (likely(idev != NULL))
491                 in6_dev_put(idev);
492 out_dst_release:
493         dst_release(dst);
494 out: 
495         icmpv6_xmit_unlock();
496 }
497 
498 static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
499 {
500         struct in6_addr *saddr, *daddr;
501         struct inet6_protocol *ipprot;
502         struct sock *sk;
503         int inner_offset;
504         int hash;
505         u8 nexthdr;
506 
507         if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
508                 return;
509 
510         nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
511         if (ipv6_ext_hdr(nexthdr)) {
512                 /* now skip over extension headers */
513                 inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, skb->len - sizeof(struct ipv6hdr));
514                 if (inner_offset<0)
515                         return;
516         } else {
517                 inner_offset = sizeof(struct ipv6hdr);
518         }
519 
520         /* Checkin header including 8 bytes of inner protocol header. */
521         if (!pskb_may_pull(skb, inner_offset+8))
522                 return;
523 
524         saddr = &skb->nh.ipv6h->saddr;
525         daddr = &skb->nh.ipv6h->daddr;
526 
527         /* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
528            Without this we will not able f.e. to make source routed
529            pmtu discovery.
530            Corresponding argument (opt) to notifiers is already added.
531            --ANK (980726)
532          */
533 
534         hash = nexthdr & (MAX_INET_PROTOS - 1);
535 
536         rcu_read_lock();
537         ipprot = rcu_dereference(inet6_protos[hash]);
538         if (ipprot && ipprot->err_handler)
539                 ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
540         rcu_read_unlock();
541 
542         read_lock(&raw_v6_lock);
543         if ((sk = sk_head(&raw_v6_htable[hash])) != NULL) {
544                 while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr))) {
545                         rawv6_err(sk, skb, NULL, type, code, inner_offset, info);
546                         sk = sk_next(sk);
547                 }
548         }
549         read_unlock(&raw_v6_lock);
550 }
551   
552 /*
553  *      Handle icmp messages
554  */
555 
556 static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
557 {
558         struct sk_buff *skb = *pskb;
559         struct net_device *dev = skb->dev;
560         struct inet6_dev *idev = __in6_dev_get(dev);
561         struct in6_addr *saddr, *daddr;
562         struct ipv6hdr *orig_hdr;
563         struct icmp6hdr *hdr;
564         int type;
565 
566         ICMP6_INC_STATS_BH(idev, ICMP6_MIB_INMSGS);
567 
568         saddr = &skb->nh.ipv6h->saddr;
569         daddr = &skb->nh.ipv6h->daddr;
570 
571         /* Perform checksum. */
572         if (skb->ip_summed == CHECKSUM_HW) {
573                 skb->ip_summed = CHECKSUM_UNNECESSARY;
574                 if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6,
575                                     skb->csum)) {
576                         LIMIT_NETDEBUG(
577                                 printk(KERN_DEBUG "ICMPv6 hw checksum failed\n"));
578                         skb->ip_summed = CHECKSUM_NONE;
579                 }
580         }
581         if (skb->ip_summed == CHECKSUM_NONE) {
582                 if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6,
583                                     skb_checksum(skb, 0, skb->len, 0))) {
584                         LIMIT_NETDEBUG(
585                                 printk(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n",
586                                        NIP6(*saddr), NIP6(*daddr)));
587                         goto discard_it;
588                 }
589         }
590 
591         if (!pskb_pull(skb, sizeof(struct icmp6hdr)))
592                 goto discard_it;
593 
594         hdr = (struct icmp6hdr *) skb->h.raw;
595 
596         type = hdr->icmp6_type;
597 
598         if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB)
599                 ICMP6_INC_STATS_OFFSET_BH(idev, ICMP6_MIB_INDESTUNREACHS, type - ICMPV6_DEST_UNREACH);
600         else if (type >= ICMPV6_ECHO_REQUEST && type <= NDISC_REDIRECT)
601                 ICMP6_INC_STATS_OFFSET_BH(idev, ICMP6_MIB_INECHOS, type - ICMPV6_ECHO_REQUEST);
602 
603         switch (type) {
604         case ICMPV6_ECHO_REQUEST:
605                 icmpv6_echo_reply(skb);
606                 break;
607 
608         case ICMPV6_ECHO_REPLY:
609                 /* we couldn't care less */
610                 break;
611 
612         case ICMPV6_PKT_TOOBIG:
613                 /* BUGGG_FUTURE: if packet contains rthdr, we cannot update
614                    standard destination cache. Seems, only "advanced"
615                    destination cache will allow to solve this problem
616                    --ANK (980726)
617                  */
618                 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
619                         goto discard_it;
620                 hdr = (struct icmp6hdr *) skb->h.raw;
621                 orig_hdr = (struct ipv6hdr *) (hdr + 1);
622                 rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev,
623                                    ntohl(hdr->icmp6_mtu));
624 
625                 /*
626                  *      Drop through to notify
627                  */
628 
629         case ICMPV6_DEST_UNREACH:
630         case ICMPV6_TIME_EXCEED:
631         case ICMPV6_PARAMPROB:
632                 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
633                 break;
634 
635         case NDISC_ROUTER_SOLICITATION:
636         case NDISC_ROUTER_ADVERTISEMENT:
637         case NDISC_NEIGHBOUR_SOLICITATION:
638         case NDISC_NEIGHBOUR_ADVERTISEMENT:
639         case NDISC_REDIRECT:
640                 ndisc_rcv(skb);
641                 break;
642 
643         case ICMPV6_MGM_QUERY:
644                 igmp6_event_query(skb);
645                 break;
646 
647         case ICMPV6_MGM_REPORT:
648                 igmp6_event_report(skb);
649                 break;
650 
651         case ICMPV6_MGM_REDUCTION:
652         case ICMPV6_NI_QUERY:
653         case ICMPV6_NI_REPLY:
654         case ICMPV6_MLD2_REPORT:
655         case ICMPV6_DHAAD_REQUEST:
656         case ICMPV6_DHAAD_REPLY:
657         case ICMPV6_MOBILE_PREFIX_SOL:
658         case ICMPV6_MOBILE_PREFIX_ADV:
659                 break;
660 
661         default:
662                 LIMIT_NETDEBUG(
663                         printk(KERN_DEBUG "icmpv6: msg of unknown type\n"));
664 
665                 /* informational */
666                 if (type & ICMPV6_INFOMSG_MASK)
667                         break;
668 
669                 /* 
670                  * error of unknown type. 
671                  * must pass to upper level 
672                  */
673 
674                 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
675         };
676         kfree_skb(skb);
677         return 0;
678 
679 discard_it:
680         ICMP6_INC_STATS_BH(idev, ICMP6_MIB_INERRORS);
681         kfree_skb(skb);
682         return 0;
683 }
684 
685 int __init icmpv6_init(struct net_proto_family *ops)
686 {
687         struct sock *sk;
688         int err, i, j;
689 
690         for (i = 0; i < NR_CPUS; i++) {
691                 if (!cpu_possible(i))
692                         continue;
693 
694                 err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6,
695                                        &per_cpu(__icmpv6_socket, i));
696                 if (err < 0) {
697                         printk(KERN_ERR
698                                "Failed to initialize the ICMP6 control socket "
699                                "(err %d).\n",
700                                err);
701                         goto fail;
702                 }
703 
704                 sk = per_cpu(__icmpv6_socket, i)->sk;
705                 sk->sk_allocation = GFP_ATOMIC;
706 
707                 /* Enough space for 2 64K ICMP packets, including
708                  * sk_buff struct overhead.
709                  */
710                 sk->sk_sndbuf =
711                         (2 * ((64 * 1024) + sizeof(struct sk_buff)));
712 
713                 sk->sk_prot->unhash(sk);
714         }
715 
716 
717         if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0) {
718                 printk(KERN_ERR "Failed to register ICMP6 protocol\n");
719                 err = -EAGAIN;
720                 goto fail;
721         }
722 
723         return 0;
724 
725  fail:
726         for (j = 0; j < i; j++) {
727                 if (!cpu_possible(j))
728                         continue;
729                 sock_release(per_cpu(__icmpv6_socket, j));
730         }
731 
732         return err;
733 }
734 
735 void icmpv6_cleanup(void)
736 {
737         int i;
738 
739         for (i = 0; i < NR_CPUS; i++) {
740                 if (!cpu_possible(i))
741                         continue;
742                 sock_release(per_cpu(__icmpv6_socket, i));
743         }
744         inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
745 }
746 
747 static struct icmp6_err {
748         int err;
749         int fatal;
750 } tab_unreach[] = {
751         {       /* NOROUTE */
752                 .err    = ENETUNREACH,
753                 .fatal  = 0,
754         },
755         {       /* ADM_PROHIBITED */
756                 .err    = EACCES,
757                 .fatal  = 1,
758         },
759         {       /* Was NOT_NEIGHBOUR, now reserved */
760                 .err    = EHOSTUNREACH,
761                 .fatal  = 0,
762         },
763         {       /* ADDR_UNREACH */
764                 .err    = EHOSTUNREACH,
765                 .fatal  = 0,
766         },
767         {       /* PORT_UNREACH */
768                 .err    = ECONNREFUSED,
769                 .fatal  = 1,
770         },
771 };
772 
773 int icmpv6_err_convert(int type, int code, int *err)
774 {
775         int fatal = 0;
776 
777         *err = EPROTO;
778 
779         switch (type) {
780         case ICMPV6_DEST_UNREACH:
781                 fatal = 1;
782                 if (code <= ICMPV6_PORT_UNREACH) {
783                         *err  = tab_unreach[code].err;
784                         fatal = tab_unreach[code].fatal;
785                 }
786                 break;
787 
788         case ICMPV6_PKT_TOOBIG:
789                 *err = EMSGSIZE;
790                 break;
791                 
792         case ICMPV6_PARAMPROB:
793                 *err = EPROTO;
794                 fatal = 1;
795                 break;
796 
797         case ICMPV6_TIME_EXCEED:
798                 *err = EHOSTUNREACH;
799                 break;
800         };
801 
802         return fatal;
803 }
804 
805 #ifdef CONFIG_SYSCTL
806 ctl_table ipv6_icmp_table[] = {
807         {
808                 .ctl_name       = NET_IPV6_ICMP_RATELIMIT,
809                 .procname       = "ratelimit",
810                 .data           = &sysctl_icmpv6_time,
811                 .maxlen         = sizeof(int),
812                 .mode           = 0644,
813                 .proc_handler   = &proc_dointvec
814         },
815         { .ctl_name = 0 },
816 };
817 #endif
818 
819 
  This page was automatically generated by the LXR engine.