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

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

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

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

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.