icmp6.c revision 1.33.2.9 1 /* $NetBSD: icmp6.c,v 1.33.2.9 2001/04/04 17:14:31 he Exp $ */
2 /* $KAME: icmp6.c,v 1.146 2000/10/01 12:37:20 itojun Exp $ */
3
4 /*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 /*
34 * Copyright (c) 1982, 1986, 1988, 1993
35 * The Regents of the University of California. All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94
66 */
67
68 #include "opt_inet.h"
69 #include "opt_ipsec.h"
70
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/malloc.h>
74 #include <sys/mbuf.h>
75 #include <sys/protosw.h>
76 #include <sys/socket.h>
77 #include <sys/socketvar.h>
78 #include <sys/time.h>
79 #include <sys/kernel.h>
80 #include <sys/syslog.h>
81 #include <sys/domain.h>
82
83 #include <net/if.h>
84 #include <net/route.h>
85 #include <net/if_dl.h>
86 #include <net/if_types.h>
87
88 #include <netinet/in.h>
89 #include <netinet/in_var.h>
90 #include <netinet/ip6.h>
91 #include <netinet6/ip6_var.h>
92 #include <netinet/icmp6.h>
93 #include <netinet6/mld6_var.h>
94 #include <netinet6/in6_pcb.h>
95 #include <netinet6/nd6.h>
96 #include <netinet6/in6_ifattach.h>
97 #include <netinet6/ip6protosw.h>
98
99 #include <netkey/key_debug.h>
100
101 #ifdef IPSEC
102 #include <netinet6/ipsec.h>
103 #include <netkey/key.h>
104 #endif
105
106 #include "faith.h"
107
108 #include <net/net_osdep.h>
109
110 extern struct domain inet6domain;
111
112 struct icmp6stat icmp6stat;
113
114 extern struct in6pcb rawin6pcb;
115 extern int icmp6errppslim;
116 static int icmp6errpps_count = 0;
117 static struct timeval icmp6errppslim_last;
118 extern int icmp6_nodeinfo;
119 static struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL;
120 extern int pmtu_expire;
121
122 static int icmp6_rip6_input __P((struct mbuf **, int));
123 static void icmp6_mtudisc_update __P((struct in6_addr *, struct icmp6_hdr *,
124 struct mbuf *));
125 static int icmp6_ratelimit __P((const struct in6_addr *, const int, const int));
126 static const char *icmp6_redirect_diag __P((struct in6_addr *,
127 struct in6_addr *, struct in6_addr *));
128 static struct mbuf *ni6_input __P((struct mbuf *, int));
129 static struct mbuf *ni6_nametodns __P((const char *, int, int));
130 static int ni6_dnsmatch __P((const char *, int, const char *, int));
131 static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *,
132 struct ifnet **));
133 static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
134 struct ifnet *, int));
135 static struct rtentry *icmp6_mtudisc_clone __P((struct sockaddr *));
136 static void icmp6_mtudisc_timeout __P((struct rtentry *, struct rttimer *));
137
138 #ifdef COMPAT_RFC1885
139 static struct route_in6 icmp6_reflect_rt;
140 #endif
141
142 void
143 icmp6_init()
144 {
145 mld6_init();
146 icmp6_mtudisc_timeout_q = rt_timer_queue_create(pmtu_expire);
147 }
148
149 /*
150 * Generate an error packet of type error in response to bad IP6 packet.
151 */
152 void
153 icmp6_error(m, type, code, param)
154 struct mbuf *m;
155 int type, code, param;
156 {
157 struct ip6_hdr *oip6, *nip6;
158 struct icmp6_hdr *icmp6;
159 u_int preplen;
160 int off;
161 int nxt;
162
163 icmp6stat.icp6s_error++;
164
165 if (m->m_flags & M_DECRYPTED) {
166 icmp6stat.icp6s_canterror++;
167 goto freeit;
168 }
169
170 #ifndef PULLDOWN_TEST
171 IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), );
172 #else
173 if (m->m_len < sizeof(struct ip6_hdr)) {
174 m = m_pullup(m, sizeof(struct ip6_hdr));
175 if (m == NULL)
176 return;
177 }
178 #endif
179 oip6 = mtod(m, struct ip6_hdr *);
180
181 /*
182 * Multicast destination check. For unrecognized option errors,
183 * this check has already done in ip6_unknown_opt(), so we can
184 * check only for other errors.
185 */
186 if ((m->m_flags & (M_BCAST|M_MCAST) ||
187 IN6_IS_ADDR_MULTICAST(&oip6->ip6_dst)) &&
188 (type != ICMP6_PACKET_TOO_BIG &&
189 (type != ICMP6_PARAM_PROB ||
190 code != ICMP6_PARAMPROB_OPTION)))
191 goto freeit;
192
193 /* Source address check. XXX: the case of anycast source? */
194 if (IN6_IS_ADDR_UNSPECIFIED(&oip6->ip6_src) ||
195 IN6_IS_ADDR_MULTICAST(&oip6->ip6_src))
196 goto freeit;
197
198 /*
199 * If we are about to send ICMPv6 against ICMPv6 error/redirect,
200 * don't do it.
201 */
202 nxt = -1;
203 off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
204 if (off >= 0 && nxt == IPPROTO_ICMPV6) {
205 struct icmp6_hdr *icp;
206
207 #ifndef PULLDOWN_TEST
208 IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct icmp6_hdr), );
209 icp = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
210 #else
211 IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off,
212 sizeof(*icp));
213 if (icp == NULL) {
214 icmp6stat.icp6s_tooshort++;
215 return;
216 }
217 #endif
218 if (icp->icmp6_type < ICMP6_ECHO_REQUEST ||
219 icp->icmp6_type == ND_REDIRECT) {
220 /*
221 * ICMPv6 error
222 * Special case: for redirect (which is
223 * informational) we must not send icmp6 error.
224 */
225 icmp6stat.icp6s_canterror++;
226 goto freeit;
227 } else {
228 /* ICMPv6 informational - send the error */
229 }
230 } else {
231 /* non-ICMPv6 - send the error */
232 }
233
234 oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */
235
236 /* Finally, do rate limitation check. */
237 if (icmp6_ratelimit(&oip6->ip6_src, type, code)) {
238 icmp6stat.icp6s_toofreq++;
239 goto freeit;
240 }
241
242 /*
243 * OK, ICMP6 can be generated.
244 */
245
246 if (m->m_pkthdr.len >= ICMPV6_PLD_MAXLEN)
247 m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len);
248
249 preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
250 M_PREPEND(m, preplen, M_DONTWAIT);
251 if (m && m->m_len < preplen)
252 m = m_pullup(m, preplen);
253 if (m == NULL) {
254 printf("ENOBUFS in icmp6_error %d\n", __LINE__);
255 return;
256 }
257
258 nip6 = mtod(m, struct ip6_hdr *);
259 nip6->ip6_src = oip6->ip6_src;
260 nip6->ip6_dst = oip6->ip6_dst;
261
262 if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_src))
263 oip6->ip6_src.s6_addr16[1] = 0;
264 if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_dst))
265 oip6->ip6_dst.s6_addr16[1] = 0;
266
267 icmp6 = (struct icmp6_hdr *)(nip6 + 1);
268 icmp6->icmp6_type = type;
269 icmp6->icmp6_code = code;
270 icmp6->icmp6_pptr = htonl((u_int32_t)param);
271
272 /*
273 * icmp6_reflect() is designed to be in the input path.
274 * icmp6_error() can be called from both input and outut path,
275 * and if we are in output path rcvif could contain bogus value.
276 * clear m->m_pkthdr.rcvif for safety, we should have enough scope
277 * information in ip header (nip6).
278 */
279 m->m_pkthdr.rcvif = NULL;
280
281 icmp6stat.icp6s_outhist[type]++;
282 icmp6_reflect(m, sizeof(struct ip6_hdr)); /*header order: IPv6 - ICMPv6*/
283
284 return;
285
286 freeit:
287 /*
288 * If we can't tell wheter or not we can generate ICMP6, free it.
289 */
290 m_freem(m);
291 }
292
293 /*
294 * Process a received ICMP6 message.
295 */
296 int
297 icmp6_input(mp, offp, proto)
298 struct mbuf **mp;
299 int *offp, proto;
300 {
301 struct mbuf *m = *mp, *n;
302 struct ip6_hdr *ip6, *nip6;
303 struct icmp6_hdr *icmp6, *nicmp6;
304 int off = *offp;
305 int icmp6len = m->m_pkthdr.len - *offp;
306 int code, sum, noff;
307 struct sockaddr_in6 icmp6src;
308
309 #ifndef PULLDOWN_TEST
310 IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), IPPROTO_DONE);
311 /* m might change if M_LOOP. So, call mtod after this */
312 #endif
313
314 /*
315 * Locate icmp6 structure in mbuf, and check
316 * that not corrupted and of at least minimum length
317 */
318
319 ip6 = mtod(m, struct ip6_hdr *);
320 if (icmp6len < sizeof(struct icmp6_hdr)) {
321 icmp6stat.icp6s_tooshort++;
322 goto freeit;
323 }
324
325 /*
326 * calculate the checksum
327 */
328 #ifndef PULLDOWN_TEST
329 icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
330 #else
331 IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
332 if (icmp6 == NULL) {
333 icmp6stat.icp6s_tooshort++;
334 return IPPROTO_DONE;
335 }
336 #endif
337 code = icmp6->icmp6_code;
338
339 if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) {
340 #ifdef ND6_DEBUG
341 log(LOG_ERR,
342 "ICMP6 checksum error(%d|%x) %s\n",
343 icmp6->icmp6_type, sum, ip6_sprintf(&ip6->ip6_src));
344 #endif
345 icmp6stat.icp6s_checksum++;
346 goto freeit;
347 }
348
349 #if defined(NFAITH) && 0 < NFAITH
350 if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
351 /*
352 * Deliver very specific ICMP6 type only.
353 * This is important to deilver TOOBIG. Otherwise PMTUD
354 * will not work.
355 */
356 switch (icmp6->icmp6_type) {
357 case ICMP6_DST_UNREACH:
358 case ICMP6_PACKET_TOO_BIG:
359 case ICMP6_TIME_EXCEEDED:
360 break;
361 default:
362 goto freeit;
363 }
364 }
365 #endif
366
367 icmp6stat.icp6s_inhist[icmp6->icmp6_type]++;
368 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_msg);
369 if (icmp6->icmp6_type < ICMP6_INFOMSG_MASK)
370 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error);
371
372 switch (icmp6->icmp6_type) {
373
374 case ICMP6_DST_UNREACH:
375 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_dstunreach);
376 switch (code) {
377 case ICMP6_DST_UNREACH_NOROUTE:
378 code = PRC_UNREACH_NET;
379 break;
380 case ICMP6_DST_UNREACH_ADMIN:
381 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_adminprohib);
382 code = PRC_UNREACH_PROTOCOL; /* is this a good code? */
383 break;
384 case ICMP6_DST_UNREACH_ADDR:
385 code = PRC_HOSTDEAD;
386 break;
387 #ifdef COMPAT_RFC1885
388 case ICMP6_DST_UNREACH_NOTNEIGHBOR:
389 code = PRC_UNREACH_SRCFAIL;
390 break;
391 #else
392 case ICMP6_DST_UNREACH_BEYONDSCOPE:
393 /* I mean "source address was incorrect." */
394 code = PRC_PARAMPROB;
395 break;
396 #endif
397 case ICMP6_DST_UNREACH_NOPORT:
398 code = PRC_UNREACH_PORT;
399 break;
400 default:
401 goto badcode;
402 }
403 goto deliver;
404 break;
405
406 case ICMP6_PACKET_TOO_BIG:
407 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_pkttoobig);
408 if (code != 0)
409 goto badcode;
410
411 code = PRC_MSGSIZE;
412
413 /*
414 * Updating the path MTU will be done after examining
415 * intermediate extension headers.
416 */
417 goto deliver;
418 break;
419
420 case ICMP6_TIME_EXCEEDED:
421 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_timeexceed);
422 switch (code) {
423 case ICMP6_TIME_EXCEED_TRANSIT:
424 case ICMP6_TIME_EXCEED_REASSEMBLY:
425 code += PRC_TIMXCEED_INTRANS;
426 break;
427 default:
428 goto badcode;
429 }
430 goto deliver;
431 break;
432
433 case ICMP6_PARAM_PROB:
434 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_paramprob);
435 switch (code) {
436 case ICMP6_PARAMPROB_NEXTHEADER:
437 code = PRC_UNREACH_PROTOCOL;
438 break;
439 case ICMP6_PARAMPROB_HEADER:
440 case ICMP6_PARAMPROB_OPTION:
441 code = PRC_PARAMPROB;
442 break;
443 default:
444 goto badcode;
445 }
446 goto deliver;
447 break;
448
449 case ICMP6_ECHO_REQUEST:
450 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echo);
451 if (code != 0)
452 goto badcode;
453 if ((n = m_copy(m, 0, M_COPYALL)) == NULL) {
454 /* Give up remote */
455 break;
456 }
457 if ((n->m_flags & M_EXT) != 0
458 || n->m_len < off + sizeof(struct icmp6_hdr)) {
459 struct mbuf *n0 = n;
460 const int maxlen = sizeof(*nip6) + sizeof(*nicmp6);
461
462 /*
463 * Prepare an internal mbuf. m_pullup() doesn't
464 * always copy the length we specified.
465 */
466 if (maxlen >= MCLBYTES) {
467 #ifdef DIAGNOSTIC
468 printf("MCLBYTES too small\n");
469 #endif
470 /* Give up remote */
471 m_freem(n0);
472 break;
473 }
474 MGETHDR(n, M_DONTWAIT, n0->m_type);
475 if (n && maxlen >= MHLEN) {
476 MCLGET(n, M_DONTWAIT);
477 if ((n->m_flags & M_EXT) == 0) {
478 m_free(n);
479 n = NULL;
480 }
481 }
482 if (n == NULL) {
483 /* Give up remote */
484 m_freem(n0);
485 break;
486 }
487 M_COPY_PKTHDR(n, n0);
488 /*
489 * Copy IPv6 and ICMPv6 only.
490 */
491 nip6 = mtod(n, struct ip6_hdr *);
492 bcopy(ip6, nip6, sizeof(struct ip6_hdr));
493 nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
494 bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
495 noff = sizeof(struct ip6_hdr);
496 n->m_pkthdr.len = n->m_len =
497 noff + sizeof(struct icmp6_hdr);
498 /*
499 * Adjust mbuf. ip6_plen will be adjusted in
500 * ip6_output().
501 */
502 m_adj(n0, off + sizeof(struct icmp6_hdr));
503 n->m_pkthdr.len += n0->m_pkthdr.len;
504 n->m_next = n0;
505 n0->m_flags &= ~M_PKTHDR;
506 } else {
507 nip6 = mtod(n, struct ip6_hdr *);
508 nicmp6 = (struct icmp6_hdr *)((caddr_t)nip6 + off);
509 noff = off;
510 }
511 nicmp6->icmp6_type = ICMP6_ECHO_REPLY;
512 nicmp6->icmp6_code = 0;
513 if (n) {
514 icmp6stat.icp6s_reflect++;
515 icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]++;
516 icmp6_reflect(n, noff);
517 }
518 break;
519
520 case ICMP6_ECHO_REPLY:
521 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echoreply);
522 if (code != 0)
523 goto badcode;
524 break;
525
526 case MLD6_LISTENER_QUERY:
527 case MLD6_LISTENER_REPORT:
528 if (icmp6len < sizeof(struct mld6_hdr))
529 goto badlen;
530 if (icmp6->icmp6_type == MLD6_LISTENER_QUERY) /* XXX: ugly... */
531 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldquery);
532 else
533 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldreport);
534 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
535 /* give up local */
536 mld6_input(m, off);
537 m = NULL;
538 goto freeit;
539 }
540 mld6_input(n, off);
541 /* m stays. */
542 break;
543
544 case MLD6_LISTENER_DONE:
545 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mlddone);
546 if (icmp6len < sizeof(struct mld6_hdr)) /* necessary? */
547 goto badlen;
548 break; /* nothing to be done in kernel */
549
550 case MLD6_MTRACE_RESP:
551 case MLD6_MTRACE:
552 /* XXX: these two are experimental. not officially defind. */
553 /* XXX: per-interface statistics? */
554 break; /* just pass it to applications */
555
556 case ICMP6_WRUREQUEST: /* ICMP6_FQDN_QUERY */
557 {
558 enum { WRU, FQDN } mode;
559
560 if (!icmp6_nodeinfo)
561 break;
562
563 if (icmp6len == sizeof(struct icmp6_hdr) + 4)
564 mode = WRU;
565 else if (icmp6len >= sizeof(struct icmp6_nodeinfo))
566 mode = FQDN;
567 else
568 goto badlen;
569
570 if (mode == FQDN) {
571 #ifndef PULLDOWN_TEST
572 IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_nodeinfo),
573 IPPROTO_DONE);
574 #endif
575 n = m_copy(m, 0, M_COPYALL);
576 if (n)
577 n = ni6_input(n, off);
578 /* XXX meaningless if n == NULL */
579 noff = sizeof(struct ip6_hdr);
580 } else {
581 u_char *p;
582 int maxlen, maxhlen;
583
584 if (code != 0)
585 goto badcode;
586 maxlen = sizeof(*nip6) + sizeof(*nicmp6) + 4;
587 if (maxlen >= MCLBYTES) {
588 #ifdef DIAGNOSTIC
589 printf("MCLBYTES too small\n");
590 #endif
591 /* Give up remote */
592 break;
593 }
594 MGETHDR(n, M_DONTWAIT, m->m_type);
595 if (n && maxlen > MHLEN) {
596 MCLGET(n, M_DONTWAIT);
597 if ((n->m_flags & M_EXT) == 0) {
598 m_free(n);
599 n = NULL;
600 }
601 }
602 if (n == NULL) {
603 /* Give up remote */
604 break;
605 }
606 n->m_len = 0;
607 maxhlen = M_TRAILINGSPACE(n) - maxlen;
608 if (maxhlen > hostnamelen)
609 maxhlen = hostnamelen;
610 /*
611 * Copy IPv6 and ICMPv6 only.
612 */
613 nip6 = mtod(n, struct ip6_hdr *);
614 bcopy(ip6, nip6, sizeof(struct ip6_hdr));
615 nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
616 bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
617 p = (u_char *)(nicmp6 + 1);
618 bzero(p, 4);
619 bcopy(hostname, p + 4, maxhlen); /*meaningless TTL*/
620 noff = sizeof(struct ip6_hdr);
621 M_COPY_PKTHDR(n, m); /* just for recvif */
622 n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
623 sizeof(struct icmp6_hdr) + 4 + maxhlen;
624 nicmp6->icmp6_type = ICMP6_WRUREPLY;
625 nicmp6->icmp6_code = 0;
626 }
627 #undef hostnamelen
628 if (n) {
629 icmp6stat.icp6s_reflect++;
630 icmp6stat.icp6s_outhist[ICMP6_WRUREPLY]++;
631 icmp6_reflect(n, noff);
632 }
633 break;
634 }
635
636 case ICMP6_WRUREPLY:
637 if (code != 0)
638 goto badcode;
639 break;
640
641 case ND_ROUTER_SOLICIT:
642 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routersolicit);
643 if (code != 0)
644 goto badcode;
645 if (icmp6len < sizeof(struct nd_router_solicit))
646 goto badlen;
647 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
648 /* give up local */
649 nd6_rs_input(m, off, icmp6len);
650 m = NULL;
651 goto freeit;
652 }
653 nd6_rs_input(n, off, icmp6len);
654 /* m stays. */
655 break;
656
657 case ND_ROUTER_ADVERT:
658 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routeradvert);
659 if (code != 0)
660 goto badcode;
661 if (icmp6len < sizeof(struct nd_router_advert))
662 goto badlen;
663 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
664 /* give up local */
665 nd6_ra_input(m, off, icmp6len);
666 m = NULL;
667 goto freeit;
668 }
669 nd6_ra_input(n, off, icmp6len);
670 /* m stays. */
671 break;
672
673 case ND_NEIGHBOR_SOLICIT:
674 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighborsolicit);
675 if (code != 0)
676 goto badcode;
677 if (icmp6len < sizeof(struct nd_neighbor_solicit))
678 goto badlen;
679 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
680 /* give up local */
681 nd6_ns_input(m, off, icmp6len);
682 m = NULL;
683 goto freeit;
684 }
685 nd6_ns_input(n, off, icmp6len);
686 /* m stays. */
687 break;
688
689 case ND_NEIGHBOR_ADVERT:
690 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighboradvert);
691 if (code != 0)
692 goto badcode;
693 if (icmp6len < sizeof(struct nd_neighbor_advert))
694 goto badlen;
695 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
696 /* give up local */
697 nd6_na_input(m, off, icmp6len);
698 m = NULL;
699 goto freeit;
700 }
701 nd6_na_input(n, off, icmp6len);
702 /* m stays. */
703 break;
704
705 case ND_REDIRECT:
706 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_redirect);
707 if (code != 0)
708 goto badcode;
709 if (icmp6len < sizeof(struct nd_redirect))
710 goto badlen;
711 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
712 /* give up local */
713 icmp6_redirect_input(m, off);
714 m = NULL;
715 goto freeit;
716 }
717 icmp6_redirect_input(n, off);
718 /* m stays. */
719 break;
720
721 case ICMP6_ROUTER_RENUMBERING:
722 if (code != ICMP6_ROUTER_RENUMBERING_COMMAND &&
723 code != ICMP6_ROUTER_RENUMBERING_RESULT)
724 goto badcode;
725 if (icmp6len < sizeof(struct icmp6_router_renum))
726 goto badlen;
727 break;
728
729 default:
730 printf("icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n",
731 icmp6->icmp6_type, ip6_sprintf(&ip6->ip6_src),
732 ip6_sprintf(&ip6->ip6_dst),
733 m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0);
734 if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) {
735 /* ICMPv6 error: MUST deliver it by spec... */
736 code = PRC_NCMDS;
737 /* deliver */
738 } else {
739 /* ICMPv6 informational: MUST not deliver */
740 break;
741 }
742 deliver:
743 if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
744 icmp6stat.icp6s_tooshort++;
745 goto freeit;
746 }
747 #ifndef PULLDOWN_TEST
748 IP6_EXTHDR_CHECK(m, off,
749 sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr),
750 IPPROTO_DONE);
751 icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
752 #else
753 IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
754 sizeof(*icmp6) + sizeof(struct ip6_hdr));
755 if (icmp6 == NULL) {
756 icmp6stat.icp6s_tooshort++;
757 return IPPROTO_DONE;
758 }
759 #endif
760 bzero(&icmp6src, sizeof(icmp6src));
761 icmp6src.sin6_len = sizeof(struct sockaddr_in6);
762 icmp6src.sin6_family = AF_INET6;
763 icmp6src.sin6_addr = ((struct ip6_hdr *)(icmp6 + 1))->ip6_dst;
764
765 /* Detect the upper level protocol */
766 {
767 void (*ctlfunc) __P((int, struct sockaddr *, void *));
768 struct ip6_hdr *eip6 = (struct ip6_hdr *)(icmp6 + 1);
769 u_int8_t nxt = eip6->ip6_nxt;
770 int eoff = off + sizeof(struct icmp6_hdr) +
771 sizeof(struct ip6_hdr);
772 struct ip6ctlparam ip6cp;
773 struct in6_addr *finaldst = NULL;
774 int icmp6type = icmp6->icmp6_type;
775 struct ip6_frag *fh;
776 struct ip6_rthdr *rth;
777 struct ip6_rthdr0 *rth0;
778 int rthlen;
779
780 while (1) { /* XXX: should avoid inf. loop explicitly? */
781 struct ip6_ext *eh;
782
783 switch(nxt) {
784 case IPPROTO_HOPOPTS:
785 case IPPROTO_DSTOPTS:
786 case IPPROTO_AH:
787 #ifndef PULLDOWN_TEST
788 IP6_EXTHDR_CHECK(m, 0, eoff +
789 sizeof(struct ip6_ext),
790 IPPROTO_DONE);
791 eh = (struct ip6_ext *)(mtod(m, caddr_t)
792 + eoff);
793 #else
794 IP6_EXTHDR_GET(eh, struct ip6_ext *, m,
795 eoff, sizeof(*eh));
796 if (eh == NULL) {
797 icmp6stat.icp6s_tooshort++;
798 return IPPROTO_DONE;
799 }
800 #endif
801
802 if (nxt == IPPROTO_AH)
803 eoff += (eh->ip6e_len + 2) << 2;
804 else
805 eoff += (eh->ip6e_len + 1) << 3;
806 nxt = eh->ip6e_nxt;
807 break;
808 case IPPROTO_ROUTING:
809 /*
810 * When the erroneous packet contains a
811 * routing header, we should examine the
812 * header to determine the final destination.
813 * Otherwise, we can't properly update
814 * information that depends on the final
815 * destination (e.g. path MTU).
816 */
817 #ifndef PULLDOWN_TEST
818 IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(*rth),
819 IPPROTO_DONE);
820 rth = (struct ip6_rthdr *)(mtod(m, caddr_t)
821 + eoff);
822 #else
823 IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m,
824 eoff, sizeof(*rth));
825 if (rth == NULL) {
826 icmp6stat.icp6s_tooshort++;
827 return IPPROTO_DONE;
828 }
829 #endif
830 rthlen = (rth->ip6r_len + 1) << 3;
831 /*
832 * XXX: currently there is no
833 * officially defined type other
834 * than type-0.
835 * Note that if the segment left field
836 * is 0, all intermediate hops must
837 * have been passed.
838 */
839 if (rth->ip6r_segleft &&
840 rth->ip6r_type == IPV6_RTHDR_TYPE_0) {
841 int hops;
842
843 #ifndef PULLDOWN_TEST
844 IP6_EXTHDR_CHECK(m, 0, eoff + rthlen,
845 IPPROTO_DONE);
846 rth0 = (struct ip6_rthdr0 *)(mtod(m, caddr_t) + eoff);
847 #else
848 IP6_EXTHDR_GET(rth0,
849 struct ip6_rthdr0 *, m,
850 eoff, rthlen);
851 if (rth0 == NULL) {
852 icmp6stat.icp6s_tooshort++;
853 return IPPROTO_DONE;
854 }
855 #endif
856 /* just ignore a bogus header */
857 if ((rth0->ip6r0_len % 2) == 0 &&
858 (hops = rth0->ip6r0_len/2))
859 finaldst = (struct in6_addr *)(rth0 + 1) + (hops - 1);
860 }
861 eoff += rthlen;
862 nxt = rth->ip6r_nxt;
863 break;
864 case IPPROTO_FRAGMENT:
865 #ifndef PULLDOWN_TEST
866 IP6_EXTHDR_CHECK(m, 0, eoff +
867 sizeof(struct ip6_frag),
868 IPPROTO_DONE);
869 fh = (struct ip6_frag *)(mtod(m, caddr_t)
870 + eoff);
871 #else
872 IP6_EXTHDR_GET(fh, struct ip6_frag *, m,
873 eoff, sizeof(*fh));
874 if (fh == NULL) {
875 icmp6stat.icp6s_tooshort++;
876 return IPPROTO_DONE;
877 }
878 #endif
879 /*
880 * Data after a fragment header is meaningless
881 * unless it is the first fragment, but
882 * we'll go to the notify label for path MTU
883 * discovery.
884 */
885 if (fh->ip6f_offlg & IP6F_OFF_MASK)
886 goto notify;
887
888 eoff += sizeof(struct ip6_frag);
889 nxt = fh->ip6f_nxt;
890 break;
891 default:
892 /*
893 * This case includes ESP and the No Next
894 * Header. In such cases going to the notify
895 * label does not have any meaning
896 * (i.e. ctlfunc will be NULL), but we go
897 * anyway since we might have to update
898 * path MTU information.
899 */
900 goto notify;
901 }
902 }
903 notify:
904 #ifndef PULLDOWN_TEST
905 icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
906 #else
907 IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
908 sizeof(*icmp6) + sizeof(struct ip6_hdr));
909 if (icmp6 == NULL) {
910 icmp6stat.icp6s_tooshort++;
911 return IPPROTO_DONE;
912 }
913 #endif
914 if (icmp6type == ICMP6_PACKET_TOO_BIG) {
915 if (finaldst == NULL)
916 finaldst = &((struct ip6_hdr *)(icmp6 + 1))->ip6_dst;
917 icmp6_mtudisc_update(finaldst, icmp6, m);
918 }
919
920 ctlfunc = (void (*) __P((int, struct sockaddr *, void *)))
921 (inet6sw[ip6_protox[nxt]].pr_ctlinput);
922 if (ctlfunc) {
923 ip6cp.ip6c_m = m;
924 ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1);
925 ip6cp.ip6c_off = eoff;
926 (*ctlfunc)(code, (struct sockaddr *)&icmp6src, &ip6cp);
927 }
928 }
929 break;
930
931 badcode:
932 icmp6stat.icp6s_badcode++;
933 break;
934
935 badlen:
936 icmp6stat.icp6s_badlen++;
937 break;
938 }
939
940 icmp6_rip6_input(&m, *offp);
941 return IPPROTO_DONE;
942
943 freeit:
944 m_freem(m);
945 return IPPROTO_DONE;
946 }
947
948 static void
949 icmp6_mtudisc_update(dst, icmp6, m)
950 struct in6_addr *dst;
951 struct icmp6_hdr *icmp6;/* we can assume the validity of the pointer */
952 struct mbuf *m; /* currently unused but added for scoped addrs */
953 {
954 u_int mtu = ntohl(icmp6->icmp6_mtu);
955 struct rtentry *rt = NULL;
956 struct sockaddr_in6 sin6;
957
958 bzero(&sin6, sizeof(sin6));
959 sin6.sin6_family = PF_INET6;
960 sin6.sin6_len = sizeof(struct sockaddr_in6);
961 sin6.sin6_addr = *dst;
962 /* sin6.sin6_scope_id = XXX: should be set if DST is a scoped addr */
963 rt = rtalloc1((struct sockaddr *)&sin6, 1); /*clone*/
964 if (!rt || (rt->rt_flags & RTF_HOST) == 0) {
965 if (rt)
966 RTFREE(rt);
967 rt = icmp6_mtudisc_clone((struct sockaddr *)&sin6);
968 }
969
970 if (rt && (rt->rt_flags & RTF_HOST)
971 && !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
972 if (mtu < IPV6_MMTU) {
973 /* xxx */
974 rt->rt_rmx.rmx_locks |= RTV_MTU;
975 } else if (mtu < rt->rt_ifp->if_mtu &&
976 rt->rt_rmx.rmx_mtu > mtu) {
977 rt->rt_rmx.rmx_mtu = mtu;
978 }
979 }
980 if (rt)
981 RTFREE(rt);
982 }
983
984 /*
985 * Process a Node Information Query packet, based on
986 * draft-ietf-ipngwg-icmp-name-lookups-06.
987 *
988 * Spec incompatibilities:
989 * - IPv6 Subject address handling
990 * - IPv4 Subject address handling support missing
991 * - Proxy reply (answer even if it's not for me)
992 * - joins NI group address at in6_ifattach() time only, does not cope
993 * with hostname changes by sethostname(3)
994 */
995 #ifndef offsetof /* XXX */
996 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
997 #endif
998 static struct mbuf *
999 ni6_input(m, off)
1000 struct mbuf *m;
1001 int off;
1002 {
1003 struct icmp6_nodeinfo *ni6, *nni6;
1004 struct mbuf *n = NULL;
1005 u_int16_t qtype;
1006 int subjlen;
1007 int replylen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo);
1008 struct ni_reply_fqdn *fqdn;
1009 int addrs; /* for NI_QTYPE_NODEADDR */
1010 struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */
1011 struct sockaddr_in6 sin6;
1012 struct ip6_hdr *ip6;
1013 int oldfqdn = 0; /* if 1, return pascal string (03 draft) */
1014 char *subj;
1015
1016 ip6 = mtod(m, struct ip6_hdr *);
1017 #ifndef PULLDOWN_TEST
1018 ni6 = (struct icmp6_nodeinfo *)(mtod(m, caddr_t) + off);
1019 #else
1020 IP6_EXTHDR_GET(ni6, struct icmp6_nodeinfo *, m, off, sizeof(*ni6));
1021 if (ni6 == NULL) {
1022 /* m is already reclaimed */
1023 return NULL;
1024 }
1025 #endif
1026
1027 /*
1028 * Validate IPv6 destination address.
1029 *
1030 * We accept packets with the following IPv6 destination address:
1031 * - Responder's unicast/anycast address, and
1032 * - link-local multicast address (including NI group address)
1033 */
1034 bzero(&sin6, sizeof(sin6));
1035 sin6.sin6_family = AF_INET6;
1036 sin6.sin6_len = sizeof(struct sockaddr_in6);
1037 bcopy(&ip6->ip6_dst, &sin6.sin6_addr, sizeof(sin6.sin6_addr));
1038 /* XXX scopeid */
1039 if (ifa_ifwithaddr((struct sockaddr *)&sin6))
1040 ; /*unicast/anycast, fine*/
1041 else if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr))
1042 ; /*violates spec slightly, see above*/
1043 else
1044 goto bad;
1045
1046 /* guess reply length */
1047 qtype = ntohs(ni6->ni_qtype);
1048 switch (qtype) {
1049 case NI_QTYPE_NOOP:
1050 break; /* no reply data */
1051 case NI_QTYPE_SUPTYPES:
1052 replylen += sizeof(u_int32_t);
1053 break;
1054 case NI_QTYPE_FQDN:
1055 /* XXX will append a mbuf */
1056 replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
1057 break;
1058 case NI_QTYPE_NODEADDR:
1059 addrs = ni6_addrs(ni6, m, &ifp);
1060 if ((replylen += addrs * sizeof(struct in6_addr)) > MCLBYTES)
1061 replylen = MCLBYTES; /* XXX: we'll truncate later */
1062 break;
1063 default:
1064 /*
1065 * XXX: We must return a reply with the ICMP6 code
1066 * `unknown Qtype' in this case. However we regard the case
1067 * as an FQDN query for backward compatibility.
1068 * Older versions set a random value to this field,
1069 * so it rarely varies in the defined qtypes.
1070 * But the mechanism is not reliable...
1071 * maybe we should obsolete older versions.
1072 */
1073 qtype = NI_QTYPE_FQDN;
1074 /* XXX will append a mbuf */
1075 replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
1076 oldfqdn++;
1077 break;
1078 }
1079
1080 /* validate query Subject field. */
1081 subjlen = m->m_pkthdr.len - off - sizeof(struct icmp6_nodeinfo);
1082 switch (qtype) {
1083 case NI_QTYPE_NOOP:
1084 case NI_QTYPE_SUPTYPES:
1085 /* 06 draft */
1086 if (ni6->ni_code == ICMP6_NI_SUBJ_FQDN && subjlen == 0)
1087 break;
1088 /*FALLTHROUGH*/
1089 case NI_QTYPE_FQDN:
1090 case NI_QTYPE_NODEADDR:
1091 switch (ni6->ni_code) {
1092 case ICMP6_NI_SUBJ_IPV6:
1093 #if ICMP6_NI_SUBJ_IPV6 != 0
1094 case 0:
1095 #endif
1096 /*
1097 * backward compatibility - try to accept 03 draft
1098 * format, where no Subject is present.
1099 */
1100 if (qtype == NI_QTYPE_FQDN && ni6->ni_code == 0 &&
1101 subjlen == 0) {
1102 oldfqdn++;
1103 break;
1104 }
1105 #if ICMP6_NI_SUBJ_IPV6 != 0
1106 if (ni6->ni_code != ICMP6_NI_SUBJ_IPV6)
1107 goto bad;
1108 #endif
1109
1110 if (subjlen != sizeof(sin6.sin6_addr))
1111 goto bad;
1112
1113 /*
1114 * Validate Subject address.
1115 *
1116 * Not sure what exactly does "address belongs to the
1117 * node" mean in the spec, is it just unicast, or what?
1118 *
1119 * At this moment we consider Subject address as
1120 * "belong to the node" if the Subject address equals
1121 * to the IPv6 destination address; validation for
1122 * IPv6 destination address should have done enough
1123 * check for us.
1124 *
1125 * We do not do proxy at this moment.
1126 */
1127 /* m_pulldown instead of copy? */
1128 m_copydata(m, off + sizeof(struct icmp6_nodeinfo),
1129 subjlen, (caddr_t)&sin6.sin6_addr);
1130 /* XXX kame scope hack */
1131 if (IN6_IS_SCOPE_LINKLOCAL(&sin6.sin6_addr)) {
1132 #ifdef FAKE_LOOPBACK_IF
1133 if ((m->m_flags & M_PKTHDR) != 0 &&
1134 m->m_pkthdr.rcvif) {
1135 sin6.sin6_addr.s6_addr16[1] =
1136 htons(m->m_pkthdr.rcvif->if_index);
1137 }
1138 #else
1139 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
1140 sin6.sin6_addr.s6_addr16[1] =
1141 ip6->ip6_dst.s6_addr16[1];
1142 }
1143 #endif
1144 }
1145 if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &sin6.sin6_addr))
1146 break;
1147 /*
1148 * XXX if we are to allow other cases, we should really
1149 * be careful about scope here.
1150 * basically, we should disallow queries toward IPv6
1151 * destination X with subject Y, if scope(X) > scope(Y).
1152 * if we allow scope(X) > scope(Y), it will result in
1153 * information leakage across scope boundary.
1154 */
1155 goto bad;
1156
1157 case ICMP6_NI_SUBJ_FQDN:
1158 /*
1159 * Validate Subject name with gethostname(3).
1160 *
1161 * The behavior may need some debate, since:
1162 * - we are not sure if the node has FQDN as
1163 * hostname (returned by gethostname(3)).
1164 * - the code does wildcard match for truncated names.
1165 * however, we are not sure if we want to perform
1166 * wildcard match, if gethostname(3) side has
1167 * truncated hostname.
1168 */
1169 n = ni6_nametodns(hostname, hostnamelen, 0);
1170 if (!n || n->m_next || n->m_len == 0)
1171 goto bad;
1172 IP6_EXTHDR_GET(subj, char *, m,
1173 off + sizeof(struct icmp6_nodeinfo), subjlen);
1174 if (subj == NULL)
1175 goto bad;
1176 if (!ni6_dnsmatch(subj, subjlen, mtod(n, const char *),
1177 n->m_len)) {
1178 goto bad;
1179 }
1180 m_freem(n);
1181 n = NULL;
1182 break;
1183
1184 case ICMP6_NI_SUBJ_IPV4: /* xxx: to be implemented? */
1185 default:
1186 goto bad;
1187 }
1188 break;
1189 }
1190
1191 /* allocate a mbuf to reply. */
1192 MGETHDR(n, M_DONTWAIT, m->m_type);
1193 if (n == NULL) {
1194 m_freem(m);
1195 return(NULL);
1196 }
1197 M_COPY_PKTHDR(n, m); /* just for recvif */
1198 if (replylen > MHLEN) {
1199 if (replylen > MCLBYTES) {
1200 /*
1201 * XXX: should we try to allocate more? But MCLBYTES is
1202 * probably much larger than IPV6_MMTU...
1203 */
1204 goto bad;
1205 }
1206 MCLGET(n, M_DONTWAIT);
1207 if ((n->m_flags & M_EXT) == 0) {
1208 goto bad;
1209 }
1210 }
1211 n->m_pkthdr.len = n->m_len = replylen;
1212
1213 /* copy mbuf header and IPv6 + Node Information base headers */
1214 bcopy(mtod(m, caddr_t), mtod(n, caddr_t), sizeof(struct ip6_hdr));
1215 nni6 = (struct icmp6_nodeinfo *)(mtod(n, struct ip6_hdr *) + 1);
1216 bcopy((caddr_t)ni6, (caddr_t)nni6, sizeof(struct icmp6_nodeinfo));
1217
1218 /* qtype dependent procedure */
1219 switch (qtype) {
1220 case NI_QTYPE_NOOP:
1221 nni6->ni_code = ICMP6_NI_SUCCESS;
1222 nni6->ni_flags = 0;
1223 break;
1224 case NI_QTYPE_SUPTYPES:
1225 nni6->ni_code = ICMP6_NI_SUCCESS;
1226 nni6->ni_flags = htons(0x0000); /* raw bitmap */
1227 /* supports NOOP, SUPTYPES, FQDN, and NODEADDR */
1228 *(u_int32_t *)(nni6 + 1) = htonl(0x0000000f);
1229 break;
1230 case NI_QTYPE_FQDN:
1231 nni6->ni_code = ICMP6_NI_SUCCESS;
1232 fqdn = (struct ni_reply_fqdn *)(mtod(n, caddr_t) +
1233 sizeof(struct ip6_hdr) +
1234 sizeof(struct icmp6_nodeinfo));
1235 nni6->ni_flags = 0; /* XXX: meaningless TTL */
1236 fqdn->ni_fqdn_ttl = 0; /* ditto. */
1237 /*
1238 * XXX do we really have FQDN in variable "hostname"?
1239 */
1240 n->m_next = ni6_nametodns(hostname, hostnamelen, oldfqdn);
1241 if (n->m_next == NULL)
1242 goto bad;
1243 /* XXX we assume that n->m_next is not a chain */
1244 if (n->m_next->m_next != NULL)
1245 goto bad;
1246 n->m_pkthdr.len += n->m_next->m_len;
1247 break;
1248 case NI_QTYPE_NODEADDR:
1249 {
1250 int lenlim, copied;
1251
1252 nni6->ni_code = ICMP6_NI_SUCCESS;
1253 if (n->m_flags & M_EXT)
1254 lenlim = MCLBYTES - sizeof(struct ip6_hdr) -
1255 sizeof(struct icmp6_nodeinfo);
1256 else
1257 lenlim = MHLEN - sizeof(struct ip6_hdr) -
1258 sizeof(struct icmp6_nodeinfo);
1259 copied = ni6_store_addrs(ni6, nni6, ifp, lenlim);
1260 /* XXX: reset mbuf length */
1261 n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
1262 sizeof(struct icmp6_nodeinfo) + copied;
1263 break;
1264 }
1265 default:
1266 break; /* XXX impossible! */
1267 }
1268
1269 nni6->ni_type = ICMP6_NI_REPLY;
1270 m_freem(m);
1271 return(n);
1272
1273 bad:
1274 m_freem(m);
1275 if (n)
1276 m_freem(n);
1277 return(NULL);
1278 }
1279 #undef hostnamelen
1280
1281 /*
1282 * make a mbuf with DNS-encoded string. no compression support.
1283 *
1284 * XXX names with less than 2 dots (like "foo" or "foo.section") will be
1285 * treated as truncated name (two \0 at the end). this is a wild guess.
1286 */
1287 static struct mbuf *
1288 ni6_nametodns(name, namelen, old)
1289 const char *name;
1290 int namelen;
1291 int old; /* return pascal string if non-zero */
1292 {
1293 struct mbuf *m;
1294 char *cp, *ep;
1295 const char *p, *q;
1296 int i, len, nterm;
1297
1298 if (old)
1299 len = namelen + 1;
1300 else
1301 len = MCLBYTES;
1302
1303 /* because MAXHOSTNAMELEN is usually 256, we use cluster mbuf */
1304 MGET(m, M_DONTWAIT, MT_DATA);
1305 if (m && len > MLEN) {
1306 MCLGET(m, M_DONTWAIT);
1307 if ((m->m_flags & M_EXT) == 0)
1308 goto fail;
1309 }
1310 if (!m)
1311 goto fail;
1312 m->m_next = NULL;
1313
1314 if (old) {
1315 m->m_len = len;
1316 *mtod(m, char *) = namelen;
1317 bcopy(name, mtod(m, char *) + 1, namelen);
1318 return m;
1319 } else {
1320 m->m_len = 0;
1321 cp = mtod(m, char *);
1322 ep = mtod(m, char *) + M_TRAILINGSPACE(m);
1323
1324 /* if not certain about my name, return empty buffer */
1325 if (namelen == 0)
1326 return m;
1327
1328 /*
1329 * guess if it looks like shortened hostname, or FQDN.
1330 * shortened hostname needs two trailing "\0".
1331 */
1332 i = 0;
1333 for (p = name; p < name + namelen; p++) {
1334 if (*p && *p == '.')
1335 i++;
1336 }
1337 if (i < 2)
1338 nterm = 2;
1339 else
1340 nterm = 1;
1341
1342 p = name;
1343 while (cp < ep && p < name + namelen) {
1344 i = 0;
1345 for (q = p; q < name + namelen && *q && *q != '.'; q++)
1346 i++;
1347 /* result does not fit into mbuf */
1348 if (cp + i + 1 >= ep)
1349 goto fail;
1350 /* DNS label length restriction, RFC1035 page 8 */
1351 if (i >= 64)
1352 goto fail;
1353 *cp++ = i;
1354 bcopy(p, cp, i);
1355 cp += i;
1356 p = q;
1357 if (p < name + namelen && *p == '.')
1358 p++;
1359 }
1360 /* termination */
1361 if (cp + nterm >= ep)
1362 goto fail;
1363 while (nterm-- > 0)
1364 *cp++ = '\0';
1365 m->m_len = cp - mtod(m, char *);
1366 return m;
1367 }
1368
1369 panic("should not reach here");
1370 /*NOTREACHED*/
1371
1372 fail:
1373 if (m)
1374 m_freem(m);
1375 return NULL;
1376 }
1377
1378 /*
1379 * check if two DNS-encoded string matches. takes care of truncated
1380 * form (with \0\0 at the end). no compression support.
1381 * XXX upper/lowercase match (see RFC2065)
1382 */
1383 static int
1384 ni6_dnsmatch(a, alen, b, blen)
1385 const char *a;
1386 int alen;
1387 const char *b;
1388 int blen;
1389 {
1390 const char *a0, *b0;
1391 int l;
1392
1393 /* simplest case - need validation? */
1394 if (alen == blen && bcmp(a, b, alen) == 0)
1395 return 1;
1396
1397 a0 = a;
1398 b0 = b;
1399
1400 /* termination is mandatory */
1401 if (alen < 2 || blen < 2)
1402 return 0;
1403 if (a0[alen - 1] != '\0' || b0[blen - 1] != '\0')
1404 return 0;
1405 alen--;
1406 blen--;
1407
1408 while (a - a0 < alen && b - b0 < blen) {
1409 if (a - a0 + 1 > alen || b - b0 + 1 > blen)
1410 return 0;
1411
1412 if ((signed char)a[0] < 0 || (signed char)b[0] < 0)
1413 return 0;
1414 /* we don't support compression yet */
1415 if (a[0] >= 64 || b[0] >= 64)
1416 return 0;
1417
1418 /* truncated case */
1419 if (a[0] == 0 && a - a0 == alen - 1)
1420 return 1;
1421 if (b[0] == 0 && b - b0 == blen - 1)
1422 return 1;
1423 if (a[0] == 0 || b[0] == 0)
1424 return 0;
1425
1426 if (a[0] != b[0])
1427 return 0;
1428 l = a[0];
1429 if (a - a0 + 1 + l > alen || b - b0 + 1 + l > blen)
1430 return 0;
1431 if (bcmp(a + 1, b + 1, l) != 0)
1432 return 0;
1433
1434 a += 1 + l;
1435 b += 1 + l;
1436 }
1437
1438 if (a - a0 == alen && b - b0 == blen)
1439 return 1;
1440 else
1441 return 0;
1442 }
1443
1444 /*
1445 * calculate the number of addresses to be returned in the node info reply.
1446 */
1447 static int
1448 ni6_addrs(ni6, m, ifpp)
1449 struct icmp6_nodeinfo *ni6;
1450 struct mbuf *m;
1451 struct ifnet **ifpp;
1452 {
1453 register struct ifnet *ifp;
1454 register struct in6_ifaddr *ifa6;
1455 register struct ifaddr *ifa;
1456 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1457 int addrs = 0, addrsofif, iffound = 0;
1458
1459 for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
1460 {
1461 addrsofif = 0;
1462 for (ifa = ifp->if_addrlist.tqh_first; ifa;
1463 ifa = ifa->ifa_list.tqe_next)
1464 {
1465 if (ifa->ifa_addr->sa_family != AF_INET6)
1466 continue;
1467 ifa6 = (struct in6_ifaddr *)ifa;
1468
1469 if (!(ni6->ni_flags & NI_NODEADDR_FLAG_ALL) &&
1470 IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
1471 &ifa6->ia_addr.sin6_addr))
1472 iffound = 1;
1473
1474 /*
1475 * IPv4-mapped addresses can only be returned by a
1476 * Node Information proxy, since they represent
1477 * addresses of IPv4-only nodes, which perforce do
1478 * not implement this protocol.
1479 * [icmp-name-lookups-05]
1480 * So we don't support NI_NODEADDR_FLAG_COMPAT in
1481 * this function at this moment.
1482 */
1483
1484 if (ifa6->ia6_flags & IN6_IFF_ANYCAST)
1485 continue; /* we need only unicast addresses */
1486
1487 if ((ni6->ni_flags & (NI_NODEADDR_FLAG_LINKLOCAL |
1488 NI_NODEADDR_FLAG_SITELOCAL |
1489 NI_NODEADDR_FLAG_GLOBAL)) == 0)
1490 continue;
1491
1492 /* What do we have to do about ::1? */
1493 switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
1494 case IPV6_ADDR_SCOPE_LINKLOCAL:
1495 if (ni6->ni_flags & NI_NODEADDR_FLAG_LINKLOCAL)
1496 addrsofif++;
1497 break;
1498 case IPV6_ADDR_SCOPE_SITELOCAL:
1499 if (ni6->ni_flags & NI_NODEADDR_FLAG_SITELOCAL)
1500 addrsofif++;
1501 break;
1502 case IPV6_ADDR_SCOPE_GLOBAL:
1503 if (ni6->ni_flags & NI_NODEADDR_FLAG_GLOBAL)
1504 addrsofif++;
1505 break;
1506 default:
1507 continue;
1508 }
1509 }
1510 if (iffound) {
1511 *ifpp = ifp;
1512 return(addrsofif);
1513 }
1514
1515 addrs += addrsofif;
1516 }
1517
1518 return(addrs);
1519 }
1520
1521 static int
1522 ni6_store_addrs(ni6, nni6, ifp0, resid)
1523 struct icmp6_nodeinfo *ni6, *nni6;
1524 struct ifnet *ifp0;
1525 int resid;
1526 {
1527 register struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet);
1528 register struct in6_ifaddr *ifa6;
1529 register struct ifaddr *ifa;
1530 int docopy, copied = 0;
1531 u_char *cp = (u_char *)(nni6 + 1);
1532
1533 if (ifp0 == NULL && !(ni6->ni_flags & NI_NODEADDR_FLAG_ALL))
1534 return(0); /* needless to copy */
1535
1536 for (; ifp; ifp = TAILQ_NEXT(ifp, if_list))
1537 {
1538 for (ifa = ifp->if_addrlist.tqh_first; ifa;
1539 ifa = ifa->ifa_list.tqe_next)
1540 {
1541 docopy = 0;
1542
1543 if (ifa->ifa_addr->sa_family != AF_INET6)
1544 continue;
1545 ifa6 = (struct in6_ifaddr *)ifa;
1546
1547 if (ifa6->ia6_flags & IN6_IFF_ANYCAST) {
1548 /* just experimental. not in the spec. */
1549 if (ni6->ni_flags & NI_NODEADDR_FLAG_ANYCAST)
1550 docopy = 1;
1551 else
1552 continue;
1553 }
1554 else { /* unicast address */
1555 if (ni6->ni_flags & NI_NODEADDR_FLAG_ANYCAST)
1556 continue;
1557 else
1558 docopy = 1;
1559 }
1560
1561 /* What do we have to do about ::1? */
1562 switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
1563 case IPV6_ADDR_SCOPE_LINKLOCAL:
1564 if (ni6->ni_flags & NI_NODEADDR_FLAG_LINKLOCAL)
1565 docopy = 1;
1566 break;
1567 case IPV6_ADDR_SCOPE_SITELOCAL:
1568 if (ni6->ni_flags & NI_NODEADDR_FLAG_SITELOCAL)
1569 docopy = 1;
1570 break;
1571 case IPV6_ADDR_SCOPE_GLOBAL:
1572 if (ni6->ni_flags & NI_NODEADDR_FLAG_GLOBAL)
1573 docopy = 1;
1574 break;
1575 default:
1576 continue;
1577 }
1578
1579 if (docopy) {
1580 if (resid < sizeof(struct in6_addr)) {
1581 /*
1582 * We give up much more copy.
1583 * Set the truncate flag and return.
1584 */
1585 nni6->ni_flags |=
1586 NI_NODEADDR_FLAG_TRUNCATE;
1587 return(copied);
1588 }
1589 bcopy(&ifa6->ia_addr.sin6_addr, cp,
1590 sizeof(struct in6_addr));
1591 /* XXX: KAME link-local hack; remove ifindex */
1592 if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr))
1593 ((struct in6_addr *)cp)->s6_addr16[1] = 0;
1594 cp += sizeof(struct in6_addr);
1595 resid -= sizeof(struct in6_addr);
1596 copied += sizeof(struct in6_addr);
1597 }
1598 }
1599 if (ifp0) /* we need search only on the specified IF */
1600 break;
1601 }
1602
1603 return(copied);
1604 }
1605
1606 /*
1607 * XXX almost dup'ed code with rip6_input.
1608 */
1609 static int
1610 icmp6_rip6_input(mp, off)
1611 struct mbuf **mp;
1612 int off;
1613 {
1614 struct mbuf *m = *mp;
1615 register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1616 register struct in6pcb *in6p;
1617 struct in6pcb *last = NULL;
1618 struct sockaddr_in6 rip6src;
1619 struct icmp6_hdr *icmp6;
1620 struct mbuf *opts = NULL;
1621
1622 #ifndef PULLDOWN_TEST
1623 /* this is assumed to be safe. */
1624 icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
1625 #else
1626 IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
1627 if (icmp6 == NULL) {
1628 /* m is already reclaimed */
1629 return IPPROTO_DONE;
1630 }
1631 #endif
1632
1633 bzero(&rip6src, sizeof(rip6src));
1634 rip6src.sin6_len = sizeof(struct sockaddr_in6);
1635 rip6src.sin6_family = AF_INET6;
1636 rip6src.sin6_addr = ip6->ip6_src;
1637 if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr))
1638 rip6src.sin6_addr.s6_addr16[1] = 0;
1639 if (m->m_pkthdr.rcvif) {
1640 if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr))
1641 rip6src.sin6_scope_id = m->m_pkthdr.rcvif->if_index;
1642 else
1643 rip6src.sin6_scope_id = 0;
1644 } else
1645 rip6src.sin6_scope_id = 0;
1646
1647 for (in6p = rawin6pcb.in6p_next;
1648 in6p != &rawin6pcb; in6p = in6p->in6p_next)
1649 {
1650 if (in6p->in6p_ip6_nxt != IPPROTO_ICMPV6)
1651 continue;
1652 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
1653 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
1654 continue;
1655 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
1656 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
1657 continue;
1658 if (in6p->in6p_icmp6filt
1659 && ICMP6_FILTER_WILLBLOCK(icmp6->icmp6_type,
1660 in6p->in6p_icmp6filt))
1661 continue;
1662 if (last) {
1663 struct mbuf *n;
1664 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
1665 if (last->in6p_flags & IN6P_CONTROLOPTS)
1666 ip6_savecontrol(last, &opts, ip6, n);
1667 /* strip intermediate headers */
1668 m_adj(n, off);
1669 if (sbappendaddr(&last->in6p_socket->so_rcv,
1670 (struct sockaddr *)&rip6src,
1671 n, opts) == 0) {
1672 /* should notify about lost packet */
1673 m_freem(n);
1674 if (opts)
1675 m_freem(opts);
1676 } else
1677 sorwakeup(last->in6p_socket);
1678 opts = NULL;
1679 }
1680 }
1681 last = in6p;
1682 }
1683 if (last) {
1684 if (last->in6p_flags & IN6P_CONTROLOPTS)
1685 ip6_savecontrol(last, &opts, ip6, m);
1686 /* strip intermediate headers */
1687 m_adj(m, off);
1688 if (sbappendaddr(&last->in6p_socket->so_rcv,
1689 (struct sockaddr *)&rip6src, m, opts) == 0) {
1690 m_freem(m);
1691 if (opts)
1692 m_freem(opts);
1693 } else
1694 sorwakeup(last->in6p_socket);
1695 } else {
1696 m_freem(m);
1697 ip6stat.ip6s_delivered--;
1698 }
1699 return IPPROTO_DONE;
1700 }
1701
1702 /*
1703 * Reflect the ip6 packet back to the source.
1704 * OFF points to the icmp6 header, counted from the top of the mbuf.
1705 */
1706 void
1707 icmp6_reflect(m, off)
1708 struct mbuf *m;
1709 size_t off;
1710 {
1711 struct ip6_hdr *ip6;
1712 struct icmp6_hdr *icmp6;
1713 struct in6_ifaddr *ia;
1714 struct in6_addr t, *src = 0;
1715 int plen;
1716 int type, code;
1717 struct ifnet *outif = NULL;
1718 #ifdef COMPAT_RFC1885
1719 int mtu = IPV6_MMTU;
1720 struct sockaddr_in6 *sin6 = &icmp6_reflect_rt.ro_dst;
1721 #endif
1722
1723 /* too short to reflect */
1724 if (off < sizeof(struct ip6_hdr)) {
1725 printf("sanity fail: off=%lx, sizeof(ip6)=%lx in %s:%d\n",
1726 (u_long)off, (u_long)sizeof(struct ip6_hdr),
1727 __FILE__, __LINE__);
1728 goto bad;
1729 }
1730
1731 /*
1732 * If there are extra headers between IPv6 and ICMPv6, strip
1733 * off that header first.
1734 */
1735 if (off > sizeof(struct ip6_hdr)) {
1736 size_t l;
1737 struct ip6_hdr nip6;
1738
1739 l = off - sizeof(struct ip6_hdr);
1740 m_copydata(m, 0, sizeof(nip6), (caddr_t)&nip6);
1741 m_adj(m, l);
1742 l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
1743 if (m->m_len < l) {
1744 if ((m = m_pullup(m, l)) == NULL)
1745 return;
1746 }
1747 bcopy((caddr_t)&nip6, mtod(m, caddr_t), sizeof(nip6));
1748 } else /* off == sizeof(struct ip6_hdr) */ {
1749 size_t l;
1750 l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
1751 if (m->m_len < l) {
1752 if ((m = m_pullup(m, l)) == NULL)
1753 return;
1754 }
1755 }
1756 plen = m->m_pkthdr.len - sizeof(struct ip6_hdr);
1757 ip6 = mtod(m, struct ip6_hdr *);
1758 ip6->ip6_nxt = IPPROTO_ICMPV6;
1759 icmp6 = (struct icmp6_hdr *)(ip6 + 1);
1760 type = icmp6->icmp6_type; /* keep type for statistics */
1761 code = icmp6->icmp6_code; /* ditto. */
1762
1763 t = ip6->ip6_dst;
1764 /*
1765 * ip6_input() drops a packet if its src is multicast.
1766 * So, the src is never multicast.
1767 */
1768 ip6->ip6_dst = ip6->ip6_src;
1769
1770 /* XXX hack for link-local addresses */
1771 if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst))
1772 ip6->ip6_dst.s6_addr16[1] =
1773 htons(m->m_pkthdr.rcvif->if_index);
1774 if (IN6_IS_ADDR_LINKLOCAL(&t))
1775 t.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
1776
1777 #ifdef COMPAT_RFC1885
1778 /*
1779 * xxx guess MTU
1780 * RFC 1885 requires that echo reply should be truncated if it
1781 * does not fit in with (return) path MTU, but the description was
1782 * removed in the new spec.
1783 */
1784 if (icmp6_reflect_rt.ro_rt == 0 ||
1785 ! (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &ip6->ip6_dst))) {
1786 if (icmp6_reflect_rt.ro_rt) {
1787 icmp6_reflect_rt.ro_rt = 0;
1788 }
1789 bzero(sin6, sizeof(*sin6));
1790 sin6->sin6_family = PF_INET6;
1791 sin6->sin6_len = sizeof(struct sockaddr_in6);
1792 sin6->sin6_addr = ip6->ip6_dst;
1793
1794 rtalloc((struct route *)&icmp6_reflect_rt.ro_rt);
1795 }
1796
1797 if (icmp6_reflect_rt.ro_rt == 0)
1798 goto bad;
1799
1800 if ((icmp6_reflect_rt.ro_rt->rt_flags & RTF_HOST)
1801 && mtu < icmp6_reflect_rt.ro_rt->rt_ifp->if_mtu)
1802 mtu = icmp6_reflect_rt.ro_rt->rt_rmx.rmx_mtu;
1803
1804 if (mtu < m->m_pkthdr.len) {
1805 plen -= (m->m_pkthdr.len - mtu);
1806 m_adj(m, mtu - m->m_pkthdr.len);
1807 }
1808 #endif
1809 /*
1810 * If the incoming packet was addressed directly to us(i.e. unicast),
1811 * use dst as the src for the reply.
1812 * The IN6_IFF_NOTREADY case would be VERY rare, but is possible
1813 * (for example) when we encounter an error while forwarding procedure
1814 * destined to a duplicated address of ours.
1815 */
1816 for (ia = in6_ifaddr; ia; ia = ia->ia_next)
1817 if (IN6_ARE_ADDR_EQUAL(&t, &ia->ia_addr.sin6_addr) &&
1818 (ia->ia6_flags & (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0) {
1819 src = &t;
1820 break;
1821 }
1822 if (ia == NULL && IN6_IS_ADDR_LINKLOCAL(&t) && (m->m_flags & M_LOOP)) {
1823 /*
1824 * This is the case if the dst is our link-local address
1825 * and the sender is also ourseleves.
1826 */
1827 src = &t;
1828 }
1829
1830 if (src == 0)
1831 /*
1832 * This case matches to multicasts, our anycast, or unicasts
1833 * that we do not own. Select a source address which has the
1834 * same scope.
1835 * XXX: for (non link-local) multicast addresses, this might
1836 * not be a good choice.
1837 */
1838 if ((ia = in6_ifawithscope(m->m_pkthdr.rcvif, &t)) != 0)
1839 src = &IA6_SIN6(ia)->sin6_addr;
1840
1841 if (src == 0)
1842 goto bad;
1843
1844 ip6->ip6_src = *src;
1845
1846 ip6->ip6_flow = 0;
1847 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
1848 ip6->ip6_vfc |= IPV6_VERSION;
1849 ip6->ip6_nxt = IPPROTO_ICMPV6;
1850 if (m->m_pkthdr.rcvif) {
1851 /* XXX: This may not be the outgoing interface */
1852 ip6->ip6_hlim = nd_ifinfo[m->m_pkthdr.rcvif->if_index].chlim;
1853 }
1854
1855 icmp6->icmp6_cksum = 0;
1856 icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6,
1857 sizeof(struct ip6_hdr), plen);
1858
1859 /*
1860 * xxx option handling
1861 */
1862
1863 m->m_flags &= ~(M_BCAST|M_MCAST);
1864 #ifdef IPSEC
1865 /* Don't lookup socket */
1866 ipsec_setsocket(m, NULL);
1867 #endif /*IPSEC*/
1868
1869 #ifdef COMPAT_RFC1885
1870 ip6_output(m, NULL, &icmp6_reflect_rt, 0, NULL, &outif);
1871 #else
1872 ip6_output(m, NULL, NULL, 0, NULL, &outif);
1873 #endif
1874 if (outif)
1875 icmp6_ifoutstat_inc(outif, type, code);
1876
1877 return;
1878
1879 bad:
1880 m_freem(m);
1881 return;
1882 }
1883
1884 void
1885 icmp6_fasttimo()
1886 {
1887
1888 mld6_fasttimeo();
1889 }
1890
1891 static const char *
1892 icmp6_redirect_diag(src6, dst6, tgt6)
1893 struct in6_addr *src6;
1894 struct in6_addr *dst6;
1895 struct in6_addr *tgt6;
1896 {
1897 static char buf[1024];
1898 snprintf(buf, sizeof(buf), "(src=%s dst=%s tgt=%s)",
1899 ip6_sprintf(src6), ip6_sprintf(dst6), ip6_sprintf(tgt6));
1900 return buf;
1901 }
1902
1903 void
1904 icmp6_redirect_input(m, off)
1905 register struct mbuf *m;
1906 int off;
1907 {
1908 struct ifnet *ifp = m->m_pkthdr.rcvif;
1909 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1910 struct nd_redirect *nd_rd;
1911 int icmp6len = ntohs(ip6->ip6_plen);
1912 char *lladdr = NULL;
1913 int lladdrlen = 0;
1914 u_char *redirhdr = NULL;
1915 int redirhdrlen = 0;
1916 struct rtentry *rt = NULL;
1917 int is_router;
1918 int is_onlink;
1919 struct in6_addr src6 = ip6->ip6_src;
1920 struct in6_addr redtgt6;
1921 struct in6_addr reddst6;
1922 union nd_opts ndopts;
1923
1924 if (!m || !ifp)
1925 return;
1926
1927 /* XXX if we are router, we don't update route by icmp6 redirect */
1928 if (ip6_forwarding)
1929 goto freeit;
1930 if (!icmp6_rediraccept)
1931 goto freeit;
1932
1933 #ifndef PULLDOWN_TEST
1934 IP6_EXTHDR_CHECK(m, off, icmp6len,);
1935 nd_rd = (struct nd_redirect *)((caddr_t)ip6 + off);
1936 #else
1937 IP6_EXTHDR_GET(nd_rd, struct nd_redirect *, m, off, icmp6len);
1938 if (nd_rd == NULL) {
1939 icmp6stat.icp6s_tooshort++;
1940 return;
1941 }
1942 #endif
1943 redtgt6 = nd_rd->nd_rd_target;
1944 reddst6 = nd_rd->nd_rd_dst;
1945
1946 if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
1947 redtgt6.s6_addr16[1] = htons(ifp->if_index);
1948 if (IN6_IS_ADDR_LINKLOCAL(&reddst6))
1949 reddst6.s6_addr16[1] = htons(ifp->if_index);
1950
1951 /* validation */
1952 if (!IN6_IS_ADDR_LINKLOCAL(&src6)) {
1953 log(LOG_ERR,
1954 "ICMP6 redirect sent from %s rejected; "
1955 "must be from linklocal\n", ip6_sprintf(&src6));
1956 goto freeit;
1957 }
1958 if (ip6->ip6_hlim != 255) {
1959 log(LOG_ERR,
1960 "ICMP6 redirect sent from %s rejected; "
1961 "hlim=%d (must be 255)\n",
1962 ip6_sprintf(&src6), ip6->ip6_hlim);
1963 goto freeit;
1964 }
1965 {
1966 /* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */
1967 struct sockaddr_in6 sin6;
1968 struct in6_addr *gw6;
1969
1970 bzero(&sin6, sizeof(sin6));
1971 sin6.sin6_family = AF_INET6;
1972 sin6.sin6_len = sizeof(struct sockaddr_in6);
1973 bcopy(&reddst6, &sin6.sin6_addr, sizeof(reddst6));
1974 rt = rtalloc1((struct sockaddr *)&sin6, 0);
1975 if (rt) {
1976 if (rt->rt_gateway == NULL ||
1977 rt->rt_gateway->sa_family != AF_INET6) {
1978 log(LOG_ERR,
1979 "ICMP6 redirect rejected; no route "
1980 "with inet6 gateway found for redirect dst: %s\n",
1981 icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
1982 RTFREE(rt);
1983 goto freeit;
1984 }
1985
1986 gw6 = &(((struct sockaddr_in6 *)rt->rt_gateway)->sin6_addr);
1987 if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) {
1988 log(LOG_ERR,
1989 "ICMP6 redirect rejected; "
1990 "not equal to gw-for-src=%s (must be same): "
1991 "%s\n",
1992 ip6_sprintf(gw6),
1993 icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
1994 RTFREE(rt);
1995 goto freeit;
1996 }
1997 } else {
1998 log(LOG_ERR,
1999 "ICMP6 redirect rejected; "
2000 "no route found for redirect dst: %s\n",
2001 icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
2002 goto freeit;
2003 }
2004 RTFREE(rt);
2005 rt = NULL;
2006 }
2007 if (IN6_IS_ADDR_MULTICAST(&reddst6)) {
2008 log(LOG_ERR,
2009 "ICMP6 redirect rejected; "
2010 "redirect dst must be unicast: %s\n",
2011 icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
2012 goto freeit;
2013 }
2014
2015 is_router = is_onlink = 0;
2016 if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
2017 is_router = 1; /* router case */
2018 if (bcmp(&redtgt6, &reddst6, sizeof(redtgt6)) == 0)
2019 is_onlink = 1; /* on-link destination case */
2020 if (!is_router && !is_onlink) {
2021 log(LOG_ERR,
2022 "ICMP6 redirect rejected; "
2023 "neither router case nor onlink case: %s\n",
2024 icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
2025 goto freeit;
2026 }
2027 /* validation passed */
2028
2029 icmp6len -= sizeof(*nd_rd);
2030 nd6_option_init(nd_rd + 1, icmp6len, &ndopts);
2031 if (nd6_options(&ndopts) < 0) {
2032 log(LOG_INFO, "icmp6_redirect_input: "
2033 "invalid ND option, rejected: %s\n",
2034 icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
2035 goto freeit;
2036 }
2037
2038 if (ndopts.nd_opts_tgt_lladdr) {
2039 lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
2040 lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
2041 }
2042
2043 if (ndopts.nd_opts_rh) {
2044 redirhdrlen = ndopts.nd_opts_rh->nd_opt_rh_len;
2045 redirhdr = (u_char *)(ndopts.nd_opts_rh + 1); /* xxx */
2046 }
2047
2048 if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
2049 log(LOG_INFO,
2050 "icmp6_redirect_input: lladdrlen mismatch for %s "
2051 "(if %d, icmp6 packet %d): %s\n",
2052 ip6_sprintf(&redtgt6), ifp->if_addrlen, lladdrlen - 2,
2053 icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
2054 }
2055
2056 /* RFC 2461 8.3 */
2057 nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT,
2058 is_onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER);
2059
2060 if (!is_onlink) { /* better router case. perform rtredirect. */
2061 /* perform rtredirect */
2062 struct sockaddr_in6 sdst;
2063 struct sockaddr_in6 sgw;
2064 struct sockaddr_in6 ssrc;
2065
2066 bzero(&sdst, sizeof(sdst));
2067 bzero(&sgw, sizeof(sgw));
2068 bzero(&ssrc, sizeof(ssrc));
2069 sdst.sin6_family = sgw.sin6_family = ssrc.sin6_family = AF_INET6;
2070 sdst.sin6_len = sgw.sin6_len = ssrc.sin6_len =
2071 sizeof(struct sockaddr_in6);
2072 bcopy(&redtgt6, &sgw.sin6_addr, sizeof(struct in6_addr));
2073 bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
2074 bcopy(&src6, &ssrc.sin6_addr, sizeof(struct in6_addr));
2075 rtredirect((struct sockaddr *)&sdst, (struct sockaddr *)&sgw,
2076 (struct sockaddr *)NULL, RTF_GATEWAY | RTF_HOST,
2077 (struct sockaddr *)&ssrc,
2078 (struct rtentry **)NULL
2079 );
2080 }
2081 /* finally update cached route in each socket via pfctlinput */
2082 {
2083 struct sockaddr_in6 sdst;
2084 #if 1
2085 #else
2086 struct ip6protosw *pr;
2087 #endif
2088
2089 bzero(&sdst, sizeof(sdst));
2090 sdst.sin6_family = AF_INET6;
2091 sdst.sin6_len = sizeof(struct sockaddr_in6);
2092 bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
2093 #if 1
2094 pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst);
2095 #else
2096 /*
2097 * do not use pfctlinput() here, we have different prototype for
2098 * xx_ctlinput() in ip6proto.
2099 */
2100 for (pr = (struct ip6protosw *)inet6domain.dom_protosw;
2101 pr < (struct ip6protosw *)inet6domain.dom_protoswNPROTOSW;
2102 pr++) {
2103 if (pr->pr_ctlinput) {
2104 (*pr->pr_ctlinput)(PRC_REDIRECT_HOST,
2105 (struct sockaddr *)&sdst, NULL, NULL, 0);
2106 }
2107 }
2108 #endif
2109 #ifdef IPSEC
2110 key_sa_routechange((struct sockaddr *)&sdst);
2111 #endif
2112 }
2113
2114 freeit:
2115 m_freem(m);
2116 }
2117
2118 void
2119 icmp6_redirect_output(m0, rt)
2120 struct mbuf *m0;
2121 struct rtentry *rt;
2122 {
2123 struct ifnet *ifp; /* my outgoing interface */
2124 struct in6_addr *ifp_ll6;
2125 struct in6_addr *router_ll6;
2126 struct ip6_hdr *sip6; /* m0 as struct ip6_hdr */
2127 struct mbuf *m = NULL; /* newly allocated one */
2128 struct ip6_hdr *ip6; /* m as struct ip6_hdr */
2129 struct nd_redirect *nd_rd;
2130 size_t maxlen;
2131 u_char *p;
2132 struct ifnet *outif = NULL;
2133 struct sockaddr_in6 src_sa;
2134
2135 /* if we are not router, we don't send icmp6 redirect */
2136 if (!ip6_forwarding || ip6_accept_rtadv)
2137 goto fail;
2138
2139 /* sanity check */
2140 if (!m0 || !rt || !(rt->rt_flags & RTF_UP) || !(ifp = rt->rt_ifp))
2141 goto fail;
2142
2143 /*
2144 * Address check:
2145 * the source address must identify a neighbor, and
2146 * the destination address must not be a multicast address
2147 * [RFC 2461, sec 8.2]
2148 */
2149 sip6 = mtod(m0, struct ip6_hdr *);
2150 bzero(&src_sa, sizeof(src_sa));
2151 src_sa.sin6_family = AF_INET6;
2152 src_sa.sin6_len = sizeof(src_sa);
2153 src_sa.sin6_addr = sip6->ip6_src;
2154 /* we don't currently use sin6_scope_id, but eventually use it */
2155 src_sa.sin6_scope_id = in6_addr2scopeid(ifp, &sip6->ip6_src);
2156 if (nd6_is_addr_neighbor(&src_sa, ifp) == 0)
2157 goto fail;
2158 if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst))
2159 goto fail; /* what should we do here? */
2160
2161 /* rate limit */
2162 if (icmp6_ratelimit(&sip6->ip6_src, ND_REDIRECT, 0))
2163 goto fail;
2164
2165 /*
2166 * Since we are going to append up to 1280 bytes (= IPV6_MMTU),
2167 * we almost always ask for an mbuf cluster for simplicity.
2168 * (MHLEN < IPV6_MMTU is almost always true)
2169 */
2170 #if IPV6_MMTU >= MCLBYTES
2171 # error assumption failed about IPV6_MMTU and MCLBYTES
2172 #endif
2173 MGETHDR(m, M_DONTWAIT, MT_HEADER);
2174 if (m && IPV6_MMTU >= MHLEN)
2175 MCLGET(m, M_DONTWAIT);
2176 if (!m)
2177 goto fail;
2178 maxlen = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN;
2179 maxlen = min(IPV6_MMTU, maxlen);
2180 /* just for safety */
2181 if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) +
2182 ((sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7)) {
2183 goto fail;
2184 }
2185
2186 {
2187 /* get ip6 linklocal address for ifp(my outgoing interface). */
2188 struct in6_ifaddr *ia;
2189 if ((ia = in6ifa_ifpforlinklocal(ifp,
2190 IN6_IFF_NOTREADY|
2191 IN6_IFF_ANYCAST)) == NULL)
2192 goto fail;
2193 ifp_ll6 = &ia->ia_addr.sin6_addr;
2194 }
2195
2196 /* get ip6 linklocal address for the router. */
2197 if (rt->rt_gateway && (rt->rt_flags & RTF_GATEWAY)) {
2198 struct sockaddr_in6 *sin6;
2199 sin6 = (struct sockaddr_in6 *)rt->rt_gateway;
2200 router_ll6 = &sin6->sin6_addr;
2201 if (!IN6_IS_ADDR_LINKLOCAL(router_ll6))
2202 router_ll6 = (struct in6_addr *)NULL;
2203 } else
2204 router_ll6 = (struct in6_addr *)NULL;
2205
2206 /* ip6 */
2207 ip6 = mtod(m, struct ip6_hdr *);
2208 ip6->ip6_flow = 0;
2209 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
2210 ip6->ip6_vfc |= IPV6_VERSION;
2211 /* ip6->ip6_plen will be set later */
2212 ip6->ip6_nxt = IPPROTO_ICMPV6;
2213 ip6->ip6_hlim = 255;
2214 /* ip6->ip6_src must be linklocal addr for my outgoing if. */
2215 bcopy(ifp_ll6, &ip6->ip6_src, sizeof(struct in6_addr));
2216 bcopy(&sip6->ip6_src, &ip6->ip6_dst, sizeof(struct in6_addr));
2217
2218 /* ND Redirect */
2219 nd_rd = (struct nd_redirect *)(ip6 + 1);
2220 nd_rd->nd_rd_type = ND_REDIRECT;
2221 nd_rd->nd_rd_code = 0;
2222 nd_rd->nd_rd_reserved = 0;
2223 if (rt->rt_flags & RTF_GATEWAY) {
2224 /*
2225 * nd_rd->nd_rd_target must be a link-local address in
2226 * better router cases.
2227 */
2228 if (!router_ll6)
2229 goto fail;
2230 bcopy(router_ll6, &nd_rd->nd_rd_target,
2231 sizeof(nd_rd->nd_rd_target));
2232 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
2233 sizeof(nd_rd->nd_rd_dst));
2234 } else {
2235 /* make sure redtgt == reddst */
2236 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_target,
2237 sizeof(nd_rd->nd_rd_target));
2238 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
2239 sizeof(nd_rd->nd_rd_dst));
2240 }
2241
2242 p = (u_char *)(nd_rd + 1);
2243
2244 if (!router_ll6)
2245 goto nolladdropt;
2246
2247 {
2248 /* target lladdr option */
2249 struct rtentry *rt_router = NULL;
2250 int len;
2251 struct sockaddr_dl *sdl;
2252 struct nd_opt_hdr *nd_opt;
2253 char *lladdr;
2254
2255 rt_router = nd6_lookup(router_ll6, 0, ifp);
2256 if (!rt_router)
2257 goto nolladdropt;
2258 len = sizeof(*nd_opt) + ifp->if_addrlen;
2259 len = (len + 7) & ~7; /*round by 8*/
2260 /* safety check */
2261 if (len + (p - (u_char *)ip6) > maxlen)
2262 goto nolladdropt;
2263 if (!(rt_router->rt_flags & RTF_GATEWAY) &&
2264 (rt_router->rt_flags & RTF_LLINFO) &&
2265 (rt_router->rt_gateway->sa_family == AF_LINK) &&
2266 (sdl = (struct sockaddr_dl *)rt_router->rt_gateway) &&
2267 sdl->sdl_alen) {
2268 nd_opt = (struct nd_opt_hdr *)p;
2269 nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
2270 nd_opt->nd_opt_len = len >> 3;
2271 lladdr = (char *)(nd_opt + 1);
2272 bcopy(LLADDR(sdl), lladdr, ifp->if_addrlen);
2273 p += len;
2274 }
2275 }
2276 nolladdropt:;
2277
2278 m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
2279
2280 /* just to be safe */
2281 if (m0->m_flags & M_DECRYPTED)
2282 goto noredhdropt;
2283 if (p - (u_char *)ip6 > maxlen)
2284 goto noredhdropt;
2285
2286 {
2287 /* redirected header option */
2288 int len;
2289 struct nd_opt_rd_hdr *nd_opt_rh;
2290
2291 /*
2292 * compute the maximum size for icmp6 redirect header option.
2293 * XXX room for auth header?
2294 */
2295 len = maxlen - (p - (u_char *)ip6);
2296 len &= ~7;
2297
2298 /* This is just for simplicity. */
2299 if (m0->m_pkthdr.len != m0->m_len) {
2300 if (m0->m_next) {
2301 m_freem(m0->m_next);
2302 m0->m_next = NULL;
2303 }
2304 m0->m_pkthdr.len = m0->m_len;
2305 }
2306
2307 /*
2308 * Redirected header option spec (RFC2461 4.6.3) talks nothing
2309 * about padding/truncate rule for the original IP packet.
2310 * From the discussion on IPv6imp in Feb 1999, the consensus was:
2311 * - "attach as much as possible" is the goal
2312 * - pad if not aligned (original size can be guessed by original
2313 * ip6 header)
2314 * Following code adds the padding if it is simple enough,
2315 * and truncates if not.
2316 */
2317 if (m0->m_next || m0->m_pkthdr.len != m0->m_len)
2318 panic("assumption failed in %s:%d\n", __FILE__, __LINE__);
2319
2320 if (len - sizeof(*nd_opt_rh) < m0->m_pkthdr.len) {
2321 /* not enough room, truncate */
2322 m0->m_pkthdr.len = m0->m_len = len - sizeof(*nd_opt_rh);
2323 } else {
2324 /* enough room, pad or truncate */
2325 size_t extra;
2326
2327 extra = m0->m_pkthdr.len % 8;
2328 if (extra) {
2329 /* pad if easy enough, truncate if not */
2330 if (8 - extra <= M_TRAILINGSPACE(m0)) {
2331 /* pad */
2332 m0->m_len += (8 - extra);
2333 m0->m_pkthdr.len += (8 - extra);
2334 } else {
2335 /* truncate */
2336 m0->m_pkthdr.len -= extra;
2337 m0->m_len -= extra;
2338 }
2339 }
2340 len = m0->m_pkthdr.len + sizeof(*nd_opt_rh);
2341 m0->m_pkthdr.len = m0->m_len = len - sizeof(*nd_opt_rh);
2342 }
2343
2344 nd_opt_rh = (struct nd_opt_rd_hdr *)p;
2345 bzero(nd_opt_rh, sizeof(*nd_opt_rh));
2346 nd_opt_rh->nd_opt_rh_type = ND_OPT_REDIRECTED_HEADER;
2347 nd_opt_rh->nd_opt_rh_len = len >> 3;
2348 p += sizeof(*nd_opt_rh);
2349 m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
2350
2351 /* connect m0 to m */
2352 m->m_next = m0;
2353 m->m_pkthdr.len = m->m_len + m0->m_len;
2354 }
2355 noredhdropt:;
2356
2357 if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_src))
2358 sip6->ip6_src.s6_addr16[1] = 0;
2359 if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_dst))
2360 sip6->ip6_dst.s6_addr16[1] = 0;
2361 #if 0
2362 if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src))
2363 ip6->ip6_src.s6_addr16[1] = 0;
2364 if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst))
2365 ip6->ip6_dst.s6_addr16[1] = 0;
2366 #endif
2367 if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_target))
2368 nd_rd->nd_rd_target.s6_addr16[1] = 0;
2369 if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_dst))
2370 nd_rd->nd_rd_dst.s6_addr16[1] = 0;
2371
2372 ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
2373
2374 nd_rd->nd_rd_cksum = 0;
2375 nd_rd->nd_rd_cksum
2376 = in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), ntohs(ip6->ip6_plen));
2377
2378 /* send the packet to outside... */
2379 #ifdef IPSEC
2380 /* Don't lookup socket */
2381 ipsec_setsocket(m, NULL);
2382 #endif /*IPSEC*/
2383 ip6_output(m, NULL, NULL, 0, NULL, &outif);
2384 if (outif) {
2385 icmp6_ifstat_inc(outif, ifs6_out_msg);
2386 icmp6_ifstat_inc(outif, ifs6_out_redirect);
2387 }
2388 icmp6stat.icp6s_outhist[ND_REDIRECT]++;
2389
2390 return;
2391
2392 fail:
2393 if (m)
2394 m_freem(m);
2395 if (m0)
2396 m_freem(m0);
2397 }
2398
2399 /*
2400 * ICMPv6 socket option processing.
2401 */
2402 int
2403 icmp6_ctloutput(op, so, level, optname, mp)
2404 int op;
2405 struct socket *so;
2406 int level, optname;
2407 struct mbuf **mp;
2408 {
2409 register struct in6pcb *in6p = sotoin6pcb(so);
2410 register struct mbuf *m = *mp;
2411 int error = 0;
2412
2413 if (level != IPPROTO_ICMPV6) {
2414 error = EINVAL;
2415 if (op == PRCO_SETOPT && m)
2416 (void)m_free(m);
2417 } else switch(op) {
2418 case PRCO_SETOPT:
2419 switch (optname) {
2420 case ICMP6_FILTER:
2421 {
2422 struct icmp6_filter *p;
2423
2424 p = mtod(m, struct icmp6_filter *);
2425 if (!p || !in6p->in6p_icmp6filt) {
2426 error = EINVAL;
2427 break;
2428 }
2429 bcopy(p, in6p->in6p_icmp6filt,
2430 sizeof(struct icmp6_filter));
2431 error = 0;
2432 break;
2433 }
2434
2435 default:
2436 error = ENOPROTOOPT;
2437 break;
2438 }
2439 if (m)
2440 (void)m_free(m);
2441 break;
2442
2443 case PRCO_GETOPT:
2444 switch (optname) {
2445 case ICMP6_FILTER:
2446 {
2447 struct icmp6_filter *p;
2448
2449 if (!in6p->in6p_icmp6filt) {
2450 error = EINVAL;
2451 break;
2452 }
2453 *mp = m = m_get(M_WAIT, MT_SOOPTS);
2454 m->m_len = sizeof(struct icmp6_filter);
2455 p = mtod(m, struct icmp6_filter *);
2456 bcopy(in6p->in6p_icmp6filt, p,
2457 sizeof(struct icmp6_filter));
2458 error = 0;
2459 break;
2460 }
2461
2462 default:
2463 error = ENOPROTOOPT;
2464 break;
2465 }
2466 break;
2467 }
2468
2469 return(error);
2470 }
2471
2472 /*
2473 * Perform rate limit check.
2474 * Returns 0 if it is okay to send the icmp6 packet.
2475 * Returns 1 if the router SHOULD NOT send this icmp6 packet due to rate
2476 * limitation.
2477 *
2478 * XXX per-destination/type check necessary?
2479 */
2480 static int
2481 icmp6_ratelimit(dst, type, code)
2482 const struct in6_addr *dst; /* not used at this moment */
2483 const int type; /* not used at this moment */
2484 const int code; /* not used at this moment */
2485 {
2486 int ret;
2487
2488 ret = 0; /*okay to send*/
2489
2490 /* PPS limit */
2491 if (!ppsratecheck(&icmp6errppslim_last, &icmp6errpps_count,
2492 icmp6errppslim)) {
2493 /* The packet is subject to rate limit */
2494 ret++;
2495 }
2496
2497 return ret;
2498 }
2499
2500 static struct rtentry *
2501 icmp6_mtudisc_clone(dst)
2502 struct sockaddr *dst;
2503 {
2504 struct rtentry *rt;
2505 int error;
2506
2507 rt = rtalloc1(dst, 1);
2508 if (rt == 0)
2509 return NULL;
2510
2511 /* If we didn't get a host route, allocate one */
2512 if ((rt->rt_flags & RTF_HOST) == 0) {
2513 struct rtentry *nrt;
2514
2515 error = rtrequest((int) RTM_ADD, dst,
2516 (struct sockaddr *) rt->rt_gateway,
2517 (struct sockaddr *) 0,
2518 RTF_GATEWAY | RTF_HOST | RTF_DYNAMIC, &nrt);
2519 if (error) {
2520 rtfree(rt);
2521 rtfree(nrt);
2522 return NULL;
2523 }
2524 nrt->rt_rmx = rt->rt_rmx;
2525 rtfree(rt);
2526 rt = nrt;
2527 }
2528 error = rt_timer_add(rt, icmp6_mtudisc_timeout,
2529 icmp6_mtudisc_timeout_q);
2530 if (error) {
2531 rtfree(rt);
2532 return NULL;
2533 }
2534
2535 return rt; /* caller need to call rtfree() */
2536 }
2537
2538 static void
2539 icmp6_mtudisc_timeout(rt, r)
2540 struct rtentry *rt;
2541 struct rttimer *r;
2542 {
2543 if (rt == NULL)
2544 panic("icmp6_mtudisc_timeout: bad route to timeout");
2545 if ((rt->rt_flags & (RTF_DYNAMIC | RTF_HOST)) ==
2546 (RTF_DYNAMIC | RTF_HOST)) {
2547 rtrequest((int) RTM_DELETE, (struct sockaddr *)rt_key(rt),
2548 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
2549 } else {
2550 if ((rt->rt_rmx.rmx_locks & RTV_MTU) == 0) {
2551 rt->rt_rmx.rmx_mtu = 0;
2552 }
2553 }
2554 }
2555
2556 #include <vm/vm.h>
2557 #include <sys/sysctl.h>
2558 int
2559 icmp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
2560 int *name;
2561 u_int namelen;
2562 void *oldp;
2563 size_t *oldlenp;
2564 void *newp;
2565 size_t newlen;
2566 {
2567
2568 /* All sysctl names at this level are terminal. */
2569 if (namelen != 1)
2570 return ENOTDIR;
2571
2572 switch (name[0]) {
2573
2574 case ICMPV6CTL_REDIRACCEPT:
2575 return sysctl_int(oldp, oldlenp, newp, newlen,
2576 &icmp6_rediraccept);
2577 case ICMPV6CTL_REDIRTIMEOUT:
2578 return sysctl_int(oldp, oldlenp, newp, newlen,
2579 &icmp6_redirtimeout);
2580 case ICMPV6CTL_STATS:
2581 return sysctl_rdstruct(oldp, oldlenp, newp,
2582 &icmp6stat, sizeof(icmp6stat));
2583 case ICMPV6CTL_ND6_PRUNE:
2584 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_prune);
2585 case ICMPV6CTL_ND6_DELAY:
2586 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_delay);
2587 case ICMPV6CTL_ND6_UMAXTRIES:
2588 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_umaxtries);
2589 case ICMPV6CTL_ND6_MMAXTRIES:
2590 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_mmaxtries);
2591 case ICMPV6CTL_ND6_USELOOPBACK:
2592 return sysctl_int(oldp, oldlenp, newp, newlen,
2593 &nd6_useloopback);
2594 case ICMPV6CTL_NODEINFO:
2595 return sysctl_int(oldp, oldlenp, newp, newlen, &icmp6_nodeinfo);
2596 case ICMPV6CTL_ERRPPSLIMIT:
2597 return sysctl_int(oldp, oldlenp, newp, newlen, &icmp6errppslim);
2598 case ICMPV6CTL_ND6_MAXNUDHINT:
2599 return sysctl_int(oldp, oldlenp, newp, newlen,
2600 &nd6_maxnudhint);
2601 default:
2602 return ENOPROTOOPT;
2603 }
2604 /* NOTREACHED */
2605 }
2606