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