]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/icmp6.c
xnu-6153.121.1.tar.gz
[apple/xnu.git] / bsd / netinet6 / icmp6.c
CommitLineData
b0d623f7 1/*
0a7de745 2 * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
b0d623f7
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
39037602 5 *
b0d623f7
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
39037602 14 *
b0d623f7
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
39037602 17 *
b0d623f7
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
39037602 25 *
b0d623f7
A
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
9bccf70c
A
29/* $FreeBSD: src/sys/netinet6/icmp6.c,v 1.6.2.6 2001/07/10 09:44:16 ume Exp $ */
30/* $KAME: icmp6.c,v 1.211 2001/04/04 05:56:20 itojun Exp $ */
1c79356b
A
31
32/*
33 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
34 * 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. Neither the name of the project nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 */
60
61/*
62 * Copyright (c) 1982, 1986, 1988, 1993
63 * The Regents of the University of California. All rights reserved.
64 *
65 * Redistribution and use in source and binary forms, with or without
66 * modification, are permitted provided that the following conditions
67 * are met:
68 * 1. Redistributions of source code must retain the above copyright
69 * notice, this list of conditions and the following disclaimer.
70 * 2. Redistributions in binary form must reproduce the above copyright
71 * notice, this list of conditions and the following disclaimer in the
72 * documentation and/or other materials provided with the distribution.
73 * 3. All advertising materials mentioning features or use of this software
74 * must display the following acknowledgement:
75 * This product includes software developed by the University of
76 * California, Berkeley and its contributors.
77 * 4. Neither the name of the University nor the names of its contributors
78 * may be used to endorse or promote products derived from this software
79 * without specific prior written permission.
80 *
81 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
82 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
83 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
84 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
85 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
86 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
87 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
88 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
89 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
90 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
91 * SUCH DAMAGE.
92 *
93 * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94
94 */
95
1c79356b
A
96
97#include <sys/param.h>
98#include <sys/systm.h>
91447636 99#include <sys/lock.h>
1c79356b 100#include <sys/malloc.h>
316670eb 101#include <sys/mcache.h>
1c79356b
A
102#include <sys/mbuf.h>
103#include <sys/protosw.h>
104#include <sys/socket.h>
105#include <sys/socketvar.h>
106#include <sys/time.h>
107#include <sys/kernel.h>
108#include <sys/syslog.h>
109#include <sys/domain.h>
316670eb 110#include <sys/kauth.h>
1c79356b
A
111
112#include <net/if.h>
113#include <net/route.h>
114#include <net/if_dl.h>
115#include <net/if_types.h>
116
117#include <netinet/in.h>
118#include <netinet/in_var.h>
1c79356b
A
119#include <netinet/ip6.h>
120#include <netinet6/ip6_var.h>
121#include <netinet/icmp6.h>
122#include <netinet6/mld6_var.h>
1c79356b 123#include <netinet/in_pcb.h>
9bccf70c 124#include <netinet6/in6_pcb.h>
39236c6e 125#include <netinet6/in6_var.h>
1c79356b
A
126#include <netinet6/nd6.h>
127#include <netinet6/in6_ifattach.h>
128#include <netinet6/ip6protosw.h>
6d2010ae 129#include <netinet6/scope6_var.h>
1c79356b 130
1c79356b
A
131#if IPSEC
132#include <netinet6/ipsec.h>
133#include <netkey/key.h>
1c79356b
A
134#endif
135
1c79356b
A
136#include <net/net_osdep.h>
137
fe8ab488
A
138#if NECP
139#include <net/necp.h>
140#endif
141
1c79356b
A
142extern struct ip6protosw *ip6_protox[];
143
b0d623f7
A
144extern uint32_t rip_sendspace;
145extern uint32_t rip_recvspace;
2d21ac55 146
1c79356b
A
147struct icmp6stat icmp6stat;
148
1c79356b 149extern struct inpcbhead ripcb;
9bccf70c 150extern int icmp6errppslim;
fe8ab488 151extern int icmp6rappslim;
9bccf70c 152static int icmp6errpps_count = 0;
fe8ab488 153static int icmp6rapps_count = 0;
9bccf70c 154static struct timeval icmp6errppslim_last;
fe8ab488 155static struct timeval icmp6rappslim_last;
1c79356b 156extern int icmp6_nodeinfo;
91447636 157extern struct inpcbinfo ripcbinfo;
91447636
A
158
159static void icmp6_errcount(struct icmp6errstat *, int, int);
160static int icmp6_rip6_input(struct mbuf **, int);
161static int icmp6_ratelimit(const struct in6_addr *, const int, const int);
162static const char *icmp6_redirect_diag(struct in6_addr *,
0a7de745 163 struct in6_addr *, struct in6_addr *);
91447636
A
164static struct mbuf *ni6_input(struct mbuf *, int);
165static struct mbuf *ni6_nametodns(const char *, int, int);
166static int ni6_dnsmatch(const char *, int, const char *, int);
743345f9 167static int ni6_addrs(struct icmp6_nodeinfo *,
0a7de745 168 struct ifnet **, char *);
91447636 169static int ni6_store_addrs(struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
0a7de745 170 struct ifnet *, int);
91447636 171static int icmp6_notify_error(struct mbuf *, int, int, int);
1c79356b 172
1c79356b 173
1c79356b
A
174
175void
39236c6e 176icmp6_init(struct ip6protosw *pp, struct domain *dp)
1c79356b 177{
39236c6e
A
178#pragma unused(dp)
179 static int icmp6_initialized = 0;
180
181 /* Also called from ip6_init() without pp */
182 VERIFY(pp == NULL ||
0a7de745 183 (pp->pr_flags & (PR_INITIALIZED | PR_ATTACHED)) == PR_ATTACHED);
39236c6e
A
184
185 /* This gets called by more than one protocols, so initialize once */
186 if (!icmp6_initialized) {
187 icmp6_initialized = 1;
188 mld_init();
189 }
9bccf70c
A
190}
191
192static void
39037602 193icmp6_errcount(struct icmp6errstat *stat, int type, int code)
9bccf70c
A
194{
195 switch (type) {
196 case ICMP6_DST_UNREACH:
197 switch (code) {
198 case ICMP6_DST_UNREACH_NOROUTE:
199 stat->icp6errs_dst_unreach_noroute++;
200 return;
201 case ICMP6_DST_UNREACH_ADMIN:
202 stat->icp6errs_dst_unreach_admin++;
203 return;
204 case ICMP6_DST_UNREACH_BEYONDSCOPE:
205 stat->icp6errs_dst_unreach_beyondscope++;
206 return;
207 case ICMP6_DST_UNREACH_ADDR:
208 stat->icp6errs_dst_unreach_addr++;
209 return;
210 case ICMP6_DST_UNREACH_NOPORT:
211 stat->icp6errs_dst_unreach_noport++;
212 return;
213 }
214 break;
215 case ICMP6_PACKET_TOO_BIG:
216 stat->icp6errs_packet_too_big++;
217 return;
218 case ICMP6_TIME_EXCEEDED:
219 switch (code) {
220 case ICMP6_TIME_EXCEED_TRANSIT:
221 stat->icp6errs_time_exceed_transit++;
222 return;
223 case ICMP6_TIME_EXCEED_REASSEMBLY:
224 stat->icp6errs_time_exceed_reassembly++;
225 return;
226 }
227 break;
228 case ICMP6_PARAM_PROB:
229 switch (code) {
230 case ICMP6_PARAMPROB_HEADER:
231 stat->icp6errs_paramprob_header++;
232 return;
233 case ICMP6_PARAMPROB_NEXTHEADER:
234 stat->icp6errs_paramprob_nextheader++;
235 return;
236 case ICMP6_PARAMPROB_OPTION:
237 stat->icp6errs_paramprob_option++;
238 return;
239 }
240 break;
241 case ND_REDIRECT:
242 stat->icp6errs_redirect++;
243 return;
244 }
245 stat->icp6errs_unknown++;
1c79356b
A
246}
247
6d2010ae
A
248/*
249 * A wrapper function for icmp6_error() necessary when the erroneous packet
250 * may not contain enough scope zone information.
251 */
252void
253icmp6_error2(struct mbuf *m, int type, int code, int param,
254 struct ifnet *ifp)
255{
256 struct ip6_hdr *ip6;
257
0a7de745 258 if (ifp == NULL) {
6d2010ae 259 return;
0a7de745 260 }
6d2010ae
A
261
262#ifndef PULLDOWN_TEST
0a7de745 263 IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), return );
6d2010ae
A
264#else
265 if (m->m_len < sizeof(struct ip6_hdr)) {
266 m = m_pullup(m, sizeof(struct ip6_hdr));
0a7de745 267 if (m == NULL) {
6d2010ae 268 return;
0a7de745 269 }
6d2010ae
A
270 }
271#endif
272
273 ip6 = mtod(m, struct ip6_hdr *);
274
0a7de745 275 if (in6_setscope(&ip6->ip6_src, ifp, NULL) != 0) {
6d2010ae 276 return;
0a7de745
A
277 }
278 if (in6_setscope(&ip6->ip6_dst, ifp, NULL) != 0) {
6d2010ae 279 return;
0a7de745 280 }
6d2010ae
A
281
282 icmp6_error(m, type, code, param);
283}
284
1c79356b
A
285/*
286 * Generate an error packet of type error in response to bad IP6 packet.
287 */
288void
0a7de745
A
289icmp6_error(struct mbuf *m, int type, int code, int param)
290{
3e170ce0
A
291 icmp6_error_flag(m, type, code, param, ICMP6_ERROR_RST_MRCVIF);
292}
293
0a7de745
A
294void
295icmp6_error_flag(struct mbuf *m, int type, int code, int param, int flags)
1c79356b
A
296{
297 struct ip6_hdr *oip6, *nip6;
298 struct icmp6_hdr *icmp6;
299 u_int preplen;
300 int off;
301 int nxt;
302
303 icmp6stat.icp6s_error++;
304
9bccf70c
A
305 /* count per-type-code statistics */
306 icmp6_errcount(&icmp6stat.icp6s_outerrhist, type, code);
307
0a7de745 308#ifdef M_DECRYPTED /*not openbsd*/
1c79356b
A
309 if (m->m_flags & M_DECRYPTED) {
310 icmp6stat.icp6s_canterror++;
311 goto freeit;
312 }
313#endif
314
315#ifndef PULLDOWN_TEST
0a7de745 316 IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), return );
1c79356b
A
317#else
318 if (m->m_len < sizeof(struct ip6_hdr)) {
319 m = m_pullup(m, sizeof(struct ip6_hdr));
0a7de745 320 if (m == NULL) {
1c79356b 321 return;
0a7de745 322 }
1c79356b
A
323 }
324#endif
325 oip6 = mtod(m, struct ip6_hdr *);
326
327 /*
6d2010ae
A
328 * If the destination address of the erroneous packet is a multicast
329 * address, or the packet was sent using link-layer multicast,
330 * we should basically suppress sending an error (RFC 2463, Section
331 * 2.4).
332 * We have two exceptions (the item e.2 in that section):
333 * - the Pakcet Too Big message can be sent for path MTU discovery.
334 * - the Parameter Problem Message that can be allowed an icmp6 error
335 * in the option type field. This check has been done in
336 * ip6_unknown_opt(), so we can just check the type and code.
1c79356b 337 */
0a7de745
A
338 if ((m->m_flags & (M_BCAST | M_MCAST) ||
339 IN6_IS_ADDR_MULTICAST(&oip6->ip6_dst)) &&
1c79356b 340 (type != ICMP6_PACKET_TOO_BIG &&
0a7de745
A
341 (type != ICMP6_PARAM_PROB ||
342 code != ICMP6_PARAMPROB_OPTION))) {
1c79356b 343 goto freeit;
0a7de745 344 }
1c79356b 345
6d2010ae
A
346 /*
347 * RFC 2463, 2.4 (e.5): source address check.
348 * XXX: the case of anycast source?
349 */
1c79356b 350 if (IN6_IS_ADDR_UNSPECIFIED(&oip6->ip6_src) ||
0a7de745 351 IN6_IS_ADDR_MULTICAST(&oip6->ip6_src)) {
1c79356b 352 goto freeit;
0a7de745 353 }
1c79356b
A
354
355 /*
356 * If we are about to send ICMPv6 against ICMPv6 error/redirect,
357 * don't do it.
358 */
359 nxt = -1;
360 off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
361 if (off >= 0 && nxt == IPPROTO_ICMPV6) {
362 struct icmp6_hdr *icp;
363
364#ifndef PULLDOWN_TEST
0a7de745 365 IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct icmp6_hdr), return );
1c79356b
A
366 icp = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
367#else
368 IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off,
0a7de745 369 sizeof(*icp));
1c79356b
A
370 if (icp == NULL) {
371 icmp6stat.icp6s_tooshort++;
372 return;
373 }
374#endif
375 if (icp->icmp6_type < ICMP6_ECHO_REQUEST ||
376 icp->icmp6_type == ND_REDIRECT) {
377 /*
378 * ICMPv6 error
379 * Special case: for redirect (which is
380 * informational) we must not send icmp6 error.
381 */
382 icmp6stat.icp6s_canterror++;
383 goto freeit;
384 } else {
385 /* ICMPv6 informational - send the error */
386 }
387 } else {
388 /* non-ICMPv6 - send the error */
389 }
390
391 oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */
392
393 /* Finally, do rate limitation check. */
394 if (icmp6_ratelimit(&oip6->ip6_src, type, code)) {
395 icmp6stat.icp6s_toofreq++;
396 goto freeit;
397 }
398
399 /*
400 * OK, ICMP6 can be generated.
401 */
402
0a7de745 403 if (m->m_pkthdr.len >= ICMPV6_PLD_MAXLEN) {
1c79356b 404 m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len);
0a7de745 405 }
1c79356b
A
406
407 preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
3e170ce0 408 M_PREPEND(m, preplen, M_DONTWAIT, 1);
0a7de745 409 if (m && m->m_len < preplen) {
1c79356b 410 m = m_pullup(m, preplen);
0a7de745 411 }
1c79356b 412 if (m == NULL) {
cb323159 413 nd6log(debug, "ENOBUFS in icmp6_error %d\n", __LINE__);
1c79356b
A
414 return;
415 }
416
417 nip6 = mtod(m, struct ip6_hdr *);
418 nip6->ip6_src = oip6->ip6_src;
419 nip6->ip6_dst = oip6->ip6_dst;
420
6d2010ae
A
421 in6_clearscope(&oip6->ip6_src);
422 in6_clearscope(&oip6->ip6_dst);
1c79356b
A
423
424 icmp6 = (struct icmp6_hdr *)(nip6 + 1);
425 icmp6->icmp6_type = type;
426 icmp6->icmp6_code = code;
427 icmp6->icmp6_pptr = htonl((u_int32_t)param);
428
9bccf70c
A
429 /*
430 * icmp6_reflect() is designed to be in the input path.
6d2010ae 431 * icmp6_error() can be called from both input and output path,
9bccf70c
A
432 * and if we are in output path rcvif could contain bogus value.
433 * clear m->m_pkthdr.rcvif for safety, we should have enough scope
434 * information in ip header (nip6).
435 */
3e170ce0
A
436 if (flags & ICMP6_ERROR_RST_MRCVIF) {
437 m->m_pkthdr.rcvif = NULL;
438 }
9bccf70c 439
1c79356b 440 icmp6stat.icp6s_outhist[type]++;
55e303ae 441 icmp6_reflect(m, sizeof(struct ip6_hdr)); /* header order: IPv6 - ICMPv6 */
1c79356b
A
442
443 return;
444
0a7de745 445freeit:
1c79356b 446 /*
6d2010ae 447 * If we can't tell whether or not we can generate ICMP6, free it.
1c79356b
A
448 */
449 m_freem(m);
450}
451
452/*
453 * Process a received ICMP6 message.
454 */
455int
6d2010ae 456icmp6_input(struct mbuf **mp, int *offp, int proto)
1c79356b 457{
6d2010ae 458#pragma unused(proto)
1c79356b 459 struct mbuf *m = *mp, *n;
6d2010ae 460 struct ifnet *ifp;
1c79356b
A
461 struct ip6_hdr *ip6, *nip6;
462 struct icmp6_hdr *icmp6, *nicmp6;
463 int off = *offp;
464 int icmp6len = m->m_pkthdr.len - *offp;
316670eb 465 int code, sum, noff, proxy = 0;
1c79356b 466
6d2010ae
A
467 ifp = m->m_pkthdr.rcvif;
468
1c79356b 469#ifndef PULLDOWN_TEST
91447636 470 IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), return IPPROTO_DONE);
55e303ae 471 /* m might change if M_LOOP. So, call mtod after this */
1c79356b
A
472#endif
473
316670eb
A
474 /* Expect 32-bit aligned data pointer on strict-align platforms */
475 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
476
1c79356b
A
477 /*
478 * Locate icmp6 structure in mbuf, and check
479 * that not corrupted and of at least minimum length
480 */
1c79356b
A
481 ip6 = mtod(m, struct ip6_hdr *);
482 if (icmp6len < sizeof(struct icmp6_hdr)) {
483 icmp6stat.icp6s_tooshort++;
484 goto freeit;
485 }
486
39236c6e
A
487#ifndef PULLDOWN_TEST
488 icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
489#else
490 IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
491 if (icmp6 == NULL) {
492 icmp6stat.icp6s_tooshort++;
493 return IPPROTO_DONE;
494 }
495#endif
496 code = icmp6->icmp6_code;
497
39037602
A
498 /*
499 * Early check for RFC 6980
500 * Drop certain NDP packets if they came in fragmented
501 */
502 switch (icmp6->icmp6_type) {
503 case ND_ROUTER_SOLICIT:
504 case ND_ROUTER_ADVERT:
505 case ND_NEIGHBOR_SOLICIT:
506 case ND_NEIGHBOR_ADVERT:
507 case ND_REDIRECT:
508 if (m->m_pkthdr.pkt_flags & PKTF_REASSEMBLED) {
509 icmp6stat.icp6s_rfc6980_drop++;
510 goto freeit;
511 }
512 break;
513 default:
514 break;
515 }
516
39236c6e
A
517 /* Apply rate limit before checksum validation. */
518 if (icmp6_ratelimit(&ip6->ip6_dst, icmp6->icmp6_type, code)) {
519 icmp6stat.icp6s_toofreq++;
520 goto freeit;
521 }
522
6d2010ae
A
523 /*
524 * Check multicast group membership.
525 * Note: SSM filters are not applied for ICMPv6 traffic.
526 */
527 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
0a7de745 528 struct in6_multi *inm;
6d2010ae
A
529
530 in6_multihead_lock_shared();
531 IN6_LOOKUP_MULTI(&ip6->ip6_dst, ifp, inm);
532 in6_multihead_lock_done();
533
534 if (inm == NULL) {
316670eb
A
535 /*
536 * Don't discard if this is a Neighbor Solicitation
537 * that needs to be proxied (see check down below.)
538 */
39236c6e 539 if (!(m->m_pkthdr.pkt_flags & PKTF_PROXY_DST)) {
316670eb
A
540 ip6stat.ip6s_notmember++;
541 in6_ifstat_inc(m->m_pkthdr.rcvif,
542 ifs6_in_discard);
543 goto freeit;
544 }
6d2010ae
A
545 } else {
546 IN6M_REMREF(inm);
547 }
548 }
549
1c79356b
A
550 /*
551 * calculate the checksum
552 */
1c79356b 553 if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) {
cb323159 554 nd6log(error,
1c79356b 555 "ICMP6 checksum error(%d|%x) %s\n",
cb323159 556 icmp6->icmp6_type, sum, ip6_sprintf(&ip6->ip6_src));
1c79356b
A
557 icmp6stat.icp6s_checksum++;
558 goto freeit;
559 }
560
39236c6e 561 if (m->m_pkthdr.pkt_flags & PKTF_PROXY_DST) {
1c79356b 562 /*
316670eb
A
563 * This is the special case of proxying NS (dst is either
564 * solicited-node multicast or unicast); process it locally
565 * but don't deliver it to sockets. It practically lets us
566 * steer the packet to nd6_prproxy_ns_input, where more
567 * specific tests and actions will be taken.
1c79356b
A
568 */
569 switch (icmp6->icmp6_type) {
316670eb
A
570 case ND_NEIGHBOR_SOLICIT:
571 proxy = 1;
1c79356b
A
572 break;
573 default:
574 goto freeit;
575 }
576 }
1c79356b 577
1c79356b
A
578 icmp6stat.icp6s_inhist[icmp6->icmp6_type]++;
579 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_msg);
0a7de745 580 if (icmp6->icmp6_type < ICMP6_INFOMSG_MASK) {
1c79356b 581 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error);
0a7de745 582 }
1c79356b 583
1c79356b 584 switch (icmp6->icmp6_type) {
1c79356b
A
585 case ICMP6_DST_UNREACH:
586 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_dstunreach);
587 switch (code) {
588 case ICMP6_DST_UNREACH_NOROUTE:
0a7de745 589 case ICMP6_DST_UNREACH_ADDR: /* PRC_HOSTDEAD is a DOS */
1c79356b
A
590 code = PRC_UNREACH_NET;
591 break;
592 case ICMP6_DST_UNREACH_ADMIN:
593 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_adminprohib);
594 code = PRC_UNREACH_PROTOCOL; /* is this a good code? */
595 break;
1c79356b
A
596 case ICMP6_DST_UNREACH_BEYONDSCOPE:
597 /* I mean "source address was incorrect." */
598 code = PRC_PARAMPROB;
599 break;
1c79356b
A
600 case ICMP6_DST_UNREACH_NOPORT:
601 code = PRC_UNREACH_PORT;
602 break;
603 default:
604 goto badcode;
605 }
606 goto deliver;
1c79356b
A
607
608 case ICMP6_PACKET_TOO_BIG:
609 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_pkttoobig);
1c79356b
A
610
611 code = PRC_MSGSIZE;
612
613 /*
614 * Updating the path MTU will be done after examining
615 * intermediate extension headers.
616 */
617 goto deliver;
1c79356b
A
618
619 case ICMP6_TIME_EXCEEDED:
620 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_timeexceed);
621 switch (code) {
622 case ICMP6_TIME_EXCEED_TRANSIT:
6d2010ae
A
623 code = PRC_TIMXCEED_INTRANS;
624 break;
1c79356b 625 case ICMP6_TIME_EXCEED_REASSEMBLY:
6d2010ae 626 code = PRC_TIMXCEED_REASS;
1c79356b
A
627 break;
628 default:
629 goto badcode;
630 }
631 goto deliver;
1c79356b
A
632
633 case ICMP6_PARAM_PROB:
634 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_paramprob);
635 switch (code) {
636 case ICMP6_PARAMPROB_NEXTHEADER:
637 code = PRC_UNREACH_PROTOCOL;
638 break;
639 case ICMP6_PARAMPROB_HEADER:
640 case ICMP6_PARAMPROB_OPTION:
641 code = PRC_PARAMPROB;
642 break;
643 default:
644 goto badcode;
645 }
646 goto deliver;
1c79356b
A
647
648 case ICMP6_ECHO_REQUEST:
649 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echo);
0a7de745 650 if (code != 0) {
1c79356b 651 goto badcode;
0a7de745 652 }
e2fac8b1 653
1c79356b
A
654 if ((n = m_copy(m, 0, M_COPYALL)) == NULL) {
655 /* Give up remote */
e2fac8b1 656 goto rate_limit_checked;
1c79356b
A
657 }
658 if ((n->m_flags & M_EXT) != 0
0a7de745 659 || n->m_len < off + sizeof(struct icmp6_hdr)) {
1c79356b
A
660 struct mbuf *n0 = n;
661 const int maxlen = sizeof(*nip6) + sizeof(*nicmp6);
662
663 /*
664 * Prepare an internal mbuf. m_pullup() doesn't
665 * always copy the length we specified.
666 */
667 if (maxlen >= MCLBYTES) {
1c79356b
A
668 /* Give up remote */
669 m_freem(n0);
e2fac8b1 670 goto rate_limit_checked;
1c79356b 671 }
0a7de745 672 MGETHDR(n, M_DONTWAIT, n0->m_type); /* MAC-OK */
1c79356b
A
673 if (n && maxlen >= MHLEN) {
674 MCLGET(n, M_DONTWAIT);
675 if ((n->m_flags & M_EXT) == 0) {
676 m_free(n);
677 n = NULL;
678 }
679 }
680 if (n == NULL) {
681 /* Give up remote */
682 m_freem(n0);
e2fac8b1 683 goto rate_limit_checked;
1c79356b
A
684 }
685 M_COPY_PKTHDR(n, n0);
686 /*
687 * Copy IPv6 and ICMPv6 only.
688 */
689 nip6 = mtod(n, struct ip6_hdr *);
690 bcopy(ip6, nip6, sizeof(struct ip6_hdr));
691 nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
692 bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
693 noff = sizeof(struct ip6_hdr);
694 n->m_pkthdr.len = n->m_len =
0a7de745 695 noff + sizeof(struct icmp6_hdr);
1c79356b
A
696 /*
697 * Adjust mbuf. ip6_plen will be adjusted in
698 * ip6_output().
699 */
700 m_adj(n0, off + sizeof(struct icmp6_hdr));
701 n->m_pkthdr.len += n0->m_pkthdr.len;
702 n->m_next = n0;
703 n0->m_flags &= ~M_PKTHDR;
704 } else {
705 nip6 = mtod(n, struct ip6_hdr *);
2d21ac55 706 IP6_EXTHDR_GET(nicmp6, struct icmp6_hdr *, n, off,
0a7de745 707 sizeof(*nicmp6));
1c79356b
A
708 noff = off;
709 }
0a7de745 710 if (nicmp6 == NULL) {
316670eb 711 panic("nicmp6 is NULL in %s, which isn't good!\n", __FUNCTION__);
0a7de745 712 } else {
316670eb
A
713 nicmp6->icmp6_type = ICMP6_ECHO_REPLY;
714 nicmp6->icmp6_code = 0;
715 }
1c79356b
A
716 if (n) {
717 icmp6stat.icp6s_reflect++;
718 icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]++;
719 icmp6_reflect(n, noff);
720 }
e2fac8b1 721 goto rate_limit_checked;
1c79356b
A
722
723 case ICMP6_ECHO_REPLY:
724 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echoreply);
0a7de745 725 if (code != 0) {
1c79356b 726 goto badcode;
0a7de745 727 }
1c79356b
A
728 break;
729
6d2010ae
A
730 case MLD_LISTENER_QUERY:
731 case MLD_LISTENER_REPORT:
732
0a7de745 733 if (icmp6len < sizeof(struct mld_hdr)) {
1c79356b 734 goto badlen;
0a7de745
A
735 }
736 if (icmp6->icmp6_type == MLD_LISTENER_QUERY) { /* XXX: ugly... */
1c79356b 737 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldquery);
0a7de745 738 } else {
1c79356b 739 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldreport);
0a7de745 740 }
e2fac8b1 741
1c79356b
A
742 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
743 /* give up local */
0a7de745 744 if (mld_input(m, off, icmp6len) == IPPROTO_DONE) {
6d2010ae 745 m = NULL;
0a7de745 746 }
1c79356b
A
747 goto freeit;
748 }
0a7de745 749 if (mld_input(n, off, icmp6len) != IPPROTO_DONE) {
6d2010ae 750 m_freem(n);
0a7de745 751 }
1c79356b 752 /* m stays. */
e2fac8b1 753 goto rate_limit_checked;
1c79356b 754
6d2010ae 755 case MLD_LISTENER_DONE:
1c79356b 756 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mlddone);
0a7de745 757 if (icmp6len < sizeof(struct mld_hdr)) { /* necessary? */
1c79356b 758 goto badlen;
0a7de745
A
759 }
760 break; /* nothing to be done in kernel */
1c79356b 761
6d2010ae
A
762 case MLD_MTRACE_RESP:
763 case MLD_MTRACE:
764 /* XXX: these two are experimental. not officially defined. */
1c79356b 765 /* XXX: per-interface statistics? */
0a7de745 766 break; /* just pass it to applications */
1c79356b 767
2d21ac55 768 case ICMP6_NI_QUERY:
0a7de745 769 if (!icmp6_nodeinfo) {
1c79356b 770 break;
0a7de745 771 }
6d2010ae 772//### LD 10/20 Check fbsd differences here. Not sure we're more advanced or not.
743345f9 773 /* By RFC 4620 refuse to answer queries from global scope addresses */
0a7de745 774 if ((icmp6_nodeinfo & 8) != 8 && in6_addrscope(&ip6->ip6_src) == IPV6_ADDR_SCOPE_GLOBAL) {
6601e61a 775 break;
0a7de745 776 }
6601e61a 777
0a7de745 778 if (icmp6len < sizeof(struct icmp6_nodeinfo)) {
1c79356b 779 goto badlen;
0a7de745 780 }
1c79356b 781
1c79356b 782#ifndef PULLDOWN_TEST
6601e61a 783 IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_nodeinfo),
0a7de745 784 return IPPROTO_DONE);
1c79356b 785#endif
e2fac8b1 786
6601e61a 787 n = m_copy(m, 0, M_COPYALL);
0a7de745 788 if (n) {
6601e61a 789 n = ni6_input(n, off);
0a7de745 790 }
1c79356b 791 if (n) {
6601e61a 792 noff = sizeof(struct ip6_hdr);
1c79356b
A
793 icmp6stat.icp6s_reflect++;
794 icmp6stat.icp6s_outhist[ICMP6_WRUREPLY]++;
795 icmp6_reflect(n, noff);
796 }
e2fac8b1 797 goto rate_limit_checked;
1c79356b
A
798
799 case ICMP6_WRUREPLY:
0a7de745 800 if (code != 0) {
1c79356b 801 goto badcode;
0a7de745 802 }
1c79356b
A
803 break;
804
805 case ND_ROUTER_SOLICIT:
806 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routersolicit);
0a7de745 807 if (code != 0) {
1c79356b 808 goto badcode;
0a7de745
A
809 }
810 if (icmp6len < sizeof(struct nd_router_solicit)) {
1c79356b 811 goto badlen;
0a7de745 812 }
e2fac8b1 813
1c79356b
A
814 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
815 /* give up local */
816 nd6_rs_input(m, off, icmp6len);
817 m = NULL;
818 goto freeit;
819 }
820 nd6_rs_input(n, off, icmp6len);
821 /* m stays. */
e2fac8b1 822 goto rate_limit_checked;
1c79356b
A
823
824 case ND_ROUTER_ADVERT:
825 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routeradvert);
0a7de745 826 if (code != 0) {
1c79356b 827 goto badcode;
0a7de745
A
828 }
829 if (icmp6len < sizeof(struct nd_router_advert)) {
1c79356b 830 goto badlen;
0a7de745 831 }
e2fac8b1 832
1c79356b
A
833 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
834 /* give up local */
835 nd6_ra_input(m, off, icmp6len);
836 m = NULL;
837 goto freeit;
838 }
839 nd6_ra_input(n, off, icmp6len);
840 /* m stays. */
e2fac8b1 841 goto rate_limit_checked;
1c79356b
A
842
843 case ND_NEIGHBOR_SOLICIT:
844 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighborsolicit);
0a7de745 845 if (code != 0) {
1c79356b 846 goto badcode;
0a7de745
A
847 }
848 if (icmp6len < sizeof(struct nd_neighbor_solicit)) {
1c79356b 849 goto badlen;
0a7de745 850 }
e2fac8b1 851
39037602
A
852 if (proxy ||
853 ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL)) {
1c79356b
A
854 /* give up local */
855 nd6_ns_input(m, off, icmp6len);
856 m = NULL;
857 goto freeit;
858 }
859 nd6_ns_input(n, off, icmp6len);
860 /* m stays. */
e2fac8b1 861 goto rate_limit_checked;
1c79356b
A
862
863 case ND_NEIGHBOR_ADVERT:
864 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighboradvert);
0a7de745 865 if (code != 0) {
1c79356b 866 goto badcode;
0a7de745
A
867 }
868 if (icmp6len < sizeof(struct nd_neighbor_advert)) {
1c79356b 869 goto badlen;
0a7de745 870 }
e2fac8b1 871
1c79356b
A
872 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
873 /* give up local */
874 nd6_na_input(m, off, icmp6len);
875 m = NULL;
876 goto freeit;
877 }
878 nd6_na_input(n, off, icmp6len);
879 /* m stays. */
e2fac8b1 880 goto rate_limit_checked;
1c79356b
A
881
882 case ND_REDIRECT:
883 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_redirect);
0a7de745 884 if (code != 0) {
1c79356b 885 goto badcode;
0a7de745
A
886 }
887 if (icmp6len < sizeof(struct nd_redirect)) {
1c79356b 888 goto badlen;
0a7de745 889 }
e2fac8b1 890
1c79356b
A
891 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
892 /* give up local */
893 icmp6_redirect_input(m, off);
894 m = NULL;
895 goto freeit;
896 }
897 icmp6_redirect_input(n, off);
898 /* m stays. */
e2fac8b1 899 goto rate_limit_checked;
1c79356b
A
900
901 case ICMP6_ROUTER_RENUMBERING:
902 if (code != ICMP6_ROUTER_RENUMBERING_COMMAND &&
0a7de745 903 code != ICMP6_ROUTER_RENUMBERING_RESULT) {
1c79356b 904 goto badcode;
0a7de745
A
905 }
906 if (icmp6len < sizeof(struct icmp6_router_renum)) {
1c79356b 907 goto badlen;
0a7de745 908 }
1c79356b
A
909 break;
910
911 default:
cb323159 912 nd6log(debug,
9bccf70c
A
913 "icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n",
914 icmp6->icmp6_type, ip6_sprintf(&ip6->ip6_src),
915 ip6_sprintf(&ip6->ip6_dst),
cb323159 916 m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0);
1c79356b
A
917 if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) {
918 /* ICMPv6 error: MUST deliver it by spec... */
919 code = PRC_NCMDS;
920 /* deliver */
921 } else {
922 /* ICMPv6 informational: MUST not deliver */
e2fac8b1 923 goto rate_limit_checked;
1c79356b 924 }
0a7de745 925deliver:
9bccf70c
A
926 if (icmp6_notify_error(m, off, icmp6len, code)) {
927 /* In this case, m should've been freed. */
0a7de745 928 return IPPROTO_DONE;
1c79356b 929 }
9bccf70c
A
930 break;
931
0a7de745 932badcode:
9bccf70c
A
933 icmp6stat.icp6s_badcode++;
934 break;
935
0a7de745 936badlen:
9bccf70c
A
937 icmp6stat.icp6s_badlen++;
938 break;
939 }
940
e2fac8b1 941rate_limit_checked:
39037602
A
942 icmp6_rip6_input(&m, *offp);
943 return IPPROTO_DONE;
9bccf70c 944
316670eb 945freeit:
9bccf70c
A
946 m_freem(m);
947 return IPPROTO_DONE;
948}
949
950static int
39037602 951icmp6_notify_error(struct mbuf *m, int off, int icmp6len, int code)
9bccf70c
A
952{
953 struct icmp6_hdr *icmp6;
954 struct ip6_hdr *eip6;
955 u_int32_t notifymtu;
956 struct sockaddr_in6 icmp6src, icmp6dst;
957
958 if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
959 icmp6stat.icp6s_tooshort++;
960 goto freeit;
961 }
1c79356b 962#ifndef PULLDOWN_TEST
9bccf70c 963 IP6_EXTHDR_CHECK(m, off,
0a7de745
A
964 sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr),
965 return -1);
9bccf70c 966 icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
1c79356b 967#else
9bccf70c 968 IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
0a7de745 969 sizeof(*icmp6) + sizeof(struct ip6_hdr));
9bccf70c
A
970 if (icmp6 == NULL) {
971 icmp6stat.icp6s_tooshort++;
0a7de745 972 return -1;
9bccf70c 973 }
1c79356b 974#endif
9bccf70c 975 eip6 = (struct ip6_hdr *)(icmp6 + 1);
1c79356b 976
9bccf70c
A
977 /* Detect the upper level protocol */
978 {
5ba3f43e 979 void (*ctlfunc)(int, struct sockaddr *, void *, struct ifnet *);
1c79356b
A
980 u_int8_t nxt = eip6->ip6_nxt;
981 int eoff = off + sizeof(struct icmp6_hdr) +
0a7de745 982 sizeof(struct ip6_hdr);
1c79356b
A
983 struct ip6ctlparam ip6cp;
984 struct in6_addr *finaldst = NULL;
985 int icmp6type = icmp6->icmp6_type;
986 struct ip6_frag *fh;
987 struct ip6_rthdr *rth;
988 struct ip6_rthdr0 *rth0;
989 int rthlen;
990
55e303ae 991 while (1) { /* XXX: should avoid infinite loop explicitly? */
1c79356b
A
992 struct ip6_ext *eh;
993
9bccf70c 994 switch (nxt) {
1c79356b
A
995 case IPPROTO_HOPOPTS:
996 case IPPROTO_DSTOPTS:
997 case IPPROTO_AH:
998#ifndef PULLDOWN_TEST
0a7de745
A
999 IP6_EXTHDR_CHECK(m, 0,
1000 eoff + sizeof(struct ip6_ext), return -1);
1c79356b 1001 eh = (struct ip6_ext *)(mtod(m, caddr_t)
0a7de745 1002 + eoff);
1c79356b
A
1003#else
1004 IP6_EXTHDR_GET(eh, struct ip6_ext *, m,
0a7de745 1005 eoff, sizeof(*eh));
1c79356b
A
1006 if (eh == NULL) {
1007 icmp6stat.icp6s_tooshort++;
0a7de745 1008 return -1;
1c79356b
A
1009 }
1010#endif
6d2010ae 1011
0a7de745 1012 if (nxt == IPPROTO_AH) {
1c79356b 1013 eoff += (eh->ip6e_len + 2) << 2;
0a7de745 1014 } else {
1c79356b 1015 eoff += (eh->ip6e_len + 1) << 3;
0a7de745 1016 }
1c79356b
A
1017 nxt = eh->ip6e_nxt;
1018 break;
1019 case IPPROTO_ROUTING:
1020 /*
1021 * When the erroneous packet contains a
1022 * routing header, we should examine the
1023 * header to determine the final destination.
1024 * Otherwise, we can't properly update
1025 * information that depends on the final
1026 * destination (e.g. path MTU).
1027 */
1028#ifndef PULLDOWN_TEST
1029 IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(*rth),
0a7de745
A
1030 return -1);
1031 rth = (struct ip6_rthdr *)
1032 (mtod(m, caddr_t) + eoff);
1c79356b
A
1033#else
1034 IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m,
0a7de745 1035 eoff, sizeof(*rth));
1c79356b
A
1036 if (rth == NULL) {
1037 icmp6stat.icp6s_tooshort++;
0a7de745 1038 return -1;
1c79356b
A
1039 }
1040#endif
1041 rthlen = (rth->ip6r_len + 1) << 3;
1042 /*
1043 * XXX: currently there is no
1044 * officially defined type other
1045 * than type-0.
1046 * Note that if the segment left field
1047 * is 0, all intermediate hops must
1048 * have been passed.
1049 */
1050 if (rth->ip6r_segleft &&
1051 rth->ip6r_type == IPV6_RTHDR_TYPE_0) {
1052 int hops;
1053
1054#ifndef PULLDOWN_TEST
1055 IP6_EXTHDR_CHECK(m, 0, eoff + rthlen,
0a7de745 1056 return -1);
1c79356b
A
1057 rth0 = (struct ip6_rthdr0 *)(mtod(m, caddr_t) + eoff);
1058#else
1059 IP6_EXTHDR_GET(rth0,
0a7de745
A
1060 struct ip6_rthdr0 *, m,
1061 eoff, rthlen);
1c79356b
A
1062 if (rth0 == NULL) {
1063 icmp6stat.icp6s_tooshort++;
0a7de745 1064 return -1;
1c79356b
A
1065 }
1066#endif
1067 /* just ignore a bogus header */
1068 if ((rth0->ip6r0_len % 2) == 0 &&
0a7de745 1069 (hops = rth0->ip6r0_len / 2)) {
316670eb 1070 finaldst = (struct in6_addr *)(void *)(rth0 + 1) + (hops - 1);
0a7de745 1071 }
1c79356b
A
1072 }
1073 eoff += rthlen;
1074 nxt = rth->ip6r_nxt;
1075 break;
1076 case IPPROTO_FRAGMENT:
1077#ifndef PULLDOWN_TEST
1078 IP6_EXTHDR_CHECK(m, 0, eoff +
0a7de745
A
1079 sizeof(struct ip6_frag),
1080 return -1);
1c79356b 1081 fh = (struct ip6_frag *)(mtod(m, caddr_t)
0a7de745 1082 + eoff);
1c79356b
A
1083#else
1084 IP6_EXTHDR_GET(fh, struct ip6_frag *, m,
0a7de745 1085 eoff, sizeof(*fh));
1c79356b
A
1086 if (fh == NULL) {
1087 icmp6stat.icp6s_tooshort++;
0a7de745 1088 return -1;
1c79356b
A
1089 }
1090#endif
1091 /*
1092 * Data after a fragment header is meaningless
1093 * unless it is the first fragment, but
1094 * we'll go to the notify label for path MTU
1095 * discovery.
1096 */
0a7de745 1097 if (fh->ip6f_offlg & IP6F_OFF_MASK) {
1c79356b 1098 goto notify;
0a7de745 1099 }
1c79356b
A
1100
1101 eoff += sizeof(struct ip6_frag);
1102 nxt = fh->ip6f_nxt;
1103 break;
1104 default:
1105 /*
1106 * This case includes ESP and the No Next
55e303ae 1107 * Header. In such cases going to the notify
1c79356b
A
1108 * label does not have any meaning
1109 * (i.e. ctlfunc will be NULL), but we go
1110 * anyway since we might have to update
1111 * path MTU information.
1112 */
1113 goto notify;
1114 }
1115 }
0a7de745 1116notify:
1c79356b
A
1117#ifndef PULLDOWN_TEST
1118 icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
1119#else
1120 IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
6d2010ae 1121 sizeof(*icmp6) + sizeof(struct ip6_hdr));
1c79356b
A
1122 if (icmp6 == NULL) {
1123 icmp6stat.icp6s_tooshort++;
0a7de745 1124 return -1;
1c79356b
A
1125 }
1126#endif
9bccf70c 1127
6d2010ae
A
1128 /*
1129 * retrieve parameters from the inner IPv6 header, and convert
1130 * them into sockaddr structures.
1131 * XXX: there is no guarantee that the source or destination
1132 * addresses of the inner packet are in the same scope as
1133 * the addresses of the icmp packet. But there is no other
1134 * way to determine the zone.
1135 */
9bccf70c 1136 eip6 = (struct ip6_hdr *)(icmp6 + 1);
6d2010ae 1137
9bccf70c
A
1138 bzero(&icmp6dst, sizeof(icmp6dst));
1139 icmp6dst.sin6_len = sizeof(struct sockaddr_in6);
1140 icmp6dst.sin6_family = AF_INET6;
0a7de745 1141 if (finaldst == NULL) {
9bccf70c 1142 icmp6dst.sin6_addr = eip6->ip6_dst;
0a7de745 1143 } else {
9bccf70c 1144 icmp6dst.sin6_addr = *finaldst;
0a7de745
A
1145 }
1146 if (in6_setscope(&icmp6dst.sin6_addr, m->m_pkthdr.rcvif, NULL)) {
9bccf70c 1147 goto freeit;
0a7de745 1148 }
9bccf70c
A
1149 bzero(&icmp6src, sizeof(icmp6src));
1150 icmp6src.sin6_len = sizeof(struct sockaddr_in6);
1151 icmp6src.sin6_family = AF_INET6;
1152 icmp6src.sin6_addr = eip6->ip6_src;
0a7de745 1153 if (in6_setscope(&icmp6src.sin6_addr, m->m_pkthdr.rcvif, NULL)) {
9bccf70c 1154 goto freeit;
0a7de745 1155 }
9bccf70c 1156 icmp6src.sin6_flowinfo =
6d2010ae 1157 (eip6->ip6_flow & IPV6_FLOWLABEL_MASK);
9bccf70c 1158
0a7de745 1159 if (finaldst == NULL) {
9bccf70c 1160 finaldst = &eip6->ip6_dst;
0a7de745 1161 }
9bccf70c
A
1162 ip6cp.ip6c_m = m;
1163 ip6cp.ip6c_icmp6 = icmp6;
1164 ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1);
1165 ip6cp.ip6c_off = eoff;
1166 ip6cp.ip6c_finaldst = finaldst;
1167 ip6cp.ip6c_src = &icmp6src;
1168 ip6cp.ip6c_nxt = nxt;
1169
1c79356b 1170 if (icmp6type == ICMP6_PACKET_TOO_BIG) {
9bccf70c
A
1171 notifymtu = ntohl(icmp6->icmp6_mtu);
1172 ip6cp.ip6c_cmdarg = (void *)&notifymtu;
0a7de745 1173 icmp6_mtudisc_update(&ip6cp, 1); /*XXX*/
1c79356b
A
1174 }
1175
5ba3f43e 1176 ctlfunc = ip6_protox[nxt]->pr_ctlinput;
1c79356b 1177 if (ctlfunc) {
5c9f4661
A
1178 LCK_MTX_ASSERT(inet6_domain_mutex, LCK_MTX_ASSERT_OWNED);
1179
1180 lck_mtx_unlock(inet6_domain_mutex);
1181
9bccf70c 1182 (void) (*ctlfunc)(code, (struct sockaddr *)&icmp6dst,
5ba3f43e 1183 &ip6cp, m->m_pkthdr.rcvif);
5c9f4661
A
1184
1185 lck_mtx_lock(inet6_domain_mutex);
1c79356b 1186 }
1c79356b 1187 }
0a7de745 1188 return 0;
1c79356b 1189
b0d623f7 1190freeit:
1c79356b 1191 m_freem(m);
0a7de745 1192 return -1;
1c79356b
A
1193}
1194
9bccf70c 1195void
39037602 1196icmp6_mtudisc_update(struct ip6ctlparam *ip6cp, int validated)
1c79356b 1197{
9bccf70c
A
1198 struct in6_addr *dst = ip6cp->ip6c_finaldst;
1199 struct icmp6_hdr *icmp6 = ip6cp->ip6c_icmp6;
0a7de745 1200 struct mbuf *m = ip6cp->ip6c_m; /* will be necessary for scope issue */
1c79356b
A
1201 u_int mtu = ntohl(icmp6->icmp6_mtu);
1202 struct rtentry *rt = NULL;
1203 struct sockaddr_in6 sin6;
6d2010ae
A
1204 /*
1205 * we reject ICMPv6 too big with abnormally small value.
1206 * XXX what is the good definition of "abnormally small"?
1207 */
0a7de745 1208 if (mtu < sizeof(struct ip6_hdr) + sizeof(struct ip6_frag) + 8) {
6d2010ae 1209 return;
0a7de745 1210 }
9bccf70c 1211
0a7de745 1212 if (!validated) {
9bccf70c 1213 return;
0a7de745 1214 }
6d2010ae 1215
cb323159 1216 /* Limit the MTU to the minimum IPv6 MTU */
0a7de745 1217 if (mtu < IPV6_MMTU) {
cb323159 1218 mtu = IPV6_MMTU;
0a7de745 1219 }
c910b4d9 1220
1c79356b
A
1221 bzero(&sin6, sizeof(sin6));
1222 sin6.sin6_family = PF_INET6;
1223 sin6.sin6_len = sizeof(struct sockaddr_in6);
1224 sin6.sin6_addr = *dst;
9bccf70c
A
1225 /* XXX normally, this won't happen */
1226 if (IN6_IS_ADDR_LINKLOCAL(dst)) {
1227 sin6.sin6_addr.s6_addr16[1] =
1228 htons(m->m_pkthdr.rcvif->if_index);
1c79356b 1229 }
9bccf70c 1230 /* sin6.sin6_scope_id = XXX: should be set if DST is a scoped addr */
39037602
A
1231 /*
1232 * XXX On a side note, for asymmetric data-path
1233 * the lookup on receive interace is probably not
1234 * what we want to do.
1235 * That requires looking at the cached route for the
1236 * protocol control block.
1237 */
6d2010ae
A
1238 rt = rtalloc1_scoped((struct sockaddr *)&sin6, 0,
1239 RTF_CLONING | RTF_PRCLONING, m->m_pkthdr.rcvif->if_index);
b0d623f7
A
1240 if (rt != NULL) {
1241 RT_LOCK(rt);
1242 if ((rt->rt_flags & RTF_HOST) &&
6d2010ae
A
1243 !(rt->rt_rmx.rmx_locks & RTV_MTU) &&
1244 mtu < IN6_LINKMTU(rt->rt_ifp) &&
1245 rt->rt_rmx.rmx_mtu > mtu) {
1246 icmp6stat.icp6s_pmtuchg++;
1247 rt->rt_rmx.rmx_mtu = mtu;
1c79356b 1248 }
b0d623f7 1249 RT_UNLOCK(rt);
9bccf70c 1250 rtfree(rt);
b0d623f7 1251 }
1c79356b
A
1252}
1253
1254/*
9bccf70c
A
1255 * Process a Node Information Query packet, based on
1256 * draft-ietf-ipngwg-icmp-name-lookups-07.
6d2010ae 1257 *
9bccf70c
A
1258 * Spec incompatibilities:
1259 * - IPv6 Subject address handling
1260 * - IPv4 Subject address handling support missing
1261 * - Proxy reply (answer even if it's not for me)
1262 * - joins NI group address at in6_ifattach() time only, does not cope
1263 * with hostname changes by sethostname(3)
1c79356b 1264 */
0a7de745 1265#define hostnamelen strlen(hostname)
1c79356b 1266static struct mbuf *
39037602 1267ni6_input(struct mbuf *m, int off)
1c79356b
A
1268{
1269 struct icmp6_nodeinfo *ni6, *nni6;
1270 struct mbuf *n = NULL;
1271 u_int16_t qtype;
9bccf70c 1272 int subjlen;
1c79356b
A
1273 int replylen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo);
1274 struct ni_reply_fqdn *fqdn;
0a7de745 1275 int addrs; /* for NI_QTYPE_NODEADDR */
1c79356b 1276 struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */
9bccf70c
A
1277 struct sockaddr_in6 sin6; /* double meaning; ip6_dst and subjectaddr */
1278 struct sockaddr_in6 sin6_d; /* XXX: we should retrieve this from m_aux */
1279 struct ip6_hdr *ip6;
0a7de745 1280 int oldfqdn = 0; /* if 1, return pascal string (03 draft) */
9bccf70c 1281 char *subj = NULL;
1c79356b 1282
9bccf70c 1283 ip6 = mtod(m, struct ip6_hdr *);
1c79356b
A
1284#ifndef PULLDOWN_TEST
1285 ni6 = (struct icmp6_nodeinfo *)(mtod(m, caddr_t) + off);
1286#else
1287 IP6_EXTHDR_GET(ni6, struct icmp6_nodeinfo *, m, off, sizeof(*ni6));
1288 if (ni6 == NULL) {
1289 /* m is already reclaimed */
0a7de745 1290 return NULL;
1c79356b
A
1291 }
1292#endif
9bccf70c 1293
6d2010ae
A
1294 /*
1295 * Validate IPv6 source address.
1296 * The default configuration MUST be to refuse answering queries from
1297 * global-scope addresses according to RFC4602.
1298 * Notes:
1299 * - it's not very clear what "refuse" means; this implementation
1300 * simply drops it.
1301 * - it's not very easy to identify global-scope (unicast) addresses
1302 * since there are many prefixes for them. It should be safer
1303 * and in practice sufficient to check "all" but loopback and
1304 * link-local (note that site-local unicast was deprecated and
1305 * ULA is defined as global scope-wise)
1306 */
1307 if ((icmp6_nodeinfo & ICMP6_NODEINFO_GLOBALOK) == 0 &&
1308 !IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) &&
0a7de745 1309 !IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) {
6d2010ae 1310 goto bad;
0a7de745 1311 }
6d2010ae 1312
9bccf70c
A
1313 /*
1314 * Validate IPv6 destination address.
1315 *
1316 * The Responder must discard the Query without further processing
1317 * unless it is one of the Responder's unicast or anycast addresses, or
1318 * a link-local scope multicast address which the Responder has joined.
6d2010ae 1319 * [RFC4602, Section 5.]
9bccf70c 1320 */
6d2010ae 1321 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
0a7de745 1322 if (!IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst)) {
6d2010ae 1323 goto bad;
0a7de745 1324 }
6d2010ae 1325 /* else it's a link-local multicast, fine */
0a7de745 1326 } else { /* unicast or anycast */
39236c6e 1327 uint32_t ia6_flags;
6d2010ae 1328
0a7de745 1329 if (ip6_getdstifaddr_info(m, NULL, &ia6_flags) != 0) {
6d2010ae 1330 goto bad; /* XXX impossible */
0a7de745 1331 }
39236c6e 1332 if ((ia6_flags & IN6_IFF_TEMPORARY) &&
6d2010ae 1333 !(icmp6_nodeinfo & ICMP6_NODEINFO_TMPADDROK)) {
cb323159
A
1334 nd6log(debug, "ni6_input: ignore node info to a temporary address in %s:%d",
1335 __func__, __LINE__);
9bccf70c
A
1336 goto bad;
1337 }
6d2010ae 1338 }
9bccf70c
A
1339
1340 /* validate query Subject field. */
1c79356b 1341 qtype = ntohs(ni6->ni_qtype);
9bccf70c
A
1342 subjlen = m->m_pkthdr.len - off - sizeof(struct icmp6_nodeinfo);
1343 switch (qtype) {
1344 case NI_QTYPE_NOOP:
1345 case NI_QTYPE_SUPTYPES:
1346 /* 07 draft */
0a7de745 1347 if (ni6->ni_code == ICMP6_NI_SUBJ_FQDN && subjlen == 0) {
9bccf70c 1348 break;
0a7de745
A
1349 }
1350 /* FALLTHROUGH */
9bccf70c
A
1351 case NI_QTYPE_FQDN:
1352 case NI_QTYPE_NODEADDR:
6d2010ae 1353 case NI_QTYPE_IPV4ADDR:
9bccf70c
A
1354 switch (ni6->ni_code) {
1355 case ICMP6_NI_SUBJ_IPV6:
1356#if ICMP6_NI_SUBJ_IPV6 != 0
1357 case 0:
1358#endif
1359 /*
1360 * backward compatibility - try to accept 03 draft
1361 * format, where no Subject is present.
1362 */
1363 if (qtype == NI_QTYPE_FQDN && ni6->ni_code == 0 &&
1364 subjlen == 0) {
1365 oldfqdn++;
1366 break;
1367 }
1368#if ICMP6_NI_SUBJ_IPV6 != 0
0a7de745 1369 if (ni6->ni_code != ICMP6_NI_SUBJ_IPV6) {
9bccf70c 1370 goto bad;
0a7de745 1371 }
9bccf70c
A
1372#endif
1373
0a7de745 1374 if (subjlen != sizeof(struct in6_addr)) {
9bccf70c 1375 goto bad;
0a7de745 1376 }
9bccf70c
A
1377
1378 /*
1379 * Validate Subject address.
1380 *
1381 * Not sure what exactly "address belongs to the node"
1382 * means in the spec, is it just unicast, or what?
1383 *
1384 * At this moment we consider Subject address as
1385 * "belong to the node" if the Subject address equals
1386 * to the IPv6 destination address; validation for
1387 * IPv6 destination address should have done enough
1388 * check for us.
1389 *
1390 * We do not do proxy at this moment.
1391 */
1392 /* m_pulldown instead of copy? */
1393 m_copydata(m, off + sizeof(struct icmp6_nodeinfo),
1394 subjlen, (caddr_t)&sin6.sin6_addr);
1395 sin6.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
0a7de745 1396 &sin6.sin6_addr);
6d2010ae
A
1397 in6_embedscope(&sin6.sin6_addr, &sin6, NULL, NULL,
1398 NULL);
9bccf70c
A
1399 bzero(&sin6_d, sizeof(sin6_d));
1400 sin6_d.sin6_family = AF_INET6; /* not used, actually */
1401 sin6_d.sin6_len = sizeof(sin6_d); /* ditto */
1402 sin6_d.sin6_addr = ip6->ip6_dst;
1403 sin6_d.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
0a7de745 1404 &ip6->ip6_dst);
6d2010ae
A
1405 in6_embedscope(&sin6_d.sin6_addr, &sin6_d, NULL, NULL,
1406 NULL);
9bccf70c 1407 subj = (char *)&sin6;
0a7de745 1408 if (SA6_ARE_ADDR_EQUAL(&sin6, &sin6_d)) {
9bccf70c 1409 break;
0a7de745 1410 }
9bccf70c
A
1411
1412 /*
1413 * XXX if we are to allow other cases, we should really
1414 * be careful about scope here.
1415 * basically, we should disallow queries toward IPv6
6d2010ae
A
1416 * destination X with subject Y,
1417 * if scope(X) > scope(Y).
9bccf70c
A
1418 * if we allow scope(X) > scope(Y), it will result in
1419 * information leakage across scope boundary.
1420 */
1421 goto bad;
1c79356b 1422
9bccf70c
A
1423 case ICMP6_NI_SUBJ_FQDN:
1424 /*
1425 * Validate Subject name with gethostname(3).
1426 *
1427 * The behavior may need some debate, since:
1428 * - we are not sure if the node has FQDN as
1429 * hostname (returned by gethostname(3)).
1430 * - the code does wildcard match for truncated names.
1431 * however, we are not sure if we want to perform
1432 * wildcard match, if gethostname(3) side has
1433 * truncated hostname.
1434 */
cb323159 1435 lck_mtx_lock(&hostname_lock);
9bccf70c 1436 n = ni6_nametodns(hostname, hostnamelen, 0);
cb323159 1437 lck_mtx_unlock(&hostname_lock);
0a7de745 1438 if (!n || n->m_next || n->m_len == 0) {
9bccf70c 1439 goto bad;
0a7de745 1440 }
9bccf70c
A
1441 IP6_EXTHDR_GET(subj, char *, m,
1442 off + sizeof(struct icmp6_nodeinfo), subjlen);
0a7de745 1443 if (subj == NULL) {
9bccf70c 1444 goto bad;
0a7de745 1445 }
9bccf70c 1446 if (!ni6_dnsmatch(subj, subjlen, mtod(n, const char *),
0a7de745 1447 n->m_len)) {
9bccf70c
A
1448 goto bad;
1449 }
1450 m_freem(n);
1451 n = NULL;
1452 break;
1453
0a7de745 1454 case ICMP6_NI_SUBJ_IPV4: /* XXX: to be implemented? */
9bccf70c
A
1455 default:
1456 goto bad;
1457 }
1458 break;
1c79356b
A
1459 }
1460
9bccf70c
A
1461 /* refuse based on configuration. XXX ICMP6_NI_REFUSED? */
1462 switch (qtype) {
1463 case NI_QTYPE_FQDN:
0a7de745 1464 if ((icmp6_nodeinfo & ICMP6_NODEINFO_FQDNOK) == 0) {
9bccf70c 1465 goto bad;
0a7de745 1466 }
9bccf70c
A
1467 break;
1468 case NI_QTYPE_NODEADDR:
6d2010ae 1469 case NI_QTYPE_IPV4ADDR:
0a7de745 1470 if ((icmp6_nodeinfo & ICMP6_NODEINFO_NODEADDROK) == 0) {
9bccf70c 1471 goto bad;
0a7de745 1472 }
9bccf70c
A
1473 break;
1474 }
1475
1476 /* guess reply length */
1477 switch (qtype) {
1478 case NI_QTYPE_NOOP:
0a7de745 1479 break; /* no reply data */
9bccf70c
A
1480 case NI_QTYPE_SUPTYPES:
1481 replylen += sizeof(u_int32_t);
1482 break;
1483 case NI_QTYPE_FQDN:
1484 /* XXX will append an mbuf */
1485 replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
1486 break;
1487 case NI_QTYPE_NODEADDR:
91447636 1488 addrs = ni6_addrs(ni6, &ifp, subj);
9bccf70c 1489 if ((replylen += addrs * (sizeof(struct in6_addr) +
0a7de745 1490 sizeof(u_int32_t))) > MCLBYTES) {
9bccf70c 1491 replylen = MCLBYTES; /* XXX: will truncate pkt later */
0a7de745 1492 }
9bccf70c 1493 break;
6d2010ae
A
1494 case NI_QTYPE_IPV4ADDR:
1495 /* unsupported - should respond with unknown Qtype? */
1496 break;
9bccf70c
A
1497 default:
1498 /*
1499 * XXX: We must return a reply with the ICMP6 code
6d2010ae 1500 * `unknown Qtype' in this case. However we regard the case
9bccf70c
A
1501 * as an FQDN query for backward compatibility.
1502 * Older versions set a random value to this field,
1503 * so it rarely varies in the defined qtypes.
1504 * But the mechanism is not reliable...
1505 * maybe we should obsolete older versions.
1506 */
1507 qtype = NI_QTYPE_FQDN;
1508 /* XXX will append an mbuf */
1509 replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
1510 oldfqdn++;
1511 break;
1512 }
1513
1514 /* allocate an mbuf to reply. */
0a7de745 1515 MGETHDR(n, M_DONTWAIT, m->m_type); /* MAC-OK */
1c79356b
A
1516 if (n == NULL) {
1517 m_freem(m);
0a7de745 1518 if (ifp != NULL) {
6d2010ae 1519 ifnet_release(ifp);
0a7de745
A
1520 }
1521 return NULL;
1c79356b
A
1522 }
1523 M_COPY_PKTHDR(n, m); /* just for recvif */
1524 if (replylen > MHLEN) {
9bccf70c
A
1525 if (replylen > MCLBYTES) {
1526 /*
1527 * XXX: should we try to allocate more? But MCLBYTES
1528 * is probably much larger than IPV6_MMTU...
1529 */
1c79356b 1530 goto bad;
9bccf70c 1531 }
1c79356b
A
1532 MCLGET(n, M_DONTWAIT);
1533 if ((n->m_flags & M_EXT) == 0) {
1534 goto bad;
1535 }
1536 }
1537 n->m_pkthdr.len = n->m_len = replylen;
1538
9bccf70c
A
1539 /* copy mbuf header and IPv6 + Node Information base headers */
1540 bcopy(mtod(m, caddr_t), mtod(n, caddr_t), sizeof(struct ip6_hdr));
1541 nni6 = (struct icmp6_nodeinfo *)(mtod(n, struct ip6_hdr *) + 1);
1542 bcopy((caddr_t)ni6, (caddr_t)nni6, sizeof(struct icmp6_nodeinfo));
1543
1544 /* qtype dependent procedure */
1545 switch (qtype) {
1546 case NI_QTYPE_NOOP:
1547 nni6->ni_code = ICMP6_NI_SUCCESS;
1548 nni6->ni_flags = 0;
1549 break;
1550 case NI_QTYPE_SUPTYPES:
1551 {
1552 u_int32_t v;
1553 nni6->ni_code = ICMP6_NI_SUCCESS;
0a7de745 1554 nni6->ni_flags = htons(0x0000); /* raw bitmap */
9bccf70c
A
1555 /* supports NOOP, SUPTYPES, FQDN, and NODEADDR */
1556 v = (u_int32_t)htonl(0x0000000f);
1557 bcopy(&v, nni6 + 1, sizeof(u_int32_t));
1558 break;
1559 }
1560 case NI_QTYPE_FQDN:
1561 nni6->ni_code = ICMP6_NI_SUCCESS;
1562 fqdn = (struct ni_reply_fqdn *)(mtod(n, caddr_t) +
0a7de745
A
1563 sizeof(struct ip6_hdr) +
1564 sizeof(struct icmp6_nodeinfo));
9bccf70c 1565 nni6->ni_flags = 0; /* XXX: meaningless TTL */
0a7de745 1566 fqdn->ni_fqdn_ttl = 0; /* ditto. */
9bccf70c
A
1567 /*
1568 * XXX do we really have FQDN in variable "hostname"?
1569 */
cb323159 1570 lck_mtx_lock(&hostname_lock);
9bccf70c 1571 n->m_next = ni6_nametodns(hostname, hostnamelen, oldfqdn);
cb323159 1572 lck_mtx_unlock(&hostname_lock);
0a7de745 1573 if (n->m_next == NULL) {
9bccf70c 1574 goto bad;
0a7de745 1575 }
9bccf70c 1576 /* XXX we assume that n->m_next is not a chain */
0a7de745 1577 if (n->m_next->m_next != NULL) {
9bccf70c 1578 goto bad;
0a7de745 1579 }
9bccf70c
A
1580 n->m_pkthdr.len += n->m_next->m_len;
1581 break;
1582 case NI_QTYPE_NODEADDR:
1583 {
1584 int lenlim, copied;
1585
1586 nni6->ni_code = ICMP6_NI_SUCCESS;
1587 n->m_pkthdr.len = n->m_len =
1588 sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo);
1589 lenlim = M_TRAILINGSPACE(n);
1590 copied = ni6_store_addrs(ni6, nni6, ifp, lenlim);
1591 /* XXX: reset mbuf length */
1592 n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
0a7de745 1593 sizeof(struct icmp6_nodeinfo) + copied;
9bccf70c
A
1594 break;
1595 }
1596 default:
0a7de745 1597 break; /* XXX impossible! */
9bccf70c
A
1598 }
1599
1600 nni6->ni_type = ICMP6_NI_REPLY;
1601 m_freem(m);
0a7de745 1602 if (ifp != NULL) {
6d2010ae 1603 ifnet_release(ifp);
0a7de745
A
1604 }
1605 return n;
9bccf70c 1606
6d2010ae 1607bad:
9bccf70c 1608 m_freem(m);
0a7de745 1609 if (n) {
9bccf70c 1610 m_freem(n);
0a7de745
A
1611 }
1612 if (ifp != NULL) {
6d2010ae 1613 ifnet_release(ifp);
0a7de745
A
1614 }
1615 return NULL;
9bccf70c
A
1616}
1617#undef hostnamelen
1618
1619/*
1620 * make a mbuf with DNS-encoded string. no compression support.
1621 *
1622 * XXX names with less than 2 dots (like "foo" or "foo.section") will be
1623 * treated as truncated name (two \0 at the end). this is a wild guess.
1624 */
1625static struct mbuf *
39037602
A
1626ni6_nametodns(
1627 const char *name,
1628 int namelen,
0a7de745 1629 int old) /* return pascal string if non-zero */
9bccf70c
A
1630{
1631 struct mbuf *m;
1632 char *cp, *ep;
1633 const char *p, *q;
1634 int i, len, nterm;
1635
0a7de745 1636 if (old) {
9bccf70c 1637 len = namelen + 1;
0a7de745 1638 } else {
9bccf70c 1639 len = MCLBYTES;
0a7de745 1640 }
9bccf70c
A
1641
1642 /* because MAXHOSTNAMELEN is usually 256, we use cluster mbuf */
1643 MGET(m, M_DONTWAIT, MT_DATA);
1644 if (m && len > MLEN) {
1645 MCLGET(m, M_DONTWAIT);
0a7de745 1646 if ((m->m_flags & M_EXT) == 0) {
9bccf70c 1647 goto fail;
0a7de745 1648 }
9bccf70c 1649 }
0a7de745 1650 if (!m) {
9bccf70c 1651 goto fail;
0a7de745 1652 }
9bccf70c
A
1653 m->m_next = NULL;
1654
1655 if (old) {
1656 m->m_len = len;
1657 *mtod(m, char *) = namelen;
1658 bcopy(name, mtod(m, char *) + 1, namelen);
1659 return m;
1660 } else {
1661 m->m_len = 0;
1662 cp = mtod(m, char *);
1663 ep = mtod(m, char *) + M_TRAILINGSPACE(m);
1664
1665 /* if not certain about my name, return empty buffer */
0a7de745 1666 if (namelen == 0) {
9bccf70c 1667 return m;
0a7de745 1668 }
9bccf70c
A
1669
1670 /*
1671 * guess if it looks like shortened hostname, or FQDN.
1672 * shortened hostname needs two trailing "\0".
1673 */
1674 i = 0;
1675 for (p = name; p < name + namelen; p++) {
0a7de745 1676 if (*p && *p == '.') {
9bccf70c 1677 i++;
0a7de745 1678 }
9bccf70c 1679 }
0a7de745 1680 if (i < 2) {
9bccf70c 1681 nterm = 2;
0a7de745 1682 } else {
9bccf70c 1683 nterm = 1;
0a7de745 1684 }
9bccf70c
A
1685
1686 p = name;
1687 while (cp < ep && p < name + namelen) {
1688 i = 0;
0a7de745 1689 for (q = p; q < name + namelen && *q && *q != '.'; q++) {
9bccf70c 1690 i++;
0a7de745 1691 }
9bccf70c 1692 /* result does not fit into mbuf */
0a7de745 1693 if (cp + i + 1 >= ep) {
9bccf70c 1694 goto fail;
0a7de745 1695 }
9bccf70c
A
1696 /*
1697 * DNS label length restriction, RFC1035 page 8.
1698 * "i == 0" case is included here to avoid returning
1699 * 0-length label on "foo..bar".
1700 */
0a7de745 1701 if (i <= 0 || i >= 64) {
9bccf70c 1702 goto fail;
0a7de745 1703 }
9bccf70c
A
1704 *cp++ = i;
1705 bcopy(p, cp, i);
1706 cp += i;
1707 p = q;
0a7de745 1708 if (p < name + namelen && *p == '.') {
9bccf70c 1709 p++;
0a7de745 1710 }
9bccf70c
A
1711 }
1712 /* termination */
0a7de745 1713 if (cp + nterm >= ep) {
9bccf70c 1714 goto fail;
0a7de745
A
1715 }
1716 while (nterm-- > 0) {
9bccf70c 1717 *cp++ = '\0';
0a7de745 1718 }
9bccf70c
A
1719 m->m_len = cp - mtod(m, char *);
1720 return m;
1721 }
1722
1723 panic("should not reach here");
55e303ae 1724 /* NOTREACHED */
9bccf70c 1725
0a7de745
A
1726fail:
1727 if (m) {
9bccf70c 1728 m_freem(m);
0a7de745 1729 }
9bccf70c
A
1730 return NULL;
1731}
1732
1733/*
1734 * check if two DNS-encoded string matches. takes care of truncated
1735 * form (with \0\0 at the end). no compression support.
1736 * XXX upper/lowercase match (see RFC2065)
1737 */
1738static int
39037602 1739ni6_dnsmatch(const char *a, int alen, const char *b, int blen)
9bccf70c
A
1740{
1741 const char *a0, *b0;
1742 int l;
1743
1744 /* simplest case - need validation? */
0a7de745 1745 if (alen == blen && bcmp(a, b, alen) == 0) {
9bccf70c 1746 return 1;
0a7de745 1747 }
1c79356b 1748
9bccf70c
A
1749 a0 = a;
1750 b0 = b;
1c79356b 1751
9bccf70c 1752 /* termination is mandatory */
0a7de745 1753 if (alen < 2 || blen < 2) {
9bccf70c 1754 return 0;
0a7de745
A
1755 }
1756 if (a0[alen - 1] != '\0' || b0[blen - 1] != '\0') {
9bccf70c 1757 return 0;
0a7de745 1758 }
9bccf70c
A
1759 alen--;
1760 blen--;
1761
1762 while (a - a0 < alen && b - b0 < blen) {
0a7de745 1763 if (a - a0 + 1 > alen || b - b0 + 1 > blen) {
9bccf70c 1764 return 0;
0a7de745 1765 }
9bccf70c 1766
0a7de745 1767 if ((signed char)a[0] < 0 || (signed char)b[0] < 0) {
9bccf70c 1768 return 0;
0a7de745 1769 }
9bccf70c 1770 /* we don't support compression yet */
0a7de745 1771 if (a[0] >= 64 || b[0] >= 64) {
9bccf70c 1772 return 0;
0a7de745 1773 }
9bccf70c
A
1774
1775 /* truncated case */
0a7de745 1776 if (a[0] == 0 && a - a0 == alen - 1) {
9bccf70c 1777 return 1;
0a7de745
A
1778 }
1779 if (b[0] == 0 && b - b0 == blen - 1) {
9bccf70c 1780 return 1;
0a7de745
A
1781 }
1782 if (a[0] == 0 || b[0] == 0) {
9bccf70c 1783 return 0;
0a7de745 1784 }
9bccf70c 1785
0a7de745 1786 if (a[0] != b[0]) {
9bccf70c 1787 return 0;
0a7de745 1788 }
9bccf70c 1789 l = a[0];
0a7de745 1790 if (a - a0 + 1 + l > alen || b - b0 + 1 + l > blen) {
9bccf70c 1791 return 0;
0a7de745
A
1792 }
1793 if (bcmp(a + 1, b + 1, l) != 0) {
9bccf70c 1794 return 0;
0a7de745 1795 }
9bccf70c
A
1796
1797 a += 1 + l;
1798 b += 1 + l;
1799 }
1c79356b 1800
0a7de745 1801 if (a - a0 == alen && b - b0 == blen) {
9bccf70c 1802 return 1;
0a7de745 1803 } else {
9bccf70c 1804 return 0;
0a7de745 1805 }
1c79356b 1806}
1c79356b
A
1807
1808/*
1809 * calculate the number of addresses to be returned in the node info reply.
1810 */
1811static int
39037602 1812ni6_addrs(struct icmp6_nodeinfo *ni6, struct ifnet **ifpp, char *subj)
1c79356b 1813{
9bccf70c
A
1814 struct ifnet *ifp;
1815 struct in6_ifaddr *ifa6;
1816 struct ifaddr *ifa;
1817 struct sockaddr_in6 *subj_ip6 = NULL; /* XXX pedant */
1c79356b 1818 int addrs = 0, addrsofif, iffound = 0;
9bccf70c
A
1819 int niflags = ni6->ni_flags;
1820
0a7de745 1821 if (ifpp != NULL) {
6d2010ae 1822 *ifpp = NULL;
0a7de745 1823 }
6d2010ae 1824
9bccf70c
A
1825 if ((niflags & NI_NODEADDR_FLAG_ALL) == 0) {
1826 switch (ni6->ni_code) {
1827 case ICMP6_NI_SUBJ_IPV6:
0a7de745
A
1828 if (subj == NULL) { /* must be impossible... */
1829 return 0;
1830 }
316670eb 1831 subj_ip6 = (struct sockaddr_in6 *)(void *)subj;
9bccf70c
A
1832 break;
1833 default:
1834 /*
1835 * XXX: we only support IPv6 subject address for
1836 * this Qtype.
1837 */
0a7de745 1838 return 0;
9bccf70c
A
1839 }
1840 }
1c79356b 1841
91447636
A
1842 ifnet_head_lock_shared();
1843 TAILQ_FOREACH(ifp, &ifnet_head, if_list) {
1c79356b 1844 addrsofif = 0;
91447636 1845 ifnet_lock_shared(ifp);
9bccf70c 1846 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
1c79356b 1847 {
6d2010ae
A
1848 IFA_LOCK(ifa);
1849 if (ifa->ifa_addr->sa_family != AF_INET6) {
1850 IFA_UNLOCK(ifa);
1c79356b 1851 continue;
6d2010ae 1852 }
1c79356b
A
1853 ifa6 = (struct in6_ifaddr *)ifa;
1854
9bccf70c
A
1855 if ((niflags & NI_NODEADDR_FLAG_ALL) == 0 &&
1856 IN6_ARE_ADDR_EQUAL(&subj_ip6->sin6_addr,
0a7de745 1857 &ifa6->ia_addr.sin6_addr)) {
1c79356b 1858 iffound = 1;
0a7de745 1859 }
1c79356b
A
1860
1861 /*
1862 * IPv4-mapped addresses can only be returned by a
1863 * Node Information proxy, since they represent
1864 * addresses of IPv4-only nodes, which perforce do
1865 * not implement this protocol.
9bccf70c 1866 * [icmp-name-lookups-07, Section 5.4]
1c79356b
A
1867 * So we don't support NI_NODEADDR_FLAG_COMPAT in
1868 * this function at this moment.
1869 */
1870
1c79356b 1871 /* What do we have to do about ::1? */
9bccf70c
A
1872 switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
1873 case IPV6_ADDR_SCOPE_LINKLOCAL:
6d2010ae
A
1874 if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0) {
1875 IFA_UNLOCK(ifa);
9bccf70c 1876 continue;
6d2010ae 1877 }
9bccf70c
A
1878 break;
1879 case IPV6_ADDR_SCOPE_SITELOCAL:
6d2010ae
A
1880 if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0) {
1881 IFA_UNLOCK(ifa);
9bccf70c 1882 continue;
6d2010ae 1883 }
1c79356b 1884 break;
9bccf70c 1885 case IPV6_ADDR_SCOPE_GLOBAL:
6d2010ae
A
1886 if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0) {
1887 IFA_UNLOCK(ifa);
9bccf70c 1888 continue;
6d2010ae 1889 }
1c79356b 1890 break;
9bccf70c 1891 default:
6d2010ae 1892 IFA_UNLOCK(ifa);
9bccf70c
A
1893 continue;
1894 }
1895
1896 /*
1897 * check if anycast is okay.
55e303ae 1898 * XXX: just experimental. not in the spec.
9bccf70c
A
1899 */
1900 if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 &&
6d2010ae
A
1901 (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0) {
1902 IFA_UNLOCK(ifa);
9bccf70c 1903 continue; /* we need only unicast addresses */
6d2010ae 1904 }
9bccf70c 1905 if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0 &&
6d2010ae
A
1906 (icmp6_nodeinfo & ICMP6_NODEINFO_TMPADDROK) == 0) {
1907 IFA_UNLOCK(ifa);
9bccf70c 1908 continue;
1c79356b 1909 }
9bccf70c 1910 addrsofif++; /* count the address */
6d2010ae 1911 IFA_UNLOCK(ifa);
1c79356b 1912 }
91447636 1913 ifnet_lock_done(ifp);
1c79356b 1914 if (iffound) {
6d2010ae
A
1915 if (ifpp != NULL) {
1916 *ifpp = ifp;
1917 ifnet_reference(ifp);
1918 }
91447636 1919 ifnet_head_done();
0a7de745 1920 return addrsofif;
1c79356b
A
1921 }
1922
1923 addrs += addrsofif;
1924 }
91447636 1925 ifnet_head_done();
1c79356b 1926
0a7de745 1927 return addrs;
1c79356b
A
1928}
1929
1930static int
39037602 1931ni6_store_addrs(struct icmp6_nodeinfo *ni6, struct icmp6_nodeinfo *nni6,
0a7de745 1932 struct ifnet *ifp0, int resid)
1c79356b 1933{
91447636 1934 struct ifnet *ifp = ifp0;
9bccf70c
A
1935 struct in6_ifaddr *ifa6;
1936 struct ifaddr *ifa;
1937 struct ifnet *ifp_dep = NULL;
1938 int copied = 0, allow_deprecated = 0;
1c79356b 1939 u_char *cp = (u_char *)(nni6 + 1);
9bccf70c
A
1940 int niflags = ni6->ni_flags;
1941 u_int32_t ltime;
39236c6e 1942 uint64_t now = net_uptime();
1c79356b 1943
0a7de745
A
1944 if (ifp0 == NULL && !(niflags & NI_NODEADDR_FLAG_ALL)) {
1945 return 0; /* needless to copy */
1946 }
1947again:
9bccf70c 1948
91447636 1949 ifnet_head_lock_shared();
0a7de745 1950 if (ifp == NULL) {
6d2010ae 1951 ifp = TAILQ_FIRST(&ifnet_head);
0a7de745 1952 }
6d2010ae 1953
91447636
A
1954 for (; ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
1955 ifnet_lock_shared(ifp);
1c79356b 1956 for (ifa = ifp->if_addrlist.tqh_first; ifa;
0a7de745 1957 ifa = ifa->ifa_list.tqe_next) {
39236c6e
A
1958 struct in6_addrlifetime_i *lt;
1959
6d2010ae
A
1960 IFA_LOCK(ifa);
1961 if (ifa->ifa_addr->sa_family != AF_INET6) {
1962 IFA_UNLOCK(ifa);
1c79356b 1963 continue;
6d2010ae 1964 }
1c79356b
A
1965 ifa6 = (struct in6_ifaddr *)ifa;
1966
9bccf70c
A
1967 if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) != 0 &&
1968 allow_deprecated == 0) {
1969 /*
1970 * prefererred address should be put before
1971 * deprecated addresses.
1972 */
1973
1974 /* record the interface for later search */
0a7de745 1975 if (ifp_dep == NULL) {
9bccf70c 1976 ifp_dep = ifp;
0a7de745 1977 }
9bccf70c 1978
6d2010ae 1979 IFA_UNLOCK(ifa);
9bccf70c 1980 continue;
6d2010ae
A
1981 } else if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) == 0 &&
1982 allow_deprecated != 0) {
1983 IFA_UNLOCK(ifa);
9bccf70c 1984 continue; /* we now collect deprecated addrs */
6d2010ae 1985 }
1c79356b 1986 /* What do we have to do about ::1? */
9bccf70c
A
1987 switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
1988 case IPV6_ADDR_SCOPE_LINKLOCAL:
6d2010ae
A
1989 if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0) {
1990 IFA_UNLOCK(ifa);
9bccf70c 1991 continue;
6d2010ae 1992 }
9bccf70c
A
1993 break;
1994 case IPV6_ADDR_SCOPE_SITELOCAL:
6d2010ae
A
1995 if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0) {
1996 IFA_UNLOCK(ifa);
9bccf70c 1997 continue;
6d2010ae 1998 }
1c79356b 1999 break;
9bccf70c 2000 case IPV6_ADDR_SCOPE_GLOBAL:
6d2010ae
A
2001 if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0) {
2002 IFA_UNLOCK(ifa);
9bccf70c 2003 continue;
6d2010ae 2004 }
1c79356b 2005 break;
9bccf70c 2006 default:
6d2010ae 2007 IFA_UNLOCK(ifa);
9bccf70c 2008 continue;
1c79356b
A
2009 }
2010
9bccf70c
A
2011 /*
2012 * check if anycast is okay.
6d2010ae 2013 * XXX: just experimental. not in the spec.
9bccf70c
A
2014 */
2015 if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 &&
6d2010ae
A
2016 (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0) {
2017 IFA_UNLOCK(ifa);
9bccf70c 2018 continue;
6d2010ae 2019 }
9bccf70c 2020 if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0 &&
6d2010ae
A
2021 (icmp6_nodeinfo & ICMP6_NODEINFO_TMPADDROK) == 0) {
2022 IFA_UNLOCK(ifa);
9bccf70c
A
2023 continue;
2024 }
2025
2026 /* now we can copy the address */
2027 if (resid < sizeof(struct in6_addr) +
2028 sizeof(u_int32_t)) {
6d2010ae 2029 IFA_UNLOCK(ifa);
9bccf70c
A
2030 /*
2031 * We give up much more copy.
2032 * Set the truncate flag and return.
2033 */
2034 nni6->ni_flags |=
0a7de745 2035 NI_NODEADDR_FLAG_TRUNCATE;
91447636
A
2036 ifnet_lock_done(ifp);
2037 ifnet_head_done();
0a7de745 2038 return copied;
9bccf70c
A
2039 }
2040
2041 /*
2042 * Set the TTL of the address.
2043 * The TTL value should be one of the following
2044 * according to the specification:
2045 *
2046 * 1. The remaining lifetime of a DHCP lease on the
2047 * address, or
2048 * 2. The remaining Valid Lifetime of a prefix from
2049 * which the address was derived through Stateless
2050 * Autoconfiguration.
2051 *
2052 * Note that we currently do not support stateful
2053 * address configuration by DHCPv6, so the former
2054 * case can't happen.
2055 */
39236c6e
A
2056 lt = &ifa6->ia6_lifetime;
2057 if (lt->ia6ti_expire == 0) {
9bccf70c 2058 ltime = ND6_INFINITE_LIFETIME;
39236c6e 2059 } else {
0a7de745 2060 if (lt->ia6ti_expire > now) {
39236c6e 2061 ltime = htonl(lt->ia6ti_expire - now);
0a7de745 2062 } else {
9bccf70c 2063 ltime = 0;
0a7de745 2064 }
1c79356b 2065 }
6d2010ae 2066
9bccf70c
A
2067 bcopy(&ltime, cp, sizeof(u_int32_t));
2068 cp += sizeof(u_int32_t);
2069
2070 /* copy the address itself */
2071 bcopy(&ifa6->ia_addr.sin6_addr, cp,
0a7de745 2072 sizeof(struct in6_addr));
9bccf70c 2073 /* XXX: KAME link-local hack; remove ifindex */
0a7de745 2074 if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr)) {
316670eb 2075 ((struct in6_addr *)(void *)cp)->s6_addr16[1] = 0;
0a7de745 2076 }
9bccf70c 2077 cp += sizeof(struct in6_addr);
6d2010ae 2078
9bccf70c
A
2079 resid -= (sizeof(struct in6_addr) + sizeof(u_int32_t));
2080 copied += (sizeof(struct in6_addr) +
0a7de745 2081 sizeof(u_int32_t));
6d2010ae 2082 IFA_UNLOCK(ifa);
1c79356b 2083 }
91447636 2084 ifnet_lock_done(ifp);
0a7de745 2085 if (ifp0) { /* we need search only on the specified IF */
1c79356b 2086 break;
0a7de745 2087 }
1c79356b 2088 }
91447636 2089 ifnet_head_done();
1c79356b 2090
9bccf70c
A
2091 if (allow_deprecated == 0 && ifp_dep != NULL) {
2092 ifp = ifp_dep;
2093 allow_deprecated = 1;
2094
2095 goto again;
2096 }
2097
0a7de745 2098 return copied;
1c79356b
A
2099}
2100
1c79356b
A
2101/*
2102 * XXX almost dup'ed code with rip6_input.
2103 */
2104static int
39037602 2105icmp6_rip6_input(struct mbuf **mp, int off)
1c79356b
A
2106{
2107 struct mbuf *m = *mp;
9bccf70c
A
2108 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
2109 struct in6pcb *in6p;
1c79356b
A
2110 struct in6pcb *last = NULL;
2111 struct sockaddr_in6 rip6src;
2112 struct icmp6_hdr *icmp6;
9bccf70c 2113 struct mbuf *opts = NULL;
6d2010ae 2114 int ret = 0;
39236c6e 2115 struct ifnet *ifp = m->m_pkthdr.rcvif;
1c79356b
A
2116
2117#ifndef PULLDOWN_TEST
2118 /* this is assumed to be safe. */
2119 icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
2120#else
2121 IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
2122 if (icmp6 == NULL) {
2123 /* m is already reclaimed */
2124 return IPPROTO_DONE;
2125 }
2126#endif
2127
6d2010ae
A
2128 /*
2129 * XXX: the address may have embedded scope zone ID, which should be
2130 * hidden from applications.
2131 */
1c79356b 2132 bzero(&rip6src, sizeof(rip6src));
1c79356b 2133 rip6src.sin6_family = AF_INET6;
6d2010ae
A
2134 rip6src.sin6_len = sizeof(struct sockaddr_in6);
2135 rip6src.sin6_addr = ip6->ip6_src;
0a7de745
A
2136 if (sa6_recoverscope(&rip6src, TRUE)) {
2137 return IPPROTO_DONE;
2138 }
316670eb 2139
39236c6e 2140 lck_rw_lock_shared(ripcbinfo.ipi_lock);
1c79356b 2141 LIST_FOREACH(in6p, &ripcb, inp_list)
1c79356b 2142 {
0a7de745 2143 if ((in6p->inp_vflag & INP_IPV6) == 0) {
9bccf70c 2144 continue;
0a7de745
A
2145 }
2146 if (in6p->in6p_ip6_nxt != IPPROTO_ICMPV6) {
1c79356b 2147 continue;
0a7de745 2148 }
1c79356b 2149 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
0a7de745 2150 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) {
1c79356b 2151 continue;
0a7de745 2152 }
1c79356b 2153 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
0a7de745 2154 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) {
1c79356b 2155 continue;
0a7de745 2156 }
1c79356b
A
2157 if (in6p->in6p_icmp6filt
2158 && ICMP6_FILTER_WILLBLOCK(icmp6->icmp6_type,
0a7de745 2159 in6p->in6p_icmp6filt)) {
1c79356b 2160 continue;
0a7de745 2161 }
39236c6e 2162
0a7de745 2163 if (inp_restricted_recv(in6p, ifp)) {
39236c6e 2164 continue;
0a7de745 2165 }
39236c6e 2166
1c79356b 2167 if (last) {
0a7de745 2168 struct mbuf *n;
1c79356b 2169 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
39236c6e 2170 if ((last->in6p_flags & INP_CONTROLOPTS) != 0 ||
6d2010ae 2171 (last->in6p_socket->so_options & SO_TIMESTAMP) != 0 ||
d9a64523 2172 (last->in6p_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0 ||
0a7de745 2173 (last->in6p_socket->so_options & SO_TIMESTAMP_CONTINUOUS) != 0) {
6d2010ae
A
2174 ret = ip6_savecontrol(last, n, &opts);
2175 if (ret != 0) {
2176 m_freem(n);
2177 m_freem(opts);
2178 last = in6p;
2179 continue;
2180 }
2181 }
1c79356b
A
2182 /* strip intermediate headers */
2183 m_adj(n, off);
6d2010ae 2184 so_recv_data_stat(last->in6p_socket, m, 0);
1c79356b 2185 if (sbappendaddr(&last->in6p_socket->so_rcv,
0a7de745
A
2186 (struct sockaddr *)&rip6src,
2187 n, opts, NULL) != 0) {
1c79356b 2188 sorwakeup(last->in6p_socket);
91447636 2189 }
9bccf70c 2190 opts = NULL;
1c79356b
A
2191 }
2192 }
2193 last = in6p;
2194 }
2195 if (last) {
6d2010ae
A
2196 if ((last->in6p_flags & INP_CONTROLOPTS) != 0 ||
2197 (last->in6p_socket->so_options & SO_TIMESTAMP) != 0 ||
d9a64523 2198 (last->in6p_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0 ||
0a7de745 2199 (last->in6p_socket->so_options & SO_TIMESTAMP_CONTINUOUS) != 0) {
6d2010ae
A
2200 ret = ip6_savecontrol(last, m, &opts);
2201 if (ret != 0) {
2202 goto error;
2203 }
2204 }
1c79356b
A
2205 /* strip intermediate headers */
2206 m_adj(m, off);
6d2010ae 2207 so_recv_data_stat(last->in6p_socket, m, 0);
1c79356b 2208 if (sbappendaddr(&last->in6p_socket->so_rcv,
0a7de745 2209 (struct sockaddr *)&rip6src, m, opts, NULL) != 0) {
1c79356b 2210 sorwakeup(last->in6p_socket);
91447636 2211 }
1c79356b 2212 } else {
6d2010ae 2213 goto error;
1c79356b 2214 }
39236c6e 2215 lck_rw_done(ripcbinfo.ipi_lock);
1c79356b 2216 return IPPROTO_DONE;
6d2010ae
A
2217
2218error:
39236c6e 2219 lck_rw_done(ripcbinfo.ipi_lock);
6d2010ae
A
2220 m_freem(m);
2221 m_freem(opts);
2222 ip6stat.ip6s_delivered--;
316670eb 2223 return IPPROTO_DONE;
1c79356b 2224}
1c79356b
A
2225
2226/*
2227 * Reflect the ip6 packet back to the source.
2228 * OFF points to the icmp6 header, counted from the top of the mbuf.
2229 */
2230void
39037602 2231icmp6_reflect(struct mbuf *m, size_t off)
1c79356b 2232{
39236c6e 2233 struct mbuf *m_ip6hdr = m;
1c79356b
A
2234 struct ip6_hdr *ip6;
2235 struct icmp6_hdr *icmp6;
2236 struct in6_ifaddr *ia;
91447636 2237 struct in6_addr t, src_storage, *src = 0;
1c79356b
A
2238 int plen;
2239 int type, code;
2240 struct ifnet *outif = NULL;
9bccf70c 2241 struct sockaddr_in6 sa6_src, sa6_dst;
3e170ce0 2242 struct nd_ifinfo *ndi = NULL;
b0d623f7 2243 u_int32_t oflow;
a39ff7e2
A
2244 struct ip6_out_args ip6oa;
2245
2246 bzero(&ip6oa, sizeof(ip6oa));
2247 ip6oa.ip6oa_boundif = IFSCOPE_NONE;
2248 ip6oa.ip6oa_flags = IP6OAF_SELECT_SRCIF | IP6OAF_BOUND_SRCADDR |
2249 IP6OAF_INTCOPROC_ALLOWED | IP6OAF_AWDL_UNRESTRICTED;
2250 ip6oa.ip6oa_sotc = SO_TC_UNSPEC;
2251 ip6oa.ip6oa_netsvctype = _NET_SERVICE_TYPE_UNSPEC;
6d2010ae 2252
39236c6e 2253 if (!(m->m_pkthdr.pkt_flags & PKTF_LOOP) && m->m_pkthdr.rcvif != NULL) {
6d2010ae 2254 ip6oa.ip6oa_boundif = m->m_pkthdr.rcvif->if_index;
316670eb
A
2255 ip6oa.ip6oa_flags |= IP6OAF_BOUND_IF;
2256 }
1c79356b
A
2257
2258 /* too short to reflect */
2259 if (off < sizeof(struct ip6_hdr)) {
cb323159
A
2260 nd6log(debug,
2261 "sanity fail: off=%x, sizeof(ip6)=%x in %s:%d\n",
b0d623f7 2262 (u_int32_t)off, (u_int32_t)sizeof(struct ip6_hdr),
cb323159 2263 __func__, __LINE__);
1c79356b
A
2264 goto bad;
2265 }
2266
2267 /*
2268 * If there are extra headers between IPv6 and ICMPv6, strip
2269 * off that header first.
2270 */
2271 if (off > sizeof(struct ip6_hdr)) {
2272 size_t l;
2273 struct ip6_hdr nip6;
2274
2275 l = off - sizeof(struct ip6_hdr);
2276 m_copydata(m, 0, sizeof(nip6), (caddr_t)&nip6);
2277 m_adj(m, l);
2278 l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
2279 if (m->m_len < l) {
0a7de745 2280 if ((m_ip6hdr = m_pulldown(m, 0, l, NULL)) == NULL) {
1c79356b 2281 return;
0a7de745 2282 }
1c79356b
A
2283 }
2284 bcopy((caddr_t)&nip6, mtod(m, caddr_t), sizeof(nip6));
0a7de745 2285 } else { /* off == sizeof(struct ip6_hdr) */
1c79356b
A
2286 size_t l;
2287 l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
2288 if (m->m_len < l) {
0a7de745 2289 if ((m_ip6hdr = m_pulldown(m, 0, l, NULL)) == NULL) {
1c79356b 2290 return;
0a7de745 2291 }
1c79356b
A
2292 }
2293 }
2294 plen = m->m_pkthdr.len - sizeof(struct ip6_hdr);
39236c6e 2295 ip6 = mtod(m_ip6hdr, struct ip6_hdr *);
1c79356b
A
2296 ip6->ip6_nxt = IPPROTO_ICMPV6;
2297 icmp6 = (struct icmp6_hdr *)(ip6 + 1);
2298 type = icmp6->icmp6_type; /* keep type for statistics */
2299 code = icmp6->icmp6_code; /* ditto. */
2300
2301 t = ip6->ip6_dst;
2302 /*
2303 * ip6_input() drops a packet if its src is multicast.
2304 * So, the src is never multicast.
2305 */
2306 ip6->ip6_dst = ip6->ip6_src;
2307
9bccf70c
A
2308 /*
2309 * XXX: make sure to embed scope zone information, using
2310 * already embedded IDs or the received interface (if any).
2311 * Note that rcvif may be NULL.
9bccf70c
A
2312 */
2313 bzero(&sa6_src, sizeof(sa6_src));
2314 sa6_src.sin6_family = AF_INET6;
2315 sa6_src.sin6_len = sizeof(sa6_src);
2316 sa6_src.sin6_addr = ip6->ip6_dst;
2317 in6_recoverscope(&sa6_src, &ip6->ip6_dst, m->m_pkthdr.rcvif);
6d2010ae 2318 in6_embedscope(&ip6->ip6_dst, &sa6_src, NULL, NULL, NULL);
9bccf70c
A
2319 bzero(&sa6_dst, sizeof(sa6_dst));
2320 sa6_dst.sin6_family = AF_INET6;
2321 sa6_dst.sin6_len = sizeof(sa6_dst);
2322 sa6_dst.sin6_addr = t;
2323 in6_recoverscope(&sa6_dst, &t, m->m_pkthdr.rcvif);
6d2010ae 2324 in6_embedscope(&t, &sa6_dst, NULL, NULL, NULL);
1c79356b 2325
1c79356b
A
2326 /*
2327 * If the incoming packet was addressed directly to us(i.e. unicast),
2328 * use dst as the src for the reply.
6d2010ae 2329 * The IN6_IFF_NOTREADY case should be VERY rare, but is possible
1c79356b
A
2330 * (for example) when we encounter an error while forwarding procedure
2331 * destined to a duplicated address of ours.
6d2010ae
A
2332 * Note that ip6_getdstifaddr() may fail if we are in an error handling
2333 * procedure of an outgoing packet of our own, in which case we need
2334 * to search in the ifaddr list.
1c79356b 2335 */
6d2010ae
A
2336 lck_rw_lock_shared(&in6_ifaddr_rwlock);
2337 for (ia = in6_ifaddrs; ia; ia = ia->ia_next) {
2338 IFA_LOCK(&ia->ia_ifa);
1c79356b 2339 if (IN6_ARE_ADDR_EQUAL(&t, &ia->ia_addr.sin6_addr) &&
0a7de745 2340 (ia->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY | IN6_IFF_CLAT46)) == 0) {
6d2010ae 2341 IFA_UNLOCK(&ia->ia_ifa);
1c79356b
A
2342 src = &t;
2343 break;
2344 }
6d2010ae
A
2345 IFA_UNLOCK(&ia->ia_ifa);
2346 }
2347 lck_rw_done(&in6_ifaddr_rwlock);
39236c6e
A
2348 if (ia == NULL && IN6_IS_ADDR_LINKLOCAL(&t) &&
2349 ((m->m_flags & M_LOOP) || (m->m_pkthdr.pkt_flags & PKTF_LOOP))) {
1c79356b
A
2350 /*
2351 * This is the case if the dst is our link-local address
39236c6e
A
2352 * and the sender is also ourselves. Here we test for both
2353 * M_LOOP and PKTF_LOOP, since the former may have been set
2354 * in ip6_output() and that we get here as part of callling
2355 * ip6_process_hopopts(). See comments in <sys/mbuf.h>
1c79356b
A
2356 */
2357 src = &t;
2358 }
2359
6d2010ae 2360 if (src == NULL) {
9bccf70c 2361 int e;
6d2010ae 2362 struct sockaddr_in6 sin6;
9bccf70c
A
2363 struct route_in6 ro;
2364
1c79356b
A
2365 /*
2366 * This case matches to multicasts, our anycast, or unicasts
55e303ae 2367 * that we do not own. Select a source address based on the
9bccf70c 2368 * source address of the erroneous packet.
1c79356b 2369 */
6d2010ae
A
2370 bzero(&sin6, sizeof(sin6));
2371 sin6.sin6_family = AF_INET6;
2372 sin6.sin6_len = sizeof(sin6);
2373 sin6.sin6_addr = ip6->ip6_dst; /* zone ID should be embedded */
2374
9bccf70c 2375 bzero(&ro, sizeof(ro));
316670eb
A
2376 /*
2377 * in6_selectsrc() might return outif with its reference held
2378 * even in the error case, so we always need to release it
2379 * if non-NULL.
2380 */
6d2010ae
A
2381 src = in6_selectsrc(&sin6, NULL, NULL, &ro, &outif,
2382 &src_storage, ip6oa.ip6oa_boundif, &e);
39236c6e 2383 ROUTE_RELEASE(&ro);
9bccf70c 2384 if (src == NULL) {
cb323159 2385 nd6log(debug,
9bccf70c
A
2386 "icmp6_reflect: source can't be determined: "
2387 "dst=%s, error=%d\n",
cb323159 2388 ip6_sprintf(&sa6_src.sin6_addr), e);
9bccf70c
A
2389 goto bad;
2390 }
2391 }
b0d623f7 2392 oflow = ip6->ip6_flow; /* Save for later */
6d2010ae 2393 ip6->ip6_src = *src;
1c79356b
A
2394 ip6->ip6_flow = 0;
2395 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
2396 ip6->ip6_vfc |= IPV6_VERSION;
b0d623f7
A
2397 if (icmp6->icmp6_type == ICMP6_ECHO_REPLY && icmp6->icmp6_code == 0) {
2398 ip6->ip6_flow |= (oflow & htonl(0x0ff00000));
2399 }
1c79356b 2400 ip6->ip6_nxt = IPPROTO_ICMPV6;
316670eb
A
2401 if (outif != NULL && (ndi = ND_IFINFO(outif)) != NULL &&
2402 ndi->initialized) {
2403 lck_mtx_lock(&ndi->lock);
2404 ip6->ip6_hlim = ndi->chlim;
2405 lck_mtx_unlock(&ndi->lock);
2406 }
2407 if (m->m_pkthdr.rcvif != NULL &&
2408 (ndi = ND_IFINFO(m->m_pkthdr.rcvif)) != NULL &&
2409 ndi->initialized) {
1c79356b 2410 /* XXX: This may not be the outgoing interface */
316670eb
A
2411 lck_mtx_lock(&ndi->lock);
2412 ip6->ip6_hlim = ndi->chlim;
2413 lck_mtx_unlock(&ndi->lock);
b0d623f7 2414 } else {
9bccf70c 2415 ip6->ip6_hlim = ip6_defhlim;
b0d623f7
A
2416 }
2417 /* Use the same traffic class as in the request to match IPv4 */
1c79356b
A
2418 icmp6->icmp6_cksum = 0;
2419 icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6,
3e170ce0 2420 sizeof(struct ip6_hdr), plen);
1c79356b
A
2421
2422 /*
9bccf70c 2423 * XXX option handling
1c79356b 2424 */
0a7de745 2425 m->m_flags &= ~(M_BCAST | M_MCAST);
1c79356b 2426
6d2010ae
A
2427 if (outif != NULL) {
2428 ifnet_release(outif);
2429 outif = NULL;
2430 }
3e170ce0 2431
316670eb
A
2432 m->m_pkthdr.csum_data = 0;
2433 m->m_pkthdr.csum_flags = 0;
6d2010ae
A
2434 ip6_output(m, NULL, NULL, IPV6_OUTARGS, NULL, &outif, &ip6oa);
2435 if (outif != NULL) {
1c79356b 2436 icmp6_ifoutstat_inc(outif, type, code);
6d2010ae
A
2437 ifnet_release(outif);
2438 }
1c79356b
A
2439 return;
2440
6d2010ae 2441bad:
1c79356b 2442 m_freem(m);
0a7de745 2443 if (outif != NULL) {
6d2010ae 2444 ifnet_release(outif);
0a7de745 2445 }
1c79356b
A
2446 return;
2447}
2448
1c79356b 2449static const char *
39037602 2450icmp6_redirect_diag(struct in6_addr *src6,
0a7de745
A
2451 struct in6_addr *dst6,
2452 struct in6_addr *tgt6)
1c79356b
A
2453{
2454 static char buf[1024];
1c79356b 2455 snprintf(buf, sizeof(buf), "(src=%s dst=%s tgt=%s)",
0a7de745 2456 ip6_sprintf(src6), ip6_sprintf(dst6), ip6_sprintf(tgt6));
1c79356b
A
2457 return buf;
2458}
2459
2460void
39037602 2461icmp6_redirect_input(struct mbuf *m, int off)
1c79356b 2462{
cb323159
A
2463 struct ifnet *ifp = NULL;
2464 struct ip6_hdr *ip6 = NULL;
2465 struct nd_redirect *nd_rd = NULL;
1c79356b 2466 char *lladdr = NULL;
cb323159 2467 int icmp6len = 0;
1c79356b
A
2468 int lladdrlen = 0;
2469 u_char *redirhdr = NULL;
2470 int redirhdrlen = 0;
2471 struct rtentry *rt = NULL;
2472 int is_router;
2473 int is_onlink;
cb323159 2474 struct in6_addr src6;
1c79356b
A
2475 struct in6_addr redtgt6;
2476 struct in6_addr reddst6;
2477 union nd_opts ndopts;
2478
cb323159 2479 if (m == NULL) {
1c79356b 2480 return;
0a7de745 2481 }
1c79356b 2482
cb323159
A
2483 ifp = m->m_pkthdr.rcvif;
2484 if (ifp == NULL) {
2485 goto freeit;
2486 }
2487
2488 ip6 = mtod(m, struct ip6_hdr *);
2489 icmp6len = ntohs(ip6->ip6_plen);
2490 src6 = ip6->ip6_src;
2491
316670eb
A
2492 /*
2493 * If we are an advertising router on this interface,
2494 * don't update route by icmp6 redirect.
2495 */
0a7de745 2496 if (ifp->if_eflags & IFEF_IPV6_ROUTER) {
1c79356b 2497 goto freeit;
0a7de745
A
2498 }
2499 if (!icmp6_rediraccept) {
1c79356b 2500 goto freeit;
0a7de745 2501 }
1c79356b
A
2502
2503#ifndef PULLDOWN_TEST
0a7de745 2504 IP6_EXTHDR_CHECK(m, off, icmp6len, return );
1c79356b
A
2505 nd_rd = (struct nd_redirect *)((caddr_t)ip6 + off);
2506#else
2507 IP6_EXTHDR_GET(nd_rd, struct nd_redirect *, m, off, icmp6len);
2508 if (nd_rd == NULL) {
2509 icmp6stat.icp6s_tooshort++;
cb323159 2510 goto freeit;
1c79356b
A
2511 }
2512#endif
2513 redtgt6 = nd_rd->nd_rd_target;
2514 reddst6 = nd_rd->nd_rd_dst;
2515
6d2010ae
A
2516 if (in6_setscope(&redtgt6, m->m_pkthdr.rcvif, NULL) ||
2517 in6_setscope(&reddst6, m->m_pkthdr.rcvif, NULL)) {
2518 goto freeit;
2519 }
1c79356b
A
2520
2521 /* validation */
2522 if (!IN6_IS_ADDR_LINKLOCAL(&src6)) {
cb323159 2523 nd6log(error,
0a7de745 2524 "ICMP6 redirect sent from %s rejected; "
cb323159 2525 "must be from linklocal\n", ip6_sprintf(&src6));
9bccf70c 2526 goto bad;
1c79356b 2527 }
cb323159
A
2528 if (ip6->ip6_hlim != IPV6_MAXHLIM) {
2529 nd6log(error,
0a7de745
A
2530 "ICMP6 redirect sent from %s rejected; "
2531 "hlim=%d (must be 255)\n",
cb323159 2532 ip6_sprintf(&src6), ip6->ip6_hlim);
9bccf70c 2533 goto bad;
1c79356b 2534 }
0a7de745
A
2535 {
2536 /* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */
2537 struct sockaddr_in6 sin6;
2538 struct in6_addr *gw6;
1c79356b 2539
0a7de745
A
2540 bzero(&sin6, sizeof(sin6));
2541 sin6.sin6_family = AF_INET6;
2542 sin6.sin6_len = sizeof(struct sockaddr_in6);
2543 bcopy(&reddst6, &sin6.sin6_addr, sizeof(reddst6));
2544 rt = rtalloc1_scoped((struct sockaddr *)&sin6, 0, 0, ifp->if_index);
2545 if (rt) {
2546 RT_LOCK(rt);
2547 if (rt->rt_gateway == NULL ||
2548 rt->rt_gateway->sa_family != AF_INET6) {
cb323159 2549 nd6log(error,
0a7de745
A
2550 "ICMP6 redirect rejected; no route "
2551 "with inet6 gateway found for redirect dst: %s\n",
cb323159 2552 icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
0a7de745
A
2553 RT_UNLOCK(rt);
2554 rtfree(rt);
2555 goto bad;
2556 }
9bccf70c 2557
0a7de745
A
2558 gw6 = &(((struct sockaddr_in6 *)(void *)
2559 rt->rt_gateway)->sin6_addr);
2560 if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) {
cb323159 2561 nd6log(error,
0a7de745
A
2562 "ICMP6 redirect rejected; "
2563 "not equal to gw-for-src=%s (must be same): "
2564 "%s\n",
2565 ip6_sprintf(gw6),
cb323159 2566 icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
0a7de745
A
2567 RT_UNLOCK(rt);
2568 rtfree(rt);
2569 goto bad;
2570 }
2571 } else {
cb323159 2572 nd6log(error,
0a7de745
A
2573 "ICMP6 redirect rejected; "
2574 "no route found for redirect dst: %s\n",
cb323159 2575 icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
9bccf70c 2576 goto bad;
1c79356b 2577 }
0a7de745
A
2578 RT_UNLOCK(rt);
2579 rtfree(rt);
2580 rt = NULL;
1c79356b 2581 }
1c79356b 2582 if (IN6_IS_ADDR_MULTICAST(&reddst6)) {
cb323159 2583 nd6log(error,
0a7de745
A
2584 "ICMP6 redirect rejected; "
2585 "redirect dst must be unicast: %s\n",
cb323159 2586 icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
9bccf70c 2587 goto bad;
1c79356b
A
2588 }
2589
2590 is_router = is_onlink = 0;
0a7de745
A
2591 if (IN6_IS_ADDR_LINKLOCAL(&redtgt6)) {
2592 is_router = 1; /* router case */
2593 }
2594 if (bcmp(&redtgt6, &reddst6, sizeof(redtgt6)) == 0) {
2595 is_onlink = 1; /* on-link destination case */
2596 }
1c79356b 2597 if (!is_router && !is_onlink) {
cb323159 2598 nd6log(error,
0a7de745
A
2599 "ICMP6 redirect rejected; "
2600 "neither router case nor onlink case: %s\n",
cb323159 2601 icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
9bccf70c 2602 goto bad;
1c79356b
A
2603 }
2604 /* validation passed */
2605
2606 icmp6len -= sizeof(*nd_rd);
2607 nd6_option_init(nd_rd + 1, icmp6len, &ndopts);
2608 if (nd6_options(&ndopts) < 0) {
cb323159 2609 nd6log(info, "icmp6_redirect_input: "
0a7de745 2610 "invalid ND option, rejected: %s\n",
cb323159 2611 icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
9bccf70c 2612 /* nd6_options have incremented stats */
1c79356b
A
2613 goto freeit;
2614 }
2615
2616 if (ndopts.nd_opts_tgt_lladdr) {
2617 lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
2618 lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
2619 }
2620
2621 if (ndopts.nd_opts_rh) {
2622 redirhdrlen = ndopts.nd_opts_rh->nd_opt_rh_len;
2623 redirhdr = (u_char *)(ndopts.nd_opts_rh + 1); /* xxx */
2624 }
2625
2626 if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
cb323159 2627 nd6log(info,
0a7de745
A
2628 "icmp6_redirect_input: lladdrlen mismatch for %s "
2629 "(if %d, icmp6 packet %d): %s\n",
2630 ip6_sprintf(&redtgt6), ifp->if_addrlen, lladdrlen - 2,
cb323159 2631 icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
9bccf70c 2632 goto bad;
1c79356b
A
2633 }
2634
2635 /* RFC 2461 8.3 */
2636 nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT,
0a7de745 2637 is_onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER);
1c79356b 2638
0a7de745 2639 if (!is_onlink) { /* better router case. perform rtredirect. */
1c79356b
A
2640 /* perform rtredirect */
2641 struct sockaddr_in6 sdst;
2642 struct sockaddr_in6 sgw;
2643 struct sockaddr_in6 ssrc;
1c79356b
A
2644
2645 bzero(&sdst, sizeof(sdst));
2646 bzero(&sgw, sizeof(sgw));
2647 bzero(&ssrc, sizeof(ssrc));
2648 sdst.sin6_family = sgw.sin6_family = ssrc.sin6_family = AF_INET6;
2649 sdst.sin6_len = sgw.sin6_len = ssrc.sin6_len =
0a7de745 2650 sizeof(struct sockaddr_in6);
1c79356b
A
2651 bcopy(&redtgt6, &sgw.sin6_addr, sizeof(struct in6_addr));
2652 bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
2653 bcopy(&src6, &ssrc.sin6_addr, sizeof(struct in6_addr));
c910b4d9
A
2654 rtredirect(ifp, (struct sockaddr *)&sdst,
2655 (struct sockaddr *)&sgw, NULL, RTF_GATEWAY | RTF_HOST,
2656 (struct sockaddr *)&ssrc, NULL);
1c79356b
A
2657 }
2658 /* finally update cached route in each socket via pfctlinput */
0a7de745
A
2659 {
2660 struct sockaddr_in6 sdst;
1c79356b 2661
0a7de745
A
2662 bzero(&sdst, sizeof(sdst));
2663 sdst.sin6_family = AF_INET6;
2664 sdst.sin6_len = sizeof(struct sockaddr_in6);
2665 bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
316670eb 2666
0a7de745 2667 pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst);
1c79356b 2668#if IPSEC
0a7de745 2669 key_sa_routechange((struct sockaddr *)&sdst);
1c79356b 2670#endif
0a7de745 2671 }
1c79356b 2672
0a7de745 2673freeit:
1c79356b 2674 m_freem(m);
9bccf70c
A
2675 return;
2676
0a7de745 2677bad:
9bccf70c
A
2678 icmp6stat.icp6s_badredirect++;
2679 m_freem(m);
1c79356b
A
2680}
2681
2682void
39037602 2683icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt)
1c79356b 2684{
0a7de745 2685 struct ifnet *ifp; /* my outgoing interface */
91447636 2686 struct in6_addr ifp_ll6;
1c79356b 2687 struct in6_addr *router_ll6;
0a7de745
A
2688 struct ip6_hdr *sip6; /* m0 as struct ip6_hdr */
2689 struct mbuf *m = NULL; /* newly allocated one */
2690 struct ip6_hdr *ip6; /* m as struct ip6_hdr */
1c79356b
A
2691 struct nd_redirect *nd_rd;
2692 size_t maxlen;
2693 u_char *p;
2694 struct ifnet *outif = NULL;
9bccf70c 2695 struct sockaddr_in6 src_sa;
a39ff7e2
A
2696 struct ip6_out_args ip6oa;
2697
2698 bzero(&ip6oa, sizeof(ip6oa));
2699 ip6oa.ip6oa_boundif = IFSCOPE_NONE;
2700 ip6oa.ip6oa_flags = IP6OAF_SELECT_SRCIF | IP6OAF_BOUND_SRCADDR;
2701 ip6oa.ip6oa_sotc = SO_TC_UNSPEC;
2702 ip6oa.ip6oa_netsvctype = _NET_SERVICE_TYPE_UNSPEC;
9bccf70c
A
2703
2704 icmp6_errcount(&icmp6stat.icp6s_outerrhist, ND_REDIRECT, 0);
1c79356b 2705
0a7de745 2706 if (rt != NULL) {
b0d623f7 2707 RT_LOCK(rt);
0a7de745 2708 }
b0d623f7 2709
1c79356b 2710 /* sanity check */
0a7de745 2711 if (!m0 || !rt || !(rt->rt_flags & RTF_UP) || !(ifp = rt->rt_ifp)) {
1c79356b 2712 goto fail;
0a7de745 2713 }
1c79356b 2714
316670eb
A
2715 /*
2716 * If we are not a router to begin with, or not an advertising
2717 * router on this interface, don't send icmp6 redirect.
2718 */
0a7de745 2719 if (!ip6_forwarding || !(ifp->if_eflags & IFEF_IPV6_ROUTER)) {
55e303ae 2720 goto fail;
0a7de745 2721 }
55e303ae 2722
1c79356b
A
2723 /*
2724 * Address check:
2725 * the source address must identify a neighbor, and
2726 * the destination address must not be a multicast address
2727 * [RFC 2461, sec 8.2]
2728 */
2729 sip6 = mtod(m0, struct ip6_hdr *);
9bccf70c
A
2730 bzero(&src_sa, sizeof(src_sa));
2731 src_sa.sin6_family = AF_INET6;
2732 src_sa.sin6_len = sizeof(src_sa);
2733 src_sa.sin6_addr = sip6->ip6_src;
2734 /* we don't currently use sin6_scope_id, but eventually use it */
2735 src_sa.sin6_scope_id = in6_addr2scopeid(ifp, &sip6->ip6_src);
b0d623f7
A
2736 RT_UNLOCK(rt);
2737 if (nd6_is_addr_neighbor(&src_sa, ifp, 0) == 0) {
2738 /* already unlocked */
2739 rt = NULL;
1c79356b 2740 goto fail;
b0d623f7
A
2741 }
2742 RT_LOCK(rt);
0a7de745
A
2743 if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst)) {
2744 goto fail; /* what should we do here? */
2745 }
1c79356b 2746 /* rate limit */
0a7de745 2747 if (icmp6_ratelimit(&sip6->ip6_src, ND_REDIRECT, 0)) {
1c79356b 2748 goto fail;
0a7de745 2749 }
1c79356b
A
2750
2751 /*
2752 * Since we are going to append up to 1280 bytes (= IPV6_MMTU),
2753 * we almost always ask for an mbuf cluster for simplicity.
2754 * (MHLEN < IPV6_MMTU is almost always true)
2755 */
2756#if IPV6_MMTU >= MCLBYTES
2757# error assumption failed about IPV6_MMTU and MCLBYTES
2758#endif
0a7de745
A
2759 MGETHDR(m, M_DONTWAIT, MT_HEADER); /* MAC-OK */
2760 if (m && IPV6_MMTU >= MHLEN) {
1c79356b 2761 MCLGET(m, M_DONTWAIT);
0a7de745
A
2762 }
2763 if (!m) {
1c79356b 2764 goto fail;
0a7de745 2765 }
9bccf70c
A
2766 m->m_pkthdr.rcvif = NULL;
2767 m->m_len = 0;
2768 maxlen = M_TRAILINGSPACE(m);
1c79356b
A
2769 maxlen = min(IPV6_MMTU, maxlen);
2770 /* just for safety */
2771 if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) +
2772 ((sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7)) {
2773 goto fail;
2774 }
2775
2776 {
2777 /* get ip6 linklocal address for ifp(my outgoing interface). */
2778 struct in6_ifaddr *ia;
2779 if ((ia = in6ifa_ifpforlinklocal(ifp,
0a7de745
A
2780 IN6_IFF_NOTREADY |
2781 IN6_IFF_ANYCAST)) == NULL) {
1c79356b 2782 goto fail;
0a7de745 2783 }
6d2010ae 2784 IFA_LOCK(&ia->ia_ifa);
91447636 2785 ifp_ll6 = ia->ia_addr.sin6_addr;
6d2010ae
A
2786 IFA_UNLOCK(&ia->ia_ifa);
2787 IFA_REMREF(&ia->ia_ifa);
1c79356b
A
2788 }
2789
2790 /* get ip6 linklocal address for the router. */
2791 if (rt->rt_gateway && (rt->rt_flags & RTF_GATEWAY)) {
2792 struct sockaddr_in6 *sin6;
316670eb 2793 sin6 = (struct sockaddr_in6 *)(void *)rt->rt_gateway;
1c79356b 2794 router_ll6 = &sin6->sin6_addr;
0a7de745 2795 if (!IN6_IS_ADDR_LINKLOCAL(router_ll6)) {
1c79356b 2796 router_ll6 = (struct in6_addr *)NULL;
0a7de745
A
2797 }
2798 } else {
1c79356b 2799 router_ll6 = (struct in6_addr *)NULL;
0a7de745 2800 }
1c79356b
A
2801
2802 /* ip6 */
2803 ip6 = mtod(m, struct ip6_hdr *);
2804 ip6->ip6_flow = 0;
2805 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
2806 ip6->ip6_vfc |= IPV6_VERSION;
2807 /* ip6->ip6_plen will be set later */
2808 ip6->ip6_nxt = IPPROTO_ICMPV6;
cb323159 2809 ip6->ip6_hlim = IPV6_MAXHLIM;
1c79356b 2810 /* ip6->ip6_src must be linklocal addr for my outgoing if. */
91447636 2811 bcopy(&ifp_ll6, &ip6->ip6_src, sizeof(struct in6_addr));
1c79356b
A
2812 bcopy(&sip6->ip6_src, &ip6->ip6_dst, sizeof(struct in6_addr));
2813
2814 /* ND Redirect */
2815 nd_rd = (struct nd_redirect *)(ip6 + 1);
2816 nd_rd->nd_rd_type = ND_REDIRECT;
2817 nd_rd->nd_rd_code = 0;
2818 nd_rd->nd_rd_reserved = 0;
2819 if (rt->rt_flags & RTF_GATEWAY) {
2820 /*
2821 * nd_rd->nd_rd_target must be a link-local address in
2822 * better router cases.
2823 */
0a7de745 2824 if (!router_ll6) {
1c79356b 2825 goto fail;
0a7de745 2826 }
1c79356b 2827 bcopy(router_ll6, &nd_rd->nd_rd_target,
0a7de745 2828 sizeof(nd_rd->nd_rd_target));
1c79356b 2829 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
0a7de745 2830 sizeof(nd_rd->nd_rd_dst));
1c79356b
A
2831 } else {
2832 /* make sure redtgt == reddst */
2833 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_target,
0a7de745 2834 sizeof(nd_rd->nd_rd_target));
1c79356b 2835 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
0a7de745 2836 sizeof(nd_rd->nd_rd_dst));
1c79356b 2837 }
b0d623f7
A
2838 RT_UNLOCK(rt);
2839 rt = NULL;
1c79356b
A
2840
2841 p = (u_char *)(nd_rd + 1);
2842
0a7de745 2843 if (!router_ll6) {
1c79356b 2844 goto nolladdropt;
0a7de745 2845 }
1c79356b 2846
6d2010ae
A
2847 {
2848 /* target lladdr option */
2849 struct rtentry *rt_router = NULL;
2850 int len;
2851 struct sockaddr_dl *sdl;
2852 struct nd_opt_hdr *nd_opt;
2853 char *lladdr;
2854
2855 /* Callee returns a locked route upon success */
2856 rt_router = nd6_lookup(router_ll6, 0, ifp, 0);
0a7de745 2857 if (!rt_router) {
6d2010ae 2858 goto nolladdropt;
0a7de745 2859 }
6d2010ae
A
2860 RT_LOCK_ASSERT_HELD(rt_router);
2861 len = sizeof(*nd_opt) + ifp->if_addrlen;
0a7de745 2862 len = (len + 7) & ~7; /* round by 8 */
6d2010ae
A
2863 /* safety check */
2864 if (len + (p - (u_char *)ip6) > maxlen) {
2865 RT_REMREF_LOCKED(rt_router);
2866 RT_UNLOCK(rt_router);
2867 goto nolladdropt;
2868 }
2869
2870 if (!(rt_router->rt_flags & RTF_GATEWAY) &&
0a7de745
A
2871 (rt_router->rt_flags & RTF_LLINFO) &&
2872 (rt_router->rt_gateway->sa_family == AF_LINK) &&
2873 (sdl = (struct sockaddr_dl *)(void *)
2874 rt_router->rt_gateway) && sdl->sdl_alen) {
2875 nd_opt = (struct nd_opt_hdr *)p;
2876 nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
2877 nd_opt->nd_opt_len = len >> 3;
2878 lladdr = (char *)(nd_opt + 1);
2879 bcopy(LLADDR(sdl), lladdr, ifp->if_addrlen);
2880 p += len;
6d2010ae 2881 }
b0d623f7
A
2882 RT_REMREF_LOCKED(rt_router);
2883 RT_UNLOCK(rt_router);
316670eb 2884 }
6d2010ae 2885
1c79356b
A
2886nolladdropt:;
2887
2888 m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
2889
2890 /* just to be safe */
0a7de745
A
2891#ifdef M_DECRYPTED /*not openbsd*/
2892 if (m0->m_flags & M_DECRYPTED) {
1c79356b 2893 goto noredhdropt;
0a7de745 2894 }
1c79356b 2895#endif
0a7de745 2896 if (p - (u_char *)ip6 > maxlen) {
1c79356b 2897 goto noredhdropt;
0a7de745 2898 }
1c79356b 2899
0a7de745
A
2900 {
2901 /* redirected header option */
2902 int len;
2903 struct nd_opt_rd_hdr *nd_opt_rh;
1c79356b 2904
0a7de745
A
2905 /*
2906 * compute the maximum size for icmp6 redirect header option.
2907 * XXX room for auth header?
2908 */
2909 len = maxlen - (p - (u_char *)ip6);
2910 len &= ~7;
2911
2912 /* This is just for simplicity. */
2913 if (m0->m_pkthdr.len != m0->m_len) {
2914 if (m0->m_next) {
2915 m_freem(m0->m_next);
2916 m0->m_next = NULL;
2917 }
2918 m0->m_pkthdr.len = m0->m_len;
1c79356b 2919 }
1c79356b 2920
0a7de745
A
2921 /*
2922 * Redirected header option spec (RFC2461 4.6.3) talks nothing
2923 * about padding/truncate rule for the original IP packet.
2924 * From the discussion on IPv6imp in Feb 1999, the consensus was:
2925 * - "attach as much as possible" is the goal
2926 * - pad if not aligned (original size can be guessed by original
2927 * ip6 header)
2928 * Following code adds the padding if it is simple enough,
2929 * and truncates if not.
2930 */
2931 if (m0->m_next || m0->m_pkthdr.len != m0->m_len) {
2932 panic("assumption failed in %s:%d\n", __func__, __LINE__);
2933 }
1c79356b 2934
0a7de745
A
2935 if (len - sizeof(*nd_opt_rh) < m0->m_pkthdr.len) {
2936 /* not enough room, truncate */
2937 m0->m_pkthdr.len = m0->m_len = len - sizeof(*nd_opt_rh);
2938 } else {
2939 /* enough room, pad or truncate */
2940 size_t extra;
2941
2942 extra = m0->m_pkthdr.len % 8;
2943 if (extra) {
2944 /* pad if easy enough, truncate if not */
2945 if (8 - extra <= M_TRAILINGSPACE(m0)) {
2946 /* pad */
2947 m0->m_len += (8 - extra);
2948 m0->m_pkthdr.len += (8 - extra);
2949 } else {
2950 /* truncate */
2951 m0->m_pkthdr.len -= extra;
2952 m0->m_len -= extra;
2953 }
1c79356b 2954 }
0a7de745
A
2955 len = m0->m_pkthdr.len + sizeof(*nd_opt_rh);
2956 m0->m_pkthdr.len = m0->m_len = len - sizeof(*nd_opt_rh);
1c79356b 2957 }
1c79356b 2958
0a7de745
A
2959 nd_opt_rh = (struct nd_opt_rd_hdr *)p;
2960 bzero(nd_opt_rh, sizeof(*nd_opt_rh));
2961 nd_opt_rh->nd_opt_rh_type = ND_OPT_REDIRECTED_HEADER;
2962 nd_opt_rh->nd_opt_rh_len = len >> 3;
2963 p += sizeof(*nd_opt_rh);
2964 m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
1c79356b 2965
0a7de745
A
2966 /* connect m0 to m */
2967 m->m_next = m0;
2968 m->m_pkthdr.len = m->m_len + m0->m_len;
2969 }
1c79356b
A
2970noredhdropt:;
2971
6d2010ae
A
2972 /* XXX: clear embedded link IDs in the inner header */
2973 in6_clearscope(&sip6->ip6_src);
2974 in6_clearscope(&sip6->ip6_dst);
2975 in6_clearscope(&nd_rd->nd_rd_target);
2976 in6_clearscope(&nd_rd->nd_rd_dst);
1c79356b
A
2977
2978 ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
2979
2980 nd_rd->nd_rd_cksum = 0;
2981 nd_rd->nd_rd_cksum
0a7de745 2982 = in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), ntohs(ip6->ip6_plen));
1c79356b
A
2983
2984 /* send the packet to outside... */
6d2010ae 2985 ip6oa.ip6oa_boundif = ifp->if_index;
316670eb 2986 ip6oa.ip6oa_flags |= IP6OAF_BOUND_IF;
6d2010ae
A
2987
2988 ip6_output(m, NULL, NULL, IPV6_OUTARGS, NULL, &outif, &ip6oa);
1c79356b
A
2989 if (outif) {
2990 icmp6_ifstat_inc(outif, ifs6_out_msg);
2991 icmp6_ifstat_inc(outif, ifs6_out_redirect);
6d2010ae 2992 ifnet_release(outif);
1c79356b
A
2993 }
2994 icmp6stat.icp6s_outhist[ND_REDIRECT]++;
2995
2996 return;
2997
2998fail:
0a7de745 2999 if (rt != NULL) {
b0d623f7 3000 RT_UNLOCK(rt);
0a7de745
A
3001 }
3002 if (m) {
1c79356b 3003 m_freem(m);
0a7de745
A
3004 }
3005 if (m0) {
1c79356b 3006 m_freem(m0);
0a7de745 3007 }
1c79356b
A
3008}
3009
1c79356b
A
3010/*
3011 * ICMPv6 socket option processing.
1c79356b
A
3012 */
3013int
39037602 3014icmp6_ctloutput(struct socket *so, struct sockopt *sopt)
1c79356b
A
3015{
3016 int error = 0;
3017 int optlen;
9bccf70c 3018 struct inpcb *inp = sotoinpcb(so);
1c79356b
A
3019 int level, op, optname;
3020
3021 if (sopt) {
3022 level = sopt->sopt_level;
3023 op = sopt->sopt_dir;
3024 optname = sopt->sopt_name;
3025 optlen = sopt->sopt_valsize;
0a7de745 3026 } else {
1c79356b 3027 level = op = optname = optlen = 0;
0a7de745 3028 }
1c79356b
A
3029
3030 if (level != IPPROTO_ICMPV6) {
1c79356b
A
3031 return EINVAL;
3032 }
3033
9bccf70c 3034 switch (op) {
1c79356b
A
3035 case PRCO_SETOPT:
3036 switch (optname) {
3037 case ICMP6_FILTER:
0a7de745 3038 {
1c79356b
A
3039 struct icmp6_filter *p;
3040
6d2010ae 3041 if (optlen != 0 && optlen != sizeof(*p)) {
1c79356b
A
3042 error = EMSGSIZE;
3043 break;
3044 }
1c79356b
A
3045 if (inp->in6p_icmp6filt == NULL) {
3046 error = EINVAL;
3047 break;
3048 }
6d2010ae
A
3049
3050 if (optlen == 0) {
743345f9 3051 /* According to RFC 3542, an installed filter can be
6d2010ae
A
3052 * cleared by issuing a setsockopt for ICMP6_FILTER
3053 * with a zero length.
3054 */
3055 ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt);
3056 } else {
3057 error = sooptcopyin(sopt, inp->in6p_icmp6filt, optlen,
0a7de745 3058 optlen);
6d2010ae 3059 }
1c79356b 3060 break;
0a7de745 3061 }
1c79356b
A
3062
3063 default:
3064 error = ENOPROTOOPT;
3065 break;
3066 }
1c79356b
A
3067 break;
3068
3069 case PRCO_GETOPT:
3070 switch (optname) {
3071 case ICMP6_FILTER:
0a7de745 3072 {
1c79356b
A
3073 if (inp->in6p_icmp6filt == NULL) {
3074 error = EINVAL;
3075 break;
3076 }
3077 error = sooptcopyout(sopt, inp->in6p_icmp6filt,
0a7de745 3078 min(sizeof(struct icmp6_filter), optlen));
1c79356b 3079 break;
0a7de745 3080 }
1c79356b
A
3081
3082 default:
3083 error = ENOPROTOOPT;
3084 break;
3085 }
3086 break;
3087 }
3088
0a7de745 3089 return error;
1c79356b 3090}
9bccf70c 3091
2d21ac55
A
3092/*
3093 * ICMPv6 socket datagram option processing.
3094 */
3095int
3096icmp6_dgram_ctloutput(struct socket *so, struct sockopt *sopt)
3097{
0a7de745 3098 if (kauth_cred_issuser(so->so_cred)) {
2d21ac55 3099 return icmp6_ctloutput(so, sopt);
0a7de745 3100 }
2d21ac55
A
3101
3102 if (sopt->sopt_level == IPPROTO_ICMPV6) {
3103 switch (sopt->sopt_name) {
0a7de745
A
3104 case ICMP6_FILTER:
3105 return icmp6_ctloutput(so, sopt);
3106 default:
3107 return EPERM;
2d21ac55
A
3108 }
3109 }
316670eb 3110
0a7de745 3111 if (sopt->sopt_level != IPPROTO_IPV6) {
2d21ac55 3112 return EINVAL;
0a7de745 3113 }
316670eb 3114
2d21ac55 3115 switch (sopt->sopt_name) {
0a7de745
A
3116 case IPV6_UNICAST_HOPS:
3117 case IPV6_CHECKSUM:
3118 case IPV6_V6ONLY:
3119 case IPV6_USE_MIN_MTU:
3120 case IPV6_RECVRTHDR:
3121 case IPV6_RECVPKTINFO:
3122 case IPV6_RECVHOPLIMIT:
3123 case IPV6_PATHMTU:
3124 case IPV6_PKTINFO:
3125 case IPV6_HOPLIMIT:
3126 case IPV6_HOPOPTS:
3127 case IPV6_DSTOPTS:
3128 case IPV6_MULTICAST_IF:
3129 case IPV6_MULTICAST_HOPS:
3130 case IPV6_MULTICAST_LOOP:
3131 case IPV6_JOIN_GROUP:
3132 case IPV6_LEAVE_GROUP:
3133 case IPV6_PORTRANGE:
3134 case IPV6_IPSEC_POLICY:
3135 case IPV6_RECVTCLASS:
3136 case IPV6_TCLASS:
3137 case IPV6_2292PKTOPTIONS:
3138 case IPV6_2292PKTINFO:
3139 case IPV6_2292HOPLIMIT:
3140 case IPV6_2292HOPOPTS:
3141 case IPV6_2292DSTOPTS:
3142 case IPV6_2292RTHDR:
3143 case IPV6_BOUND_IF:
3144 case IPV6_NO_IFT_CELLULAR:
3145
3146 return ip6_ctloutput(so, sopt);
316670eb 3147
0a7de745
A
3148 default:
3149 return EPERM;
2d21ac55
A
3150 }
3151}
3152
3153__private_extern__ int
6d2010ae
A
3154icmp6_dgram_send(struct socket *so, int flags, struct mbuf *m,
3155 struct sockaddr *nam, struct mbuf *control, struct proc *p)
2d21ac55 3156{
6d2010ae 3157#pragma unused(flags, p)
2d21ac55
A
3158 int error = 0;
3159 struct inpcb *inp = sotoinpcb(so);
2d21ac55
A
3160 struct icmp6_hdr *icmp6;
3161
fe8ab488
A
3162 if (inp == NULL
3163#if NECP
0a7de745 3164 || (necp_socket_should_use_flow_divert(inp))
fe8ab488 3165#endif /* NECP */
0a7de745 3166 ) {
39236c6e
A
3167 error = (inp == NULL ? EINVAL : EPROTOTYPE);
3168 goto bad;
3169 }
3170
0a7de745
A
3171 if (kauth_cred_issuser(so->so_cred)) {
3172 return rip6_output(m, so, SIN6(nam), control, 0);
3173 }
2d21ac55 3174
2d21ac55
A
3175 /*
3176 * For an ICMPv6 packet, we should know its type and code
3177 */
39236c6e 3178 if (SOCK_PROTO(so) == IPPROTO_ICMPV6) {
2d21ac55 3179 if (m->m_len < sizeof(struct icmp6_hdr) &&
0a7de745
A
3180 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
3181 error = ENOBUFS;
3182 goto bad;
2d21ac55
A
3183 }
3184 icmp6 = mtod(m, struct icmp6_hdr *);
316670eb 3185
2d21ac55 3186 /*
b0d623f7 3187 * Allow only to send echo request and node information request
2d21ac55
A
3188 * See RFC 2463 for Echo Request Message format
3189 */
39236c6e
A
3190 if ((icmp6->icmp6_type == ICMP6_ECHO_REQUEST &&
3191 icmp6->icmp6_code == 0) ||
3192 (icmp6->icmp6_type == ICMP6_NI_QUERY &&
3193 (icmp6->icmp6_code == ICMP6_NI_SUBJ_IPV6 ||
3194 icmp6->icmp6_code == ICMP6_NI_SUBJ_FQDN))) {
b0d623f7
A
3195 /* Good */
3196 ;
3197 } else {
2d21ac55
A
3198 error = EPERM;
3199 goto bad;
3200 }
3201 }
3202
bca245ac 3203 return rip6_output(m, so, SIN6(nam), control, 0);
2d21ac55 3204bad:
39236c6e
A
3205 VERIFY(error != 0);
3206
0a7de745 3207 if (m != NULL) {
39236c6e 3208 m_freem(m);
0a7de745
A
3209 }
3210 if (control != NULL) {
39236c6e 3211 m_freem(control);
0a7de745 3212 }
39236c6e 3213
0a7de745 3214 return error;
2d21ac55
A
3215}
3216
3217/* Like rip6_attach but without root privilege enforcement */
3218__private_extern__ int
3219icmp6_dgram_attach(struct socket *so, int proto, struct proc *p)
3220{
0a7de745
A
3221 struct inpcb *inp;
3222 int error;
3223
3224 inp = sotoinpcb(so);
3225 if (inp) {
3226 panic("icmp6_dgram_attach");
3227 }
3228
3229 if (proto != IPPROTO_ICMPV6) {
3230 return EINVAL;
3231 }
3232
3233 error = soreserve(so, rip_sendspace, rip_recvspace);
3234 if (error) {
3235 return error;
3236 }
3237 error = in_pcballoc(so, &ripcbinfo, p);
3238 if (error) {
3239 return error;
3240 }
3241 inp = (struct inpcb *)so->so_pcb;
3242 inp->inp_vflag |= INP_IPV6;
3243 inp->in6p_ip6_nxt = IPPROTO_ICMPV6;
3244 inp->in6p_hops = -1; /* use kernel default */
3245 inp->in6p_cksum = -1;
3246 MALLOC(inp->in6p_icmp6filt, struct icmp6_filter *,
3247 sizeof(struct icmp6_filter), M_PCB, M_WAITOK);
3248 if (inp->in6p_icmp6filt == NULL) {
3249 return ENOMEM;
3250 }
3251 ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt);
3252 return 0;
2d21ac55
A
3253}
3254
3255
1c79356b
A
3256/*
3257 * Perform rate limit check.
3258 * Returns 0 if it is okay to send the icmp6 packet.
3259 * Returns 1 if the router SHOULD NOT send this icmp6 packet due to rate
3260 * limitation.
3261 *
fe8ab488 3262 * XXX per-destination check necessary?
1c79356b
A
3263 */
3264static int
2d21ac55 3265icmp6_ratelimit(
0a7de745 3266 __unused const struct in6_addr *dst, /* not used at this moment */
fe8ab488
A
3267 const int type,
3268 __unused const int code)
1c79356b 3269{
9bccf70c 3270 int ret;
1c79356b 3271
0a7de745 3272 ret = 0; /* okay to send */
1c79356b 3273
9bccf70c 3274 /* PPS limit */
fe8ab488
A
3275 if (type == ND_ROUTER_ADVERT) {
3276 if (!ppsratecheck(&icmp6rappslim_last, &icmp6rapps_count,
0a7de745 3277 icmp6rappslim)) {
fe8ab488 3278 ret++;
0a7de745 3279 }
fe8ab488 3280 } else if (!ppsratecheck(&icmp6errppslim_last, &icmp6errpps_count,
9bccf70c 3281 icmp6errppslim)) {
1c79356b 3282 /* The packet is subject to rate limit */
9bccf70c 3283 ret++;
1c79356b 3284 }
1c79356b 3285
9bccf70c 3286 return ret;
1c79356b 3287}