4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
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 /*
22 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2013 by Delphix. All rights reserved.
24 */
25 /* Copyright (c) 1990 Mentat Inc. */
26
27 #include <sys/types.h>
28 #include <sys/stream.h>
29 #include <sys/stropts.h>
30 #include <sys/strlog.h>
31 #include <sys/strsun.h>
32 #define _SUN_TPI_VERSION 2
33 #include <sys/tihdr.h>
34 #include <sys/timod.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
37 #include <sys/strsubr.h>
38 #include <sys/suntpi.h>
39 #include <sys/xti_inet.h>
40 #include <sys/cmn_err.h>
41 #include <sys/kmem.h>
42 #include <sys/cred.h>
43 #include <sys/policy.h>
751 dstport = sin->sin_port;
752 IN6_IPADDR_TO_V4MAPPED(v4dst, &v6dst);
753 ASSERT(connp->conn_ipversion == IPV4_VERSION);
754 break;
755
756 case sizeof (sin6_t):
757 sin6 = (sin6_t *)sa;
758
759 /* No support for mapped addresses on raw sockets */
760 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
761 return (EADDRNOTAVAIL);
762 }
763 v6dst = sin6->sin6_addr;
764 dstport = sin6->sin6_port;
765 ASSERT(connp->conn_ipversion == IPV6_VERSION);
766 flowinfo = sin6->sin6_flowinfo;
767 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
768 scopeid = sin6->sin6_scope_id;
769 srcid = sin6->__sin6_src_id;
770 if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) {
771 ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp),
772 connp->conn_netstack);
773 }
774 break;
775 }
776
777 /*
778 * If there is a different thread using conn_ixa then we get a new
779 * copy and cut the old one loose from conn_ixa. Otherwise we use
780 * conn_ixa and prevent any other thread from using/changing it.
781 * Once connect() is done other threads can use conn_ixa since the
782 * refcnt will be back at one.
783 * We defer updating conn_ixa until later to handle any concurrent
784 * conn_ixa_cleanup thread.
785 */
786 ixa = conn_get_ixa(connp, B_FALSE);
787 if (ixa == NULL)
788 return (ENOMEM);
789
790 mutex_enter(&connp->conn_lock);
791 /*
792 * This icmp_t must have bound already before doing a connect.
793 * Reject if a connect is in progress (we drop conn_lock during
3320 * Handle T_UNITDATA_REQ with options. Both IPv4 and IPv6
3321 * Either tudr_mp or msg is set. If tudr_mp we take ancillary data from
3322 * the TPI options, otherwise we take them from msg_control.
3323 * If both sin and sin6 is set it is a connected socket and we use conn_faddr.
3324 * Always consumes mp; never consumes tudr_mp.
3325 */
3326 static int
3327 icmp_output_ancillary(conn_t *connp, sin_t *sin, sin6_t *sin6, mblk_t *mp,
3328 mblk_t *tudr_mp, struct nmsghdr *msg, cred_t *cr, pid_t pid)
3329 {
3330 icmp_t *icmp = connp->conn_icmp;
3331 icmp_stack_t *is = icmp->icmp_is;
3332 int error;
3333 ip_xmit_attr_t *ixa;
3334 ip_pkt_t *ipp;
3335 in6_addr_t v6src;
3336 in6_addr_t v6dst;
3337 in6_addr_t v6nexthop;
3338 in_port_t dstport;
3339 uint32_t flowinfo;
3340 uint_t srcid;
3341 int is_absreq_failure = 0;
3342 conn_opt_arg_t coas, *coa;
3343
3344 ASSERT(tudr_mp != NULL || msg != NULL);
3345
3346 /*
3347 * Get ixa before checking state to handle a disconnect race.
3348 *
3349 * We need an exclusive copy of conn_ixa since the ancillary data
3350 * options might modify it. That copy has no pointers hence we
3351 * need to set them up once we've parsed the ancillary data.
3352 */
3353 ixa = conn_get_ixa_exclusive(connp);
3354 if (ixa == NULL) {
3355 BUMP_MIB(&is->is_rawip_mib, rawipOutErrors);
3356 freemsg(mp);
3357 return (ENOMEM);
3358 }
3359 ASSERT(cr != NULL);
3360 ASSERT(!(ixa->ixa_free_flags & IXA_FREE_CRED));
3423 ASSERT(is_absreq_failure == 0);
3424
3425 mutex_enter(&connp->conn_lock);
3426 /*
3427 * If laddr is unspecified then we look at sin6_src_id.
3428 * We will give precedence to a source address set with IPV6_PKTINFO
3429 * (aka IPPF_ADDR) but that is handled in build_hdrs. However, we don't
3430 * want ip_attr_connect to select a source (since it can fail) when
3431 * IPV6_PKTINFO is specified.
3432 * If this doesn't result in a source address then we get a source
3433 * from ip_attr_connect() below.
3434 */
3435 v6src = connp->conn_saddr_v6;
3436 if (sin != NULL) {
3437 IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &v6dst);
3438 dstport = sin->sin_port;
3439 flowinfo = 0;
3440 ixa->ixa_flags &= ~IXAF_SCOPEID_SET;
3441 ixa->ixa_flags |= IXAF_IS_IPV4;
3442 } else if (sin6 != NULL) {
3443 v6dst = sin6->sin6_addr;
3444 dstport = sin6->sin6_port;
3445 flowinfo = sin6->sin6_flowinfo;
3446 srcid = sin6->__sin6_src_id;
3447 if (IN6_IS_ADDR_LINKSCOPE(&v6dst) && sin6->sin6_scope_id != 0) {
3448 ixa->ixa_scopeid = sin6->sin6_scope_id;
3449 ixa->ixa_flags |= IXAF_SCOPEID_SET;
3450 } else {
3451 ixa->ixa_flags &= ~IXAF_SCOPEID_SET;
3452 }
3453 if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) {
3454 ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp),
3455 connp->conn_netstack);
3456 }
3457 if (IN6_IS_ADDR_V4MAPPED(&v6dst))
3458 ixa->ixa_flags |= IXAF_IS_IPV4;
3459 else
3460 ixa->ixa_flags &= ~IXAF_IS_IPV4;
3461 } else {
3462 /* Connected case */
3463 v6dst = connp->conn_faddr_v6;
3464 flowinfo = connp->conn_flowinfo;
3465 }
3466 mutex_exit(&connp->conn_lock);
3467 /* Handle IP_PKTINFO/IPV6_PKTINFO setting source address. */
3468 if (ipp->ipp_fields & IPPF_ADDR) {
3469 if (ixa->ixa_flags & IXAF_IS_IPV4) {
3470 if (IN6_IS_ADDR_V4MAPPED(&ipp->ipp_addr))
3471 v6src = ipp->ipp_addr;
3472 } else {
3473 if (!IN6_IS_ADDR_V4MAPPED(&ipp->ipp_addr))
3474 v6src = ipp->ipp_addr;
3475 }
3476 }
3477 /*
3478 * Allow source not assigned to the system
3479 * only if it is not a local addresses
3480 */
4402 goto ud_error;
4403 }
4404
4405 /* In case previous destination was multicast or multirt */
4406 ip_attr_newdst(ixa);
4407
4408 /*
4409 * If laddr is unspecified then we look at sin6_src_id.
4410 * We will give precedence to a source address set with IPV6_PKTINFO
4411 * (aka IPPF_ADDR) but that is handled in build_hdrs. However, we don't
4412 * want ip_attr_connect to select a source (since it can fail) when
4413 * IPV6_PKTINFO is specified.
4414 * If this doesn't result in a source address then we get a source
4415 * from ip_attr_connect() below.
4416 */
4417 v6src = connp->conn_saddr_v6;
4418 if (sin != NULL) {
4419 IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &v6dst);
4420 dstport = sin->sin_port;
4421 flowinfo = 0;
4422 srcid = 0;
4423 ixa->ixa_flags &= ~IXAF_SCOPEID_SET;
4424 if (srcid != 0 && V4_PART_OF_V6(&v6src) == INADDR_ANY) {
4425 ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp),
4426 connp->conn_netstack);
4427 }
4428 ixa->ixa_flags |= IXAF_IS_IPV4;
4429 } else {
4430 v6dst = sin6->sin6_addr;
4431 dstport = sin6->sin6_port;
4432 flowinfo = sin6->sin6_flowinfo;
4433 srcid = sin6->__sin6_src_id;
4434 if (IN6_IS_ADDR_LINKSCOPE(&v6dst) && sin6->sin6_scope_id != 0) {
4435 ixa->ixa_scopeid = sin6->sin6_scope_id;
4436 ixa->ixa_flags |= IXAF_SCOPEID_SET;
4437 } else {
4438 ixa->ixa_flags &= ~IXAF_SCOPEID_SET;
4439 }
4440 if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) {
4441 ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp),
4442 connp->conn_netstack);
4443 }
4444 if (IN6_IS_ADDR_V4MAPPED(&v6dst))
4445 ixa->ixa_flags |= IXAF_IS_IPV4;
4446 else
4447 ixa->ixa_flags &= ~IXAF_IS_IPV4;
4448 }
4449 /* Handle IP_PKTINFO/IPV6_PKTINFO setting source address. */
4450 if (connp->conn_xmit_ipp.ipp_fields & IPPF_ADDR) {
4451 ip_pkt_t *ipp = &connp->conn_xmit_ipp;
4452
4453 if (ixa->ixa_flags & IXAF_IS_IPV4) {
4454 if (IN6_IS_ADDR_V4MAPPED(&ipp->ipp_addr))
4455 v6src = ipp->ipp_addr;
4456 } else {
4457 if (!IN6_IS_ADDR_V4MAPPED(&ipp->ipp_addr))
4458 v6src = ipp->ipp_addr;
4459 }
4460 }
4461
4462 /* Defer IPsec if it might need to look at ICMP type/code */
4463 switch (ixa->ixa_protocol) {
4464 case IPPROTO_ICMP:
4465 case IPPROTO_ICMPV6:
4466 do_ipsec = B_FALSE;
4467 break;
4468 default:
|
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
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 /*
22 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2013 by Delphix. All rights reserved.
24 * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
25 */
26 /* Copyright (c) 1990 Mentat Inc. */
27
28 #include <sys/types.h>
29 #include <sys/stream.h>
30 #include <sys/stropts.h>
31 #include <sys/strlog.h>
32 #include <sys/strsun.h>
33 #define _SUN_TPI_VERSION 2
34 #include <sys/tihdr.h>
35 #include <sys/timod.h>
36 #include <sys/ddi.h>
37 #include <sys/sunddi.h>
38 #include <sys/strsubr.h>
39 #include <sys/suntpi.h>
40 #include <sys/xti_inet.h>
41 #include <sys/cmn_err.h>
42 #include <sys/kmem.h>
43 #include <sys/cred.h>
44 #include <sys/policy.h>
752 dstport = sin->sin_port;
753 IN6_IPADDR_TO_V4MAPPED(v4dst, &v6dst);
754 ASSERT(connp->conn_ipversion == IPV4_VERSION);
755 break;
756
757 case sizeof (sin6_t):
758 sin6 = (sin6_t *)sa;
759
760 /* No support for mapped addresses on raw sockets */
761 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
762 return (EADDRNOTAVAIL);
763 }
764 v6dst = sin6->sin6_addr;
765 dstport = sin6->sin6_port;
766 ASSERT(connp->conn_ipversion == IPV6_VERSION);
767 flowinfo = sin6->sin6_flowinfo;
768 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
769 scopeid = sin6->sin6_scope_id;
770 srcid = sin6->__sin6_src_id;
771 if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) {
772 /* Due to check above, we know sin6_addr is v6-only. */
773 if (!ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp),
774 B_FALSE, connp->conn_netstack)) {
775 /* Mismatch - v6src would be v4mapped. */
776 return (EADDRNOTAVAIL);
777 }
778 }
779 break;
780 }
781
782 /*
783 * If there is a different thread using conn_ixa then we get a new
784 * copy and cut the old one loose from conn_ixa. Otherwise we use
785 * conn_ixa and prevent any other thread from using/changing it.
786 * Once connect() is done other threads can use conn_ixa since the
787 * refcnt will be back at one.
788 * We defer updating conn_ixa until later to handle any concurrent
789 * conn_ixa_cleanup thread.
790 */
791 ixa = conn_get_ixa(connp, B_FALSE);
792 if (ixa == NULL)
793 return (ENOMEM);
794
795 mutex_enter(&connp->conn_lock);
796 /*
797 * This icmp_t must have bound already before doing a connect.
798 * Reject if a connect is in progress (we drop conn_lock during
3325 * Handle T_UNITDATA_REQ with options. Both IPv4 and IPv6
3326 * Either tudr_mp or msg is set. If tudr_mp we take ancillary data from
3327 * the TPI options, otherwise we take them from msg_control.
3328 * If both sin and sin6 is set it is a connected socket and we use conn_faddr.
3329 * Always consumes mp; never consumes tudr_mp.
3330 */
3331 static int
3332 icmp_output_ancillary(conn_t *connp, sin_t *sin, sin6_t *sin6, mblk_t *mp,
3333 mblk_t *tudr_mp, struct nmsghdr *msg, cred_t *cr, pid_t pid)
3334 {
3335 icmp_t *icmp = connp->conn_icmp;
3336 icmp_stack_t *is = icmp->icmp_is;
3337 int error;
3338 ip_xmit_attr_t *ixa;
3339 ip_pkt_t *ipp;
3340 in6_addr_t v6src;
3341 in6_addr_t v6dst;
3342 in6_addr_t v6nexthop;
3343 in_port_t dstport;
3344 uint32_t flowinfo;
3345 int is_absreq_failure = 0;
3346 conn_opt_arg_t coas, *coa;
3347
3348 ASSERT(tudr_mp != NULL || msg != NULL);
3349
3350 /*
3351 * Get ixa before checking state to handle a disconnect race.
3352 *
3353 * We need an exclusive copy of conn_ixa since the ancillary data
3354 * options might modify it. That copy has no pointers hence we
3355 * need to set them up once we've parsed the ancillary data.
3356 */
3357 ixa = conn_get_ixa_exclusive(connp);
3358 if (ixa == NULL) {
3359 BUMP_MIB(&is->is_rawip_mib, rawipOutErrors);
3360 freemsg(mp);
3361 return (ENOMEM);
3362 }
3363 ASSERT(cr != NULL);
3364 ASSERT(!(ixa->ixa_free_flags & IXA_FREE_CRED));
3427 ASSERT(is_absreq_failure == 0);
3428
3429 mutex_enter(&connp->conn_lock);
3430 /*
3431 * If laddr is unspecified then we look at sin6_src_id.
3432 * We will give precedence to a source address set with IPV6_PKTINFO
3433 * (aka IPPF_ADDR) but that is handled in build_hdrs. However, we don't
3434 * want ip_attr_connect to select a source (since it can fail) when
3435 * IPV6_PKTINFO is specified.
3436 * If this doesn't result in a source address then we get a source
3437 * from ip_attr_connect() below.
3438 */
3439 v6src = connp->conn_saddr_v6;
3440 if (sin != NULL) {
3441 IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &v6dst);
3442 dstport = sin->sin_port;
3443 flowinfo = 0;
3444 ixa->ixa_flags &= ~IXAF_SCOPEID_SET;
3445 ixa->ixa_flags |= IXAF_IS_IPV4;
3446 } else if (sin6 != NULL) {
3447 boolean_t v4mapped;
3448 uint_t srcid;
3449
3450 v6dst = sin6->sin6_addr;
3451 dstport = sin6->sin6_port;
3452 flowinfo = sin6->sin6_flowinfo;
3453 srcid = sin6->__sin6_src_id;
3454 if (IN6_IS_ADDR_LINKSCOPE(&v6dst) && sin6->sin6_scope_id != 0) {
3455 ixa->ixa_scopeid = sin6->sin6_scope_id;
3456 ixa->ixa_flags |= IXAF_SCOPEID_SET;
3457 } else {
3458 ixa->ixa_flags &= ~IXAF_SCOPEID_SET;
3459 }
3460 v4mapped = IN6_IS_ADDR_V4MAPPED(&v6dst);
3461 if (v4mapped)
3462 ixa->ixa_flags |= IXAF_IS_IPV4;
3463 else
3464 ixa->ixa_flags &= ~IXAF_IS_IPV4;
3465 if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) {
3466 if (ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp),
3467 v4mapped, connp->conn_netstack)) {
3468 /* Mismatched v4mapped/v6 specified by srcid. */
3469 mutex_exit(&connp->conn_lock);
3470 error = EADDRNOTAVAIL;
3471 goto failed; /* Does freemsg() and mib. */
3472 }
3473 }
3474 } else {
3475 /* Connected case */
3476 v6dst = connp->conn_faddr_v6;
3477 flowinfo = connp->conn_flowinfo;
3478 }
3479 mutex_exit(&connp->conn_lock);
3480 /* Handle IP_PKTINFO/IPV6_PKTINFO setting source address. */
3481 if (ipp->ipp_fields & IPPF_ADDR) {
3482 if (ixa->ixa_flags & IXAF_IS_IPV4) {
3483 if (IN6_IS_ADDR_V4MAPPED(&ipp->ipp_addr))
3484 v6src = ipp->ipp_addr;
3485 } else {
3486 if (!IN6_IS_ADDR_V4MAPPED(&ipp->ipp_addr))
3487 v6src = ipp->ipp_addr;
3488 }
3489 }
3490 /*
3491 * Allow source not assigned to the system
3492 * only if it is not a local addresses
3493 */
4415 goto ud_error;
4416 }
4417
4418 /* In case previous destination was multicast or multirt */
4419 ip_attr_newdst(ixa);
4420
4421 /*
4422 * If laddr is unspecified then we look at sin6_src_id.
4423 * We will give precedence to a source address set with IPV6_PKTINFO
4424 * (aka IPPF_ADDR) but that is handled in build_hdrs. However, we don't
4425 * want ip_attr_connect to select a source (since it can fail) when
4426 * IPV6_PKTINFO is specified.
4427 * If this doesn't result in a source address then we get a source
4428 * from ip_attr_connect() below.
4429 */
4430 v6src = connp->conn_saddr_v6;
4431 if (sin != NULL) {
4432 IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &v6dst);
4433 dstport = sin->sin_port;
4434 flowinfo = 0;
4435 /* Don't bother with ip_srcid_find_id(), but indicate anyway. */
4436 srcid = 0;
4437 ixa->ixa_flags &= ~IXAF_SCOPEID_SET;
4438 ixa->ixa_flags |= IXAF_IS_IPV4;
4439 } else {
4440 boolean_t v4mapped;
4441
4442 v6dst = sin6->sin6_addr;
4443 dstport = sin6->sin6_port;
4444 flowinfo = sin6->sin6_flowinfo;
4445 srcid = sin6->__sin6_src_id;
4446 if (IN6_IS_ADDR_LINKSCOPE(&v6dst) && sin6->sin6_scope_id != 0) {
4447 ixa->ixa_scopeid = sin6->sin6_scope_id;
4448 ixa->ixa_flags |= IXAF_SCOPEID_SET;
4449 } else {
4450 ixa->ixa_flags &= ~IXAF_SCOPEID_SET;
4451 }
4452 v4mapped = IN6_IS_ADDR_V4MAPPED(&v6dst);
4453 if (v4mapped)
4454 ixa->ixa_flags |= IXAF_IS_IPV4;
4455 else
4456 ixa->ixa_flags &= ~IXAF_IS_IPV4;
4457 if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) {
4458 if (ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp),
4459 v4mapped, connp->conn_netstack)) {
4460 /* Mismatched v4mapped/v6 specified by srcid. */
4461 mutex_exit(&connp->conn_lock);
4462 error = EADDRNOTAVAIL;
4463 goto ud_error;
4464 }
4465 }
4466 }
4467 /* Handle IP_PKTINFO/IPV6_PKTINFO setting source address. */
4468 if (connp->conn_xmit_ipp.ipp_fields & IPPF_ADDR) {
4469 ip_pkt_t *ipp = &connp->conn_xmit_ipp;
4470
4471 if (ixa->ixa_flags & IXAF_IS_IPV4) {
4472 if (IN6_IS_ADDR_V4MAPPED(&ipp->ipp_addr))
4473 v6src = ipp->ipp_addr;
4474 } else {
4475 if (!IN6_IS_ADDR_V4MAPPED(&ipp->ipp_addr))
4476 v6src = ipp->ipp_addr;
4477 }
4478 }
4479
4480 /* Defer IPsec if it might need to look at ICMP type/code */
4481 switch (ixa->ixa_protocol) {
4482 case IPPROTO_ICMP:
4483 case IPPROTO_ICMPV6:
4484 do_ipsec = B_FALSE;
4485 break;
4486 default:
|