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

FreeBSD/Linux Kernel Cross Reference
sys/netinet6/icmp6.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  1 /*-
  2  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  3  * All rights reserved.
  4  *
  5  * Redistribution and use in source and binary forms, with or without
  6  * modification, are permitted provided that the following conditions
  7  * are met:
  8  * 1. Redistributions of source code must retain the above copyright
  9  *    notice, this list of conditions and the following disclaimer.
 10  * 2. Redistributions in binary form must reproduce the above copyright
 11  *    notice, this list of conditions and the following disclaimer in the
 12  *    documentation and/or other materials provided with the distribution.
 13  * 3. Neither the name of the project nor the names of its contributors
 14  *    may be used to endorse or promote products derived from this software
 15  *    without specific prior written permission.
 16  *
 17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
 18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
 21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 27  * SUCH DAMAGE.
 28  *
 29  *      $KAME: icmp6.c,v 1.211 2001/04/04 05:56:20 itojun Exp $
 30  */
 31 
 32 /*-
 33  * Copyright (c) 1982, 1986, 1988, 1993
 34  *      The Regents of the University of California.  All rights reserved.
 35  *
 36  * Redistribution and use in source and binary forms, with or without
 37  * modification, are permitted provided that the following conditions
 38  * are met:
 39  * 1. Redistributions of source code must retain the above copyright
 40  *    notice, this list of conditions and the following disclaimer.
 41  * 2. Redistributions in binary form must reproduce the above copyright
 42  *    notice, this list of conditions and the following disclaimer in the
 43  *    documentation and/or other materials provided with the distribution.
 44  * 4. Neither the name of the University nor the names of its contributors
 45  *    may be used to endorse or promote products derived from this software
 46  *    without specific prior written permission.
 47  *
 48  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 58  * SUCH DAMAGE.
 59  *
 60  *      @(#)ip_icmp.c   8.2 (Berkeley) 1/4/94
 61  */
 62 
 63 #include <sys/cdefs.h>
 64 __FBSDID("$FreeBSD: src/sys/netinet6/icmp6.c,v 1.95 2008/12/02 21:37:28 bz Exp $");
 65 
 66 #include "opt_inet.h"
 67 #include "opt_inet6.h"
 68 #include "opt_ipsec.h"
 69 
 70 #include <sys/param.h>
 71 #include <sys/domain.h>
 72 #include <sys/kernel.h>
 73 #include <sys/lock.h>
 74 #include <sys/malloc.h>
 75 #include <sys/mbuf.h>
 76 #include <sys/protosw.h>
 77 #include <sys/signalvar.h>
 78 #include <sys/socket.h>
 79 #include <sys/socketvar.h>
 80 #include <sys/sx.h>
 81 #include <sys/syslog.h>
 82 #include <sys/systm.h>
 83 #include <sys/time.h>
 84 #include <sys/vimage.h>
 85 
 86 #include <net/if.h>
 87 #include <net/if_dl.h>
 88 #include <net/if_types.h>
 89 #include <net/route.h>
 90 #include <net/vnet.h>
 91 
 92 #include <netinet/in.h>
 93 #include <netinet/in_pcb.h>
 94 #include <netinet/in_var.h>
 95 #include <netinet/ip6.h>
 96 #include <netinet/icmp6.h>
 97 #include <netinet/tcp_var.h>
 98 #include <netinet/vinet.h>
 99 
