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