blob: 15ca8adbaad6b8c1d866bd9ab09cf95b840c3143 [file] [log] [blame]
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
ja9789095579062006-02-23 01:18:00 -08005 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07007 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
Sowmini Varadhan53287762010-05-06 21:52:58 -040022 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070023 * Copyright (c) 1990 Mentat Inc.
Dan McDonald7199b8e2017-02-01 14:55:57 -050024 * Copyright 2017 OmniTI Computer Consulting, Inc. All rights reserved.
Dan McDonald9495f632021-10-30 00:14:30 -040025 * Copyright 2021 Joyent, Inc.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070026 */
27
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070028#include <sys/types.h>
29#include <sys/stream.h>
30#include <sys/dlpi.h>
31#include <sys/stropts.h>
32#include <sys/sysmacros.h>
33#include <sys/strsun.h>
34#include <sys/strlog.h>
35#include <sys/strsubr.h>
36#define _SUN_TPI_VERSION 2
37#include <sys/tihdr.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070038#include <sys/ddi.h>
39#include <sys/sunddi.h>
40#include <sys/cmn_err.h>
41#include <sys/debug.h>
dr146992381a2a92006-10-20 16:37:58 -070042#include <sys/sdt.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070043#include <sys/kobj.h>
44#include <sys/zone.h>
dr146992381a2a92006-10-20 16:37:58 -070045#include <sys/neti.h>
46#include <sys/hook.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070047
48#include <sys/kmem.h>
49#include <sys/systm.h>
50#include <sys/param.h>
51#include <sys/socket.h>
52#include <sys/vtrace.h>
53#include <sys/isa_defs.h>
54#include <sys/atomic.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070055#include <sys/policy.h>
Erik Nordmarkbd670b32009-11-11 11:49:49 -080056#include <sys/mac.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070057#include <net/if.h>
masputraff550d02005-10-22 22:50:14 -070058#include <net/if_types.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070059#include <net/route.h>
60#include <net/if_dl.h>
61#include <sys/sockio.h>
62#include <netinet/in.h>
63#include <netinet/ip6.h>
64#include <netinet/icmp6.h>
65#include <netinet/sctp.h>
66
67#include <inet/common.h>
68#include <inet/mi.h>
nordmarkfc80c0d2007-10-11 22:57:36 -070069#include <inet/optcom.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070070#include <inet/mib2.h>
71#include <inet/nd.h>
72#include <inet/arp.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070073
74#include <inet/ip.h>
masputraff550d02005-10-22 22:50:14 -070075#include <inet/ip_impl.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070076#include <inet/ip6.h>
77#include <inet/ip6_asp.h>
78#include <inet/tcp.h>
masputraff550d02005-10-22 22:50:14 -070079#include <inet/tcp_impl.h>
80#include <inet/udp_impl.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070081#include <inet/ipp_common.h>
82
83#include <inet/ip_multi.h>
84#include <inet/ip_if.h>
85#include <inet/ip_ire.h>
86#include <inet/ip_rts.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070087#include <inet/ip_ndp.h>
88#include <net/pfkeyv2.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070089#include <inet/sadb.h>
90#include <inet/ipsec_impl.h>
Sebastien Roy2b24ab62009-09-22 22:04:45 -040091#include <inet/iptun/iptun_impl.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070092#include <inet/sctp_ip.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070093#include <sys/pattr.h>
94#include <inet/ipclassifier.h>
95#include <inet/ipsecah.h>
nordmarkfc80c0d2007-10-11 22:57:36 -070096#include <inet/rawip_impl.h>
97#include <inet/rts_impl.h>
Eric Chengda14ceb2008-12-04 18:16:10 -080098#include <sys/squeue_impl.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070099#include <sys/squeue.h>
100
jpk45916cd2006-03-24 12:29:20 -0800101#include <sys/tsol/label.h>
102#include <sys/tsol/tnet.h>
103
carlsonj69bb4bb2006-08-14 14:10:48 -0700104/* Temporary; for CR 6451644 work-around */
105#include <sys/ethernet.h>
106
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700107/*
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700108 * Naming conventions:
109 * These rules should be judiciously applied
110 * if there is a need to identify something as IPv6 versus IPv4
111 * IPv6 funcions will end with _v6 in the ip module.
112 * IPv6 funcions will end with _ipv6 in the transport modules.
113 * IPv6 macros:
114 * Some macros end with _V6; e.g. ILL_FRAG_HASH_V6
115 * Some macros start with V6_; e.g. V6_OR_V4_INADDR_ANY
116 * And then there are ..V4_PART_OF_V6.
117 * The intent is that macros in the ip module end with _V6.
118 * IPv6 global variables will start with ipv6_
119 * IPv6 structures will start with ipv6
120 * IPv6 defined constants should start with IPV6_
121 * (but then there are NDP_DEFAULT_VERS_PRI_AND_FLOW, etc)
122 */
123
124/*
jpk45916cd2006-03-24 12:29:20 -0800125 * ip6opt_ls is used to enable IPv6 (via /etc/system on TX systems).
126 * We need to do this because we didn't obtain the IP6OPT_LS (0x0a)
127 * from IANA. This mechanism will remain in effect until an official
128 * number is obtained.
129 */
130uchar_t ip6opt_ls;
131
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700132const in6_addr_t ipv6_all_ones =
133 { 0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU };
134const in6_addr_t ipv6_all_zeros = { 0, 0, 0, 0 };
135
136#ifdef _BIG_ENDIAN
137const in6_addr_t ipv6_unspecified_group = { 0xff000000U, 0, 0, 0 };
138#else /* _BIG_ENDIAN */
139const in6_addr_t ipv6_unspecified_group = { 0x000000ffU, 0, 0, 0 };
140#endif /* _BIG_ENDIAN */
141
142#ifdef _BIG_ENDIAN
143const in6_addr_t ipv6_loopback = { 0, 0, 0, 0x00000001U };
144#else /* _BIG_ENDIAN */
145const in6_addr_t ipv6_loopback = { 0, 0, 0, 0x01000000U };
146#endif /* _BIG_ENDIAN */
147
148#ifdef _BIG_ENDIAN
149const in6_addr_t ipv6_all_hosts_mcast = { 0xff020000U, 0, 0, 0x00000001U };
150#else /* _BIG_ENDIAN */
151const in6_addr_t ipv6_all_hosts_mcast = { 0x000002ffU, 0, 0, 0x01000000U };
152#endif /* _BIG_ENDIAN */
153
154#ifdef _BIG_ENDIAN
155const in6_addr_t ipv6_all_rtrs_mcast = { 0xff020000U, 0, 0, 0x00000002U };
156#else /* _BIG_ENDIAN */
157const in6_addr_t ipv6_all_rtrs_mcast = { 0x000002ffU, 0, 0, 0x02000000U };
158#endif /* _BIG_ENDIAN */
159
160#ifdef _BIG_ENDIAN
161const in6_addr_t ipv6_all_v2rtrs_mcast = { 0xff020000U, 0, 0, 0x00000016U };
162#else /* _BIG_ENDIAN */
163const in6_addr_t ipv6_all_v2rtrs_mcast = { 0x000002ffU, 0, 0, 0x16000000U };
164#endif /* _BIG_ENDIAN */
165
166#ifdef _BIG_ENDIAN
167const in6_addr_t ipv6_solicited_node_mcast =
168 { 0xff020000U, 0, 0x00000001U, 0xff000000U };
169#else /* _BIG_ENDIAN */
170const in6_addr_t ipv6_solicited_node_mcast =
171 { 0x000002ffU, 0, 0x01000000U, 0x000000ffU };
172#endif /* _BIG_ENDIAN */
173
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800174static boolean_t icmp_inbound_verify_v6(mblk_t *, icmp6_t *, ip_recv_attr_t *);
175static void icmp_inbound_too_big_v6(icmp6_t *, ip_recv_attr_t *);
176static void icmp_pkt_v6(mblk_t *, void *, size_t, const in6_addr_t *,
177 ip_recv_attr_t *);
178static void icmp_redirect_v6(mblk_t *, ip6_t *, nd_redirect_t *,
179 ip_recv_attr_t *);
180static void icmp_send_redirect_v6(mblk_t *, in6_addr_t *,
181 in6_addr_t *, ip_recv_attr_t *);
182static void icmp_send_reply_v6(mblk_t *, ip6_t *, icmp6_t *,
183 ip_recv_attr_t *);
dh155122f4b3ec62007-01-19 16:59:38 -0800184static boolean_t ip_source_routed_v6(ip6_t *, mblk_t *, ip_stack_t *);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700185
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700186/*
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800187 * icmp_inbound_v6 deals with ICMP messages that are handled by IP.
188 * If the ICMP message is consumed by IP, i.e., it should not be delivered
189 * to any IPPROTO_ICMP raw sockets, then it returns NULL.
190 * Likewise, if the ICMP error is misformed (too short, etc), then it
191 * returns NULL. The caller uses this to determine whether or not to send
192 * to raw sockets.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700193 *
194 * All error messages are passed to the matching transport stream.
195 *
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800196 * See comment for icmp_inbound_v4() on how IPsec is handled.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700197 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800198mblk_t *
199icmp_inbound_v6(mblk_t *mp, ip_recv_attr_t *ira)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700200{
201 icmp6_t *icmp6;
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800202 ip6_t *ip6h; /* Outer header */
203 int ip_hdr_length; /* Outer header length */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700204 boolean_t interested;
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800205 ill_t *ill = ira->ira_ill;
dh155122f4b3ec62007-01-19 16:59:38 -0800206 ip_stack_t *ipst = ill->ill_ipst;
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800207 mblk_t *mp_ret = NULL;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700208
209 ip6h = (ip6_t *)mp->b_rptr;
210
211 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInMsgs);
212
Sowmini Varadhan01685f92010-03-29 21:44:09 -0400213 /* Check for Martian packets */
214 if (IN6_IS_ADDR_MULTICAST(&ip6h->ip6_src)) {
215 BUMP_MIB(ill->ill_ip_mib, ipIfStatsInAddrErrors);
216 ip_drop_input("ipIfStatsInAddrErrors: mcast src", mp, ill);
217 freemsg(mp);
218 return (NULL);
219 }
220
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800221 /* Make sure ira_l2src is set for ndp_input */
222 if (!(ira->ira_flags & IRAF_L2SRC_SET))
223 ip_setl2src(mp, ira, ira->ira_rill);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700224
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800225 ip_hdr_length = ira->ira_ip_hdr_length;
226 if ((mp->b_wptr - mp->b_rptr) < (ip_hdr_length + ICMP6_MINLEN)) {
227 if (ira->ira_pktlen < (ip_hdr_length + ICMP6_MINLEN)) {
228 BUMP_MIB(ill->ill_ip_mib, ipIfStatsInTruncatedPkts);
229 ip_drop_input("ipIfStatsInTruncatedPkts", mp, ill);
230 freemsg(mp);
231 return (NULL);
232 }
233 ip6h = ip_pullup(mp, ip_hdr_length + ICMP6_MINLEN, ira);
234 if (ip6h == NULL) {
jpk45916cd2006-03-24 12:29:20 -0800235 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInErrors);
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800236 freemsg(mp);
237 return (NULL);
jpk45916cd2006-03-24 12:29:20 -0800238 }
239 }
240
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800241 icmp6 = (icmp6_t *)(&mp->b_rptr[ip_hdr_length]);
242 DTRACE_PROBE2(icmp__inbound__v6, ip6_t *, ip6h, icmp6_t *, icmp6);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700243 ip2dbg(("icmp_inbound_v6: type %d code %d\n", icmp6->icmp6_type,
244 icmp6->icmp6_code));
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800245
246 /*
247 * We will set "interested" to "true" if we should pass a copy to
248 * the transport i.e., if it is an error message.
249 */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700250 interested = !(icmp6->icmp6_type & ICMP6_INFOMSG_MASK);
251
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700252 switch (icmp6->icmp6_type) {
253 case ICMP6_DST_UNREACH:
254 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInDestUnreachs);
255 if (icmp6->icmp6_code == ICMP6_DST_UNREACH_ADMIN)
256 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInAdminProhibs);
257 break;
258
259 case ICMP6_TIME_EXCEEDED:
260 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInTimeExcds);
261 break;
262
263 case ICMP6_PARAM_PROB:
264 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInParmProblems);
265 break;
266
267 case ICMP6_PACKET_TOO_BIG:
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800268 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInPktTooBigs);
269 break;
270
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700271 case ICMP6_ECHO_REQUEST:
272 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInEchos);
273 if (IN6_IS_ADDR_MULTICAST(&ip6h->ip6_dst) &&
dh155122f4b3ec62007-01-19 16:59:38 -0800274 !ipst->ips_ipv6_resp_echo_mcast)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700275 break;
276
277 /*
278 * We must have exclusive use of the mblk to convert it to
279 * a response.
280 * If not, we copy it.
281 */
282 if (mp->b_datap->db_ref > 1) {
283 mblk_t *mp1;
284
285 mp1 = copymsg(mp);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700286 if (mp1 == NULL) {
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800287 BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
288 ip_drop_input("ipIfStatsInDiscards - copymsg",
289 mp, ill);
290 freemsg(mp);
291 return (NULL);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700292 }
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800293 freemsg(mp);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700294 mp = mp1;
295 ip6h = (ip6_t *)mp->b_rptr;
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800296 icmp6 = (icmp6_t *)(&mp->b_rptr[ip_hdr_length]);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700297 }
298
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700299 icmp6->icmp6_type = ICMP6_ECHO_REPLY;
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800300 icmp_send_reply_v6(mp, ip6h, icmp6, ira);
301 return (NULL);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700302
303 case ICMP6_ECHO_REPLY:
304 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInEchoReplies);
305 break;
306
307 case ND_ROUTER_SOLICIT:
308 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInRouterSolicits);
309 break;
310
311 case ND_ROUTER_ADVERT:
312 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInRouterAdvertisements);
313 break;
314
315 case ND_NEIGHBOR_SOLICIT:
316 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInNeighborSolicits);
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800317 ndp_input(mp, ira);
318 return (NULL);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700319
320 case ND_NEIGHBOR_ADVERT:
321 BUMP_MIB(ill->ill_icmp6_mib,
322 ipv6IfIcmpInNeighborAdvertisements);
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800323 ndp_input(mp, ira);
324 return (NULL);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700325
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800326 case ND_REDIRECT:
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700327 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInRedirects);
328
dh155122f4b3ec62007-01-19 16:59:38 -0800329 if (ipst->ips_ipv6_ignore_redirect)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700330 break;
331
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800332 /* We now allow a RAW socket to receive this. */
333 interested = B_TRUE;
334 break;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700335
336 /*
337 * The next three icmp messages will be handled by MLD.
338 * Pass all valid MLD packets up to any process(es)
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800339 * listening on a raw ICMP socket.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700340 */
341 case MLD_LISTENER_QUERY:
342 case MLD_LISTENER_REPORT:
343 case MLD_LISTENER_REDUCTION:
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800344 mp = mld_input(mp, ira);
345 return (mp);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700346 default:
347 break;
348 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700349 /*
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800350 * See if there is an ICMP client to avoid an extra copymsg/freemsg
351 * if there isn't one.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700352 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800353 if (ipst->ips_ipcl_proto_fanout_v6[IPPROTO_ICMPV6].connf_head != NULL) {
354 /* If there is an ICMP client and we want one too, copy it. */
355
356 if (!interested) {
357 /* Caller will deliver to RAW sockets */
358 return (mp);
359 }
360 mp_ret = copymsg(mp);
361 if (mp_ret == NULL) {
362 BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
363 ip_drop_input("ipIfStatsInDiscards - copymsg", mp, ill);
364 }
365 } else if (!interested) {
366 /* Neither we nor raw sockets are interested. Drop packet now */
367 freemsg(mp);
368 return (NULL);
369 }
370
371 /*
372 * ICMP error or redirect packet. Make sure we have enough of
373 * the header and that db_ref == 1 since we might end up modifying
374 * the packet.
375 */
376 if (mp->b_cont != NULL) {
377 if (ip_pullup(mp, -1, ira) == NULL) {
378 BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
379 ip_drop_input("ipIfStatsInDiscards - ip_pullup",
380 mp, ill);
381 freemsg(mp);
382 return (mp_ret);
383 }
384 }
385
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700386 if (mp->b_datap->db_ref > 1) {
387 mblk_t *mp1;
388
389 mp1 = copymsg(mp);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700390 if (mp1 == NULL) {
apersson31736642006-12-19 17:33:00 -0800391 BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800392 ip_drop_input("ipIfStatsInDiscards - copymsg", mp, ill);
393 freemsg(mp);
394 return (mp_ret);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700395 }
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800396 freemsg(mp);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700397 mp = mp1;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700398 }
399
400 /*
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800401 * In case mp has changed, verify the message before any further
402 * processes.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700403 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800404 ip6h = (ip6_t *)mp->b_rptr;
405 icmp6 = (icmp6_t *)(&mp->b_rptr[ip_hdr_length]);
406 if (!icmp_inbound_verify_v6(mp, icmp6, ira)) {
407 freemsg(mp);
408 return (mp_ret);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700409 }
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800410
411 switch (icmp6->icmp6_type) {
412 case ND_REDIRECT:
413 icmp_redirect_v6(mp, ip6h, (nd_redirect_t *)icmp6, ira);
414 break;
415 case ICMP6_PACKET_TOO_BIG:
416 /* Update DCE and adjust MTU is icmp header if needed */
417 icmp_inbound_too_big_v6(icmp6, ira);
Toomas Soomea9f62b12018-03-27 08:17:48 +0300418 /* FALLTHROUGH */
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800419 default:
420 icmp_inbound_error_fanout_v6(mp, icmp6, ira);
421 break;
422 }
423
424 return (mp_ret);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700425}
426
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700427/*
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800428 * Send an ICMP echo reply.
429 * The caller has already updated the payload part of the packet.
430 * We handle the ICMP checksum, IP source address selection and feed
431 * the packet into ip_output_simple.
432 */
433static void
434icmp_send_reply_v6(mblk_t *mp, ip6_t *ip6h, icmp6_t *icmp6,
435 ip_recv_attr_t *ira)
436{
437 uint_t ip_hdr_length = ira->ira_ip_hdr_length;
438 ill_t *ill = ira->ira_ill;
439 ip_stack_t *ipst = ill->ill_ipst;
440 ip_xmit_attr_t ixas;
441 in6_addr_t origsrc;
442
443 /*
444 * Remove any extension headers (do not reverse a source route)
445 * and clear the flow id (keep traffic class for now).
446 */
447 if (ip_hdr_length != IPV6_HDR_LEN) {
448 int i;
449
450 for (i = 0; i < IPV6_HDR_LEN; i++) {
451 mp->b_rptr[ip_hdr_length - i - 1] =
452 mp->b_rptr[IPV6_HDR_LEN - i - 1];
453 }
454 mp->b_rptr += (ip_hdr_length - IPV6_HDR_LEN);
455 ip6h = (ip6_t *)mp->b_rptr;
456 ip6h->ip6_nxt = IPPROTO_ICMPV6;
457 i = ntohs(ip6h->ip6_plen);
458 i -= (ip_hdr_length - IPV6_HDR_LEN);
459 ip6h->ip6_plen = htons(i);
460 ip_hdr_length = IPV6_HDR_LEN;
461 ASSERT(ntohs(ip6h->ip6_plen) + IPV6_HDR_LEN == msgdsize(mp));
462 }
463 ip6h->ip6_vcf &= ~IPV6_FLOWINFO_FLOWLABEL;
464
465 /* Reverse the source and destination addresses. */
466 origsrc = ip6h->ip6_src;
467 ip6h->ip6_src = ip6h->ip6_dst;
468 ip6h->ip6_dst = origsrc;
469
470 /* set the hop limit */
471 ip6h->ip6_hops = ipst->ips_ipv6_def_hops;
472
473 /*
474 * Prepare for checksum by putting icmp length in the icmp
475 * checksum field. The checksum is calculated in ip_output
476 */
477 icmp6->icmp6_cksum = ip6h->ip6_plen;
478
479 bzero(&ixas, sizeof (ixas));
480 ixas.ixa_flags = IXAF_BASIC_SIMPLE_V6;
481 ixas.ixa_zoneid = ira->ira_zoneid;
482 ixas.ixa_cred = kcred;
483 ixas.ixa_cpid = NOPID;
484 ixas.ixa_tsl = ira->ira_tsl; /* Behave as a multi-level responder */
485 ixas.ixa_ifindex = 0;
486 ixas.ixa_ipst = ipst;
487 ixas.ixa_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
488
489 if (!(ira->ira_flags & IRAF_IPSEC_SECURE)) {
490 /*
491 * This packet should go out the same way as it
492 * came in i.e in clear, independent of the IPsec
493 * policy for transmitting packets.
494 */
495 ixas.ixa_flags |= IXAF_NO_IPSEC;
496 } else {
497 if (!ipsec_in_to_out(ira, &ixas, mp, NULL, ip6h)) {
498 BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
499 /* Note: mp already consumed and ip_drop_packet done */
500 return;
501 }
502 }
503
504 /* Was the destination (now source) link-local? Send out same group */
505 if (IN6_IS_ADDR_LINKSCOPE(&ip6h->ip6_src)) {
506 ixas.ixa_flags |= IXAF_SCOPEID_SET;
507 if (IS_UNDER_IPMP(ill))
508 ixas.ixa_scopeid = ill_get_upper_ifindex(ill);
509 else
510 ixas.ixa_scopeid = ill->ill_phyint->phyint_ifindex;
511 }
512
513 if (ira->ira_flags & IRAF_MULTIBROADCAST) {
514 /*
515 * Not one or our addresses (IRE_LOCALs), thus we let
516 * ip_output_simple pick the source.
517 */
518 ip6h->ip6_src = ipv6_all_zeros;
519 ixas.ixa_flags |= IXAF_SET_SOURCE;
520 }
521
522 /* Should we send using dce_pmtu? */
523 if (ipst->ips_ipv6_icmp_return_pmtu)
524 ixas.ixa_flags |= IXAF_PMTU_DISCOVERY;
525
526 (void) ip_output_simple(mp, &ixas);
527 ixa_cleanup(&ixas);
528
529}
530
531/*
532 * Verify the ICMP messages for either for ICMP error or redirect packet.
533 * The caller should have fully pulled up the message. If it's a redirect
534 * packet, only basic checks on IP header will be done; otherwise, verify
535 * the packet by looking at the included ULP header.
536 *
537 * Called before icmp_inbound_error_fanout_v6 is called.
Sebastien Roy2b24ab62009-09-22 22:04:45 -0400538 */
539static boolean_t
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800540icmp_inbound_verify_v6(mblk_t *mp, icmp6_t *icmp6, ip_recv_attr_t *ira)
Sebastien Roy2b24ab62009-09-22 22:04:45 -0400541{
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800542 ill_t *ill = ira->ira_ill;
543 uint16_t hdr_length;
544 uint8_t *nexthdrp;
545 uint8_t nexthdr;
546 ip_stack_t *ipst = ill->ill_ipst;
547 conn_t *connp;
548 ip6_t *ip6h; /* Inner header */
Sebastien Roy2b24ab62009-09-22 22:04:45 -0400549
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800550 ip6h = (ip6_t *)&icmp6[1];
551 if ((uchar_t *)ip6h + IPV6_HDR_LEN > mp->b_wptr)
552 goto truncated;
Sebastien Roy2b24ab62009-09-22 22:04:45 -0400553
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800554 if (icmp6->icmp6_type == ND_REDIRECT) {
555 hdr_length = sizeof (nd_redirect_t);
556 } else {
557 if ((IPH_HDR_VERSION(ip6h) != IPV6_VERSION))
558 goto discard_pkt;
559 hdr_length = IPV6_HDR_LEN;
560 }
561
562 if ((uchar_t *)ip6h + hdr_length > mp->b_wptr)
563 goto truncated;
564
565 /*
566 * Stop here for ICMP_REDIRECT.
567 */
568 if (icmp6->icmp6_type == ND_REDIRECT)
569 return (B_TRUE);
570
571 /*
572 * ICMP errors only.
573 */
574 if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &hdr_length, &nexthdrp))
575 goto discard_pkt;
576 nexthdr = *nexthdrp;
577
578 /* Try to pass the ICMP message to clients who need it */
579 switch (nexthdr) {
580 case IPPROTO_UDP:
581 /*
582 * Verify we have at least ICMP_MIN_TP_HDR_LEN bytes of
583 * transport header.
584 */
585 if ((uchar_t *)ip6h + hdr_length + ICMP_MIN_TP_HDR_LEN >
586 mp->b_wptr)
587 goto truncated;
588 break;
589 case IPPROTO_TCP: {
590 tcpha_t *tcpha;
591
592 /*
593 * Verify we have at least ICMP_MIN_TP_HDR_LEN bytes of
594 * transport header.
595 */
596 if ((uchar_t *)ip6h + hdr_length + ICMP_MIN_TP_HDR_LEN >
597 mp->b_wptr)
598 goto truncated;
599
600 tcpha = (tcpha_t *)((uchar_t *)ip6h + hdr_length);
601 /*
602 * With IPMP we need to match across group, which we do
603 * since we have the upper ill from ira_ill.
604 */
605 connp = ipcl_tcp_lookup_reversed_ipv6(ip6h, tcpha, TCPS_LISTEN,
606 ill->ill_phyint->phyint_ifindex, ipst);
607 if (connp == NULL)
608 goto discard_pkt;
609
610 if ((connp->conn_verifyicmp != NULL) &&
611 !connp->conn_verifyicmp(connp, tcpha, NULL, icmp6, ira)) {
612 CONN_DEC_REF(connp);
613 goto discard_pkt;
614 }
615 CONN_DEC_REF(connp);
616 break;
617 }
618 case IPPROTO_SCTP:
619 /*
620 * Verify we have at least ICMP_MIN_TP_HDR_LEN bytes of
621 * transport header.
622 */
623 if ((uchar_t *)ip6h + hdr_length + ICMP_MIN_TP_HDR_LEN >
624 mp->b_wptr)
625 goto truncated;
626 break;
627 case IPPROTO_ESP:
628 case IPPROTO_AH:
629 break;
630 case IPPROTO_ENCAP:
631 case IPPROTO_IPV6: {
632 /* Look for self-encapsulated packets that caused an error */
633 ip6_t *in_ip6h;
634
635 in_ip6h = (ip6_t *)((uint8_t *)ip6h + hdr_length);
636 if ((uint8_t *)in_ip6h + (nexthdr == IPPROTO_ENCAP ?
637 sizeof (ipha_t) : sizeof (ip6_t)) > mp->b_wptr)
638 goto truncated;
639 break;
640 }
641 default:
642 break;
643 }
644
Sebastien Roy2b24ab62009-09-22 22:04:45 -0400645 return (B_TRUE);
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800646
647discard_pkt:
648 /* Bogus ICMP error. */
649 BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
650 return (B_FALSE);
651
652truncated:
653 /* We pulled up everthing already. Must be truncated */
654 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInErrors);
655 return (B_FALSE);
656}
657
658/*
659 * Process received IPv6 ICMP Packet too big.
660 * The caller is responsible for validating the packet before passing it in
661 * and also to fanout the ICMP error to any matching transport conns. Assumes
662 * the message has been fully pulled up.
663 *
664 * Before getting here, the caller has called icmp_inbound_verify_v6()
665 * that should have verified with ULP to prevent undoing the changes we're
666 * going to make to DCE. For example, TCP might have verified that the packet
667 * which generated error is in the send window.
668 *
669 * In some cases modified this MTU in the ICMP header packet; the caller
670 * should pass to the matching ULP after this returns.
671 */
672static void
673icmp_inbound_too_big_v6(icmp6_t *icmp6, ip_recv_attr_t *ira)
674{
675 uint32_t mtu;
676 dce_t *dce;
677 ill_t *ill = ira->ira_ill; /* Upper ill if IPMP */
678 ip_stack_t *ipst = ill->ill_ipst;
679 int old_max_frag;
680 in6_addr_t final_dst;
681 ip6_t *ip6h; /* Inner IP header */
682
683 /* Caller has already pulled up everything. */
684 ip6h = (ip6_t *)&icmp6[1];
685 final_dst = ip_get_dst_v6(ip6h, NULL, NULL);
686
Dan McDonald7199b8e2017-02-01 14:55:57 -0500687 mtu = ntohl(icmp6->icmp6_mtu);
688 if (mtu < IPV6_MIN_MTU) {
689 /*
690 * RFC 8021 suggests to ignore messages where mtu is
691 * less than the IPv6 minimum.
692 */
693 ip1dbg(("Received mtu less than IPv6 "
694 "min mtu %d: %d\n", IPV6_MIN_MTU, mtu));
695 DTRACE_PROBE1(icmp6__too__small__mtu, uint32_t, mtu);
696 return;
697 }
698
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800699 /*
700 * For link local destinations matching simply on address is not
701 * sufficient. Same link local addresses for different ILL's is
702 * possible.
703 */
704 if (IN6_IS_ADDR_LINKSCOPE(&final_dst)) {
705 dce = dce_lookup_and_add_v6(&final_dst,
706 ill->ill_phyint->phyint_ifindex, ipst);
707 } else {
708 dce = dce_lookup_and_add_v6(&final_dst, 0, ipst);
709 }
710 if (dce == NULL) {
711 /* Couldn't add a unique one - ENOMEM */
712 if (ip_debug > 2) {
713 /* ip1dbg */
714 pr_addr_dbg("icmp_inbound_too_big_v6:"
715 "no dce for dst %s\n", AF_INET6,
716 &final_dst);
717 }
718 return;
719 }
720
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800721 mutex_enter(&dce->dce_lock);
722 if (dce->dce_flags & DCEF_PMTU)
723 old_max_frag = dce->dce_pmtu;
Erik Nordmark1eee1702010-08-16 15:30:54 -0700724 else if (IN6_IS_ADDR_MULTICAST(&final_dst))
725 old_max_frag = ill->ill_mc_mtu;
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800726 else
727 old_max_frag = ill->ill_mtu;
728
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800729 ip1dbg(("Received mtu from router: %d\n", mtu));
Dan McDonald7199b8e2017-02-01 14:55:57 -0500730 DTRACE_PROBE1(icmp6__received__mtu, uint32_t, mtu);
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800731 dce->dce_pmtu = MIN(old_max_frag, mtu);
Dan McDonald7199b8e2017-02-01 14:55:57 -0500732 icmp6->icmp6_mtu = htonl(dce->dce_pmtu);
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800733
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800734 /* We now have a PMTU for sure */
735 dce->dce_flags |= DCEF_PMTU;
Rafael Vanonid3d50732009-11-13 01:32:32 -0800736 dce->dce_last_change_time = TICK_TO_SEC(ddi_get_lbolt64());
Dan McDonald7199b8e2017-02-01 14:55:57 -0500737
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800738 mutex_exit(&dce->dce_lock);
739 /*
740 * After dropping the lock the new value is visible to everyone.
741 * Then we bump the generation number so any cached values reinspect
742 * the dce_t.
743 */
744 dce_increment_generation(dce);
745 dce_refrele(dce);
Sebastien Roy2b24ab62009-09-22 22:04:45 -0400746}
747
748/*
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700749 * Fanout received ICMPv6 error packets to the transports.
750 * Assumes the IPv6 plus ICMPv6 headers have been pulled up but nothing else.
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800751 *
752 * The caller must have called icmp_inbound_verify_v6.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700753 */
754void
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800755icmp_inbound_error_fanout_v6(mblk_t *mp, icmp6_t *icmp6, ip_recv_attr_t *ira)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700756{
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800757 uint16_t *up; /* Pointer to ports in ULP header */
758 uint32_t ports; /* reversed ports for fanout */
759 ip6_t rip6h; /* With reversed addresses */
760 ip6_t *ip6h; /* Inner IP header */
761 uint16_t hdr_length; /* Inner IP header length */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700762 uint8_t *nexthdrp;
763 uint8_t nexthdr;
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800764 tcpha_t *tcpha;
765 conn_t *connp;
766 ill_t *ill = ira->ira_ill; /* Upper in the case of IPMP */
dh155122f4b3ec62007-01-19 16:59:38 -0800767 ip_stack_t *ipst = ill->ill_ipst;
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800768 ipsec_stack_t *ipss = ipst->ips_netstack->netstack_ipsec;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700769
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800770 /* Caller has already pulled up everything. */
771 ip6h = (ip6_t *)&icmp6[1];
772 ASSERT(mp->b_cont == NULL);
773 ASSERT((uchar_t *)&ip6h[1] <= mp->b_wptr);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700774
775 if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &hdr_length, &nexthdrp))
776 goto drop_pkt;
777 nexthdr = *nexthdrp;
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800778 ira->ira_protocol = nexthdr;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700779
Sebastien Roy2b24ab62009-09-22 22:04:45 -0400780 /*
781 * We need a separate IP header with the source and destination
782 * addresses reversed to do fanout/classification because the ip6h in
783 * the ICMPv6 error is in the form we sent it out.
784 */
785 rip6h.ip6_src = ip6h->ip6_dst;
786 rip6h.ip6_dst = ip6h->ip6_src;
787 rip6h.ip6_nxt = nexthdr;
788
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700789 /* Try to pass the ICMP message to clients who need it */
790 switch (nexthdr) {
791 case IPPROTO_UDP: {
Sebastien Roy2b24ab62009-09-22 22:04:45 -0400792 /* Attempt to find a client stream based on port. */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700793 up = (uint16_t *)((uchar_t *)ip6h + hdr_length);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700794
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800795 /* Note that we send error to all matches. */
796 ira->ira_flags |= IRAF_ICMP_ERROR;
797 ip_fanout_udp_multi_v6(mp, &rip6h, up[0], up[1], ira);
798 ira->ira_flags &= ~IRAF_ICMP_ERROR;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700799 return;
800 }
801 case IPPROTO_TCP: {
802 /*
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700803 * Attempt to find a client stream based on port.
804 * Note that we do a reverse lookup since the header is
805 * in the form we sent it out.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700806 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800807 tcpha = (tcpha_t *)((uchar_t *)ip6h + hdr_length);
808 /*
809 * With IPMP we need to match across group, which we do
810 * since we have the upper ill from ira_ill.
811 */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700812 connp = ipcl_tcp_lookup_reversed_ipv6(ip6h, tcpha,
dh155122f4b3ec62007-01-19 16:59:38 -0800813 TCPS_LISTEN, ill->ill_phyint->phyint_ifindex, ipst);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700814 if (connp == NULL) {
815 goto drop_pkt;
816 }
817
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800818 if (CONN_INBOUND_POLICY_PRESENT_V6(connp, ipss) ||
819 (ira->ira_flags & IRAF_IPSEC_SECURE)) {
820 mp = ipsec_check_inbound_policy(mp, connp,
821 NULL, ip6h, ira);
822 if (mp == NULL) {
823 BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
824 /* Note that mp is NULL */
825 ip_drop_input("ipIfStatsInDiscards", mp, ill);
826 CONN_DEC_REF(connp);
827 return;
828 }
829 }
830
831 ira->ira_flags |= IRAF_ICMP_ERROR;
832 if (IPCL_IS_TCP(connp)) {
833 SQUEUE_ENTER_ONE(connp->conn_sqp, mp,
834 connp->conn_recvicmp, connp, ira, SQ_FILL,
835 SQTAG_TCP6_INPUT_ICMP_ERR);
836 } else {
837 /* Not TCP; must be SOCK_RAW, IPPROTO_TCP */
838 ill_t *rill = ira->ira_rill;
839
840 ira->ira_ill = ira->ira_rill = NULL;
841 (connp->conn_recv)(connp, mp, NULL, ira);
842 CONN_DEC_REF(connp);
843 ira->ira_ill = ill;
844 ira->ira_rill = rill;
845 }
846 ira->ira_flags &= ~IRAF_ICMP_ERROR;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700847 return;
848
849 }
850 case IPPROTO_SCTP:
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700851 up = (uint16_t *)((uchar_t *)ip6h + hdr_length);
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800852 /* Find a SCTP client stream for this packet. */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700853 ((uint16_t *)&ports)[0] = up[1];
854 ((uint16_t *)&ports)[1] = up[0];
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800855
856 ira->ira_flags |= IRAF_ICMP_ERROR;
857 ip_fanout_sctp(mp, NULL, &rip6h, ports, ira);
858 ira->ira_flags &= ~IRAF_ICMP_ERROR;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700859 return;
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800860
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700861 case IPPROTO_ESP:
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800862 case IPPROTO_AH:
dh155122f4b3ec62007-01-19 16:59:38 -0800863 if (!ipsec_loaded(ipss)) {
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800864 ip_proto_not_sup(mp, ira);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700865 return;
866 }
867
868 if (nexthdr == IPPROTO_ESP)
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800869 mp = ipsecesp_icmp_error(mp, ira);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700870 else
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800871 mp = ipsecah_icmp_error(mp, ira);
872 if (mp == NULL)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700873 return;
874
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800875 /* Just in case ipsec didn't preserve the NULL b_cont */
876 if (mp->b_cont != NULL) {
877 if (!pullupmsg(mp, -1))
878 goto drop_pkt;
kcpoon48de1bd2007-06-13 04:53:06 -0700879 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700880
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800881 /*
882 * If succesful, the mp has been modified to not include
883 * the ESP/AH header so we can fanout to the ULP's icmp
884 * error handler.
885 */
886 if (mp->b_wptr - mp->b_rptr < IPV6_HDR_LEN)
887 goto drop_pkt;
888
889 ip6h = (ip6_t *)mp->b_rptr;
890 /* Don't call hdr_length_v6() unless you have to. */
891 if (ip6h->ip6_nxt != IPPROTO_ICMPV6)
892 hdr_length = ip_hdr_length_v6(mp, ip6h);
893 else
894 hdr_length = IPV6_HDR_LEN;
895
896 /* Verify the modified message before any further processes. */
897 icmp6 = (icmp6_t *)(&mp->b_rptr[hdr_length]);
898 if (!icmp_inbound_verify_v6(mp, icmp6, ira)) {
899 freemsg(mp);
900 return;
901 }
902
903 icmp_inbound_error_fanout_v6(mp, icmp6, ira);
904 return;
905
906 case IPPROTO_IPV6: {
907 /* Look for self-encapsulated packets that caused an error */
908 ip6_t *in_ip6h;
909
910 in_ip6h = (ip6_t *)((uint8_t *)ip6h + hdr_length);
911
912 if (IN6_ARE_ADDR_EQUAL(&in_ip6h->ip6_src, &ip6h->ip6_src) &&
913 IN6_ARE_ADDR_EQUAL(&in_ip6h->ip6_dst, &ip6h->ip6_dst)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700914 /*
915 * Self-encapsulated case. As in the ipv4 case,
916 * we need to strip the 2nd IP header. Since mp
917 * is already pulled-up, we can simply bcopy
918 * the 3rd header + data over the 2nd header.
919 */
920 uint16_t unused_len;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700921
922 /*
923 * Make sure we don't do recursion more than once.
924 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800925 if (!ip_hdr_length_nexthdr_v6(mp, in_ip6h,
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700926 &unused_len, &nexthdrp) ||
927 *nexthdrp == IPPROTO_IPV6) {
928 goto drop_pkt;
929 }
930
931 /*
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700932 * Copy the 3rd header + remaining data on top
933 * of the 2nd header.
934 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800935 bcopy(in_ip6h, ip6h, mp->b_wptr - (uchar_t *)in_ip6h);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700936
937 /*
938 * Subtract length of the 2nd header.
939 */
940 mp->b_wptr -= hdr_length;
941
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800942 ip6h = (ip6_t *)mp->b_rptr;
943 /* Don't call hdr_length_v6() unless you have to. */
944 if (ip6h->ip6_nxt != IPPROTO_ICMPV6)
945 hdr_length = ip_hdr_length_v6(mp, ip6h);
946 else
947 hdr_length = IPV6_HDR_LEN;
948
949 /*
950 * Verify the modified message before any further
951 * processes.
952 */
953 icmp6 = (icmp6_t *)(&mp->b_rptr[hdr_length]);
954 if (!icmp_inbound_verify_v6(mp, icmp6, ira)) {
955 freemsg(mp);
956 return;
957 }
958
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700959 /*
960 * Now recurse, and see what I _really_ should be
961 * doing here.
962 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800963 icmp_inbound_error_fanout_v6(mp, icmp6, ira);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700964 return;
965 }
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800966 }
Toomas Soomea9f62b12018-03-27 08:17:48 +0300967 /* FALLTHROUGH */
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800968 case IPPROTO_ENCAP:
969 if ((connp = ipcl_iptun_classify_v6(&rip6h.ip6_src,
970 &rip6h.ip6_dst, ipst)) != NULL) {
971 ira->ira_flags |= IRAF_ICMP_ERROR;
972 connp->conn_recvicmp(connp, mp, NULL, ira);
973 CONN_DEC_REF(connp);
974 ira->ira_flags &= ~IRAF_ICMP_ERROR;
Sebastien Roy2b24ab62009-09-22 22:04:45 -0400975 return;
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800976 }
Sebastien Roy2b24ab62009-09-22 22:04:45 -0400977 /*
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800978 * No IP tunnel is interested, fallthrough and see
979 * if a raw socket will want it.
Sebastien Roy2b24ab62009-09-22 22:04:45 -0400980 */
Toomas Soomea9f62b12018-03-27 08:17:48 +0300981 /* FALLTHROUGH */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700982 default:
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800983 ira->ira_flags |= IRAF_ICMP_ERROR;
984 ASSERT(ira->ira_protocol == nexthdr);
985 ip_fanout_proto_v6(mp, &rip6h, ira);
986 ira->ira_flags &= ~IRAF_ICMP_ERROR;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700987 return;
988 }
989 /* NOTREACHED */
990drop_pkt:
991 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInErrors);
992 ip1dbg(("icmp_inbound_error_fanout_v6: drop pkt\n"));
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800993 freemsg(mp);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700994}
995
996/*
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700997 * Process received IPv6 ICMP Redirect messages.
Erik Nordmarkbd670b32009-11-11 11:49:49 -0800998 * Assumes the caller has verified that the headers are in the pulled up mblk.
999 * Consumes mp.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001000 */
1001/* ARGSUSED */
1002static void
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001003icmp_redirect_v6(mblk_t *mp, ip6_t *ip6h, nd_redirect_t *rd,
1004 ip_recv_attr_t *ira)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001005{
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001006 ire_t *ire, *nire;
1007 ire_t *prev_ire = NULL;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001008 ire_t *redir_ire;
1009 in6_addr_t *src, *dst, *gateway;
1010 nd_opt_hdr_t *opt;
1011 nce_t *nce;
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001012 int ncec_flags = 0;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001013 int err = 0;
1014 boolean_t redirect_to_router = B_FALSE;
1015 int len;
dd1935166bdb8e62006-10-27 15:48:26 -07001016 int optlen;
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001017 ill_t *ill = ira->ira_rill;
1018 ill_t *rill = ira->ira_rill;
dh155122f4b3ec62007-01-19 16:59:38 -08001019 ip_stack_t *ipst = ill->ill_ipst;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001020
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001021 /*
1022 * Since ira_ill is where the IRE_LOCAL was hosted we use ira_rill
1023 * and make it be the IPMP upper so avoid being confused by a packet
1024 * addressed to a unicast address on a different ill.
1025 */
1026 if (IS_UNDER_IPMP(rill)) {
1027 rill = ipmp_ill_hold_ipmp_ill(rill);
1028 if (rill == NULL) {
1029 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInBadRedirects);
1030 ip_drop_input("ipv6IfIcmpInBadRedirects - IPMP ill",
1031 mp, ill);
1032 freemsg(mp);
1033 return;
1034 }
1035 ASSERT(rill != ira->ira_rill);
1036 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001037
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001038 len = mp->b_wptr - (uchar_t *)rd;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001039 src = &ip6h->ip6_src;
1040 dst = &rd->nd_rd_dst;
1041 gateway = &rd->nd_rd_target;
dd1935166bdb8e62006-10-27 15:48:26 -07001042
1043 /* Verify if it is a valid redirect */
1044 if (!IN6_IS_ADDR_LINKLOCAL(src) ||
1045 (ip6h->ip6_hops != IPV6_MAX_HOPS) ||
1046 (rd->nd_rd_code != 0) ||
1047 (len < sizeof (nd_redirect_t)) ||
1048 (IN6_IS_ADDR_V4MAPPED(dst)) ||
1049 (IN6_IS_ADDR_MULTICAST(dst))) {
1050 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInBadRedirects);
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001051 ip_drop_input("ipv6IfIcmpInBadRedirects - addr/len", mp, ill);
1052 goto fail_redirect;
dd1935166bdb8e62006-10-27 15:48:26 -07001053 }
1054
1055 if (!(IN6_IS_ADDR_LINKLOCAL(gateway) ||
1056 IN6_ARE_ADDR_EQUAL(gateway, dst))) {
1057 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInBadRedirects);
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001058 ip_drop_input("ipv6IfIcmpInBadRedirects - bad gateway",
1059 mp, ill);
1060 goto fail_redirect;
dd1935166bdb8e62006-10-27 15:48:26 -07001061 }
1062
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001063 optlen = len - sizeof (nd_redirect_t);
1064 if (optlen != 0) {
1065 if (!ndp_verify_optlen((nd_opt_hdr_t *)&rd[1], optlen)) {
dd1935166bdb8e62006-10-27 15:48:26 -07001066 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInBadRedirects);
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001067 ip_drop_input("ipv6IfIcmpInBadRedirects - options",
1068 mp, ill);
1069 goto fail_redirect;
dd1935166bdb8e62006-10-27 15:48:26 -07001070 }
1071 }
1072
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001073 if (!IN6_ARE_ADDR_EQUAL(gateway, dst)) {
1074 redirect_to_router = B_TRUE;
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001075 ncec_flags |= NCE_F_ISROUTER;
1076 } else {
1077 gateway = dst; /* Add nce for dst */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001078 }
dd1935166bdb8e62006-10-27 15:48:26 -07001079
dd1935166bdb8e62006-10-27 15:48:26 -07001080
1081 /*
1082 * Verify that the IP source address of the redirect is
1083 * the same as the current first-hop router for the specified
1084 * ICMP destination address.
1085 * Also, Make sure we had a route for the dest in question and
1086 * that route was pointing to the old gateway (the source of the
1087 * redirect packet.)
Erik Nordmark6b7506c2009-12-19 09:42:05 -08001088 * We do longest match and then compare ire_gateway_addr_v6 below.
dd1935166bdb8e62006-10-27 15:48:26 -07001089 */
Erik Nordmark6b7506c2009-12-19 09:42:05 -08001090 prev_ire = ire_ftable_lookup_v6(dst, 0, 0, 0, rill,
1091 ALL_ZONES, NULL, MATCH_IRE_ILL, 0, ipst, NULL);
dd1935166bdb8e62006-10-27 15:48:26 -07001092
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001093 /*
1094 * Check that
1095 * the redirect was not from ourselves
1096 * old gateway is still directly reachable
1097 */
1098 if (prev_ire == NULL ||
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001099 (prev_ire->ire_type & (IRE_LOCAL|IRE_LOOPBACK)) ||
Erik Nordmark6b7506c2009-12-19 09:42:05 -08001100 (prev_ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) ||
1101 !IN6_ARE_ADDR_EQUAL(src, &prev_ire->ire_gateway_addr_v6)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001102 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInBadRedirects);
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001103 ip_drop_input("ipv6IfIcmpInBadRedirects - ire", mp, ill);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001104 goto fail_redirect;
1105 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001106
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001107 ASSERT(prev_ire->ire_ill != NULL);
1108 if (prev_ire->ire_ill->ill_flags & ILLF_NONUD)
1109 ncec_flags |= NCE_F_NONUD;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001110
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001111 opt = (nd_opt_hdr_t *)&rd[1];
dd1935166bdb8e62006-10-27 15:48:26 -07001112 opt = ndp_get_option(opt, optlen, ND_OPT_TARGET_LINKADDR);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001113 if (opt != NULL) {
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001114 err = nce_lookup_then_add_v6(rill,
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001115 (uchar_t *)&opt[1], /* Link layer address */
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001116 rill->ill_phys_addr_length,
1117 gateway, ncec_flags, ND_STALE, &nce);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001118 switch (err) {
1119 case 0:
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001120 nce_refrele(nce);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001121 break;
1122 case EEXIST:
1123 /*
1124 * Check to see if link layer address has changed and
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001125 * process the ncec_state accordingly.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001126 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001127 nce_process(nce->nce_common,
1128 (uchar_t *)&opt[1], 0, B_FALSE);
1129 nce_refrele(nce);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001130 break;
1131 default:
1132 ip1dbg(("icmp_redirect_v6: NCE create failed %d\n",
1133 err));
1134 goto fail_redirect;
1135 }
1136 }
1137 if (redirect_to_router) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001138 ASSERT(IN6_IS_ADDR_LINKLOCAL(gateway));
1139
1140 /*
1141 * Create a Route Association. This will allow us to remember
1142 * a router told us to use the particular gateway.
1143 */
1144 ire = ire_create_v6(
1145 dst,
1146 &ipv6_all_ones, /* mask */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001147 gateway, /* gateway addr */
dd1935166bdb8e62006-10-27 15:48:26 -07001148 IRE_HOST,
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001149 prev_ire->ire_ill,
1150 ALL_ZONES,
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001151 (RTF_DYNAMIC | RTF_GATEWAY | RTF_HOST),
dh155122f4b3ec62007-01-19 16:59:38 -08001152 NULL,
1153 ipst);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001154 } else {
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001155 ipif_t *ipif;
1156 in6_addr_t gw;
dd1935166bdb8e62006-10-27 15:48:26 -07001157
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001158 /*
dd1935166bdb8e62006-10-27 15:48:26 -07001159 * Just create an on link entry, i.e. interface route.
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001160 * The gateway field is our link-local on the ill.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001161 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001162 mutex_enter(&rill->ill_lock);
1163 for (ipif = rill->ill_ipif; ipif != NULL;
1164 ipif = ipif->ipif_next) {
1165 if (!(ipif->ipif_state_flags & IPIF_CONDEMNED) &&
1166 IN6_IS_ADDR_LINKLOCAL(&ipif->ipif_v6lcl_addr))
1167 break;
1168 }
1169 if (ipif == NULL) {
1170 /* We have no link-local address! */
1171 mutex_exit(&rill->ill_lock);
1172 goto fail_redirect;
1173 }
1174 gw = ipif->ipif_v6lcl_addr;
1175 mutex_exit(&rill->ill_lock);
1176
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001177 ire = ire_create_v6(
1178 dst, /* gateway == dst */
1179 &ipv6_all_ones, /* mask */
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001180 &gw, /* gateway addr */
1181 rill->ill_net_type, /* IF_[NO]RESOLVER */
1182 prev_ire->ire_ill,
1183 ALL_ZONES,
dd1935166bdb8e62006-10-27 15:48:26 -07001184 (RTF_DYNAMIC | RTF_HOST),
dh155122f4b3ec62007-01-19 16:59:38 -08001185 NULL,
1186 ipst);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001187 }
dd1935166bdb8e62006-10-27 15:48:26 -07001188
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001189 if (ire == NULL)
1190 goto fail_redirect;
1191
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001192 nire = ire_add(ire);
1193 /* Check if it was a duplicate entry */
1194 if (nire != NULL && nire != ire) {
1195 ASSERT(nire->ire_identical_ref > 1);
1196 ire_delete(nire);
1197 ire_refrele(nire);
1198 nire = NULL;
1199 }
1200 ire = nire;
1201 if (ire != NULL) {
1202 ire_refrele(ire); /* Held in ire_add */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001203
1204 /* tell routing sockets that we received a redirect */
1205 ip_rts_change_v6(RTM_REDIRECT,
1206 &rd->nd_rd_dst,
1207 &rd->nd_rd_target,
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001208 &ipv6_all_ones, 0, src,
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001209 (RTF_DYNAMIC | RTF_GATEWAY | RTF_HOST), 0,
dh155122f4b3ec62007-01-19 16:59:38 -08001210 (RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_AUTHOR), ipst);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001211
1212 /*
dd1935166bdb8e62006-10-27 15:48:26 -07001213 * Delete any existing IRE_HOST type ires for this destination.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001214 * This together with the added IRE has the effect of
1215 * modifying an existing redirect.
1216 */
dd1935166bdb8e62006-10-27 15:48:26 -07001217 redir_ire = ire_ftable_lookup_v6(dst, 0, src, IRE_HOST,
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001218 prev_ire->ire_ill, ALL_ZONES, NULL,
1219 (MATCH_IRE_GW | MATCH_IRE_TYPE | MATCH_IRE_ILL), 0, ipst,
1220 NULL);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001221
1222 if (redir_ire != NULL) {
dd1935166bdb8e62006-10-27 15:48:26 -07001223 if (redir_ire->ire_flags & RTF_DYNAMIC)
1224 ire_delete(redir_ire);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001225 ire_refrele(redir_ire);
1226 }
1227 }
1228
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001229 ire_refrele(prev_ire);
1230 prev_ire = NULL;
1231
1232fail_redirect:
1233 if (prev_ire != NULL)
1234 ire_refrele(prev_ire);
1235 freemsg(mp);
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001236 if (rill != ira->ira_rill)
1237 ill_refrele(rill);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001238}
1239
1240/*
1241 * Build and ship an IPv6 ICMP message using the packet data in mp,
1242 * and the ICMP header pointed to by "stuff". (May be called as
1243 * writer.)
1244 * Note: assumes that icmp_pkt_err_ok_v6 has been called to
1245 * verify that an icmp error packet can be sent.
1246 *
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001247 * If v6src_ptr is set use it as a source. Otherwise select a reasonable
1248 * source address (see above function).
1249 */
1250static void
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001251icmp_pkt_v6(mblk_t *mp, void *stuff, size_t len,
1252 const in6_addr_t *v6src_ptr, ip_recv_attr_t *ira)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001253{
1254 ip6_t *ip6h;
1255 in6_addr_t v6dst;
1256 size_t len_needed;
1257 size_t msg_len;
1258 mblk_t *mp1;
1259 icmp6_t *icmp6;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001260 in6_addr_t v6src;
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001261 ill_t *ill = ira->ira_ill;
1262 ip_stack_t *ipst = ill->ill_ipst;
1263 ip_xmit_attr_t ixas;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001264
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001265 ip6h = (ip6_t *)mp->b_rptr;
1266
1267 bzero(&ixas, sizeof (ixas));
1268 ixas.ixa_flags = IXAF_BASIC_SIMPLE_V6;
1269 ixas.ixa_zoneid = ira->ira_zoneid;
1270 ixas.ixa_ifindex = 0;
1271 ixas.ixa_ipst = ipst;
1272 ixas.ixa_cred = kcred;
1273 ixas.ixa_cpid = NOPID;
1274 ixas.ixa_tsl = ira->ira_tsl; /* Behave as a multi-level responder */
1275 ixas.ixa_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
1276
1277 /*
1278 * If the source of the original packet was link-local, then
1279 * make sure we send on the same ill (group) as we received it on.
1280 */
1281 if (IN6_IS_ADDR_LINKSCOPE(&ip6h->ip6_src)) {
1282 ixas.ixa_flags |= IXAF_SCOPEID_SET;
1283 if (IS_UNDER_IPMP(ill))
1284 ixas.ixa_scopeid = ill_get_upper_ifindex(ill);
1285 else
1286 ixas.ixa_scopeid = ill->ill_phyint->phyint_ifindex;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001287 }
1288
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001289 if (ira->ira_flags & IRAF_IPSEC_SECURE) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001290 /*
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001291 * Apply IPsec based on how IPsec was applied to
1292 * the packet that had the error.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001293 *
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001294 * If it was an outbound packet that caused the ICMP
1295 * error, then the caller will have setup the IRA
1296 * appropriately.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001297 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001298 if (!ipsec_in_to_out(ira, &ixas, mp, NULL, ip6h)) {
1299 BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutDiscards);
1300 /* Note: mp already consumed and ip_drop_packet done */
1301 return;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001302 }
1303 } else {
1304 /*
1305 * This is in clear. The icmp message we are building
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001306 * here should go out in clear, independent of our policy.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001307 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001308 ixas.ixa_flags |= IXAF_NO_IPSEC;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001309 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001310
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001311 /*
1312 * If the caller specified the source we use that.
1313 * Otherwise, if the packet was for one of our unicast addresses, make
1314 * sure we respond with that as the source. Otherwise
1315 * have ip_output_simple pick the source address.
1316 */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001317 if (v6src_ptr != NULL) {
1318 v6src = *v6src_ptr;
1319 } else {
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001320 ire_t *ire;
1321 uint_t match_flags = MATCH_IRE_TYPE | MATCH_IRE_ZONEONLY;
1322
1323 if (IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src) ||
1324 IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst))
1325 match_flags |= MATCH_IRE_ILL;
1326
1327 ire = ire_ftable_lookup_v6(&ip6h->ip6_dst, 0, 0,
1328 (IRE_LOCAL|IRE_LOOPBACK), ill, ira->ira_zoneid, NULL,
1329 match_flags, 0, ipst, NULL);
1330 if (ire != NULL) {
1331 v6src = ip6h->ip6_dst;
1332 ire_refrele(ire);
1333 } else {
1334 v6src = ipv6_all_zeros;
1335 ixas.ixa_flags |= IXAF_SET_SOURCE;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001336 }
1337 }
1338 v6dst = ip6h->ip6_src;
dh155122f4b3ec62007-01-19 16:59:38 -08001339 len_needed = ipst->ips_ipv6_icmp_return - IPV6_HDR_LEN - len;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001340 msg_len = msgdsize(mp);
1341 if (msg_len > len_needed) {
1342 if (!adjmsg(mp, len_needed - msg_len)) {
1343 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutErrors);
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001344 freemsg(mp);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001345 return;
1346 }
1347 msg_len = len_needed;
1348 }
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001349 mp1 = allocb(IPV6_HDR_LEN + len, BPRI_MED);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001350 if (mp1 == NULL) {
1351 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutErrors);
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001352 freemsg(mp);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001353 return;
1354 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001355 mp1->b_cont = mp;
1356 mp = mp1;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001357
1358 /*
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001359 * Set IXAF_TRUSTED_ICMP so we can let the ICMP messages this
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001360 * node generates be accepted in peace by all on-host destinations.
1361 * If we do NOT assume that all on-host destinations trust
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001362 * self-generated ICMP messages, then rework here, ip6.c, and spd.c.
1363 * (Look for IXAF_TRUSTED_ICMP).
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001364 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001365 ixas.ixa_flags |= IXAF_TRUSTED_ICMP;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001366
1367 ip6h = (ip6_t *)mp->b_rptr;
1368 mp1->b_wptr = (uchar_t *)ip6h + (IPV6_HDR_LEN + len);
1369
1370 ip6h->ip6_vcf = IPV6_DEFAULT_VERS_AND_FLOW;
1371 ip6h->ip6_nxt = IPPROTO_ICMPV6;
dh155122f4b3ec62007-01-19 16:59:38 -08001372 ip6h->ip6_hops = ipst->ips_ipv6_def_hops;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001373 ip6h->ip6_dst = v6dst;
1374 ip6h->ip6_src = v6src;
1375 msg_len += IPV6_HDR_LEN + len;
1376 if (msg_len > IP_MAXPACKET + IPV6_HDR_LEN) {
1377 (void) adjmsg(mp, IP_MAXPACKET + IPV6_HDR_LEN - msg_len);
1378 msg_len = IP_MAXPACKET + IPV6_HDR_LEN;
1379 }
1380 ip6h->ip6_plen = htons((uint16_t)(msgdsize(mp) - IPV6_HDR_LEN));
1381 icmp6 = (icmp6_t *)&ip6h[1];
1382 bcopy(stuff, (char *)icmp6, len);
1383 /*
1384 * Prepare for checksum by putting icmp length in the icmp
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001385 * checksum field. The checksum is calculated in ip_output_wire_v6.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001386 */
1387 icmp6->icmp6_cksum = ip6h->ip6_plen;
1388 if (icmp6->icmp6_type == ND_REDIRECT) {
1389 ip6h->ip6_hops = IPV6_MAX_HOPS;
1390 }
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001391
1392 (void) ip_output_simple(mp, &ixas);
1393 ixa_cleanup(&ixas);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001394}
1395
1396/*
1397 * Update the output mib when ICMPv6 packets are sent.
1398 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001399void
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001400icmp_update_out_mib_v6(ill_t *ill, icmp6_t *icmp6)
1401{
1402 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutMsgs);
1403
1404 switch (icmp6->icmp6_type) {
1405 case ICMP6_DST_UNREACH:
1406 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutDestUnreachs);
1407 if (icmp6->icmp6_code == ICMP6_DST_UNREACH_ADMIN)
1408 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutAdminProhibs);
1409 break;
1410
1411 case ICMP6_TIME_EXCEEDED:
1412 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutTimeExcds);
1413 break;
1414
1415 case ICMP6_PARAM_PROB:
1416 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutParmProblems);
1417 break;
1418
1419 case ICMP6_PACKET_TOO_BIG:
1420 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutPktTooBigs);
1421 break;
1422
1423 case ICMP6_ECHO_REQUEST:
1424 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutEchos);
1425 break;
1426
1427 case ICMP6_ECHO_REPLY:
1428 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutEchoReplies);
1429 break;
1430
1431 case ND_ROUTER_SOLICIT:
1432 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutRouterSolicits);
1433 break;
1434
1435 case ND_ROUTER_ADVERT:
1436 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutRouterAdvertisements);
1437 break;
1438
1439 case ND_NEIGHBOR_SOLICIT:
1440 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutNeighborSolicits);
1441 break;
1442
1443 case ND_NEIGHBOR_ADVERT:
1444 BUMP_MIB(ill->ill_icmp6_mib,
1445 ipv6IfIcmpOutNeighborAdvertisements);
1446 break;
1447
1448 case ND_REDIRECT:
1449 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutRedirects);
1450 break;
1451
1452 case MLD_LISTENER_QUERY:
1453 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutGroupMembQueries);
1454 break;
1455
1456 case MLD_LISTENER_REPORT:
1457 case MLD_V2_LISTENER_REPORT:
1458 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutGroupMembResponses);
1459 break;
1460
1461 case MLD_LISTENER_REDUCTION:
1462 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutGroupMembReductions);
1463 break;
1464 }
1465}
1466
1467/*
1468 * Check if it is ok to send an ICMPv6 error packet in
1469 * response to the IP packet in mp.
1470 * Free the message and return null if no
1471 * ICMP error packet should be sent.
1472 */
1473static mblk_t *
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001474icmp_pkt_err_ok_v6(mblk_t *mp, boolean_t mcast_ok, ip_recv_attr_t *ira)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001475{
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001476 ill_t *ill = ira->ira_ill;
1477 ip_stack_t *ipst = ill->ill_ipst;
1478 boolean_t llbcast;
1479 ip6_t *ip6h;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001480
1481 if (!mp)
1482 return (NULL);
1483
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001484 /* We view multicast and broadcast as the same.. */
1485 llbcast = (ira->ira_flags &
1486 (IRAF_L2DST_MULTICAST|IRAF_L2DST_BROADCAST)) != 0;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001487 ip6h = (ip6_t *)mp->b_rptr;
1488
1489 /* Check if source address uniquely identifies the host */
1490
1491 if (IN6_IS_ADDR_MULTICAST(&ip6h->ip6_src) ||
1492 IN6_IS_ADDR_V4MAPPED(&ip6h->ip6_src) ||
1493 IN6_IS_ADDR_UNSPECIFIED(&ip6h->ip6_src)) {
1494 freemsg(mp);
1495 return (NULL);
1496 }
1497
1498 if (ip6h->ip6_nxt == IPPROTO_ICMPV6) {
1499 size_t len_needed = IPV6_HDR_LEN + ICMP6_MINLEN;
1500 icmp6_t *icmp6;
1501
1502 if (mp->b_wptr - mp->b_rptr < len_needed) {
1503 if (!pullupmsg(mp, len_needed)) {
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001504 BUMP_MIB(ill->ill_icmp6_mib,
1505 ipv6IfIcmpInErrors);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001506 freemsg(mp);
1507 return (NULL);
1508 }
1509 ip6h = (ip6_t *)mp->b_rptr;
1510 }
1511 icmp6 = (icmp6_t *)&ip6h[1];
1512 /* Explicitly do not generate errors in response to redirects */
1513 if (ICMP6_IS_ERROR(icmp6->icmp6_type) ||
1514 icmp6->icmp6_type == ND_REDIRECT) {
1515 freemsg(mp);
1516 return (NULL);
1517 }
1518 }
1519 /*
1520 * Check that the destination is not multicast and that the packet
1521 * was not sent on link layer broadcast or multicast. (Exception
1522 * is Packet too big message as per the draft - when mcast_ok is set.)
1523 */
1524 if (!mcast_ok &&
1525 (llbcast || IN6_IS_ADDR_MULTICAST(&ip6h->ip6_dst))) {
1526 freemsg(mp);
1527 return (NULL);
1528 }
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001529 /*
1530 * If this is a labeled system, then check to see if we're allowed to
1531 * send a response to this particular sender. If not, then just drop.
1532 */
1533 if (is_system_labeled() && !tsol_can_reply_error(mp, ira)) {
1534 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpOutErrors);
1535 freemsg(mp);
1536 return (NULL);
1537 }
1538
dh155122f4b3ec62007-01-19 16:59:38 -08001539 if (icmp_err_rate_limit(ipst)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001540 /*
1541 * Only send ICMP error packets every so often.
1542 * This should be done on a per port/source basis,
1543 * but for now this will suffice.
1544 */
1545 freemsg(mp);
1546 return (NULL);
1547 }
1548 return (mp);
1549}
1550
1551/*
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001552 * Called when a packet was sent out the same link that it arrived on.
1553 * Check if it is ok to send a redirect and then send it.
1554 */
1555void
1556ip_send_potential_redirect_v6(mblk_t *mp, ip6_t *ip6h, ire_t *ire,
1557 ip_recv_attr_t *ira)
1558{
1559 ill_t *ill = ira->ira_ill;
1560 ip_stack_t *ipst = ill->ill_ipst;
1561 in6_addr_t *v6targ;
1562 ire_t *src_ire_v6 = NULL;
1563 mblk_t *mp1;
1564 ire_t *nhop_ire = NULL;
1565
1566 /*
1567 * Don't send a redirect when forwarding a source
1568 * routed packet.
1569 */
1570 if (ip_source_routed_v6(ip6h, mp, ipst))
1571 return;
1572
1573 if (ire->ire_type & IRE_ONLINK) {
1574 /* Target is directly connected */
1575 v6targ = &ip6h->ip6_dst;
1576 } else {
1577 /* Determine the most specific IRE used to send the packets */
1578 nhop_ire = ire_nexthop(ire);
1579 if (nhop_ire == NULL)
1580 return;
1581
1582 /*
1583 * We won't send redirects to a router
1584 * that doesn't have a link local
1585 * address, but will forward.
1586 */
1587 if (!IN6_IS_ADDR_LINKLOCAL(&nhop_ire->ire_addr_v6)) {
1588 BUMP_MIB(ill->ill_ip_mib, ipIfStatsInAddrErrors);
1589 ip_drop_input("ipIfStatsInAddrErrors", mp, ill);
1590 ire_refrele(nhop_ire);
1591 return;
1592 }
1593 v6targ = &nhop_ire->ire_addr_v6;
1594 }
1595 src_ire_v6 = ire_ftable_lookup_v6(&ip6h->ip6_src,
1596 NULL, NULL, IRE_INTERFACE, ire->ire_ill, ALL_ZONES, NULL,
1597 MATCH_IRE_ILL | MATCH_IRE_TYPE, 0, ipst, NULL);
1598
1599 if (src_ire_v6 == NULL) {
1600 if (nhop_ire != NULL)
1601 ire_refrele(nhop_ire);
1602 return;
1603 }
1604
1605 /*
1606 * The source is directly connected.
1607 */
1608 mp1 = copymsg(mp);
1609 if (mp1 != NULL)
1610 icmp_send_redirect_v6(mp1, v6targ, &ip6h->ip6_dst, ira);
1611
1612 if (nhop_ire != NULL)
1613 ire_refrele(nhop_ire);
1614 ire_refrele(src_ire_v6);
1615}
1616
1617/*
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001618 * Generate an ICMPv6 redirect message.
1619 * Include target link layer address option if it exits.
1620 * Always include redirect header.
1621 */
1622static void
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001623icmp_send_redirect_v6(mblk_t *mp, in6_addr_t *targetp, in6_addr_t *dest,
1624 ip_recv_attr_t *ira)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001625{
1626 nd_redirect_t *rd;
1627 nd_opt_rd_hdr_t *rdh;
1628 uchar_t *buf;
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001629 ncec_t *ncec = NULL;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001630 nd_opt_hdr_t *opt;
1631 int len;
1632 int ll_opt_len = 0;
1633 int max_redir_hdr_data_len;
1634 int pkt_len;
1635 in6_addr_t *srcp;
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001636 ill_t *ill;
1637 boolean_t need_refrele;
1638 ip_stack_t *ipst = ira->ira_ill->ill_ipst;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001639
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001640 mp = icmp_pkt_err_ok_v6(mp, B_FALSE, ira);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001641 if (mp == NULL)
1642 return;
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001643
1644 if (IS_UNDER_IPMP(ira->ira_ill)) {
1645 ill = ipmp_ill_hold_ipmp_ill(ira->ira_ill);
1646 if (ill == NULL) {
1647 ill = ira->ira_ill;
1648 BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInBadRedirects);
1649 ip_drop_output("no IPMP ill for sending redirect",
1650 mp, ill);
1651 freemsg(mp);
1652 return;
1653 }
1654 need_refrele = B_TRUE;
1655 } else {
1656 ill = ira->ira_ill;
1657 need_refrele = B_FALSE;
1658 }
1659
1660 ncec = ncec_lookup_illgrp_v6(ill, targetp);
1661 if (ncec != NULL && ncec->ncec_state != ND_INCOMPLETE &&
1662 ncec->ncec_lladdr != NULL) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001663 ll_opt_len = (sizeof (nd_opt_hdr_t) +
1664 ill->ill_phys_addr_length + 7)/8 * 8;
1665 }
1666 len = sizeof (nd_redirect_t) + sizeof (nd_opt_rd_hdr_t) + ll_opt_len;
1667 ASSERT(len % 4 == 0);
1668 buf = kmem_alloc(len, KM_NOSLEEP);
1669 if (buf == NULL) {
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001670 if (ncec != NULL)
1671 ncec_refrele(ncec);
1672 if (need_refrele)
1673 ill_refrele(ill);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001674 freemsg(mp);
1675 return;
1676 }
1677
1678 rd = (nd_redirect_t *)buf;
1679 rd->nd_rd_type = (uint8_t)ND_REDIRECT;
1680 rd->nd_rd_code = 0;
1681 rd->nd_rd_reserved = 0;
1682 rd->nd_rd_target = *targetp;
1683 rd->nd_rd_dst = *dest;
1684
1685 opt = (nd_opt_hdr_t *)(buf + sizeof (nd_redirect_t));
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001686 if (ncec != NULL && ll_opt_len != 0) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001687 opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
1688 opt->nd_opt_len = ll_opt_len/8;
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001689 bcopy((char *)ncec->ncec_lladdr, &opt[1],
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001690 ill->ill_phys_addr_length);
1691 }
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001692 if (ncec != NULL)
1693 ncec_refrele(ncec);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001694 rdh = (nd_opt_rd_hdr_t *)(buf + sizeof (nd_redirect_t) + ll_opt_len);
1695 rdh->nd_opt_rh_type = (uint8_t)ND_OPT_REDIRECTED_HEADER;
1696 /* max_redir_hdr_data_len and nd_opt_rh_len must be multiple of 8 */
dh155122f4b3ec62007-01-19 16:59:38 -08001697 max_redir_hdr_data_len =
1698 (ipst->ips_ipv6_icmp_return - IPV6_HDR_LEN - len)/8*8;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001699 pkt_len = msgdsize(mp);
1700 /* Make sure mp is 8 byte aligned */
1701 if (pkt_len > max_redir_hdr_data_len) {
1702 rdh->nd_opt_rh_len = (max_redir_hdr_data_len +
1703 sizeof (nd_opt_rd_hdr_t))/8;
1704 (void) adjmsg(mp, max_redir_hdr_data_len - pkt_len);
1705 } else {
1706 rdh->nd_opt_rh_len = (pkt_len + sizeof (nd_opt_rd_hdr_t))/8;
1707 (void) adjmsg(mp, -(pkt_len % 8));
1708 }
1709 rdh->nd_opt_rh_reserved1 = 0;
1710 rdh->nd_opt_rh_reserved2 = 0;
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001711 /* ipif_v6lcl_addr contains the link-local source address */
1712 srcp = &ill->ill_ipif->ipif_v6lcl_addr;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001713
nordmark5597b602006-09-14 18:05:27 -07001714 /* Redirects sent by router, and router is global zone */
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001715 ASSERT(ira->ira_zoneid == ALL_ZONES);
1716 ira->ira_zoneid = GLOBAL_ZONEID;
1717 icmp_pkt_v6(mp, buf, len, srcp, ira);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001718 kmem_free(buf, len);
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001719 if (need_refrele)
1720 ill_refrele(ill);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001721}
1722
1723
1724/* Generate an ICMP time exceeded message. (May be called as writer.) */
1725void
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001726icmp_time_exceeded_v6(mblk_t *mp, uint8_t code, boolean_t mcast_ok,
1727 ip_recv_attr_t *ira)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001728{
1729 icmp6_t icmp6;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001730
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001731 mp = icmp_pkt_err_ok_v6(mp, mcast_ok, ira);
1732 if (mp == NULL)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001733 return;
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001734
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001735 bzero(&icmp6, sizeof (icmp6_t));
1736 icmp6.icmp6_type = ICMP6_TIME_EXCEEDED;
1737 icmp6.icmp6_code = code;
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001738 icmp_pkt_v6(mp, &icmp6, sizeof (icmp6_t), NULL, ira);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001739}
1740
1741/*
1742 * Generate an ICMP unreachable message.
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001743 * When called from ip_output side a minimal ip_recv_attr_t needs to be
1744 * constructed by the caller.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001745 */
1746void
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001747icmp_unreachable_v6(mblk_t *mp, uint8_t code, boolean_t mcast_ok,
1748 ip_recv_attr_t *ira)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001749{
1750 icmp6_t icmp6;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001751
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001752 mp = icmp_pkt_err_ok_v6(mp, mcast_ok, ira);
1753 if (mp == NULL)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001754 return;
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001755
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001756 bzero(&icmp6, sizeof (icmp6_t));
1757 icmp6.icmp6_type = ICMP6_DST_UNREACH;
1758 icmp6.icmp6_code = code;
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001759 icmp_pkt_v6(mp, &icmp6, sizeof (icmp6_t), NULL, ira);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001760}
1761
1762/*
1763 * Generate an ICMP pkt too big message.
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001764 * When called from ip_output side a minimal ip_recv_attr_t needs to be
1765 * constructed by the caller.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001766 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001767void
1768icmp_pkt2big_v6(mblk_t *mp, uint32_t mtu, boolean_t mcast_ok,
1769 ip_recv_attr_t *ira)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001770{
1771 icmp6_t icmp6;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001772
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001773 mp = icmp_pkt_err_ok_v6(mp, mcast_ok, ira);
1774 if (mp == NULL)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001775 return;
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001776
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001777 bzero(&icmp6, sizeof (icmp6_t));
1778 icmp6.icmp6_type = ICMP6_PACKET_TOO_BIG;
1779 icmp6.icmp6_code = 0;
1780 icmp6.icmp6_mtu = htonl(mtu);
1781
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001782 icmp_pkt_v6(mp, &icmp6, sizeof (icmp6_t), NULL, ira);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001783}
1784
1785/*
1786 * Generate an ICMP parameter problem message. (May be called as writer.)
1787 * 'offset' is the offset from the beginning of the packet in error.
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001788 * When called from ip_output side a minimal ip_recv_attr_t needs to be
1789 * constructed by the caller.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001790 */
1791static void
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001792icmp_param_problem_v6(mblk_t *mp, uint8_t code, uint32_t offset,
1793 boolean_t mcast_ok, ip_recv_attr_t *ira)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001794{
1795 icmp6_t icmp6;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001796
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001797 mp = icmp_pkt_err_ok_v6(mp, mcast_ok, ira);
1798 if (mp == NULL)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001799 return;
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001800
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001801 bzero((char *)&icmp6, sizeof (icmp6_t));
1802 icmp6.icmp6_type = ICMP6_PARAM_PROB;
1803 icmp6.icmp6_code = code;
1804 icmp6.icmp6_pptr = htonl(offset);
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001805 icmp_pkt_v6(mp, &icmp6, sizeof (icmp6_t), NULL, ira);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001806}
1807
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001808void
1809icmp_param_problem_nexthdr_v6(mblk_t *mp, boolean_t mcast_ok,
1810 ip_recv_attr_t *ira)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001811{
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001812 ip6_t *ip6h = (ip6_t *)mp->b_rptr;
1813 uint16_t hdr_length;
1814 uint8_t *nexthdrp;
1815 uint32_t offset;
1816 ill_t *ill = ira->ira_ill;
Erik Nordmarkde8c4a12009-02-12 08:42:06 -08001817
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001818 /* Determine the offset of the bad nexthdr value */
1819 if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &hdr_length, &nexthdrp)) {
1820 /* Malformed packet */
1821 BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
1822 ip_drop_input("ipIfStatsInDiscards", mp, ill);
1823 freemsg(mp);
1824 return;
Erik Nordmarkde8c4a12009-02-12 08:42:06 -08001825 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001826
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001827 offset = nexthdrp - mp->b_rptr;
1828 icmp_param_problem_v6(mp, ICMP6_PARAMPROB_NEXTHEADER, offset,
1829 mcast_ok, ira);
Yu Xiangning0f1702c2008-12-11 20:04:13 -08001830}
1831
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001832/*
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001833 * Verify whether or not the IP address is a valid local address.
1834 * Could be a unicast, including one for a down interface.
1835 * If allow_mcbc then a multicast or broadcast address is also
1836 * acceptable.
1837 *
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001838 * In the case of a multicast address, however, the
1839 * upper protocol is expected to reset the src address
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001840 * to zero when we return IPVL_MCAST so that
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001841 * no packets are emitted with multicast address as
1842 * source address.
1843 * The addresses valid for bind are:
1844 * (1) - in6addr_any
1845 * (2) - IP address of an UP interface
1846 * (3) - IP address of a DOWN interface
1847 * (4) - a multicast address. In this case
1848 * the conn will only receive packets destined to
1849 * the specified multicast address. Note: the
1850 * application still has to issue an
1851 * IPV6_JOIN_GROUP socket option.
1852 *
1853 * In all the above cases, the bound address must be valid in the current zone.
1854 * When the address is loopback or multicast, there might be many matching IREs
1855 * so bind has to look up based on the zone.
1856 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001857ip_laddr_t
1858ip_laddr_verify_v6(const in6_addr_t *v6src, zoneid_t zoneid,
1859 ip_stack_t *ipst, boolean_t allow_mcbc, uint_t scopeid)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001860{
1861 ire_t *src_ire;
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001862 uint_t match_flags;
1863 ill_t *ill = NULL;
Yu Xiangning0f1702c2008-12-11 20:04:13 -08001864
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001865 ASSERT(!IN6_IS_ADDR_V4MAPPED(v6src));
1866 ASSERT(!IN6_IS_ADDR_UNSPECIFIED(v6src));
Yu Xiangning0f1702c2008-12-11 20:04:13 -08001867
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001868 match_flags = MATCH_IRE_ZONEONLY;
1869 if (scopeid != 0) {
1870 ill = ill_lookup_on_ifindex(scopeid, B_TRUE, ipst);
1871 if (ill == NULL)
1872 return (IPVL_BAD);
1873 match_flags |= MATCH_IRE_ILL;
Yu Xiangning0f1702c2008-12-11 20:04:13 -08001874 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001875
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001876 src_ire = ire_ftable_lookup_v6(v6src, NULL, NULL, 0,
1877 ill, zoneid, NULL, match_flags, 0, ipst, NULL);
1878 if (ill != NULL)
1879 ill_refrele(ill);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001880
ken Powell - Sun Microsystem5f9878b2009-05-22 22:15:42 -04001881 /*
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001882 * If an address other than in6addr_any is requested,
1883 * we verify that it is a valid address for bind
1884 * Note: Following code is in if-else-if form for
1885 * readability compared to a condition check.
ken Powell - Sun Microsystem5f9878b2009-05-22 22:15:42 -04001886 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001887 if (src_ire != NULL && (src_ire->ire_type & (IRE_LOCAL|IRE_LOOPBACK))) {
1888 /*
1889 * (2) Bind to address of local UP interface
1890 */
1891 ire_refrele(src_ire);
1892 return (IPVL_UNICAST_UP);
1893 } else if (IN6_IS_ADDR_MULTICAST(v6src)) {
1894 /* (4) bind to multicast address. */
1895 if (src_ire != NULL)
1896 ire_refrele(src_ire);
ken Powell - Sun Microsystem5f9878b2009-05-22 22:15:42 -04001897
1898 /*
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001899 * Note: caller should take IPV6_MULTICAST_IF
1900 * into account when selecting a real source address.
ken Powell - Sun Microsystem5f9878b2009-05-22 22:15:42 -04001901 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001902 if (allow_mcbc)
1903 return (IPVL_MCAST);
1904 else
1905 return (IPVL_BAD);
1906 } else {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001907 ipif_t *ipif;
1908
1909 /*
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001910 * (3) Bind to address of local DOWN interface?
1911 * (ipif_lookup_addr() looks up all interfaces
1912 * but we do not get here for UP interfaces
1913 * - case (2) above)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001914 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001915 if (src_ire != NULL)
1916 ire_refrele(src_ire);
1917
1918 ipif = ipif_lookup_addr_v6(v6src, NULL, zoneid, ipst);
1919 if (ipif == NULL)
1920 return (IPVL_BAD);
1921
1922 /* Not a useful source? */
1923 if (ipif->ipif_flags & (IPIF_NOLOCAL | IPIF_ANYCAST)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001924 ipif_refrele(ipif);
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001925 return (IPVL_BAD);
1926 }
1927 ipif_refrele(ipif);
1928 return (IPVL_UNICAST_DOWN);
1929 }
1930}
1931
1932/*
1933 * Verify that both the source and destination addresses are valid. If
1934 * IPDF_VERIFY_DST is not set, then the destination address may be unreachable,
1935 * i.e. have no route to it. Protocols like TCP want to verify destination
1936 * reachability, while tunnels do not.
1937 *
1938 * Determine the route, the interface, and (optionally) the source address
1939 * to use to reach a given destination.
1940 * Note that we allow connect to broadcast and multicast addresses when
1941 * IPDF_ALLOW_MCBC is set.
1942 * first_hop and dst_addr are normally the same, but if source routing
1943 * they will differ; in that case the first_hop is what we'll use for the
1944 * routing lookup but the dce and label checks will be done on dst_addr,
1945 *
1946 * If uinfo is set, then we fill in the best available information
1947 * we have for the destination. This is based on (in priority order) any
1948 * metrics and path MTU stored in a dce_t, route metrics, and finally the
Erik Nordmark1eee1702010-08-16 15:30:54 -07001949 * ill_mtu/ill_mc_mtu.
Erik Nordmarkbd670b32009-11-11 11:49:49 -08001950 *
1951 * Tsol note: If we have a source route then dst_addr != firsthop. But we
1952 * always do the label check on dst_addr.
1953 *
1954 * Assumes that the caller has set ixa_scopeid for link-local communication.
1955 */
1956int
1957ip_set_destination_v6(in6_addr_t *src_addrp, const in6_addr_t *dst_addr,
1958 const in6_addr_t *firsthop, ip_xmit_attr_t *ixa, iulp_t *uinfo,
1959 uint32_t flags, uint_t mac_mode)
1960{
1961 ire_t *ire;
1962 int error = 0;
1963 in6_addr_t setsrc; /* RTF_SETSRC */
1964 zoneid_t zoneid = ixa->ixa_zoneid; /* Honors SO_ALLZONES */
1965 ip_stack_t *ipst = ixa->ixa_ipst;
1966 dce_t *dce;
1967 uint_t pmtu;
1968 uint_t ifindex;
1969 uint_t generation;
1970 nce_t *nce;
1971 ill_t *ill = NULL;
1972 boolean_t multirt = B_FALSE;
1973
1974 ASSERT(!IN6_IS_ADDR_V4MAPPED(dst_addr));
1975
1976 ASSERT(!(ixa->ixa_flags & IXAF_IS_IPV4));
1977
1978 /*
1979 * We never send to zero; the ULPs map it to the loopback address.
1980 * We can't allow it since we use zero to mean unitialized in some
1981 * places.
1982 */
1983 ASSERT(!IN6_IS_ADDR_UNSPECIFIED(dst_addr));
1984
1985 if (is_system_labeled()) {
1986 ts_label_t *tsl = NULL;
1987
1988 error = tsol_check_dest(ixa->ixa_tsl, dst_addr, IPV6_VERSION,
1989 mac_mode, (flags & IPDF_ZONE_IS_GLOBAL) != 0, &tsl);
1990 if (error != 0)
1991 return (error);
1992 if (tsl != NULL) {
1993 /* Update the label */
1994 ip_xmit_attr_replace_tsl(ixa, tsl);
1995 }
1996 }
1997
1998 setsrc = ipv6_all_zeros;
1999 /*
2000 * Select a route; For IPMP interfaces, we would only select
2001 * a "hidden" route (i.e., going through a specific under_ill)
2002 * if ixa_ifindex has been specified.
2003 */
Sowmini Varadhan44b099c2010-02-17 22:59:58 -05002004 ire = ip_select_route_v6(firsthop, *src_addrp, ixa, &generation,
2005 &setsrc, &error, &multirt);
Erik Nordmarkbd670b32009-11-11 11:49:49 -08002006 ASSERT(ire != NULL); /* IRE_NOROUTE if none found */
2007 if (error != 0)
2008 goto bad_addr;
2009
2010 /*
2011 * ire can't be a broadcast or multicast unless IPDF_ALLOW_MCBC is set.
2012 * If IPDF_VERIFY_DST is set, the destination must be reachable.
2013 * Otherwise the destination needn't be reachable.
2014 *
2015 * If we match on a reject or black hole, then we've got a
2016 * local failure. May as well fail out the connect() attempt,
2017 * since it's never going to succeed.
2018 */
2019 if (ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002020 /*
Erik Nordmarkbd670b32009-11-11 11:49:49 -08002021 * If we're verifying destination reachability, we always want
2022 * to complain here.
2023 *
2024 * If we're not verifying destination reachability but the
2025 * destination has a route, we still want to fail on the
2026 * temporary address and broadcast address tests.
2027 *
2028 * In both cases do we let the code continue so some reasonable
2029 * information is returned to the caller. That enables the
2030 * caller to use (and even cache) the IRE. conn_ip_ouput will
2031 * use the generation mismatch path to check for the unreachable
2032 * case thereby avoiding any specific check in the main path.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002033 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -08002034 ASSERT(generation == IRE_GENERATION_VERIFY);
2035 if (flags & IPDF_VERIFY_DST) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002036 /*
Erik Nordmarkbd670b32009-11-11 11:49:49 -08002037 * Set errno but continue to set up ixa_ire to be
2038 * the RTF_REJECT|RTF_BLACKHOLE IRE.
2039 * That allows callers to use ip_output to get an
2040 * ICMP error back.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002041 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -08002042 if (!(ire->ire_type & IRE_HOST))
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002043 error = ENETUNREACH;
2044 else
2045 error = EHOSTUNREACH;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002046 }
Erik Nordmarkbd670b32009-11-11 11:49:49 -08002047 }
2048
2049 if ((ire->ire_type & (IRE_BROADCAST|IRE_MULTICAST)) &&
2050 !(flags & IPDF_ALLOW_MCBC)) {
2051 ire_refrele(ire);
2052 ire = ire_reject(ipst, B_FALSE);
2053 generation = IRE_GENERATION_VERIFY;
2054 error = ENETUNREACH;
2055 }
2056
2057 /* Cache things */
2058 if (ixa->ixa_ire != NULL)
2059 ire_refrele_notr(ixa->ixa_ire);
2060#ifdef DEBUG
2061 ire_refhold_notr(ire);
2062 ire_refrele(ire);
2063#endif
2064 ixa->ixa_ire = ire;
2065 ixa->ixa_ire_generation = generation;
2066
2067 /*
Sowmini Varadhan53287762010-05-06 21:52:58 -04002068 * Ensure that ixa_dce is always set any time that ixa_ire is set,
2069 * since some callers will send a packet to conn_ip_output() even if
2070 * there's an error.
2071 */
2072 ifindex = 0;
2073 if (IN6_IS_ADDR_LINKSCOPE(dst_addr)) {
2074 /* If we are creating a DCE we'd better have an ifindex */
2075 if (ill != NULL)
2076 ifindex = ill->ill_phyint->phyint_ifindex;
2077 else
2078 flags &= ~IPDF_UNIQUE_DCE;
2079 }
2080
2081 if (flags & IPDF_UNIQUE_DCE) {
2082 /* Fallback to the default dce if allocation fails */
2083 dce = dce_lookup_and_add_v6(dst_addr, ifindex, ipst);
2084 if (dce != NULL) {
2085 generation = dce->dce_generation;
2086 } else {
2087 dce = dce_lookup_v6(dst_addr, ifindex, ipst,
2088 &generation);
2089 }
2090 } else {
2091 dce = dce_lookup_v6(dst_addr, ifindex, ipst, &generation);
2092 }
2093 ASSERT(dce != NULL);
2094 if (ixa->ixa_dce != NULL)
2095 dce_refrele_notr(ixa->ixa_dce);
2096#ifdef DEBUG
2097 dce_refhold_notr(dce);
2098 dce_refrele(dce);
2099#endif
2100 ixa->ixa_dce = dce;
2101 ixa->ixa_dce_generation = generation;
2102
2103
2104 /*
Erik Nordmarkbd670b32009-11-11 11:49:49 -08002105 * For multicast with multirt we have a flag passed back from
2106 * ire_lookup_multi_ill_v6 since we don't have an IRE for each
2107 * possible multicast address.
2108 * We also need a flag for multicast since we can't check
2109 * whether RTF_MULTIRT is set in ixa_ire for multicast.
2110 */
2111 if (multirt) {
2112 ixa->ixa_postfragfn = ip_postfrag_multirt_v6;
2113 ixa->ixa_flags |= IXAF_MULTIRT_MULTICAST;
2114 } else {
2115 ixa->ixa_postfragfn = ire->ire_postfragfn;
2116 ixa->ixa_flags &= ~IXAF_MULTIRT_MULTICAST;
2117 }
2118 if (!(ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE))) {
2119 /* Get an nce to cache. */
Toomas Soome63d2ef32019-01-18 10:25:05 +02002120 nce = ire_to_nce(ire, 0, firsthop);
Erik Nordmarkbd670b32009-11-11 11:49:49 -08002121 if (nce == NULL) {
2122 /* Allocation failure? */
2123 ixa->ixa_ire_generation = IRE_GENERATION_VERIFY;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002124 } else {
Erik Nordmarkbd670b32009-11-11 11:49:49 -08002125 if (ixa->ixa_nce != NULL)
2126 nce_refrele(ixa->ixa_nce);
2127 ixa->ixa_nce = nce;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002128 }
2129 }
2130
2131 /*
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002132 * If the source address is a loopback address, the
2133 * destination had best be local or multicast.
Erik Nordmarkbd670b32009-11-11 11:49:49 -08002134 * If we are sending to an IRE_LOCAL using a loopback source then
2135 * it had better be the same zoneid.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002136 */
Erik Nordmarkbd670b32009-11-11 11:49:49 -08002137 if (IN6_IS_ADDR_LOOPBACK(src_addrp)) {
2138 if ((ire->ire_type & IRE_LOCAL) && ire->ire_zoneid != zoneid) {
2139 ire = NULL; /* Stored in ixa_ire */
2140 error = EADDRNOTAVAIL;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002141 goto bad_addr;
2142 }
Erik Nordmarkbd670b32009-11-11 11:49:49 -08002143 if (!(ire->ire_type & (IRE_LOOPBACK|IRE_LOCAL|IRE_MULTICAST))) {
2144 ire = NULL; /* Stored in ixa_ire */
2145 error = EADDRNOTAVAIL;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700