100 #include <netinet6/in6_ifattach.h>
101 #include <netinet6/in6_pcb.h>
102 #include <netinet6/ip6protosw.h>
103 #include <netinet6/ip6_var.h>
104 #include <netinet6/scope6_var.h>
105 #include <netinet6/mld6_var.h>
106 #include <netinet6/nd6.h>
107 #include <netinet6/vinet6.h>
108 
109 #ifdef IPSEC
110 #include <netipsec/ipsec.h>
111 #include <netipsec/key.h>
112 #endif
113 
114 extern struct domain inet6domain;
115 
116 #ifdef VIMAGE_GLOBALS
117 extern struct inpcbinfo ripcbinfo;
118 extern struct inpcbhead ripcb;
119 extern int icmp6errppslim;
120 extern int icmp6_nodeinfo;
121 
122 struct icmp6stat icmp6stat;
123 static int icmp6errpps_count;
124 static struct timeval icmp6errppslim_last;
125 #endif
126 
127 static void icmp6_errcount(struct icmp6errstat *, int, int);
128 static int icmp6_rip6_input(struct mbuf **, int);
129 static int icmp6_ratelimit(const struct in6_addr *, const int, const int);
130 static const char *icmp6_redirect_diag __P((struct in6_addr *,
131         struct in6_addr *, struct in6_addr *));
132 static struct mbuf *ni6_input(struct mbuf *, int);
133 static struct mbuf *ni6_nametodns(const char *, int, int);
134 static int ni6_dnsmatch(const char *, int, const char *, int);
135 static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *,
136                           struct ifnet **, struct in6_addr *));
137 static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
138                                 struct ifnet *, int));
139 static int icmp6_notify_error(struct mbuf **, int, int, int);
140 
141 
142 void
143 icmp6_init(void)
144 {
145         INIT_VNET_INET6(curvnet);
146 
147         V_icmp6errpps_count = 0;
148 
149         mld6_init();
150 }
151 
152 static void
153 icmp6_errcount(struct icmp6errstat *stat, int type, int code)
154 {
155         switch (type) {
156         case ICMP6_DST_UNREACH:
157                 switch (code) {
158                 case ICMP6_DST_UNREACH_NOROUTE:
159                         stat->icp6errs_dst_unreach_noroute++;
160                         return;
161                 case ICMP6_DST_UNREACH_ADMIN:
162                         stat->icp6errs_dst_unreach_admin++;
163                         return;
164                 case ICMP6_DST_UNREACH_BEYONDSCOPE:
165                         stat->icp6errs_dst_unreach_beyondscope++;
166                         return;
167                 case ICMP6_DST_UNREACH_ADDR:
168                         stat->icp6errs_dst_unreach_addr++;
169                         return;
170                 case ICMP6_DST_UNREACH_NOPORT:
171                         stat->icp6errs_dst_unreach_noport++;
172                         return;
173                 }
174                 break;
175         case ICMP6_PACKET_TOO_BIG:
176                 stat->icp6errs_packet_too_big++;
177                 return;
178         case ICMP6_TIME_EXCEEDED:
179                 switch (code) {
180                 case ICMP6_TIME_EXCEED_TRANSIT:
181                         stat->icp6errs_time_exceed_transit++;
182                         return;
183                 case ICMP6_TIME_EXCEED_REASSEMBLY:
184                         stat->icp6errs_time_exceed_reassembly++;
185                         return;
186                 }
187                 break;
188         case ICMP6_PARAM_PROB:
189                 switch (code) {
190                 case ICMP6_PARAMPROB_HEADER:
191                         stat->icp6errs_paramprob_header++;
192                         return;
193                 case ICMP6_PARAMPROB_NEXTHEADER:
194                         stat->icp6errs_paramprob_nextheader++;
195                         return;
196                 case ICMP6_PARAMPROB_OPTION:
197                         stat->icp6errs_paramprob_option++;
198                         return;
199                 }
200                 break;
201         case ND_REDIRECT:
202                 stat->icp6errs_redirect++;
203                 return;
204         }
205         stat->icp6errs_unknown++;
206 }
207 
208 /*
209  * A wrapper function for icmp6_error() necessary when the erroneous packet
210  * may not contain enough scope zone information.
211  */
212 void
213 icmp6_error2(struct mbuf *m, int type, int code, int param,
214     struct ifnet *ifp)
215 {
216         INIT_VNET_INET6(curvnet);
217         struct ip6_hdr *ip6;
218 
219         if (ifp == NULL)
220                 return;
221 
222 #ifndef PULLDOWN_TEST
223         IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), );
224 #else
225         if (m->m_len < sizeof(struct ip6_hdr)) {
226                 m = m_pullup(m, sizeof(struct ip6_hdr));
227                 if (m == NULL)
228                         return;
229         }
230 #endif
231 
232         ip6 = mtod(m, struct ip6_hdr *);
233 
234         if (in6_setscope(&ip6->ip6_src, ifp, NULL) != 0)
235                 return;
236         if (in6_setscope(&ip6->ip6_dst, ifp, NULL) != 0)
237                 return;
238 
239         icmp6_error(m, type, code, param);
240 }
241 
242 /*
243  * Generate an error packet of type error in response to bad IP6 packet.
244  */
245 void
246 icmp6_error(struct mbuf *m, int type, int code, int param)
247 {
248         INIT_VNET_INET6(curvnet);
249         struct ip6_hdr *oip6, *nip6;
250         struct icmp6_hdr *icmp6;
251         u_int preplen;
252         int off;
253         int nxt;
254 
255         V_icmp6stat.icp6s_error++;
256 
257         /* count per-type-code statistics */
258         icmp6_errcount(&V_icmp6stat.icp6s_outerrhist, type, code);
259 
260 #ifdef M_DECRYPTED      /*not openbsd*/
261         if (m->m_flags & M_DECRYPTED) {
262                 V_icmp6stat.icp6s_canterror++;
263                 goto freeit;
264         }
265 #endif
266 
267 #ifndef PULLDOWN_TEST
268         IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), );
269 #else
270         if (m->m_len < sizeof(struct ip6_hdr)) {
271                 m = m_pullup(m, sizeof(struct ip6_hdr));
272                 if (m == NULL)
273                         return;
274         }
275 #endif
276         oip6 = mtod(m, struct ip6_hdr *);
277 
278         /*
279          * If the destination address of the erroneous packet is a multicast
280          * address, or the packet was sent using link-layer multicast,
281          * we should basically suppress sending an error (RFC 2463, Section
282          * 2.4).
283          * We have two exceptions (the item e.2 in that section):
284          * - the Pakcet Too Big message can be sent for path MTU discovery.
285          * - the Parameter Problem Message that can be allowed an icmp6 error
286          *   in the option type field.  This check has been done in
287          *   ip6_unknown_opt(), so we can just check the type and code.
288          */
289         if ((m->m_flags & (M_BCAST|M_MCAST) ||
290              IN6_IS_ADDR_MULTICAST(&oip6->ip6_dst)) &&
291             (type != ICMP6_PACKET_TOO_BIG &&
292              (type != ICMP6_PARAM_PROB ||
293               code != ICMP6_PARAMPROB_OPTION)))
294                 goto freeit;
295 
296         /*
297          * RFC 2463, 2.4 (e.5): source address check.
298          * XXX: the case of anycast source?
299          */
300         if (IN6_IS_ADDR_UNSPECIFIED(&oip6->ip6_src) ||
301             IN6_IS_ADDR_MULTICAST(&oip6->ip6_src))
302                 goto freeit;
303 
304         /*
305          * If we are about to send ICMPv6 against ICMPv6 error/redirect,
306          * don't do it.
307          */
308         nxt = -1;
309         off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
310         if (off >= 0 && nxt == IPPROTO_ICMPV6) {
311                 struct icmp6_hdr *icp;
312 
313 #ifndef PULLDOWN_TEST
314                 IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct icmp6_hdr), );
315                 icp = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
316 #else
317                 IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off,
318                         sizeof(*icp));
319                 if (icp == NULL) {
320                         V_icmp6stat.icp6s_tooshort++;
321                         return;
322                 }
323 #endif
324                 if (icp->icmp6_type < ICMP6_ECHO_REQUEST ||
325                     icp->icmp6_type == ND_REDIRECT) {
326                         /*
327                          * ICMPv6 error
328                          * Special case: for redirect (which is
329                          * informational) we must not send icmp6 error.
330                          */
331                         V_icmp6stat.icp6s_canterror++;
332                         goto freeit;
333                 } else {
334                         /* ICMPv6 informational - send the error */
335                 }
336         } else {
337                 /* non-ICMPv6 - send the error */
338         }
339 
340         oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */
341 
342         /* Finally, do rate limitation check. */
343         if (icmp6_ratelimit(&oip6->ip6_src, type, code)) {
344                 V_icmp6stat.icp6s_toofreq++;
345                 goto freeit;
346         }
347 
348         /*
349          * OK, ICMP6 can be generated.
350          */
351 
352         if (m->m_pkthdr.len >= ICMPV6_PLD_MAXLEN)
353                 m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len);
354 
355         preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
356         M_PREPEND(m, preplen, M_DONTWAIT);
357         if (m && m->m_len < preplen)
358                 m = m_pullup(m, preplen);
359         if (m == NULL) {
360                 nd6log((LOG_DEBUG, "ENOBUFS in icmp6_error %d\n", __LINE__));
361                 return;
362         }
363 
364         nip6 = mtod(m, struct ip6_hdr *);
365         nip6->ip6_src  = oip6->ip6_src;
366         nip6->ip6_dst  = oip6->ip6_dst;
367 
368         in6_clearscope(&oip6->ip6_src);
369         in6_clearscope(&oip6->ip6_dst);
370 
371         icmp6 = (struct icmp6_hdr *)(nip6 + 1);
372         icmp6->icmp6_type = type;
373         icmp6->icmp6_code = code;
374         icmp6->icmp6_pptr = htonl((u_int32_t)param);
375 
376         /*
377          * icmp6_reflect() is designed to be in the input path.
378          * icmp6_error() can be called from both input and output path,
379          * and if we are in output path rcvif could contain bogus value.
380          * clear m->m_pkthdr.rcvif for safety, we should have enough scope
381          * information in ip header (nip6).
382          */
383         m->m_pkthdr.rcvif = NULL;
384 
385         V_icmp6stat.icp6s_outhist[type]++;
386         icmp6_reflect(m, sizeof(struct ip6_hdr)); /* header order: IPv6 - ICMPv6 */
387 
388         return;
389 
390   freeit:
391         /*
392          * If we can't tell whether or not we can generate ICMP6, free it.
393          */
394         m_freem(m);
395 }
396 
397 /*
398  * Process a received ICMP6 message.
399  */
400 int
401 icmp6_input(struct mbuf **mp, int *offp, int proto)
402 {
403         INIT_VNET_INET6(curvnet);
404         INIT_VPROCG(TD_TO_VPROCG(curthread)); /* XXX V_hostname needs this */
405         struct mbuf *m = *mp, *n;
406         struct ip6_hdr *ip6, *nip6;
407         struct icmp6_hdr *icmp6, *nicmp6;
408         int off = *offp;
409         int icmp6len = m->m_pkthdr.len - *offp;
410         int code, sum, noff;
411         char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
412 
413 #ifndef PULLDOWN_TEST
414         IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), IPPROTO_DONE);
415         /* m might change if M_LOOP.  So, call mtod after this */
416 #endif
417 
418         /*
419          * Locate icmp6 structure in mbuf, and check
420          * that not corrupted and of at least minimum length
421          */
422 
423         ip6 = mtod(m, struct ip6_hdr *);
424         if (icmp6len < sizeof(struct icmp6_hdr)) {
425                 V_icmp6stat.icp6s_tooshort++;
426                 goto freeit;
427         }
428 
429         /*
430          * calculate the checksum
431          */
432 #ifndef PULLDOWN_TEST
433         icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
434 #else
435         IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
436         if (icmp6 == NULL) {
437                 V_icmp6stat.icp6s_tooshort++;
438                 return IPPROTO_DONE;
439         }
440 #endif
441         code = icmp6->icmp6_code;
442 
443         if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) {
444                 nd6log((LOG_ERR,
445                     "ICMP6 checksum error(%d|%x) %s\n",
446                     icmp6->icmp6_type, sum,
447                     ip6_sprintf(ip6bufs, &ip6->ip6_src)));
448                 V_icmp6stat.icp6s_checksum++;
449                 goto freeit;
450         }
451 
452         if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) {
453                 /*
454                  * Deliver very specific ICMP6 type only.
455                  * This is important to deliver TOOBIG.  Otherwise PMTUD
456                  * will not work.
457                  */
458                 switch (icmp6->icmp6_type) {
459                 case ICMP6_DST_UNREACH:
460                 case ICMP6_PACKET_TOO_BIG:
461                 case ICMP6_TIME_EXCEEDED:
462                         break;
463                 default:
464                         goto freeit;
465                 }
466         }
467 
468         V_icmp6stat.icp6s_inhist[icmp6->icmp6_type]++;
469         icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_msg);
470         if (icmp6->icmp6_type < ICMP6_INFOMSG_MASK)
471                 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error);
472 
473         switch (icmp6->icmp6_type) {
474         case ICMP6_DST_UNREACH:
475                 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_dstunreach);
476                 switch (code) {
477                 case ICMP6_DST_UNREACH_NOROUTE:
478                         code = PRC_UNREACH_NET;
479                         break;
480                 case ICMP6_DST_UNREACH_ADMIN:
481                         icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_adminprohib);
482                         code = PRC_UNREACH_PROTOCOL; /* is this a good code? */
483                         break;
484                 case ICMP6_DST_UNREACH_ADDR:
485                         code = PRC_HOSTDEAD;
486                         break;
487                 case ICMP6_DST_UNREACH_BEYONDSCOPE:
488                         /* I mean "source address was incorrect." */
489                         code = PRC_PARAMPROB;
490                         break;
491                 case ICMP6_DST_UNREACH_NOPORT:
492                         code = PRC_UNREACH_PORT;
493                         break;
494                 default:
495                         goto badcode;
496                 }
497                 goto deliver;
498                 break;
499 
500         case ICMP6_PACKET_TOO_BIG:
501                 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_pkttoobig);
502 
503                 /* validation is made in icmp6_mtudisc_update */
504 
505                 code = PRC_MSGSIZE;
506 
507                 /*
508                  * Updating the path MTU will be done after examining
509                  * intermediate extension headers.
510                  */
511                 goto deliver;
512                 break;
513 
514         case ICMP6_TIME_EXCEEDED:
515                 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_timeexceed);
516                 switch (code) {
517                 case ICMP6_TIME_EXCEED_TRANSIT:
518                         code = PRC_TIMXCEED_INTRANS;
519                         break;
520                 case ICMP6_TIME_EXCEED_REASSEMBLY:
521                         code = PRC_TIMXCEED_REASS;
522                         break;
523                 default:
524                         goto badcode;
525                 }
526                 goto deliver;
527                 break;
528 
529         case ICMP6_PARAM_PROB:
530                 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_paramprob);
531                 switch (code) {
532                 case ICMP6_PARAMPROB_NEXTHEADER:
533                         code = PRC_UNREACH_PROTOCOL;
534                         break;
535                 case ICMP6_PARAMPROB_HEADER:
536                 case ICMP6_PARAMPROB_OPTION:
537                         code = PRC_PARAMPROB;
538                         break;
539                 default:
540                         goto badcode;
541                 }
542                 goto deliver;
543                 break;
544 
545         case ICMP6_ECHO_REQUEST:
546                 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echo);
547                 if (code != 0)
548                         goto badcode;
549                 if ((n = m_copy(m, 0, M_COPYALL)) == NULL) {
550                         /* Give up remote */
551                         break;
552                 }
553                 if ((n->m_flags & M_EXT) != 0
554                  || n->m_len < off + sizeof(struct icmp6_hdr)) {
555                         struct mbuf *n0 = n;
556                         const int maxlen = sizeof(*nip6) + sizeof(*nicmp6);
557                         int n0len;
558 
559                         MGETHDR(n, M_DONTWAIT, n0->m_type);
560                         n0len = n0->m_pkthdr.len;       /* save for use below */
561                         if (n)
562                                 M_MOVE_PKTHDR(n, n0);
563                         if (n && maxlen >= MHLEN) {
564                                 MCLGET(n, M_DONTWAIT);
565                                 if ((n->m_flags & M_EXT) == 0) {
566                                         m_free(n);
567                                         n = NULL;
568                                 }
569                         }
570                         if (n == NULL) {
571                                 /* Give up remote */
572                                 m_freem(n0);
573                                 break;
574                         }
575                         /*
576                          * Copy IPv6 and ICMPv6 only.
577                          */
578                         nip6 = mtod(n, struct ip6_hdr *);
579                         bcopy(ip6, nip6, sizeof(struct ip6_hdr));
580                         nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
581                         bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
582                         noff = sizeof(struct ip6_hdr);
583                         /* new mbuf contains only ipv6+icmpv6 headers */
584                         n->m_len = noff + sizeof(struct icmp6_hdr);
585                         /*
586                          * Adjust mbuf.  ip6_plen will be adjusted in
587                          * ip6_output().
588                          */
589                         m_adj(n0, off + sizeof(struct icmp6_hdr));
590                         /* recalculate complete packet size */
591                         n->m_pkthdr.len = n0len + (noff - off);
592                         n->m_next = n0;
593                 } else {
594                         nip6 = mtod(n, struct ip6_hdr *);
595                         IP6_EXTHDR_GET(nicmp6, struct icmp6_hdr *, n, off,
596                             sizeof(*nicmp6));
597                         noff = off;
598                 }
599                 nicmp6->icmp6_type = ICMP6_ECHO_REPLY;
600                 nicmp6->icmp6_code = 0;
601                 if (n) {
602                         V_icmp6stat.icp6s_reflect++;
603                         V_icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]++;
604                         icmp6_reflect(n, noff);
605                 }
606                 break;
607 
608         case ICMP6_ECHO_REPLY:
609                 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echoreply);
610                 if (code != 0)
611                         goto badcode;
612                 break;
613 
614         case MLD_LISTENER_QUERY:
615         case MLD_LISTENER_REPORT:
616                 if (icmp6len < sizeof(struct mld_hdr))
617                         goto badlen;
618                 if (icmp6->icmp6_type == MLD_LISTENER_QUERY) /* XXX: ugly... */
619                         icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldquery);
620                 else
621                         icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldreport);
622                 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
623                         /* give up local */
624                         mld6_input(m, off);
625                         m = NULL;
626                         goto freeit;
627                 }
628                 mld6_input(n, off);
629                 /* m stays. */
630                 break;
631 
632         case MLD_LISTENER_DONE:
633                 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mlddone);
634                 if (icmp6len < sizeof(struct mld_hdr))  /* necessary? */
635                         goto badlen;
636                 break;          /* nothing to be done in kernel */
637 
638         case MLD_MTRACE_RESP:
639         case MLD_MTRACE:
640                 /* XXX: these two are experimental.  not officially defined. */
641                 /* XXX: per-interface statistics? */
642                 break;          /* just pass it to applications */
643 
644         case ICMP6_WRUREQUEST:  /* ICMP6_FQDN_QUERY */
645             {
646                 enum { WRU, FQDN } mode;
647 
648                 if (!V_icmp6_nodeinfo)
649                         break;
650 
651                 if (icmp6len == sizeof(struct icmp6_hdr) + 4)
652                         mode = WRU;
653                 else if (icmp6len >= sizeof(struct icmp6_nodeinfo))
654                         mode = FQDN;
655                 else
656                         goto badlen;
657 
658 #define hostnamelen     strlen(V_hostname)
659                 if (mode == FQDN) {
660 #ifndef PULLDOWN_TEST
661                         IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_nodeinfo),
662                             IPPROTO_DONE);
663 #endif
664                         n = m_copy(m, 0, M_COPYALL);
665                         if (n)
666                                 n = ni6_input(n, off);
667                         /* XXX meaningless if n == NULL */
668                         noff = sizeof(struct ip6_hdr);
669                 } else {
670                         u_char *p;
671                         int maxlen, maxhlen;
672 
673                         /*
674                          * XXX: this combination of flags is pointless,
675                          * but should we keep this for compatibility?
676                          */
677                         if ((V_icmp6_nodeinfo & 5) != 5)
678                                 break;
679 
680                         if (code != 0)
681                                 goto badcode;
682                         maxlen = sizeof(*nip6) + sizeof(*nicmp6) + 4;
683                         if (maxlen >= MCLBYTES) {
684                                 /* Give up remote */
685                                 break;
686                         }
687                         MGETHDR(n, M_DONTWAIT, m->m_type);
688                         if (n && maxlen > MHLEN) {
689                                 MCLGET(n, M_DONTWAIT);
690                                 if ((n->m_flags & M_EXT) == 0) {
691                                         m_free(n);
692                                         n = NULL;
693                                 }
694                         }
695                         if (n && !m_dup_pkthdr(n, m, M_DONTWAIT)) {
696                                 /*
697                                  * Previous code did a blind M_COPY_PKTHDR
698                                  * and said "just for rcvif".  If true, then
699                                  * we could tolerate the dup failing (due to
700                                  * the deep copy of the tag chain).  For now
701                                  * be conservative and just fail.
702                                  */
703                                 m_free(n);
704                                 n = NULL;
705                         }
706                         if (n == NULL) {
707                                 /* Give up remote */
708                                 break;
709                         }
710                         n->m_pkthdr.rcvif = NULL;
711                         n->m_len = 0;
712                         maxhlen = M_TRAILINGSPACE(n) - maxlen;
713                         mtx_lock(&hostname_mtx);
714                         if (maxhlen > hostnamelen)
715                                 maxhlen = hostnamelen;
716                         /*
717                          * Copy IPv6 and ICMPv6 only.
718                          */
719                         nip6 = mtod(n, struct ip6_hdr *);
720                         bcopy(ip6, nip6, sizeof(struct ip6_hdr));
721                         nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
722                         bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
723                         p = (u_char *)(nicmp6 + 1);
724                         bzero(p, 4);
725                         bcopy(V_hostname, p + 4, maxhlen); /* meaningless TTL */
726                         mtx_unlock(&hostname_mtx);
727                         noff = sizeof(struct ip6_hdr);
728                         n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
729                                 sizeof(struct icmp6_hdr) + 4 + maxhlen;
730                         nicmp6->icmp6_type = ICMP6_WRUREPLY;
731                         nicmp6->icmp6_code = 0;
732                 }
733 #undef hostnamelen
734                 if (n) {
735                         V_icmp6stat.icp6s_reflect++;
736                         V_icmp6stat.icp6s_outhist[ICMP6_WRUREPLY]++;
737                         icmp6_reflect(n, noff);
738                 }
739                 break;
740             }
741 
742         case ICMP6_WRUREPLY:
743                 if (code != 0)
744                         goto badcode;
745                 break;
746 
747         case ND_ROUTER_SOLICIT:
748                 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routersolicit);
749                 if (code != 0)
750                         goto badcode;
751                 if (icmp6len < sizeof(struct nd_router_solicit))
752                         goto badlen;
753                 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
754                         /* give up local */
755                         nd6_rs_input(m, off, icmp6len);
756                         m = NULL;
757                         goto freeit;
758                 }
759                 nd6_rs_input(n, off, icmp6len);
760                 /* m stays. */
761                 break;
762 
763         case ND_ROUTER_ADVERT:
764                 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routeradvert);
765                 if (code != 0)
766                         goto badcode;
767                 if (icmp6len < sizeof(struct nd_router_advert))
768                         goto badlen;
769                 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
770                         /* give up local */
771                         nd6_ra_input(m, off, icmp6len);
772                         m = NULL;
773                         goto freeit;
774                 }
775                 nd6_ra_input(n, off, icmp6len);
776                 /* m stays. */
777                 break;
778 
779         case ND_NEIGHBOR_SOLICIT:
780                 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighborsolicit);
781                 if (code != 0)
782                         goto badcode;
783                 if (icmp6len < sizeof(struct nd_neighbor_solicit))
784                         goto badlen;
785                 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
786                         /* give up local */
787                         nd6_ns_input(m, off, icmp6len);
788                         m = NULL;
789                         goto freeit;
790                 }
791                 nd6_ns_input(n, off, icmp6len);
792                 /* m stays. */
793                 break;
794 
795         case ND_NEIGHBOR_ADVERT:
796                 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighboradvert);
797                 if (code != 0)
798                         goto badcode;
799                 if (icmp6len < sizeof(struct nd_neighbor_advert))
800                         goto badlen;
801                 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
802                         /* give up local */
803                         nd6_na_input(m, off, icmp6len);
804                         m = NULL;
805                         goto freeit;
806                 }
807                 nd6_na_input(n, off, icmp6len);
808                 /* m stays. */
809                 break;
810 
811         case ND_REDIRECT:
812                 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_redirect);
813                 if (code != 0)
814                         goto badcode;
815                 if (icmp6len < sizeof(struct nd_redirect))
816                         goto badlen;
817                 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
818                         /* give up local */
819                         icmp6_redirect_input(m, off);
820                         m = NULL;
821                         goto freeit;
822                 }
823                 icmp6_redirect_input(n, off);
824                 /* m stays. */
825                 break;
826 
827         case ICMP6_ROUTER_RENUMBERING:
828                 if (code != ICMP6_ROUTER_RENUMBERING_COMMAND &&
829                     code != ICMP6_ROUTER_RENUMBERING_RESULT)
830                         goto badcode;
831                 if (icmp6len < sizeof(struct icmp6_router_renum))
832                         goto badlen;
833                 break;
834 
835         default:
836                 nd6log((LOG_DEBUG,
837                     "icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n",
838                     icmp6->icmp6_type, ip6_sprintf(ip6bufs, &ip6->ip6_src),
839                     ip6_sprintf(ip6bufd, &ip6->ip6_dst),
840                     m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0));
841                 if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) {
842                         /* ICMPv6 error: MUST deliver it by spec... */
843                         code = PRC_NCMDS;
844                         /* deliver */
845                 } else {
846                         /* ICMPv6 informational: MUST not deliver */
847                         break;
848                 }
849         deliver:
850                 if (icmp6_notify_error(&m, off, icmp6len, code)) {
851                         /* In this case, m should've been freed. */
852                         return (IPPROTO_DONE);
853                 }
854                 break;
855 
856         badcode:
857                 V_icmp6stat.icp6s_badcode++;
858                 break;
859 
860         badlen:
861                 V_icmp6stat.icp6s_badlen++;
862                 break;
863         }
864 
865         /* deliver the packet to appropriate sockets */
866         icmp6_rip6_input(&m, *offp);
867 
868         return IPPROTO_DONE;
869 
870  freeit:
871         m_freem(m);
872         return IPPROTO_DONE;
873 }
874 
875 static int
876 icmp6_notify_error(struct mbuf **mp, int off, int icmp6len, int code)
877 {
878         INIT_VNET_INET6(curvnet);
879         struct mbuf *m = *mp;
880         struct icmp6_hdr *icmp6;
881         struct ip6_hdr *eip6;
882         u_int32_t notifymtu;
883         struct sockaddr_in6 icmp6src, icmp6dst;
884 
885         if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
886                 V_icmp6stat.icp6s_tooshort++;
887                 goto freeit;
888         }
889 #ifndef PULLDOWN_TEST
890         IP6_EXTHDR_CHECK(m, off,
891             sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr), -1);
892         icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
893 #else
894         IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
895             sizeof(*icmp6) + sizeof(struct ip6_hdr));
896         if (icmp6 == NULL) {
897                 V_icmp6stat.icp6s_tooshort++;
898                 return (-1);
899         }
900 #endif
901         eip6 = (struct ip6_hdr *)(icmp6 + 1);
902 
903         /* Detect the upper level protocol */
904         {
905                 void (*ctlfunc)(int, struct sockaddr *, void *);
906                 u_int8_t nxt = eip6->ip6_nxt;
907                 int eoff = off + sizeof(struct icmp6_hdr) +
908                     sizeof(struct ip6_hdr);
909                 struct ip6ctlparam ip6cp;
910                 struct in6_addr *finaldst = NULL;
911                 int icmp6type = icmp6->icmp6_type;
912                 struct ip6_frag *fh;
913                 struct ip6_rthdr *rth;
914                 struct ip6_rthdr0 *rth0;
915                 int rthlen;
916 
917                 while (1) { /* XXX: should avoid infinite loop explicitly? */
918                         struct ip6_ext *eh;
919 
920                         switch (nxt) {
921                         case IPPROTO_HOPOPTS:
922                         case IPPROTO_DSTOPTS:
923                         case IPPROTO_AH:
924 #ifndef PULLDOWN_TEST
925                                 IP6_EXTHDR_CHECK(m, 0,
926                                     eoff + sizeof(struct ip6_ext), -1);
927                                 eh = (struct ip6_ext *)(mtod(m, caddr_t) + eoff);
928 #else
929                                 IP6_EXTHDR_GET(eh, struct ip6_ext *, m,
930                                     eoff, sizeof(*eh));
931                                 if (eh == NULL) {
932                                         V_icmp6stat.icp6s_tooshort++;
933                                         return (-1);
934                                 }
935 #endif
936 
937                                 if (nxt == IPPROTO_AH)
938                                         eoff += (eh->ip6e_len + 2) << 2;
939                                 else
940                                         eoff += (eh->ip6e_len + 1) << 3;
941                                 nxt = eh->ip6e_nxt;
942                                 break;
943                         case IPPROTO_ROUTING:
944                                 /*
945                                  * When the erroneous packet contains a
946                                  * routing header, we should examine the
947                                  * header to determine the final destination.
948                                  * Otherwise, we can't properly update
949                                  * information that depends on the final
950                                  * destination (e.g. path MTU).
951                                  */
952 #ifndef PULLDOWN_TEST
953                                 IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(*rth), -1);
954                                 rth = (struct ip6_rthdr *)
955                                     (mtod(m, caddr_t) + eoff);
956 #else
957                                 IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m,
958                                     eoff, sizeof(*rth));
959                                 if (rth == NULL) {
960                                         V_icmp6stat.icp6s_tooshort++;
961                                         return (-1);
962                                 }
963 #endif
964                                 rthlen = (rth->ip6r_len + 1) << 3;
965                                 /*
966                                  * XXX: currently there is no
967                                  * officially defined type other
968                                  * than type-0.
969                                  * Note that if the segment left field
970                                  * is 0, all intermediate hops must
971                                  * have been passed.
972                                  */
973                                 if (rth->ip6r_segleft &&
974                                     rth->ip6r_type == IPV6_RTHDR_TYPE_0) {
975                                         int hops;
976 
977 #ifndef PULLDOWN_TEST
978                                         IP6_EXTHDR_CHECK(m, 0, eoff + rthlen, -1);
979                                         rth0 = (struct ip6_rthdr0 *)
980                                             (mtod(m, caddr_t) + eoff);
981 #else
982                                         IP6_EXTHDR_GET(rth0,
983                                             struct ip6_rthdr0 *, m,
984                                             eoff, rthlen);
985                                         if (rth0 == NULL) {
986                                                 V_icmp6stat.icp6s_tooshort++;
987                                                 return (-1);
988                                         }
989 #endif
990                                         /* just ignore a bogus header */
991                                         if ((rth0->ip6r0_len % 2) == 0 &&
992                                             (hops = rth0->ip6r0_len/2))
993                                                 finaldst = (struct in6_addr *)(rth0 + 1) + (hops - 1);
994                                 }
995                                 eoff += rthlen;
996                                 nxt = rth->ip6r_nxt;
997                                 break;
998                         case IPPROTO_FRAGMENT:
999 #ifndef PULLDOWN_TEST
1000                                 IP6_EXTHDR_CHECK(m, 0, eoff +
1001                                     sizeof(struct ip6_frag), -1);
1002                                 fh = (struct ip6_frag *)(mtod(m, caddr_t) +
1003                                     eoff);
1004 #else
1005                                 IP6_EXTHDR_GET(fh, struct ip6_frag *, m,
1006                                     eoff, sizeof(*fh));
1007                                 if (fh == NULL) {
1008                                         V_icmp6stat.icp6s_tooshort++;
1009                                         return (-1);
1010                                 }
1011 #endif