icmp6.c revision 1.8 1 /* $NetBSD: icmp6.c,v 1.8 1999/07/22 12:56:57 itojun Exp $ */
2
3 /*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright (c) 1982, 1986, 1988, 1993
34 * The Regents of the University of California. All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94
65 */
66
67 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
68 #include "opt_inet.h"
69 #include "opt_ipsec.h"
70 #endif
71
72 #include <sys/param.h>
73 #include <sys/systm.h>
74 #include <sys/malloc.h>
75 #include <sys/mbuf.h>
76 #include <sys/protosw.h>
77 #include <sys/socket.h>
78 #include <sys/socketvar.h>
79 #include <sys/time.h>
80 #include <sys/kernel.h>
81 #include <sys/syslog.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 <netinet6/in6_systm.h>
91 #include <netinet6/ip6.h>
92 #include <netinet6/ip6_var.h>
93 #include <netinet6/icmp6.h>
94 #include <netinet6/mld6_var.h>
95 #if !defined(__FreeBSD__) || __FreeBSD__ < 3
96 #include <netinet6/in6_pcb.h>
97 #else
98 #include <netinet/in_pcb.h>
99 #endif
100 #include <netinet6/nd6.h>
101 #include <netinet6/in6_ifattach.h>
102
103 #ifdef IPSEC
104 #include <netkey/key.h>
105 #include <netkey/key_debug.h>
106 #endif
107
108 #include "faith.h"
109
110 extern struct protosw inet6sw[];
111 extern u_char ip6_protox[];
112
113 struct icmp6stat icmp6stat;
114
115 #if !defined(__FreeBSD__) || __FreeBSD__ < 3
116 extern struct in6pcb rawin6pcb;
117 #else
118 extern struct inpcbhead ripcb;
119 #endif
120 extern u_int icmp6errratelim;
121 #ifdef __NetBSD__
122 static struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL;
123 extern int pmtu_expire;
124 #endif
125
126 static int icmp6_rip6_input __P((struct mbuf **, int));
127 static int icmp6_ratelimit __P((const struct in6_addr *, const int, const int));
128 static struct mbuf * ni6_input __P((struct mbuf *, int));
129 static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *,
130 struct ifnet **));
131 static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
132 struct ifnet *, int));
133 static struct rtentry *icmp6_mtudisc_clone __P((struct sockaddr *));
134 static void icmp6_mtudisc_timeout __P((struct rtentry *, struct rttimer *));
135
136 #ifdef COMPAT_RFC1885
137 static struct route_in6 icmp6_reflect_rt;
138 #endif
139 static struct timeval icmp6_nextsend = {0, 0};
140
141 void
142 icmp6_init()
143 {
144 mld6_init();
145 #ifdef __NetBSD__
146 icmp6_mtudisc_timeout_q = rt_timer_queue_create(pmtu_expire);
147 #endif
148 }
149
150 /*
151 * Generate an error packet of type error in response to bad IP6 packet.
152 */
153 void
154 icmp6_error(m, type, code, param)
155 struct mbuf *m;
156 int type, code, param;
157 {
158 struct ip6_hdr *oip6, *nip6;
159 struct icmp6_hdr *icmp6;
160 u_int prep;
161 int off;
162 u_char nxt;
163
164 icmp6stat.icp6s_error++;
165
166 if (m->m_flags & M_DECRYPTED)
167 goto freeit;
168
169 oip6 = mtod(m, struct ip6_hdr *);
170
171 /*
172 * Multicast destination check. For unrecognized option errors,
173 * this check has already done in ip6_unknown_opt(), so we can
174 * check only for other errors.
175 */
176 if ((m->m_flags & (M_BCAST|M_MCAST) ||
177 IN6_IS_ADDR_MULTICAST(&oip6->ip6_dst)) &&
178 (type != ICMP6_PACKET_TOO_BIG &&
179 (type != ICMP6_PARAM_PROB ||
180 code != ICMP6_PARAMPROB_OPTION)))
181 goto freeit;
182
183 /* Source address check. XXX: the case of anycast source? */
184 if (IN6_IS_ADDR_UNSPECIFIED(&oip6->ip6_src) ||
185 IN6_IS_ADDR_MULTICAST(&oip6->ip6_src))
186 goto freeit;
187
188 /*
189 * If the erroneous packet is also an ICMP error, discard it.
190 */
191 IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), );
192 off = sizeof(struct ip6_hdr);
193 nxt = oip6->ip6_nxt;
194 while(1) { /* XXX: should avoid inf. loop explicitly? */
195 struct ip6_ext *ip6e;
196 struct icmp6_hdr *icp;
197
198 switch(nxt) {
199 case IPPROTO_IPV6:
200 case IPPROTO_IPV4:
201 case IPPROTO_UDP:
202 case IPPROTO_TCP:
203 case IPPROTO_ESP:
204 case IPPROTO_FRAGMENT:
205 /*
206 * ICMPv6 error must not be fragmented.
207 * XXX: but can we trust the sender?
208 */
209 default:
210 /* What if unknown header followed by ICMP error? */
211 goto generate;
212 case IPPROTO_ICMPV6:
213 IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct icmp6_hdr), );
214 icp = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
215 if (icp->icmp6_type < ICMP6_ECHO_REQUEST
216 || icp->icmp6_type == ND_REDIRECT) {
217 /*
218 * ICMPv6 error
219 * Special case: for redirect (which is
220 * informational) we must not send icmp6 error.
221 */
222 icmp6stat.icp6s_canterror++;
223 goto freeit;
224 } else {
225 /* ICMPv6 informational */
226 goto generate;
227 }
228 case IPPROTO_HOPOPTS:
229 case IPPROTO_DSTOPTS:
230 case IPPROTO_ROUTING:
231 case IPPROTO_AH:
232 IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct ip6_ext), );
233 ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off);
234 if (nxt == IPPROTO_AH)
235 off += (ip6e->ip6e_len + 2) << 2;
236 else
237 off += (ip6e->ip6e_len + 1) << 3;
238 nxt = ip6e->ip6e_nxt;
239 break;
240 }
241 }
242
243 freeit:
244 /*
245 * If we can't tell wheter or not we can generate ICMP6, free it.
246 */
247 m_freem(m);
248 return;
249
250 generate:
251 oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */
252
253 /* Finally, do rate limitation check. */
254 if (icmp6_ratelimit(&oip6->ip6_src, type, code)) {
255 icmp6stat.icp6s_toofreq++;
256 goto freeit;
257 }
258
259 /*
260 * OK, ICMP6 can be generated.
261 */
262
263 if (m->m_pkthdr.len >= ICMPV6_PLD_MAXLEN)
264 m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len);
265
266 prep = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
267 M_PREPEND(m, prep, M_DONTWAIT);
268 if (m && m->m_len < prep)
269 m = m_pullup(m, prep);
270 if (m == NULL) {
271 printf("ENOBUFS in icmp6_error %d\n", __LINE__);
272 return;
273 }
274
275 nip6 = mtod(m, struct ip6_hdr *);
276 nip6->ip6_src = oip6->ip6_src;
277 nip6->ip6_dst = oip6->ip6_dst;
278
279 if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_src))
280 oip6->ip6_src.s6_addr16[1] = 0;
281 if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_dst))
282 oip6->ip6_dst.s6_addr16[1] = 0;
283
284 icmp6 = (struct icmp6_hdr *)(nip6 + 1);
285 icmp6->icmp6_type = type;
286 icmp6->icmp6_code = code;
287 icmp6->icmp6_pptr = htonl((u_int32_t)param);
288
289 icmp6stat.icp6s_outhist[type]++;
290 icmp6_reflect(m, sizeof(struct ip6_hdr)); /*header order: IPv6 - ICMPv6*/
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 IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), IPPROTO_DONE);
310 /* m might change if M_LOOP. So, call mtod after this */
311
312 /*
313 * Locate icmp6 structure in mbuf, and check
314 * that not corrupted and of at least minimum length
315 */
316
317 ip6 = mtod(m, struct ip6_hdr *);
318 if (icmp6len < sizeof(struct icmp6_hdr)) {
319 icmp6stat.icp6s_tooshort++;
320 goto freeit;
321 }
322
323 /*
324 * calculate the checksum
325 */
326
327 icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
328 code = icmp6->icmp6_code;
329
330 if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) {
331 log(LOG_ERR,
332 "ICMP6 checksum error(%d|%x) %s\n",
333 icmp6->icmp6_type,
334 sum,
335 ip6_sprintf(&ip6->ip6_src));
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 #ifdef IPSEC
359 /* drop it if it does not match the default policy */
360 if (ipsec6_in_reject(m, NULL)) {
361 ipsecstat.in_polvio++;
362 goto freeit;
363 }
364 #endif
365
366 icmp6stat.icp6s_inhist[icmp6->icmp6_type]++;
367
368 switch (icmp6->icmp6_type) {
369
370 case ICMP6_DST_UNREACH:
371 switch (code) {
372 case ICMP6_DST_UNREACH_NOROUTE:
373 code = PRC_UNREACH_NET;
374 break;
375 case ICMP6_DST_UNREACH_ADMIN:
376 case ICMP6_DST_UNREACH_ADDR:
377 code = PRC_UNREACH_HOST;
378 break;
379 case ICMP6_DST_UNREACH_NOTNEIGHBOR:
380 code = PRC_UNREACH_SRCFAIL;
381 break;
382 case ICMP6_DST_UNREACH_NOPORT:
383 code = PRC_UNREACH_PORT;
384 break;
385 default:
386 goto badcode;
387 }
388 goto deliver;
389 break;
390
391 case ICMP6_PACKET_TOO_BIG:
392 if (code != 0)
393 goto badcode;
394 {
395 u_int mtu = ntohl(icmp6->icmp6_mtu);
396 struct rtentry *rt;
397 struct sockaddr_in6 sin6;
398 #ifdef __bsdi__
399 struct route_in6 ro6;
400 #endif
401
402 code = PRC_MSGSIZE;
403 bzero(&sin6, sizeof(sin6));
404 sin6.sin6_family = PF_INET6;
405 sin6.sin6_len = sizeof(struct sockaddr_in6);
406 sin6.sin6_addr = ((struct ip6_hdr *)(icmp6 + 1))->ip6_dst;
407 #ifdef __NetBSD__
408 rt = rtalloc1((struct sockaddr *)&sin6, 1); /*clone*/
409 if (!rt || (rt->rt_flags & RTF_HOST) == 0) {
410 if (rt)
411 RTFREE(rt);
412 rt = icmp6_mtudisc_clone((struct sockaddr *)&sin6);
413 }
414 #endif
415 #ifdef __FreeBSD__
416 rt = rtalloc1((struct sockaddr *)&sin6, 0,
417 RTF_CLONING | RTF_PRCLONING);
418 #endif /*__FreeBSD__*/
419 #ifdef __bsdi__
420 bcopy(&sin6, &ro6.ro_dst, sizeof(struct sockaddr_in6));
421 ro6.ro_rt = 0;
422 rtcalloc((struct route *)&ro6);
423 rt = ro6.ro_rt;
424 #endif /*__bsdi__*/
425
426 if (rt && (rt->rt_flags & RTF_HOST)
427 && !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
428 if (mtu < IPV6_MMTU) {
429 /* xxx */
430 rt->rt_rmx.rmx_locks |= RTV_MTU;
431 } else if (mtu < rt->rt_ifp->if_mtu &&
432 rt->rt_rmx.rmx_mtu > mtu) {
433 rt->rt_rmx.rmx_mtu = mtu;
434 }
435 }
436 if (rt)
437 RTFREE(rt);
438
439 goto deliver;
440 }
441 break;
442
443 case ICMP6_TIME_EXCEEDED:
444 switch (code) {
445 case ICMP6_TIME_EXCEED_TRANSIT:
446 case ICMP6_TIME_EXCEED_REASSEMBLY:
447 code += PRC_TIMXCEED_INTRANS;
448 break;
449 default:
450 goto badcode;
451 }
452 goto deliver;
453 break;
454
455 case ICMP6_PARAM_PROB:
456 switch (code) {
457 case ICMP6_PARAMPROB_NEXTHEADER:
458 code = PRC_UNREACH_PROTOCOL;
459 break;
460 case ICMP6_PARAMPROB_HEADER:
461 case ICMP6_PARAMPROB_OPTION:
462 code = PRC_PARAMPROB;
463 break;
464 default:
465 goto badcode;
466 }
467 goto deliver;
468 break;
469
470 case ICMP6_ECHO_REQUEST:
471 if (code != 0)
472 goto badcode;
473 if ((n = m_copy(m, 0, M_COPYALL)) == NULL) {
474 /* Give up remote */
475 break;
476 }
477 if (n->m_flags & M_EXT) {
478 int gap, move;
479 struct mbuf *n0 = n;
480
481 /*
482 * Prepare an internal mbuf. m_pullup() doesn't
483 * always copy the length we specified.
484 */
485 MGETHDR(n, M_DONTWAIT, n0->m_type);
486 if (n == NULL) {
487 /* Give up remote */
488 m_freem(n0);
489 break;
490 }
491 M_COPY_PKTHDR(n, n0);
492 n0->m_flags &= ~M_PKTHDR;
493 n->m_next = n0;
494 /*
495 * Copy IPv6 and ICMPv6 only.
496 */
497 nip6 = mtod(n, struct ip6_hdr *);
498 bcopy(ip6, nip6, sizeof(struct ip6_hdr));
499 nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
500 bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
501 /*
502 * Adjust mbuf. ip6_plen will be adjusted.
503 */
504 noff = sizeof(struct ip6_hdr);
505 n->m_len = noff + sizeof(struct icmp6_hdr);
506 move = off + sizeof(struct icmp6_hdr);
507 n0->m_len -= move;
508 n0->m_data += move;
509 gap = off - noff;
510 n->m_pkthdr.len -= gap;
511 } else {
512 nip6 = mtod(n, struct ip6_hdr *);
513 nicmp6 = (struct icmp6_hdr *)((caddr_t)nip6 + off);
514 noff = off;
515 }
516 nicmp6->icmp6_type = ICMP6_ECHO_REPLY;
517 nicmp6->icmp6_code = 0;
518 icmp6stat.icp6s_reflect++;
519 icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]++;
520 icmp6_reflect(n, noff);
521 break;
522
523 case ICMP6_ECHO_REPLY:
524 if (code != 0)
525 goto badcode;
526 break;
527
528 case MLD6_LISTENER_QUERY:
529 case MLD6_LISTENER_REPORT:
530 if (icmp6len < sizeof(struct mld6_hdr))
531 goto badlen;
532 IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE);
533 mld6_input(m, off);
534 /* m stays. */
535 break;
536
537 case MLD6_LISTENER_DONE:
538 if (icmp6len < sizeof(struct mld6_hdr))
539 goto badlen;
540 break; /* nothing to be done in kernel */
541
542 case ICMP6_WRUREQUEST: /* ICMP6_FQDN_QUERY */
543 {
544 enum { WRU, FQDN } mode;
545
546 if (code != 0)
547 goto badcode;
548 if (icmp6len == sizeof(struct icmp6_hdr) + 4)
549 mode = WRU;
550 else if (icmp6len >= sizeof(struct icmp6_hdr) + 8) /* XXX */
551 mode = FQDN;
552 else
553 goto badlen;
554
555 #ifdef __FreeBSD__
556 #define hostnamelen strlen(hostname)
557 #endif
558 if (mode == FQDN) {
559 IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_nodeinfo),
560 IPPROTO_DONE);
561 n = ni6_input(m, off);
562 noff = sizeof(struct ip6_hdr);
563 }
564 else {
565 u_char *p;
566
567 MGETHDR(n, M_DONTWAIT, m->m_type);
568 if (n == NULL) {
569 /* Give up remote */
570 break;
571 }
572 /*
573 * Copy IPv6 and ICMPv6 only.
574 */
575 nip6 = mtod(n, struct ip6_hdr *);
576 bcopy(ip6, nip6, sizeof(struct ip6_hdr));
577 nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
578 bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
579 p = (u_char *)(nicmp6 + 1);
580 bzero(p, 4);
581 bcopy(hostname, p + 4, hostnamelen);
582 noff = sizeof(struct ip6_hdr);
583 M_COPY_PKTHDR(n, m); /* just for recvif */
584 n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
585 sizeof(struct icmp6_hdr) + 4 + hostnamelen;
586 nicmp6->icmp6_type = ICMP6_WRUREPLY;
587 nicmp6->icmp6_code = 0;
588 }
589 #undef hostnamelen
590 if (n) {
591 icmp6stat.icp6s_reflect++;
592 icmp6stat.icp6s_outhist[ICMP6_WRUREPLY]++;
593 icmp6_reflect(n, noff);
594 }
595 break;
596 }
597
598 case ICMP6_WRUREPLY:
599 if (code != 0)
600 goto badcode;
601 break;
602
603 case ND_ROUTER_SOLICIT:
604 if (code != 0)
605 goto badcode;
606 if (icmp6len < sizeof(struct nd_router_solicit))
607 goto badlen;
608 IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE);
609 nd6_rs_input(m, off, icmp6len);
610 /* m stays. */
611 break;
612
613 case ND_ROUTER_ADVERT:
614 if (code != 0)
615 goto badcode;
616 if (icmp6len < sizeof(struct nd_router_advert))
617 goto badlen;
618 IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE);
619 nd6_ra_input(m, off, icmp6len);
620 /* m stays. */
621 break;
622
623 case ND_NEIGHBOR_SOLICIT:
624 if (code != 0)
625 goto badcode;
626 if (icmp6len < sizeof(struct nd_neighbor_solicit))
627 goto badlen;
628 IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE);
629 nd6_ns_input(m, off, icmp6len);
630 /* m stays. */
631 break;
632
633 case ND_NEIGHBOR_ADVERT:
634 if (code != 0)
635 goto badcode;
636 if (icmp6len < sizeof(struct nd_neighbor_advert))
637 goto badlen;
638 IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE);
639 nd6_na_input(m, off, icmp6len);
640 /* m stays. */
641 break;
642
643 case ND_REDIRECT:
644 if (code != 0)
645 goto badcode;
646 if (icmp6len < sizeof(struct nd_redirect))
647 goto badlen;
648 icmp6_redirect_input(m, off);
649 /* m stays. */
650 break;
651
652 case ICMP6_ROUTER_RENUMBERING:
653 if (code != ICMP6_ROUTER_RENUMBERING_COMMAND &&
654 code != ICMP6_ROUTER_RENUMBERING_RESULT)
655 goto badcode;
656 if (icmp6len < sizeof(struct icmp6_router_renum))
657 goto badlen;
658 break;
659
660 default:
661 printf("icmp6_input: unknown type %d\n", icmp6->icmp6_type);
662 if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) {
663 /* ICMPv6 error: MUST deliver it by spec... */
664 code = PRC_NCMDS;
665 /* deliver */
666 } else {
667 /* ICMPv6 informational: MUST not deliver */
668 break;
669 }
670 deliver:
671 if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
672 icmp6stat.icp6s_tooshort++;
673 goto freeit;
674 }
675 IP6_EXTHDR_CHECK(m, off,
676 sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr),
677 IPPROTO_DONE);
678 icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
679 bzero(&icmp6src, sizeof(icmp6src));
680 icmp6src.sin6_len = sizeof(struct sockaddr_in6);
681 icmp6src.sin6_family = AF_INET6;
682 icmp6src.sin6_addr = ((struct ip6_hdr *)(icmp6 + 1))->ip6_dst;
683
684 /* Detect the upper level protocol */
685 {
686 void (*ctlfunc) __P((int, struct sockaddr *,
687 struct ip6_hdr *,
688 struct mbuf *, int)); /* XXX */
689 struct ip6_hdr *eip6 = (struct ip6_hdr *)(icmp6 + 1);
690 u_int8_t nxt = eip6->ip6_nxt;
691 int eoff = off + sizeof(struct icmp6_hdr) +
692 sizeof(struct ip6_hdr);
693
694 while (1) { /* XXX: should avoid inf. loop explicitly? */
695 struct ip6_ext *eh;
696
697 switch(nxt) {
698 case IPPROTO_ESP:
699 case IPPROTO_NONE:
700 goto passit;
701 case IPPROTO_HOPOPTS:
702 case IPPROTO_DSTOPTS:
703 case IPPROTO_ROUTING:
704 case IPPROTO_AH:
705 case IPPROTO_FRAGMENT:
706 IP6_EXTHDR_CHECK(m, 0, eoff +
707 sizeof(struct ip6_ext),
708 IPPROTO_DONE);
709 eh = (struct ip6_ext *)(mtod(m, caddr_t)
710 + eoff);
711 if (nxt == IPPROTO_AH)
712 eoff += (eh->ip6e_len + 2) << 2;
713 else if (nxt == IPPROTO_FRAGMENT)
714 eoff += sizeof(struct ip6_frag);
715 else
716 eoff += (eh->ip6e_len + 1) << 3;
717 nxt = eh->ip6e_nxt;
718 break;
719 default:
720 goto notify;
721 }
722 }
723 notify:
724 icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
725 ctlfunc = (void (*) __P((int, struct sockaddr *,
726 struct ip6_hdr *,
727 struct mbuf *, int)))
728 (inet6sw[ip6_protox[nxt]].pr_ctlinput);
729 if (ctlfunc)
730 (*ctlfunc)(code, (struct sockaddr *)&icmp6src,
731 (struct ip6_hdr *)(icmp6 + 1),
732 m, eoff);
733 }
734 break;
735
736 badcode:
737 icmp6stat.icp6s_badcode++;
738 break;
739
740 badlen:
741 icmp6stat.icp6s_badlen++;
742 break;
743 }
744
745 passit:
746 icmp6_rip6_input(&m, *offp);
747 return IPPROTO_DONE;
748
749 freeit:
750 m_freem(m);
751 return IPPROTO_DONE;
752 }
753
754 /*
755 * Process a Node Information Query
756 */
757 #ifdef __FreeBSD__
758 #define hostnamelen strlen(hostname)
759 #endif
760 #ifndef offsetof /* XXX */
761 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
762 #endif
763
764 static struct mbuf *
765 ni6_input(m, off)
766 struct mbuf *m;
767 int off;
768 {
769 struct icmp6_nodeinfo *ni6 =
770 (struct icmp6_nodeinfo *)(mtod(m, caddr_t) + off), *nni6;
771 struct mbuf *n = NULL;
772 u_int16_t qtype = ntohs(ni6->ni_qtype);
773 int replylen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo);
774 struct ni_reply_fqdn *fqdn;
775 int addrs; /* for NI_QTYPE_NODEADDR */
776 struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */
777
778 switch(qtype) {
779 case NI_QTYPE_NOOP:
780 break; /* no reply data */
781 case NI_QTYPE_SUPTYPES:
782 goto bad; /* xxx: to be implemented */
783 break;
784 case NI_QTYPE_FQDN:
785 replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_name) +
786 hostnamelen;
787 break;
788 case NI_QTYPE_NODEADDR:
789 addrs = ni6_addrs(ni6, m, &ifp);
790 if ((replylen += addrs * sizeof(struct in6_addr)) > MCLBYTES)
791 replylen = MCLBYTES; /* XXX: we'll truncate later */
792
793 break;
794 default:
795 /*
796 * XXX: We must return a reply with the ICMP6 code
797 * `unknown Qtype' in this case. However we regard the case
798 * as an FQDN query for backward compatibility.
799 * Older versions set a random value to this field,
800 * so it rarely varies in the defined qtypes.
801 * But the mechanism is not reliable...
802 * maybe we should obsolete older versions.
803 */
804 qtype = NI_QTYPE_FQDN;
805 replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_name) +
806 hostnamelen;
807 break;
808 }
809
810 /* allocate a mbuf to reply. */
811 MGETHDR(n, M_DONTWAIT, m->m_type);
812 if (n == NULL)
813 return(NULL);
814 M_COPY_PKTHDR(n, m); /* just for recvif */
815 if (replylen > MHLEN) {
816 if (replylen > MCLBYTES)
817 /*
818 * XXX: should we try to allocate more? But MCLBYTES is
819 * probably much larger than IPV6_MMTU...
820 */
821 goto bad;
822 MCLGET(n, M_DONTWAIT);
823 if ((n->m_flags & M_EXT) == 0) {
824 goto bad;
825 }
826 }
827 n->m_pkthdr.len = n->m_len = replylen;
828
829 /* copy mbuf header and IPv6 + Node Information base headers */
830 bcopy(mtod(m, caddr_t), mtod(n, caddr_t), sizeof(struct ip6_hdr));
831 nni6 = (struct icmp6_nodeinfo *)(mtod(n, struct ip6_hdr *) + 1);
832 bcopy(mtod(m, caddr_t) + off, (caddr_t)nni6, sizeof(struct icmp6_nodeinfo));
833
834 /* qtype dependent procedure */
835 switch (qtype) {
836 case NI_QTYPE_NOOP:
837 nni6->ni_flags = 0;
838 break;
839 case NI_QTYPE_SUPTYPES:
840 goto bad; /* xxx: to be implemented */
841 break;
842 case NI_QTYPE_FQDN:
843 if (hostnamelen > 255) { /* XXX: rare case, but may happen */
844 printf("ni6_input: "
845 "hostname length(%d) is too large for reply\n",
846 hostnamelen);
847 goto bad;
848 }
849 fqdn = (struct ni_reply_fqdn *)(mtod(n, caddr_t) +
850 sizeof(struct ip6_hdr) +
851 sizeof(struct icmp6_nodeinfo));
852 nni6->ni_flags = 0; /* XXX: meaningless TTL */
853 fqdn->ni_fqdn_ttl = 0; /* ditto. */
854 fqdn->ni_fqdn_namelen = hostnamelen;
855 bcopy(hostname, &fqdn->ni_fqdn_name[0], hostnamelen);
856 break;
857 case NI_QTYPE_NODEADDR:
858 {
859 int lenlim, copied;
860
861 if (n->m_flags & M_EXT)
862 lenlim = MCLBYTES - sizeof(struct ip6_hdr) -
863 sizeof(struct icmp6_nodeinfo);
864 else
865 lenlim = MHLEN - sizeof(struct ip6_hdr) -
866 sizeof(struct icmp6_nodeinfo);
867 copied = ni6_store_addrs(ni6, nni6, ifp, lenlim);
868 /* XXX: reset mbuf length */
869 n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
870 sizeof(struct icmp6_nodeinfo) + copied;
871 break;
872 }
873 default:
874 break; /* XXX impossible! */
875 }
876
877 nni6->ni_type = ICMP6_NI_REPLY;
878 nni6->ni_code = ICMP6_NI_SUCESS;
879 return(n);
880
881 bad:
882 if (n)
883 m_freem(n);
884 return(NULL);
885 }
886 #undef hostnamelen
887
888 /*
889 * calculate the number of addresses to be returned in the node info reply.
890 */
891 static int
892 ni6_addrs(ni6, m, ifpp)
893 struct icmp6_nodeinfo *ni6;
894 struct mbuf *m;
895 struct ifnet **ifpp;
896 {
897 register struct ifnet *ifp;
898 register struct in6_ifaddr *ifa6;
899 register struct ifaddr *ifa;
900 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
901 int addrs = 0, addrsofif, iffound = 0;
902
903 #ifdef __NetBSD__
904 for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
905 #else
906 for (ifp = ifnet; ifp; ifp = ifp->if_next)
907 #endif
908 {
909 addrsofif = 0;
910 #ifdef __NetBSD__
911 for (ifa = ifp->if_addrlist.tqh_first; ifa;
912 ifa = ifa->ifa_list.tqe_next)
913 #else
914 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
915 #endif
916 {
917 if (ifa->ifa_addr->sa_family != AF_INET6)
918 continue;
919 ifa6 = (struct in6_ifaddr *)ifa;
920
921 if (!(ni6->ni_flags & NI_NODEADDR_FLAG_ALL) &&
922 IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
923 &ifa6->ia_addr.sin6_addr))
924 iffound = 1;
925
926 if (ifa6->ia6_flags & IN6_IFF_ANYCAST)
927 continue; /* we need only unicast addresses */
928
929 if ((ni6->ni_flags & (NI_NODEADDR_FLAG_LINKLOCAL |
930 NI_NODEADDR_FLAG_SITELOCAL |
931 NI_NODEADDR_FLAG_GLOBAL)) == 0)
932 continue;
933
934 /* What do we have to do about ::1? */
935 switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
936 case IPV6_ADDR_SCOPE_LINKLOCAL:
937 if (ni6->ni_flags & NI_NODEADDR_FLAG_LINKLOCAL)
938 addrsofif++;
939 break;
940 case IPV6_ADDR_SCOPE_SITELOCAL:
941 if (ni6->ni_flags & NI_NODEADDR_FLAG_SITELOCAL)
942 addrsofif++;
943 break;
944 case IPV6_ADDR_SCOPE_GLOBAL:
945 if (ni6->ni_flags & NI_NODEADDR_FLAG_GLOBAL)
946 addrsofif++;
947 break;
948 default:
949 continue;
950 }
951 }
952 if (iffound) {
953 *ifpp = ifp;
954 return(addrsofif);
955 }
956
957 addrs += addrsofif;
958 }
959
960 return(addrs);
961 }
962
963 static int
964 ni6_store_addrs(ni6, nni6, ifp0, resid)
965 struct icmp6_nodeinfo *ni6, *nni6;
966 struct ifnet *ifp0;
967 int resid;
968 {
969 #ifdef __NetBSD__
970 register struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet);
971 #else
972 register struct ifnet *ifp = ifp0 ? ifp0 : ifnet;
973 #endif
974 register struct in6_ifaddr *ifa6;
975 register struct ifaddr *ifa;
976 int docopy, copied = 0;
977 u_char *cp = (u_char *)(nni6 + 1);
978
979 if (ifp0 == NULL && !(ni6->ni_flags & NI_NODEADDR_FLAG_ALL))
980 return(0); /* needless to copy */
981
982 #ifdef __NetBSD__
983 for (; ifp; ifp = TAILQ_NEXT(ifp, if_list))
984 #else
985 for (; ifp; ifp = ifp->if_next)
986 #endif
987 {
988 #ifdef __NetBSD__
989 for (ifa = ifp->if_addrlist.tqh_first; ifa;
990 ifa = ifa->ifa_list.tqe_next)
991 #else
992 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
993 #endif
994 {
995 docopy = 0;
996
997 if (ifa->ifa_addr->sa_family != AF_INET6)
998 continue;
999 ifa6 = (struct in6_ifaddr *)ifa;
1000
1001 if (ifa6->ia6_flags & IN6_IFF_ANYCAST)
1002 continue; /* we need only unicast addresses */
1003
1004 /* What do we have to do about ::1? */
1005 switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
1006 case IPV6_ADDR_SCOPE_LINKLOCAL:
1007 if (ni6->ni_flags & NI_NODEADDR_FLAG_LINKLOCAL)
1008 docopy = 1;
1009 break;
1010 case IPV6_ADDR_SCOPE_SITELOCAL:
1011 if (ni6->ni_flags & NI_NODEADDR_FLAG_SITELOCAL)
1012 docopy = 1;
1013 break;
1014 case IPV6_ADDR_SCOPE_GLOBAL:
1015 if (ni6->ni_flags & NI_NODEADDR_FLAG_GLOBAL)
1016 docopy = 1;
1017 break;
1018 default:
1019 continue;
1020 }
1021
1022 if (docopy) {
1023 if (resid < sizeof(struct in6_addr)) {
1024 /*
1025 * We give up much more copy.
1026 * Set the truncate flag and return.
1027 */
1028 nni6->ni_flags |=
1029 NI_NODEADDR_FLAG_TRUNCATE;
1030 return(copied);
1031 }
1032 bcopy(&ifa6->ia_addr.sin6_addr, cp,
1033 sizeof(struct in6_addr));
1034 /* XXX: KAME link-local hack; remove ifindex */
1035 if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr))
1036 ((struct in6_addr *)cp)->s6_addr16[1] = 0;
1037 cp += sizeof(struct in6_addr);
1038 resid -= sizeof(struct in6_addr);
1039 copied += sizeof(struct in6_addr);
1040 }
1041 }
1042 if (ifp0) /* we need search only on the specified IF */
1043 break;
1044 }
1045
1046 return(copied);
1047 }
1048
1049 /*
1050 * XXX almost dup'ed code with rip6_input.
1051 */
1052 static int
1053 icmp6_rip6_input(mp, off)
1054 struct mbuf **mp;
1055 int off;
1056 {
1057 struct mbuf *m = *mp;
1058 register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1059 register struct in6pcb *in6p;
1060 struct in6pcb *last = NULL;
1061 struct sockaddr_in6 rip6src;
1062 struct icmp6_hdr *icmp6;
1063 struct mbuf *opts = NULL;
1064
1065 /* this is assumed to be safe. */
1066 icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
1067
1068 bzero(&rip6src, sizeof(rip6src));
1069 rip6src.sin6_len = sizeof(struct sockaddr_in6);
1070 rip6src.sin6_family = AF_INET6;
1071 rip6src.sin6_addr = ip6->ip6_src;
1072 if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr))
1073 rip6src.sin6_addr.s6_addr16[1] = 0;
1074 if (m->m_pkthdr.rcvif) {
1075 if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr))
1076 rip6src.sin6_scope_id = m->m_pkthdr.rcvif->if_index;
1077 else
1078 rip6src.sin6_scope_id = 0;
1079 } else
1080 rip6src.sin6_scope_id = 0;
1081
1082 #if !defined(__FreeBSD__) || __FreeBSD__ < 3
1083 for (in6p = rawin6pcb.in6p_next;
1084 in6p != &rawin6pcb; in6p = in6p->in6p_next)
1085 #else
1086 LIST_FOREACH(in6p, &ripcb, inp_list)
1087 #endif
1088 {
1089 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
1090 if ((in6p->inp_vflag & INP_IPV6) == NULL)
1091 continue;
1092 #endif
1093 if (in6p->in6p_ip6_nxt != IPPROTO_ICMPV6)
1094 continue;
1095 if (!IN6_IS_ADDR_ANY(&in6p->in6p_laddr) &&
1096 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
1097 continue;
1098 if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr) &&
1099 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
1100 continue;
1101 if (in6p->in6p_icmp6filt
1102 && ICMP6_FILTER_WILLBLOCK(icmp6->icmp6_type,
1103 in6p->in6p_icmp6filt))
1104 continue;
1105 if (last) {
1106 struct mbuf *n;
1107 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
1108 if (last->in6p_flags & IN6P_CONTROLOPTS)
1109 ip6_savecontrol(last, &opts, ip6, n);
1110 /* strip intermediate headers */
1111 m_adj(n, off);
1112 if (sbappendaddr(&last->in6p_socket->so_rcv,
1113 (struct sockaddr *)&rip6src,
1114 n, opts) == 0) {
1115 /* should notify about lost packet */
1116 m_freem(n);
1117 if (opts)
1118 m_freem(opts);
1119 } else
1120 sorwakeup(last->in6p_socket);
1121 opts = NULL;
1122 }
1123 }
1124 last = in6p;
1125 }
1126 if (last) {
1127 if (last->in6p_flags & IN6P_CONTROLOPTS)
1128 ip6_savecontrol(last, &opts, ip6, m);
1129 /* strip intermediate headers */
1130 m_adj(m, off);
1131 if (sbappendaddr(&last->in6p_socket->so_rcv,
1132 (struct sockaddr *)&rip6src, m, opts) == 0) {
1133 m_freem(m);
1134 if (opts)
1135 m_freem(opts);
1136 } else
1137 sorwakeup(last->in6p_socket);
1138 } else {
1139 m_freem(m);
1140 ip6stat.ip6s_delivered--;
1141 }
1142 return IPPROTO_DONE;
1143 }
1144
1145 /*
1146 * Reflect the ip6 packet back to the source.
1147 * The caller MUST check if the destination is multicast or not.
1148 * This function is usually called with a unicast destination which
1149 * can be safely the source of the reply packet. But some exceptions
1150 * exist(e.g. ECHOREPLY, PATCKET_TOOBIG, "10" in OPTION type).
1151 * ``off'' points to the icmp6 header, counted from the top of the mbuf.
1152 */
1153 void
1154 icmp6_reflect(m, off)
1155 struct mbuf *m;
1156 size_t off;
1157 {
1158 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1159 struct icmp6_hdr *icmp6;
1160 struct in6_ifaddr *ia;
1161 struct in6_addr t, *src = 0;
1162 int plen = m->m_pkthdr.len - sizeof(struct ip6_hdr);
1163 #ifdef COMPAT_RFC1885
1164 int mtu = IPV6_MMTU;
1165 struct sockaddr_in6 *sin6 = &icmp6_reflect_rt.ro_dst;
1166 #endif
1167
1168 /*
1169 * If there are extra headers between IPv6 and ICMPv6, strip
1170 * off that header first.
1171 */
1172 if (off != sizeof(struct ip6_hdr)) {
1173 size_t siz;
1174
1175 /* sanity checks */
1176 if (off < sizeof(struct ip6_hdr)) {
1177 printf("sanity fail: off=%x, sizeof(ip6)=%x in %s:%d\n",
1178 (unsigned int)off,
1179 (unsigned int)sizeof(struct ip6_hdr),
1180 __FILE__, __LINE__);
1181 goto bad;
1182 }
1183 siz = off - sizeof(struct ip6_hdr);
1184 if (plen < siz) {
1185 printf("sanity fail: siz=%x, payloadlen=%x in %s:%d\n",
1186 (unsigned int)siz, plen, __FILE__, __LINE__);
1187 goto bad;
1188 }
1189 IP6_EXTHDR_CHECK(m, 0, off, /*nothing*/);
1190 IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), /*nothing*/);
1191
1192 bcopy((caddr_t)ip6,
1193 (caddr_t)(mtod(m, u_char *) + siz),
1194 sizeof(struct ip6_hdr));
1195 m->m_data += siz;
1196 m->m_len -= siz;
1197 m->m_pkthdr.len -= siz;
1198 ip6 = mtod(m, struct ip6_hdr *);
1199 ip6->ip6_nxt = IPPROTO_ICMPV6;
1200 plen -= siz;
1201 }
1202
1203 icmp6 = (struct icmp6_hdr *)(ip6 + 1);
1204
1205 t = ip6->ip6_dst;
1206 /*
1207 * ip6_input() drops a packet if its src is multicast.
1208 * So, the src is never multicast.
1209 */
1210 ip6->ip6_dst = ip6->ip6_src;
1211
1212 /* XXX hack for link-local addresses */
1213 if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst))
1214 ip6->ip6_dst.s6_addr16[1] =
1215 htons(m->m_pkthdr.rcvif->if_index);
1216 if (IN6_IS_ADDR_LINKLOCAL(&t))
1217 t.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
1218
1219 #ifdef COMPAT_RFC1885
1220 /*
1221 * xxx guess MTU
1222 * RFC 1885 requires that echo reply should be truncated if it
1223 * does not fit in with (return) path MTU, but the description was
1224 * removed in the new spec.
1225 */
1226 if (icmp6_reflect_rt.ro_rt == 0 ||
1227 ! (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &ip6->ip6_dst))) {
1228 if (icmp6_reflect_rt.ro_rt) {
1229 #ifdef __FreeBSD__
1230 RTFREE(icmp6_reflect_rt.ro_rt);
1231 #endif
1232 #ifdef __bsdi__
1233 rtfree(icmp6_reflect_rt.ro_rt);
1234 #endif
1235 icmp6_reflect_rt.ro_rt = 0;
1236 }
1237 bzero(sin6, sizeof(*sin6));
1238 sin6->sin6_family = PF_INET6;
1239 sin6->sin6_len = sizeof(struct sockaddr_in6);
1240 sin6->sin6_addr = ip6->ip6_dst;
1241
1242 #ifdef __NetBSD__
1243 rtalloc((struct route *)&icmp6_reflect_rt.ro_rt);
1244 #else
1245 rtalloc_ign((struct route *)&icmp6_reflect_rt.ro_rt,
1246 RTF_PRCLONING);
1247 #endif
1248 }
1249
1250 if (icmp6_reflect_rt.ro_rt == 0)
1251 goto bad;
1252
1253 if ((icmp6_reflect_rt.ro_rt->rt_flags & RTF_HOST)
1254 && mtu < icmp6_reflect_rt.ro_rt->rt_ifp->if_mtu)
1255 mtu = icmp6_reflect_rt.ro_rt->rt_rmx.rmx_mtu;
1256
1257 if (mtu < m->m_pkthdr.len) {
1258 plen -= (m->m_pkthdr.len - mtu);
1259 m_adj(m, mtu - m->m_pkthdr.len);
1260 }
1261 #endif
1262 /*
1263 * If the incoming packet was addressed directly to us(i.e. unicast),
1264 * use dst as the src for the reply.
1265 */
1266 for (ia = in6_ifaddr; ia; ia = ia->ia_next)
1267 if (IN6_ARE_ADDR_EQUAL(&t, &ia->ia_addr.sin6_addr) &&
1268 (ia->ia6_flags & IN6_IFF_ANYCAST) == 0) {
1269 src = &t;
1270 break;
1271 }
1272 if (ia == NULL && IN6_IS_ADDR_LINKLOCAL(&t) && (m->m_flags & M_LOOP)) {
1273 /*
1274 * This is the case if the dst is our link-local address
1275 * and the sender is also ourseleves.
1276 */
1277 src = &t;
1278 }
1279
1280 if (src == 0)
1281 /*
1282 * We have not multicast routing yet. So this case matches
1283 * to our multicast, our anycast or not to our unicast.
1284 * Select a source address which has the same scope.
1285 */
1286 if ((ia = in6_ifawithscope(m->m_pkthdr.rcvif, &t)) != 0)
1287 src = &IA6_SIN6(ia)->sin6_addr;
1288
1289 if (src == 0)
1290 goto bad;
1291
1292 ip6->ip6_src = *src;
1293
1294 ip6->ip6_flow = 0;
1295 ip6->ip6_vfc = IPV6_VERSION;
1296 ip6->ip6_nxt = IPPROTO_ICMPV6;
1297 if (m->m_pkthdr.rcvif) {
1298 /* XXX: This may not be the outgoing interface */
1299 ip6->ip6_hlim = nd_ifinfo[m->m_pkthdr.rcvif->if_index].chlim;
1300 }
1301
1302 icmp6->icmp6_cksum = 0;
1303 icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6,
1304 sizeof(struct ip6_hdr), plen);
1305
1306 /*
1307 * xxx option handling
1308 */
1309
1310 m->m_flags &= ~(M_BCAST|M_MCAST);
1311 #ifdef IPSEC
1312 m->m_pkthdr.rcvif = NULL;
1313 #endif /*IPSEC*/
1314
1315 #ifdef COMPAT_RFC1885
1316 ip6_output(m, NULL, &icmp6_reflect_rt, 0, NULL);
1317 #else
1318 ip6_output(m, NULL, NULL, 0, NULL);
1319 #endif
1320
1321 return;
1322
1323 bad:
1324 m_freem(m);
1325 return;
1326 }
1327
1328 void
1329 icmp6_fasttimo()
1330 {
1331 mld6_fasttimeo();
1332 }
1333
1334 void
1335 icmp6_redirect_input(m, off)
1336 register struct mbuf *m;
1337 int off;
1338 {
1339 struct ifnet *ifp = m->m_pkthdr.rcvif;
1340 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1341 struct nd_redirect *nd_rd = (struct nd_redirect *)((caddr_t)ip6 + off);
1342 int icmp6len = ntohs(ip6->ip6_plen);
1343 char *lladdr = NULL;
1344 int lladdrlen = 0;
1345 u_char *redirhdr = NULL;
1346 int redirhdrlen = 0;
1347 struct rtentry *rt = NULL;
1348 int is_router;
1349 int is_onlink;
1350 struct in6_addr src6 = ip6->ip6_src;
1351 struct in6_addr redtgt6 = nd_rd->nd_rd_target;
1352 struct in6_addr reddst6 = nd_rd->nd_rd_dst;
1353 union nd_opts ndopts;
1354
1355 if (!m || !ifp)
1356 return;
1357
1358 /* XXX if we are router, we don't update route by icmp6 redirect */
1359 if (ip6_forwarding)
1360 return;
1361 if (!icmp6_rediraccept)
1362 return;
1363
1364 if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
1365 redtgt6.s6_addr16[1] = htons(ifp->if_index);
1366 if (IN6_IS_ADDR_LINKLOCAL(&reddst6))
1367 reddst6.s6_addr16[1] = htons(ifp->if_index);
1368
1369 /* validation */
1370 if (!IN6_IS_ADDR_LINKLOCAL(&src6)) {
1371 log(LOG_ERR,
1372 "ICMP6 redirect sent from %s rejected; "
1373 "must be from linklocal\n", ip6_sprintf(&src6));
1374 return;
1375 }
1376 if (ip6->ip6_hlim != 255) {
1377 log(LOG_ERR,
1378 "ICMP6 redirect sent from %s rejected; "
1379 "hlim=%d (must be 255)\n",
1380 ip6_sprintf(&src6), ip6->ip6_hlim);
1381 return;
1382 }
1383 {
1384 /* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */
1385 struct sockaddr_in6 sin6;
1386 struct in6_addr *gw6;
1387
1388 bzero(&sin6, sizeof(sin6));
1389 sin6.sin6_family = AF_INET6;
1390 sin6.sin6_len = sizeof(struct sockaddr_in6);
1391 bcopy(&reddst6, &sin6.sin6_addr, sizeof(reddst6));
1392 rt = rtalloc1((struct sockaddr *)&sin6, 0
1393 #ifdef __FreeBSD__
1394 , 0UL
1395 #endif
1396 );
1397 if (rt) {
1398 gw6 = &(((struct sockaddr_in6 *)rt->rt_gateway)->sin6_addr);
1399 if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) {
1400 log(LOG_ERR,
1401 "ICMP6 redirect sent from %s rejected; "
1402 "ip src=%s, gw for %s=%s (must be same)\n",
1403 ip6_sprintf(&src6), ip6_sprintf(&src6),
1404 ip6_sprintf(&reddst6), ip6_sprintf(gw6));
1405 RTFREE(rt);
1406 return;
1407 }
1408 } else {
1409 log(LOG_ERR,
1410 "ICMP6 redirect sent from %s rejected; "
1411 "no route found for redirect destination %s\n",
1412 ip6_sprintf(&src6), ip6_sprintf(&reddst6));
1413 return;
1414 }
1415 RTFREE(rt);
1416 rt = NULL;
1417 }
1418 if (IN6_IS_ADDR_MULTICAST(&reddst6)) {
1419 log(LOG_ERR,
1420 "ICMP6 redirect sent from %s rejected; "
1421 "redirect destination=%s (must be unicast)\n",
1422 ip6_sprintf(&src6), ip6_sprintf(&reddst6));
1423 return;
1424 }
1425
1426 is_router = is_onlink = 0;
1427 if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
1428 is_router = 1; /* router case */
1429 if (bcmp(&redtgt6, &reddst6, sizeof(redtgt6)) == 0)
1430 is_onlink = 1; /* on-link destination case */
1431 if (!is_router && !is_onlink) {
1432 log(LOG_ERR,
1433 "ICMP6 redirect sent from %s rejected; "
1434 "redirect target=%s, destination=%s\n",
1435 ip6_sprintf(&src6), ip6_sprintf(&redtgt6),
1436 ip6_sprintf(&reddst6));
1437 return;
1438 }
1439 /* validation passed */
1440
1441 icmp6len -= sizeof(*nd_rd);
1442 nd6_option_init(nd_rd + 1, icmp6len, &ndopts);
1443 if (nd6_options(&ndopts) < 0) {
1444 log(LOG_INFO, "icmp6_redirect_input: "
1445 "invalid ND option, rejected\n");
1446 return;
1447 }
1448
1449 if (ndopts.nd_opts_tgt_lladdr) {
1450 lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
1451 lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
1452 }
1453
1454 if (ndopts.nd_opts_rh) {
1455 redirhdrlen = ndopts.nd_opts_rh->nd_opt_rh_len;
1456 redirhdr = (u_char *)(ndopts.nd_opts_rh + 1); /* xxx */
1457 }
1458
1459 if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
1460 log(LOG_INFO,
1461 "icmp6_redirect_input: lladdrlen mismatch for %s "
1462 "(if %d, icmp6 packet %d)\n",
1463 ip6_sprintf(&redtgt6), ifp->if_addrlen, lladdrlen - 2);
1464 }
1465
1466 /* RFC 2461 8.3 */
1467 nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT);
1468
1469 if (!is_onlink) { /* better router case. perform rtredirect. */
1470 /* perform rtredirect */
1471 struct sockaddr_in6 sdst;
1472 struct sockaddr_in6 sgw;
1473 struct sockaddr_in6 ssrc;
1474 #ifdef __bsdi__
1475 extern int icmp_redirtimeout; /*XXX*/
1476 #endif
1477
1478 bzero(&sdst, sizeof(sdst));
1479 bzero(&sgw, sizeof(sgw));
1480 bzero(&ssrc, sizeof(ssrc));
1481 sdst.sin6_family = sgw.sin6_family = ssrc.sin6_family = AF_INET6;
1482 sdst.sin6_len = sgw.sin6_len = ssrc.sin6_len =
1483 sizeof(struct sockaddr_in6);
1484 bcopy(&redtgt6, &sgw.sin6_addr, sizeof(struct in6_addr));
1485 bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
1486 bcopy(&src6, &ssrc.sin6_addr, sizeof(struct in6_addr));
1487 rtredirect((struct sockaddr *)&sdst, (struct sockaddr *)&sgw,
1488 (struct sockaddr *)NULL, RTF_GATEWAY | RTF_HOST,
1489 (struct sockaddr *)&ssrc,
1490 #if defined(__FreeBSD__) || defined(__NetBSD__)
1491 (struct rtentry **)NULL
1492 #elif defined(__bsdi__)
1493 icmp_redirtimeout /*XXX*/
1494 #endif /*__FreeBSD__, __NetBSD__, __bsdi__*/
1495 );
1496 }
1497 /* finally update cached route in each socket via pfctlinput */
1498 {
1499 struct sockaddr_in6 sdst;
1500
1501 bzero(&sdst, sizeof(sdst));
1502 sdst.sin6_family = AF_INET6;
1503 sdst.sin6_len = sizeof(struct sockaddr_in6);
1504 bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
1505 pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst);
1506 #ifdef IPSEC
1507 key_sa_routechange((struct sockaddr *)&sdst);
1508 #endif
1509 }
1510 }
1511
1512 void
1513 icmp6_redirect_output(m0, rt)
1514 struct mbuf *m0;
1515 struct rtentry *rt;
1516 {
1517 struct ifnet *ifp; /* my outgoing interface */
1518 struct in6_addr *ifp_ll6;
1519 struct in6_addr *router_ll6;
1520 struct ip6_hdr *sip6; /* m0 as struct ip6_hdr */
1521 struct mbuf *m = NULL; /* newly allocated one */
1522 struct ip6_hdr *ip6; /* m as struct ip6_hdr */
1523 struct nd_redirect *nd_rd;
1524 size_t maxlen;
1525 u_char *p;
1526
1527 /* if we are not router, we don't send icmp6 redirect */
1528 if (!ip6_forwarding || ip6_accept_rtadv)
1529 goto fail;
1530
1531 /* sanity check */
1532 if (!m0 || !rt || !(rt->rt_flags & RTF_UP) || !(ifp = rt->rt_ifp))
1533 goto fail;
1534
1535 /*
1536 * Address check:
1537 * the source address must identify a neighbor, and
1538 * the destination address must not be a multicast address
1539 * [RFC 2461, sec 8.2]
1540 */
1541 sip6 = mtod(m0, struct ip6_hdr *);
1542 if (nd6_is_addr_neighbor(&sip6->ip6_src, ifp) == 0)
1543 goto fail;
1544 if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst))
1545 goto fail; /* what should we do here? */
1546
1547 /* rate limit */
1548 if (icmp6_ratelimit(&sip6->ip6_src, ND_REDIRECT, 0))
1549 goto fail;
1550
1551 /*
1552 * Since we are going to append up to 1280 bytes (= IPV6_MMTU),
1553 * we almost always ask for an mbuf cluster for simplicity.
1554 * (MHLEN < IPV6_MMTU is almost always true)
1555 */
1556 MGETHDR(m, M_DONTWAIT, MT_HEADER);
1557 if (!m)
1558 goto fail;
1559 if (MHLEN < IPV6_MMTU)
1560 MCLGET(m, M_DONTWAIT);
1561 maxlen = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN;
1562 maxlen = min(IPV6_MMTU, maxlen);
1563 /* just for safety */
1564 if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
1565 goto fail;
1566
1567 {
1568 /* get ip6 linklocal address for ifp(my outgoing interface). */
1569 struct in6_ifaddr *ia = in6ifa_ifpforlinklocal(ifp);
1570 if (ia == NULL)
1571 goto fail;
1572 ifp_ll6 = &ia->ia_addr.sin6_addr;
1573 }
1574
1575 /* get ip6 linklocal address for the router. */
1576 if (rt->rt_gateway && (rt->rt_flags & RTF_GATEWAY)) {
1577 struct sockaddr_in6 *sin6;
1578 sin6 = (struct sockaddr_in6 *)rt->rt_gateway;
1579 router_ll6 = &sin6->sin6_addr;
1580 if (!IN6_IS_ADDR_LINKLOCAL(router_ll6))
1581 router_ll6 = (struct in6_addr *)NULL;
1582 } else
1583 router_ll6 = (struct in6_addr *)NULL;
1584
1585 /* ip6 */
1586 ip6 = mtod(m, struct ip6_hdr *);
1587 ip6->ip6_flow = 0;
1588 ip6->ip6_vfc = IPV6_VERSION;
1589 /* ip6->ip6_plen will be set later */
1590 ip6->ip6_nxt = IPPROTO_ICMPV6;
1591 ip6->ip6_hlim = 255;
1592 /* ip6->ip6_src must be linklocal addr for my outgoing if. */
1593 bcopy(ifp_ll6, &ip6->ip6_src, sizeof(struct in6_addr));
1594 bcopy(&sip6->ip6_src, &ip6->ip6_dst, sizeof(struct in6_addr));
1595
1596 /* ND Redirect */
1597 nd_rd = (struct nd_redirect *)(ip6 + 1);
1598 nd_rd->nd_rd_type = ND_REDIRECT;
1599 nd_rd->nd_rd_code = 0;
1600 nd_rd->nd_rd_reserved = 0;
1601 if (rt->rt_flags & RTF_GATEWAY) {
1602 /*
1603 * nd_rd->nd_rd_target must be a link-local address in
1604 * better router cases.
1605 */
1606 if (!router_ll6)
1607 goto fail;
1608 bcopy(router_ll6, &nd_rd->nd_rd_target,
1609 sizeof(nd_rd->nd_rd_target));
1610 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
1611 sizeof(nd_rd->nd_rd_dst));
1612 } else {
1613 /* make sure redtgt == reddst */
1614 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_target,
1615 sizeof(nd_rd->nd_rd_target));
1616 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
1617 sizeof(nd_rd->nd_rd_dst));
1618 }
1619
1620 p = (u_char *)(nd_rd + 1);
1621
1622 if (!router_ll6)
1623 goto nolladdropt;
1624
1625 {
1626 /* target lladdr option */
1627 struct rtentry *rt_router = NULL;
1628 int len;
1629 struct sockaddr_dl *sdl;
1630 struct nd_opt_hdr *nd_opt;
1631 char *lladdr;
1632
1633 rt_router = nd6_lookup(router_ll6, 0, ifp);
1634 if (!rt_router)
1635 goto nolladdropt;
1636 if (!(rt_router->rt_flags & RTF_GATEWAY)
1637 && (rt_router->rt_flags & RTF_LLINFO)
1638 && (rt_router->rt_gateway->sa_family == AF_LINK)
1639 && (sdl = (struct sockaddr_dl *)rt_router->rt_gateway)) {
1640 nd_opt = (struct nd_opt_hdr *)p;
1641 nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
1642 len = 2 + ifp->if_addrlen;
1643 len = (len + 7) & ~7; /*round by 8*/
1644 nd_opt->nd_opt_len = len >> 3;
1645 p += len;
1646 lladdr = (char *)(nd_opt + 1);
1647 bcopy(LLADDR(sdl), lladdr, ifp->if_addrlen);
1648 }
1649 }
1650 nolladdropt:;
1651
1652 m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
1653
1654 /* just to be safe */
1655 if (m0->m_flags & M_DECRYPTED)
1656 goto noredhdropt;
1657
1658 {
1659 /* redirected header option */
1660 int len;
1661 struct nd_opt_rd_hdr *nd_opt_rh;
1662
1663 /*
1664 * compute the maximum size for icmp6 redirect header option.
1665 * XXX room for auth header?
1666 */
1667 len = maxlen - (p - (u_char *)ip6);
1668 len &= ~7;
1669
1670 /* This is just for simplicity. */
1671 if (m0->m_pkthdr.len != m0->m_len) {
1672 if (m0->m_next) {
1673 m_freem(m0->m_next);
1674 m0->m_next = NULL;
1675 }
1676 m0->m_pkthdr.len = m0->m_len;
1677 }
1678
1679 /*
1680 * Redirected header option spec (RFC2461 4.6.3) talks nothing
1681 * about padding/trancate rule for the original IP packet.
1682 * From the discussion on IPv6imp in Feb 1999, the consensus was:
1683 * - "attach as much as possible" is the goal
1684 * - pad if not aligned (original size can be guessed by original
1685 * ip6 header)
1686 * Following code adds the padding if it is simple enough,
1687 * and truncates if not.
1688 */
1689 if (m0->m_next || m0->m_pkthdr.len != m0->m_len)
1690 panic("assumption failed in %s:%d\n", __FILE__, __LINE__);
1691
1692 if (len - sizeof(*nd_opt_rh) < m0->m_pkthdr.len) {
1693 /* not enough room, truncate */
1694 m0->m_pkthdr.len = m0->m_len = len - sizeof(*nd_opt_rh);
1695 } else {
1696 /* enough room, pad or truncate */
1697 size_t extra;
1698
1699 extra = m0->m_pkthdr.len % 8;
1700 if (extra) {
1701 /* pad if easy enough, truncate if not */
1702 if (8 - extra <= M_TRAILINGSPACE(m0)) {
1703 /* pad */
1704 m0->m_len += (8 - extra);
1705 m0->m_pkthdr.len += (8 - extra);
1706 } else {
1707 /* truncate */
1708 m0->m_pkthdr.len -= extra;
1709 m0->m_len -= extra;
1710 }
1711 }
1712 len = m0->m_pkthdr.len + sizeof(*nd_opt_rh);
1713 m0->m_pkthdr.len = m0->m_len = len - sizeof(*nd_opt_rh);
1714 }
1715
1716 nd_opt_rh = (struct nd_opt_rd_hdr *)p;
1717 bzero(nd_opt_rh, sizeof(*nd_opt_rh));
1718 nd_opt_rh->nd_opt_rh_type = ND_OPT_REDIRECTED_HEADER;
1719 nd_opt_rh->nd_opt_rh_len = len >> 3;
1720 p += sizeof(*nd_opt_rh);
1721 m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
1722
1723 /* connect m0 to m */
1724 m->m_next = m0;
1725 m->m_pkthdr.len = m->m_len + m0->m_len;
1726 }
1727 noredhdropt:;
1728
1729 if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_src))
1730 sip6->ip6_src.s6_addr16[1] = 0;
1731 if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_dst))
1732 sip6->ip6_dst.s6_addr16[1] = 0;
1733 #if 0
1734 if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src))
1735 ip6->ip6_src.s6_addr16[1] = 0;
1736 if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst))
1737 ip6->ip6_dst.s6_addr16[1] = 0;
1738 #endif
1739 if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_target))
1740 nd_rd->nd_rd_target.s6_addr16[1] = 0;
1741 if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_dst))
1742 nd_rd->nd_rd_dst.s6_addr16[1] = 0;
1743
1744 ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
1745
1746 nd_rd->nd_rd_cksum = 0;
1747 nd_rd->nd_rd_cksum
1748 = in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), ntohs(ip6->ip6_plen));
1749
1750 /* send the packet to outside... */
1751 #ifdef IPSEC
1752 m->m_pkthdr.rcvif = NULL;
1753 #endif /*IPSEC*/
1754 ip6_output(m, NULL, NULL, 0, NULL);
1755 icmp6stat.icp6s_outhist[ND_REDIRECT]++;
1756
1757 return;
1758
1759 fail:
1760 if (m)
1761 m_freem(m);
1762 if (m0)
1763 m_freem(m0);
1764 }
1765
1766 /*
1767 * ICMPv6 socket option processing.
1768 */
1769 int
1770 icmp6_ctloutput(op, so, level, optname, mp)
1771 int op;
1772 struct socket *so;
1773 int level, optname;
1774 struct mbuf **mp;
1775 {
1776 register struct in6pcb *in6p = sotoin6pcb(so);
1777 register struct mbuf *m = *mp;
1778 int error = 0;
1779
1780 if (level != IPPROTO_ICMPV6) {
1781 error = EINVAL;
1782 if (op == PRCO_SETOPT && m)
1783 (void)m_free(m);
1784 } else switch(op) {
1785 case PRCO_SETOPT:
1786 switch (optname) {
1787 case ICMP6_FILTER:
1788 {
1789 struct icmp6_filter *p;
1790
1791 p = mtod(m, struct icmp6_filter *);
1792 if (!p || !in6p->in6p_icmp6filt) {
1793 error = EINVAL;
1794 break;
1795 }
1796 bcopy(p, in6p->in6p_icmp6filt,
1797 sizeof(struct icmp6_filter));
1798 error = 0;
1799 break;
1800 }
1801
1802 default:
1803 error = ENOPROTOOPT;
1804 break;
1805 }
1806 if (m)
1807 (void)m_free(m);
1808 break;
1809
1810 case PRCO_GETOPT:
1811 switch (optname) {
1812 case ICMP6_FILTER:
1813 {
1814 struct icmp6_filter *p;
1815
1816 p = mtod(m, struct icmp6_filter *);
1817 if (!p || !in6p->in6p_icmp6filt) {
1818 error = EINVAL;
1819 break;
1820 }
1821 bcopy(in6p->in6p_icmp6filt, p,
1822 sizeof(struct icmp6_filter));
1823 error = 0;
1824 break;
1825 }
1826
1827 default:
1828 error = ENOPROTOOPT;
1829 break;
1830 }
1831 break;
1832 }
1833
1834 return(error);
1835 }
1836
1837 /*
1838 * Perform rate limit check.
1839 * Returns 0 if it is okay to send the icmp6 packet.
1840 * Returns 1 if the router SHOULD NOT send this icmp6 packet due to rate
1841 * limitation.
1842 *
1843 * XXX per-destination/type check necessary?
1844 */
1845 static int
1846 icmp6_ratelimit(dst, type, code)
1847 const struct in6_addr *dst; /* not used at this moment */
1848 const int type; /* not used at this moment */
1849 const int code; /* not used at this moment */
1850 {
1851 struct timeval tp;
1852 long sec_diff, usec_diff;
1853
1854 /* If we are not doing rate limitation, it is always okay to send */
1855 if (!icmp6errratelim)
1856 return 0;
1857
1858 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
1859 microtime(&tp);
1860 tp.tv_sec = time_second;
1861 #else
1862 tp = time;
1863 #endif
1864 if (tp.tv_sec < icmp6_nextsend.tv_sec
1865 || (tp.tv_sec == icmp6_nextsend.tv_sec
1866 && tp.tv_usec < icmp6_nextsend.tv_usec)) {
1867 /* The packet is subject to rate limit */
1868 return 1;
1869 }
1870 sec_diff = icmp6errratelim / 1000000;
1871 usec_diff = icmp6errratelim % 1000000;
1872 icmp6_nextsend.tv_sec = tp.tv_sec + sec_diff;
1873 if ((tp.tv_usec = tp.tv_usec + usec_diff) >= 1000000) {
1874 icmp6_nextsend.tv_sec++;
1875 icmp6_nextsend.tv_usec -= 1000000;
1876 }
1877
1878 /* it is okay to send this */
1879 return 0;
1880 }
1881
1882 #ifdef __NetBSD__
1883 static struct rtentry *
1884 icmp6_mtudisc_clone(dst)
1885 struct sockaddr *dst;
1886 {
1887 struct rtentry *rt;
1888 int error;
1889
1890 rt = rtalloc1(dst, 1);
1891 if (rt == 0)
1892 return NULL;
1893
1894 /* If we didn't get a host route, allocate one */
1895 if ((rt->rt_flags & RTF_HOST) == 0) {
1896 struct rtentry *nrt;
1897
1898 error = rtrequest((int) RTM_ADD, dst,
1899 (struct sockaddr *) rt->rt_gateway,
1900 (struct sockaddr *) 0,
1901 RTF_GATEWAY | RTF_HOST | RTF_DYNAMIC, &nrt);
1902 if (error) {
1903 rtfree(rt);
1904 rtfree(nrt);
1905 return NULL;
1906 }
1907 nrt->rt_rmx = rt->rt_rmx;
1908 rtfree(rt);
1909 rt = nrt;
1910 }
1911 error = rt_timer_add(rt, icmp6_mtudisc_timeout,
1912 icmp6_mtudisc_timeout_q);
1913 if (error) {
1914 rtfree(rt);
1915 return NULL;
1916 }
1917
1918 return rt; /* caller need to call rtfree() */
1919 }
1920
1921 static void
1922 icmp6_mtudisc_timeout(rt, r)
1923 struct rtentry *rt;
1924 struct rttimer *r;
1925 {
1926 if (rt == NULL)
1927 panic("icmp6_mtudisc_timeout: bad route to timeout");
1928 if ((rt->rt_flags & (RTF_DYNAMIC | RTF_HOST)) ==
1929 (RTF_DYNAMIC | RTF_HOST)) {
1930 rtrequest((int) RTM_DELETE, (struct sockaddr *)rt_key(rt),
1931 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
1932 } else {
1933 if ((rt->rt_rmx.rmx_locks & RTV_MTU) == 0) {
1934 rt->rt_rmx.rmx_mtu = 0;
1935 }
1936 }
1937 }
1938 #endif /*__NetBSD__*/
1939
1940 #ifdef __bsdi__
1941 void
1942 icmp6_mtuexpire(rt, rtt)
1943 struct rtentry *rt;
1944 struct rttimer *rtt;
1945 {
1946 rt->rt_flags |= RTF_PROBEMTU;
1947 Free(rtt);
1948 }
1949
1950 int *icmp6_sysvars[] = ICMPV6CTL_VARS;
1951
1952 int
1953 icmp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
1954 int *name;
1955 u_int namelen;
1956 void *oldp;
1957 size_t *oldlenp;
1958 void *newp;
1959 size_t newlen;
1960 {
1961 if (name[0] >= ICMPV6CTL_MAXID)
1962 return (EOPNOTSUPP);
1963 switch (name[0]) {
1964 #if 0
1965 ICMPV6CTL_ND6_PRUNE:
1966 ICMPV6CTL_ND6_DELAY:
1967 ICMPV6CTL_ND6_UMAXTRIES:
1968 ICMPV6CTL_ND6_MMAXTRIES:
1969 ICMPV6CTL_ND6_USELOOPBACK:
1970 ICMPV6CTL_ND6_PROXYALL:
1971 /* need to check the value. */
1972 #endif
1973 case ICMPV6CTL_STATS:
1974 return sysctl_rdtrunc(oldp, oldlenp, newp, &icmp6stat,
1975 sizeof(icmp6stat));
1976
1977 default:
1978 return (sysctl_int_arr(icmp6_sysvars, name, namelen,
1979 oldp, oldlenp, newp, newlen));
1980 }
1981 }
1982 #endif /*__bsdi__*/
1983
1984 #ifdef __NetBSD__
1985 #include <vm/vm.h>
1986 #include <sys/sysctl.h>
1987 int
1988 icmp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
1989 int *name;
1990 u_int namelen;
1991 void *oldp;
1992 size_t *oldlenp;
1993 void *newp;
1994 size_t newlen;
1995 {
1996
1997 /* All sysctl names at this level are terminal. */
1998 if (namelen != 1)
1999 return ENOTDIR;
2000
2001 switch (name[0]) {
2002
2003 case ICMPV6CTL_REDIRACCEPT:
2004 return sysctl_int(oldp, oldlenp, newp, newlen,
2005 &icmp6_rediraccept);
2006 case ICMPV6CTL_REDIRTIMEOUT:
2007 return sysctl_int(oldp, oldlenp, newp, newlen,
2008 &icmp6_redirtimeout);
2009 case ICMPV6CTL_STATS:
2010 return sysctl_rdstruct(oldp, oldlenp, newp,
2011 &icmp6stat, sizeof(icmp6stat));
2012 case ICMPV6CTL_ERRRATELIMIT:
2013 return sysctl_int(oldp, oldlenp, newp, newlen,
2014 &icmp6errratelim);
2015 case ICMPV6CTL_ND6_PRUNE:
2016 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_prune);
2017 case ICMPV6CTL_ND6_DELAY:
2018 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_delay);
2019 case ICMPV6CTL_ND6_UMAXTRIES:
2020 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_umaxtries);
2021 case ICMPV6CTL_ND6_MMAXTRIES:
2022 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_mmaxtries);
2023 case ICMPV6CTL_ND6_USELOOPBACK:
2024 return sysctl_int(oldp, oldlenp, newp, newlen,
2025 &nd6_useloopback);
2026 case ICMPV6CTL_ND6_PROXYALL:
2027 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_proxyall);
2028 default:
2029 return ENOPROTOOPT;
2030 }
2031 /* NOTREACHED */
2032 }
2033 #endif /* __NetBSD__ */
2034