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