111042SErik.Nordmark@Sun.COM /*
211042SErik.Nordmark@Sun.COM * CDDL HEADER START
311042SErik.Nordmark@Sun.COM *
411042SErik.Nordmark@Sun.COM * The contents of this file are subject to the terms of the
511042SErik.Nordmark@Sun.COM * Common Development and Distribution License (the "License").
611042SErik.Nordmark@Sun.COM * You may not use this file except in compliance with the License.
711042SErik.Nordmark@Sun.COM *
811042SErik.Nordmark@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911042SErik.Nordmark@Sun.COM * or http://www.opensolaris.org/os/licensing.
1011042SErik.Nordmark@Sun.COM * See the License for the specific language governing permissions
1111042SErik.Nordmark@Sun.COM * and limitations under the License.
1211042SErik.Nordmark@Sun.COM *
1311042SErik.Nordmark@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1411042SErik.Nordmark@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511042SErik.Nordmark@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1611042SErik.Nordmark@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1711042SErik.Nordmark@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1811042SErik.Nordmark@Sun.COM *
1911042SErik.Nordmark@Sun.COM * CDDL HEADER END
2011042SErik.Nordmark@Sun.COM */
2111042SErik.Nordmark@Sun.COM
2211042SErik.Nordmark@Sun.COM /*
23*12595SMarcel.Telka@Sun.COM * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2411042SErik.Nordmark@Sun.COM */
2511042SErik.Nordmark@Sun.COM /* Copyright (c) 1990 Mentat Inc. */
2611042SErik.Nordmark@Sun.COM
2711042SErik.Nordmark@Sun.COM #include <sys/types.h>
2811042SErik.Nordmark@Sun.COM #include <sys/stream.h>
2911042SErik.Nordmark@Sun.COM #include <sys/strsun.h>
3011042SErik.Nordmark@Sun.COM #define _SUN_TPI_VERSION 2
3111042SErik.Nordmark@Sun.COM #include <sys/tihdr.h>
3211042SErik.Nordmark@Sun.COM #include <sys/xti_inet.h>
3311042SErik.Nordmark@Sun.COM #include <sys/ucred.h>
3411042SErik.Nordmark@Sun.COM #include <sys/zone.h>
3511042SErik.Nordmark@Sun.COM #include <sys/ddi.h>
3611042SErik.Nordmark@Sun.COM #include <sys/sunddi.h>
3711042SErik.Nordmark@Sun.COM #include <sys/cmn_err.h>
3811042SErik.Nordmark@Sun.COM #include <sys/debug.h>
3911042SErik.Nordmark@Sun.COM #include <sys/atomic.h>
4011042SErik.Nordmark@Sun.COM #include <sys/policy.h>
4111042SErik.Nordmark@Sun.COM
4211042SErik.Nordmark@Sun.COM #include <sys/systm.h>
4311042SErik.Nordmark@Sun.COM #include <sys/param.h>
4411042SErik.Nordmark@Sun.COM #include <sys/kmem.h>
4511042SErik.Nordmark@Sun.COM #include <sys/sdt.h>
4611042SErik.Nordmark@Sun.COM #include <sys/socket.h>
4711042SErik.Nordmark@Sun.COM #include <sys/ethernet.h>
4811042SErik.Nordmark@Sun.COM #include <sys/mac.h>
4911042SErik.Nordmark@Sun.COM #include <net/if.h>
5011042SErik.Nordmark@Sun.COM #include <net/if_types.h>
5111042SErik.Nordmark@Sun.COM #include <net/if_arp.h>
5211042SErik.Nordmark@Sun.COM #include <net/route.h>
5311042SErik.Nordmark@Sun.COM #include <sys/sockio.h>
5411042SErik.Nordmark@Sun.COM #include <netinet/in.h>
5511042SErik.Nordmark@Sun.COM #include <net/if_dl.h>
5611042SErik.Nordmark@Sun.COM
5711042SErik.Nordmark@Sun.COM #include <inet/common.h>
5811042SErik.Nordmark@Sun.COM #include <inet/mi.h>
5911042SErik.Nordmark@Sun.COM #include <inet/mib2.h>
6011042SErik.Nordmark@Sun.COM #include <inet/nd.h>
6111042SErik.Nordmark@Sun.COM #include <inet/arp.h>
6211042SErik.Nordmark@Sun.COM #include <inet/snmpcom.h>
6311042SErik.Nordmark@Sun.COM #include <inet/kstatcom.h>
6411042SErik.Nordmark@Sun.COM
6511042SErik.Nordmark@Sun.COM #include <netinet/igmp_var.h>
6611042SErik.Nordmark@Sun.COM #include <netinet/ip6.h>
6711042SErik.Nordmark@Sun.COM #include <netinet/icmp6.h>
6811042SErik.Nordmark@Sun.COM #include <netinet/sctp.h>
6911042SErik.Nordmark@Sun.COM
7011042SErik.Nordmark@Sun.COM #include <inet/ip.h>
7111042SErik.Nordmark@Sun.COM #include <inet/ip_impl.h>
7211042SErik.Nordmark@Sun.COM #include <inet/ip6.h>
7311042SErik.Nordmark@Sun.COM #include <inet/ip6_asp.h>
7411042SErik.Nordmark@Sun.COM #include <inet/tcp.h>
7511042SErik.Nordmark@Sun.COM #include <inet/ip_multi.h>
7611042SErik.Nordmark@Sun.COM #include <inet/ip_if.h>
7711042SErik.Nordmark@Sun.COM #include <inet/ip_ire.h>
7811042SErik.Nordmark@Sun.COM #include <inet/ip_ftable.h>
7911042SErik.Nordmark@Sun.COM #include <inet/ip_rts.h>
8011042SErik.Nordmark@Sun.COM #include <inet/optcom.h>
8111042SErik.Nordmark@Sun.COM #include <inet/ip_ndp.h>
8211042SErik.Nordmark@Sun.COM #include <inet/ip_listutils.h>
8311042SErik.Nordmark@Sun.COM #include <netinet/igmp.h>
8411042SErik.Nordmark@Sun.COM #include <netinet/ip_mroute.h>
8511042SErik.Nordmark@Sun.COM #include <netinet/udp.h>
8611042SErik.Nordmark@Sun.COM #include <inet/ipp_common.h>
8711042SErik.Nordmark@Sun.COM
8811042SErik.Nordmark@Sun.COM #include <net/pfkeyv2.h>
8911042SErik.Nordmark@Sun.COM #include <inet/sadb.h>
9011042SErik.Nordmark@Sun.COM #include <inet/ipsec_impl.h>
9111042SErik.Nordmark@Sun.COM #include <inet/ipdrop.h>
9211042SErik.Nordmark@Sun.COM #include <inet/ip_netinfo.h>
9311042SErik.Nordmark@Sun.COM
9411042SErik.Nordmark@Sun.COM #include <inet/ipclassifier.h>
9511042SErik.Nordmark@Sun.COM #include <inet/sctp_ip.h>
9611042SErik.Nordmark@Sun.COM #include <inet/sctp/sctp_impl.h>
9711042SErik.Nordmark@Sun.COM #include <inet/udp_impl.h>
9811042SErik.Nordmark@Sun.COM #include <sys/sunddi.h>
9911042SErik.Nordmark@Sun.COM
10011042SErik.Nordmark@Sun.COM #include <sys/tsol/label.h>
10111042SErik.Nordmark@Sun.COM #include <sys/tsol/tnet.h>
10211042SErik.Nordmark@Sun.COM
10311042SErik.Nordmark@Sun.COM /*
10411042SErik.Nordmark@Sun.COM * Return how much size is needed for the different ancillary data items
10511042SErik.Nordmark@Sun.COM */
10611042SErik.Nordmark@Sun.COM uint_t
conn_recvancillary_size(conn_t * connp,crb_t recv_ancillary,ip_recv_attr_t * ira,mblk_t * mp,ip_pkt_t * ipp)10711042SErik.Nordmark@Sun.COM conn_recvancillary_size(conn_t *connp, crb_t recv_ancillary,
10811042SErik.Nordmark@Sun.COM ip_recv_attr_t *ira, mblk_t *mp, ip_pkt_t *ipp)
10911042SErik.Nordmark@Sun.COM {
11011042SErik.Nordmark@Sun.COM uint_t ancil_size;
11111042SErik.Nordmark@Sun.COM ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
11211042SErik.Nordmark@Sun.COM
11311042SErik.Nordmark@Sun.COM /*
11411042SErik.Nordmark@Sun.COM * If IP_RECVDSTADDR is set we include the destination IP
11511042SErik.Nordmark@Sun.COM * address as an option. With IP_RECVOPTS we include all
11611042SErik.Nordmark@Sun.COM * the IP options.
11711042SErik.Nordmark@Sun.COM */
11811042SErik.Nordmark@Sun.COM ancil_size = 0;
11911042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_recvdstaddr &&
12011042SErik.Nordmark@Sun.COM (ira->ira_flags & IRAF_IS_IPV4)) {
12111042SErik.Nordmark@Sun.COM ancil_size += sizeof (struct T_opthdr) +
12211042SErik.Nordmark@Sun.COM sizeof (struct in_addr);
12311042SErik.Nordmark@Sun.COM IP_STAT(ipst, conn_in_recvdstaddr);
12411042SErik.Nordmark@Sun.COM }
12511042SErik.Nordmark@Sun.COM
12611042SErik.Nordmark@Sun.COM /*
12711042SErik.Nordmark@Sun.COM * ip_recvpktinfo is used for both AF_INET and AF_INET6 but
12811042SErik.Nordmark@Sun.COM * are different
12911042SErik.Nordmark@Sun.COM */
13011042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_ip_recvpktinfo &&
13111042SErik.Nordmark@Sun.COM connp->conn_family == AF_INET) {
13211042SErik.Nordmark@Sun.COM ancil_size += sizeof (struct T_opthdr) +
13311042SErik.Nordmark@Sun.COM sizeof (struct in_pktinfo);
13411042SErik.Nordmark@Sun.COM IP_STAT(ipst, conn_in_recvpktinfo);
13511042SErik.Nordmark@Sun.COM }
13611042SErik.Nordmark@Sun.COM
13711042SErik.Nordmark@Sun.COM if ((recv_ancillary.crb_recvopts) &&
13811042SErik.Nordmark@Sun.COM (ipp->ipp_fields & IPPF_IPV4_OPTIONS)) {
13911042SErik.Nordmark@Sun.COM ancil_size += sizeof (struct T_opthdr) +
14011042SErik.Nordmark@Sun.COM ipp->ipp_ipv4_options_len;
14111042SErik.Nordmark@Sun.COM IP_STAT(ipst, conn_in_recvopts);
14211042SErik.Nordmark@Sun.COM }
14311042SErik.Nordmark@Sun.COM
14411042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_recvslla) {
14511042SErik.Nordmark@Sun.COM ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
14611042SErik.Nordmark@Sun.COM ill_t *ill;
14711042SErik.Nordmark@Sun.COM
14811042SErik.Nordmark@Sun.COM /* Make sure ira_l2src is setup if not already */
14911042SErik.Nordmark@Sun.COM if (!(ira->ira_flags & IRAF_L2SRC_SET)) {
15011042SErik.Nordmark@Sun.COM ill = ill_lookup_on_ifindex(ira->ira_rifindex, B_FALSE,
15111042SErik.Nordmark@Sun.COM ipst);
15211042SErik.Nordmark@Sun.COM if (ill != NULL) {
15311042SErik.Nordmark@Sun.COM ip_setl2src(mp, ira, ill);
15411042SErik.Nordmark@Sun.COM ill_refrele(ill);
15511042SErik.Nordmark@Sun.COM }
15611042SErik.Nordmark@Sun.COM }
15711042SErik.Nordmark@Sun.COM ancil_size += sizeof (struct T_opthdr) +
15811042SErik.Nordmark@Sun.COM sizeof (struct sockaddr_dl);
15911042SErik.Nordmark@Sun.COM IP_STAT(ipst, conn_in_recvslla);
16011042SErik.Nordmark@Sun.COM }
16111042SErik.Nordmark@Sun.COM
16211042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_recvif) {
16311042SErik.Nordmark@Sun.COM ancil_size += sizeof (struct T_opthdr) + sizeof (uint_t);
16411042SErik.Nordmark@Sun.COM IP_STAT(ipst, conn_in_recvif);
16511042SErik.Nordmark@Sun.COM }
16611042SErik.Nordmark@Sun.COM
16711042SErik.Nordmark@Sun.COM /*
16811042SErik.Nordmark@Sun.COM * ip_recvpktinfo is used for both AF_INET and AF_INET6 but
16911042SErik.Nordmark@Sun.COM * are different
17011042SErik.Nordmark@Sun.COM */
17111042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_ip_recvpktinfo &&
17211042SErik.Nordmark@Sun.COM connp->conn_family == AF_INET6) {
17311042SErik.Nordmark@Sun.COM ancil_size += sizeof (struct T_opthdr) +
17411042SErik.Nordmark@Sun.COM sizeof (struct in6_pktinfo);
17511042SErik.Nordmark@Sun.COM IP_STAT(ipst, conn_in_recvpktinfo);
17611042SErik.Nordmark@Sun.COM }
17711042SErik.Nordmark@Sun.COM
17811042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_ipv6_recvhoplimit) {
17911042SErik.Nordmark@Sun.COM ancil_size += sizeof (struct T_opthdr) + sizeof (int);
18011042SErik.Nordmark@Sun.COM IP_STAT(ipst, conn_in_recvhoplimit);
18111042SErik.Nordmark@Sun.COM }
18211042SErik.Nordmark@Sun.COM
18311042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_ipv6_recvtclass) {
18411042SErik.Nordmark@Sun.COM ancil_size += sizeof (struct T_opthdr) + sizeof (int);
18511042SErik.Nordmark@Sun.COM IP_STAT(ipst, conn_in_recvtclass);
18611042SErik.Nordmark@Sun.COM }
18711042SErik.Nordmark@Sun.COM
18811042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_ipv6_recvhopopts &&
18911042SErik.Nordmark@Sun.COM (ipp->ipp_fields & IPPF_HOPOPTS)) {
19011042SErik.Nordmark@Sun.COM ancil_size += sizeof (struct T_opthdr) + ipp->ipp_hopoptslen;
19111042SErik.Nordmark@Sun.COM IP_STAT(ipst, conn_in_recvhopopts);
19211042SErik.Nordmark@Sun.COM }
19311042SErik.Nordmark@Sun.COM /*
19411042SErik.Nordmark@Sun.COM * To honor RFC3542 when an application asks for both IPV6_RECVDSTOPTS
19511042SErik.Nordmark@Sun.COM * and IPV6_RECVRTHDR, we pass up the item rthdrdstopts (the destination
19611042SErik.Nordmark@Sun.COM * options that appear before a routing header.
19711042SErik.Nordmark@Sun.COM * We also pass them up if IPV6_RECVRTHDRDSTOPTS is set.
19811042SErik.Nordmark@Sun.COM */
19911042SErik.Nordmark@Sun.COM if (ipp->ipp_fields & IPPF_RTHDRDSTOPTS) {
20011042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_ipv6_recvrthdrdstopts ||
20111042SErik.Nordmark@Sun.COM (recv_ancillary.crb_ipv6_recvdstopts &&
20211042SErik.Nordmark@Sun.COM recv_ancillary.crb_ipv6_recvrthdr)) {
20311042SErik.Nordmark@Sun.COM ancil_size += sizeof (struct T_opthdr) +
20411042SErik.Nordmark@Sun.COM ipp->ipp_rthdrdstoptslen;
20511042SErik.Nordmark@Sun.COM IP_STAT(ipst, conn_in_recvrthdrdstopts);
20611042SErik.Nordmark@Sun.COM }
20711042SErik.Nordmark@Sun.COM }
20811042SErik.Nordmark@Sun.COM if ((recv_ancillary.crb_ipv6_recvrthdr) &&
20911042SErik.Nordmark@Sun.COM (ipp->ipp_fields & IPPF_RTHDR)) {
21011042SErik.Nordmark@Sun.COM ancil_size += sizeof (struct T_opthdr) + ipp->ipp_rthdrlen;
21111042SErik.Nordmark@Sun.COM IP_STAT(ipst, conn_in_recvrthdr);
21211042SErik.Nordmark@Sun.COM }
21311042SErik.Nordmark@Sun.COM if ((recv_ancillary.crb_ipv6_recvdstopts ||
21411042SErik.Nordmark@Sun.COM recv_ancillary.crb_old_ipv6_recvdstopts) &&
21511042SErik.Nordmark@Sun.COM (ipp->ipp_fields & IPPF_DSTOPTS)) {
21611042SErik.Nordmark@Sun.COM ancil_size += sizeof (struct T_opthdr) + ipp->ipp_dstoptslen;
21711042SErik.Nordmark@Sun.COM IP_STAT(ipst, conn_in_recvdstopts);
21811042SErik.Nordmark@Sun.COM }
21911042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_recvucred && ira->ira_cred != NULL) {
22011134SCasper.Dik@Sun.COM ancil_size += sizeof (struct T_opthdr) +
22111134SCasper.Dik@Sun.COM ucredminsize(ira->ira_cred);
22211042SErik.Nordmark@Sun.COM IP_STAT(ipst, conn_in_recvucred);
22311042SErik.Nordmark@Sun.COM }
22411042SErik.Nordmark@Sun.COM
22511042SErik.Nordmark@Sun.COM /*
22611042SErik.Nordmark@Sun.COM * If SO_TIMESTAMP is set allocate the appropriate sized
22711042SErik.Nordmark@Sun.COM * buffer. Since gethrestime() expects a pointer aligned
22811042SErik.Nordmark@Sun.COM * argument, we allocate space necessary for extra
22911042SErik.Nordmark@Sun.COM * alignment (even though it might not be used).
23011042SErik.Nordmark@Sun.COM */
23111042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_timestamp) {
23211042SErik.Nordmark@Sun.COM ancil_size += sizeof (struct T_opthdr) +
23311042SErik.Nordmark@Sun.COM sizeof (timestruc_t) + _POINTER_ALIGNMENT;
23411042SErik.Nordmark@Sun.COM IP_STAT(ipst, conn_in_timestamp);
23511042SErik.Nordmark@Sun.COM }
23611042SErik.Nordmark@Sun.COM
23711042SErik.Nordmark@Sun.COM /*
23811042SErik.Nordmark@Sun.COM * If IP_RECVTTL is set allocate the appropriate sized buffer
23911042SErik.Nordmark@Sun.COM */
24011042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_recvttl &&
24111042SErik.Nordmark@Sun.COM (ira->ira_flags & IRAF_IS_IPV4)) {
24211042SErik.Nordmark@Sun.COM ancil_size += sizeof (struct T_opthdr) + sizeof (uint8_t);
24311042SErik.Nordmark@Sun.COM IP_STAT(ipst, conn_in_recvttl);
24411042SErik.Nordmark@Sun.COM }
24511042SErik.Nordmark@Sun.COM
24611042SErik.Nordmark@Sun.COM return (ancil_size);
24711042SErik.Nordmark@Sun.COM }
24811042SErik.Nordmark@Sun.COM
24911042SErik.Nordmark@Sun.COM /*
25011042SErik.Nordmark@Sun.COM * Lay down the ancillary data items at "ancil_buf".
25111042SErik.Nordmark@Sun.COM * Assumes caller has used conn_recvancillary_size to allocate a sufficiently
25211042SErik.Nordmark@Sun.COM * large buffer - ancil_size.
25311042SErik.Nordmark@Sun.COM */
25411042SErik.Nordmark@Sun.COM void
conn_recvancillary_add(conn_t * connp,crb_t recv_ancillary,ip_recv_attr_t * ira,ip_pkt_t * ipp,uchar_t * ancil_buf,uint_t ancil_size)25511042SErik.Nordmark@Sun.COM conn_recvancillary_add(conn_t *connp, crb_t recv_ancillary,
25611042SErik.Nordmark@Sun.COM ip_recv_attr_t *ira, ip_pkt_t *ipp, uchar_t *ancil_buf, uint_t ancil_size)
25711042SErik.Nordmark@Sun.COM {
25811042SErik.Nordmark@Sun.COM /*
25911042SErik.Nordmark@Sun.COM * Copy in destination address before options to avoid
26011042SErik.Nordmark@Sun.COM * any padding issues.
26111042SErik.Nordmark@Sun.COM */
26211042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_recvdstaddr &&
26311042SErik.Nordmark@Sun.COM (ira->ira_flags & IRAF_IS_IPV4)) {
26411042SErik.Nordmark@Sun.COM struct T_opthdr *toh;
26511042SErik.Nordmark@Sun.COM ipaddr_t *dstptr;
26611042SErik.Nordmark@Sun.COM
26711042SErik.Nordmark@Sun.COM toh = (struct T_opthdr *)ancil_buf;
26811042SErik.Nordmark@Sun.COM toh->level = IPPROTO_IP;
26911042SErik.Nordmark@Sun.COM toh->name = IP_RECVDSTADDR;
27011042SErik.Nordmark@Sun.COM toh->len = sizeof (struct T_opthdr) + sizeof (ipaddr_t);
27111042SErik.Nordmark@Sun.COM toh->status = 0;
27211042SErik.Nordmark@Sun.COM ancil_buf += sizeof (struct T_opthdr);
27311042SErik.Nordmark@Sun.COM dstptr = (ipaddr_t *)ancil_buf;
27411042SErik.Nordmark@Sun.COM *dstptr = ipp->ipp_addr_v4;
27511042SErik.Nordmark@Sun.COM ancil_buf += sizeof (ipaddr_t);
27611042SErik.Nordmark@Sun.COM ancil_size -= toh->len;
27711042SErik.Nordmark@Sun.COM }
27811042SErik.Nordmark@Sun.COM
27911042SErik.Nordmark@Sun.COM /*
28011042SErik.Nordmark@Sun.COM * ip_recvpktinfo is used for both AF_INET and AF_INET6 but
28111042SErik.Nordmark@Sun.COM * are different
28211042SErik.Nordmark@Sun.COM */
28311042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_ip_recvpktinfo &&
28411042SErik.Nordmark@Sun.COM connp->conn_family == AF_INET) {
28511042SErik.Nordmark@Sun.COM ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
28611042SErik.Nordmark@Sun.COM struct T_opthdr *toh;
28711042SErik.Nordmark@Sun.COM struct in_pktinfo *pktinfop;
28811042SErik.Nordmark@Sun.COM ill_t *ill;
28911042SErik.Nordmark@Sun.COM ipif_t *ipif;
29011042SErik.Nordmark@Sun.COM
29111042SErik.Nordmark@Sun.COM toh = (struct T_opthdr *)ancil_buf;
29211042SErik.Nordmark@Sun.COM toh->level = IPPROTO_IP;
29311042SErik.Nordmark@Sun.COM toh->name = IP_PKTINFO;
29411042SErik.Nordmark@Sun.COM toh->len = sizeof (struct T_opthdr) + sizeof (*pktinfop);
29511042SErik.Nordmark@Sun.COM toh->status = 0;
29611042SErik.Nordmark@Sun.COM ancil_buf += sizeof (struct T_opthdr);
29711042SErik.Nordmark@Sun.COM pktinfop = (struct in_pktinfo *)ancil_buf;
29811042SErik.Nordmark@Sun.COM
29911042SErik.Nordmark@Sun.COM pktinfop->ipi_ifindex = ira->ira_ruifindex;
30011042SErik.Nordmark@Sun.COM pktinfop->ipi_spec_dst.s_addr = INADDR_ANY;
30111042SErik.Nordmark@Sun.COM
30211042SErik.Nordmark@Sun.COM /* Find a good address to report */
30311042SErik.Nordmark@Sun.COM ill = ill_lookup_on_ifindex(ira->ira_ruifindex, B_FALSE, ipst);
30411042SErik.Nordmark@Sun.COM if (ill != NULL) {
30511042SErik.Nordmark@Sun.COM ipif = ipif_good_addr(ill, IPCL_ZONEID(connp));
30611042SErik.Nordmark@Sun.COM if (ipif != NULL) {
30711042SErik.Nordmark@Sun.COM pktinfop->ipi_spec_dst.s_addr =
30811042SErik.Nordmark@Sun.COM ipif->ipif_lcl_addr;
30911042SErik.Nordmark@Sun.COM ipif_refrele(ipif);
31011042SErik.Nordmark@Sun.COM }
31111042SErik.Nordmark@Sun.COM ill_refrele(ill);
31211042SErik.Nordmark@Sun.COM }
31311042SErik.Nordmark@Sun.COM pktinfop->ipi_addr.s_addr = ipp->ipp_addr_v4;
31411042SErik.Nordmark@Sun.COM ancil_buf += sizeof (struct in_pktinfo);
31511042SErik.Nordmark@Sun.COM ancil_size -= toh->len;
31611042SErik.Nordmark@Sun.COM }
31711042SErik.Nordmark@Sun.COM
31811042SErik.Nordmark@Sun.COM if ((recv_ancillary.crb_recvopts) &&
31911042SErik.Nordmark@Sun.COM (ipp->ipp_fields & IPPF_IPV4_OPTIONS)) {
32011042SErik.Nordmark@Sun.COM struct T_opthdr *toh;
32111042SErik.Nordmark@Sun.COM
32211042SErik.Nordmark@Sun.COM toh = (struct T_opthdr *)ancil_buf;
32311042SErik.Nordmark@Sun.COM toh->level = IPPROTO_IP;
32411042SErik.Nordmark@Sun.COM toh->name = IP_RECVOPTS;
32511042SErik.Nordmark@Sun.COM toh->len = sizeof (struct T_opthdr) + ipp->ipp_ipv4_options_len;
32611042SErik.Nordmark@Sun.COM toh->status = 0;
32711042SErik.Nordmark@Sun.COM ancil_buf += sizeof (struct T_opthdr);
32811042SErik.Nordmark@Sun.COM bcopy(ipp->ipp_ipv4_options, ancil_buf,
32911042SErik.Nordmark@Sun.COM ipp->ipp_ipv4_options_len);
33011042SErik.Nordmark@Sun.COM ancil_buf += ipp->ipp_ipv4_options_len;
33111042SErik.Nordmark@Sun.COM ancil_size -= toh->len;
33211042SErik.Nordmark@Sun.COM }
33311042SErik.Nordmark@Sun.COM
33411042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_recvslla) {
33511042SErik.Nordmark@Sun.COM ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
33611042SErik.Nordmark@Sun.COM struct T_opthdr *toh;
33711042SErik.Nordmark@Sun.COM struct sockaddr_dl *dstptr;
33811042SErik.Nordmark@Sun.COM ill_t *ill;
33911042SErik.Nordmark@Sun.COM int alen = 0;
34011042SErik.Nordmark@Sun.COM
34111042SErik.Nordmark@Sun.COM ill = ill_lookup_on_ifindex(ira->ira_rifindex, B_FALSE, ipst);
34211042SErik.Nordmark@Sun.COM if (ill != NULL)
34311042SErik.Nordmark@Sun.COM alen = ill->ill_phys_addr_length;
34411042SErik.Nordmark@Sun.COM
34511042SErik.Nordmark@Sun.COM /*
34611042SErik.Nordmark@Sun.COM * For loopback multicast and broadcast the packet arrives
34711042SErik.Nordmark@Sun.COM * with ira_ruifdex being the physical interface, but
34811042SErik.Nordmark@Sun.COM * ira_l2src is all zero since ip_postfrag_loopback doesn't
34911042SErik.Nordmark@Sun.COM * know our l2src. We don't report the address in that case.
35011042SErik.Nordmark@Sun.COM */
35111042SErik.Nordmark@Sun.COM if (ira->ira_flags & IRAF_LOOPBACK)
35211042SErik.Nordmark@Sun.COM alen = 0;
35311042SErik.Nordmark@Sun.COM
35411042SErik.Nordmark@Sun.COM toh = (struct T_opthdr *)ancil_buf;
35511042SErik.Nordmark@Sun.COM toh->level = IPPROTO_IP;
35611042SErik.Nordmark@Sun.COM toh->name = IP_RECVSLLA;
35711042SErik.Nordmark@Sun.COM toh->len = sizeof (struct T_opthdr) +
35811042SErik.Nordmark@Sun.COM sizeof (struct sockaddr_dl);
35911042SErik.Nordmark@Sun.COM toh->status = 0;
36011042SErik.Nordmark@Sun.COM ancil_buf += sizeof (struct T_opthdr);
36111042SErik.Nordmark@Sun.COM dstptr = (struct sockaddr_dl *)ancil_buf;
36211042SErik.Nordmark@Sun.COM dstptr->sdl_family = AF_LINK;
36311042SErik.Nordmark@Sun.COM dstptr->sdl_index = ira->ira_ruifindex;
36411042SErik.Nordmark@Sun.COM if (ill != NULL)
36511042SErik.Nordmark@Sun.COM dstptr->sdl_type = ill->ill_type;
36611042SErik.Nordmark@Sun.COM else
36711042SErik.Nordmark@Sun.COM dstptr->sdl_type = 0;
36811042SErik.Nordmark@Sun.COM dstptr->sdl_nlen = 0;
36911042SErik.Nordmark@Sun.COM dstptr->sdl_alen = alen;
37011042SErik.Nordmark@Sun.COM dstptr->sdl_slen = 0;
37111042SErik.Nordmark@Sun.COM bcopy(ira->ira_l2src, dstptr->sdl_data, alen);
37211042SErik.Nordmark@Sun.COM ancil_buf += sizeof (struct sockaddr_dl);
37311042SErik.Nordmark@Sun.COM ancil_size -= toh->len;
37411042SErik.Nordmark@Sun.COM if (ill != NULL)
37511042SErik.Nordmark@Sun.COM ill_refrele(ill);
37611042SErik.Nordmark@Sun.COM }
37711042SErik.Nordmark@Sun.COM
37811042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_recvif) {
37911042SErik.Nordmark@Sun.COM struct T_opthdr *toh;
38011042SErik.Nordmark@Sun.COM uint_t *dstptr;
38111042SErik.Nordmark@Sun.COM
38211042SErik.Nordmark@Sun.COM toh = (struct T_opthdr *)ancil_buf;
38311042SErik.Nordmark@Sun.COM toh->level = IPPROTO_IP;
38411042SErik.Nordmark@Sun.COM toh->name = IP_RECVIF;
38511042SErik.Nordmark@Sun.COM toh->len = sizeof (struct T_opthdr) + sizeof (uint_t);
38611042SErik.Nordmark@Sun.COM toh->status = 0;
38711042SErik.Nordmark@Sun.COM ancil_buf += sizeof (struct T_opthdr);
38811042SErik.Nordmark@Sun.COM dstptr = (uint_t *)ancil_buf;
38911042SErik.Nordmark@Sun.COM *dstptr = ira->ira_ruifindex;
39011042SErik.Nordmark@Sun.COM ancil_buf += sizeof (uint_t);
39111042SErik.Nordmark@Sun.COM ancil_size -= toh->len;
39211042SErik.Nordmark@Sun.COM }
39311042SErik.Nordmark@Sun.COM
39411042SErik.Nordmark@Sun.COM /*
39511042SErik.Nordmark@Sun.COM * ip_recvpktinfo is used for both AF_INET and AF_INET6 but
39611042SErik.Nordmark@Sun.COM * are different
39711042SErik.Nordmark@Sun.COM */
39811042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_ip_recvpktinfo &&
39911042SErik.Nordmark@Sun.COM connp->conn_family == AF_INET6) {
40011042SErik.Nordmark@Sun.COM struct T_opthdr *toh;
40111042SErik.Nordmark@Sun.COM struct in6_pktinfo *pkti;
40211042SErik.Nordmark@Sun.COM
40311042SErik.Nordmark@Sun.COM toh = (struct T_opthdr *)ancil_buf;
40411042SErik.Nordmark@Sun.COM toh->level = IPPROTO_IPV6;
40511042SErik.Nordmark@Sun.COM toh->name = IPV6_PKTINFO;
40611042SErik.Nordmark@Sun.COM toh->len = sizeof (struct T_opthdr) + sizeof (*pkti);
40711042SErik.Nordmark@Sun.COM toh->status = 0;
40811042SErik.Nordmark@Sun.COM ancil_buf += sizeof (struct T_opthdr);
40911042SErik.Nordmark@Sun.COM pkti = (struct in6_pktinfo *)ancil_buf;
41011042SErik.Nordmark@Sun.COM if (ira->ira_flags & IRAF_IS_IPV4) {
41111042SErik.Nordmark@Sun.COM IN6_IPADDR_TO_V4MAPPED(ipp->ipp_addr_v4,
41211042SErik.Nordmark@Sun.COM &pkti->ipi6_addr);
41311042SErik.Nordmark@Sun.COM } else {
41411042SErik.Nordmark@Sun.COM pkti->ipi6_addr = ipp->ipp_addr;
41511042SErik.Nordmark@Sun.COM }
41611042SErik.Nordmark@Sun.COM pkti->ipi6_ifindex = ira->ira_ruifindex;
41711042SErik.Nordmark@Sun.COM
41811042SErik.Nordmark@Sun.COM ancil_buf += sizeof (*pkti);
41911042SErik.Nordmark@Sun.COM ancil_size -= toh->len;
42011042SErik.Nordmark@Sun.COM }
42111042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_ipv6_recvhoplimit) {
42211042SErik.Nordmark@Sun.COM struct T_opthdr *toh;
42311042SErik.Nordmark@Sun.COM
42411042SErik.Nordmark@Sun.COM toh = (struct T_opthdr *)ancil_buf;
42511042SErik.Nordmark@Sun.COM toh->level = IPPROTO_IPV6;
42611042SErik.Nordmark@Sun.COM toh->name = IPV6_HOPLIMIT;
42711042SErik.Nordmark@Sun.COM toh->len = sizeof (struct T_opthdr) + sizeof (uint_t);
42811042SErik.Nordmark@Sun.COM toh->status = 0;
42911042SErik.Nordmark@Sun.COM ancil_buf += sizeof (struct T_opthdr);
43011042SErik.Nordmark@Sun.COM *(uint_t *)ancil_buf = ipp->ipp_hoplimit;
43111042SErik.Nordmark@Sun.COM ancil_buf += sizeof (uint_t);
43211042SErik.Nordmark@Sun.COM ancil_size -= toh->len;
43311042SErik.Nordmark@Sun.COM }
43411042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_ipv6_recvtclass) {
43511042SErik.Nordmark@Sun.COM struct T_opthdr *toh;
43611042SErik.Nordmark@Sun.COM
43711042SErik.Nordmark@Sun.COM toh = (struct T_opthdr *)ancil_buf;
43811042SErik.Nordmark@Sun.COM toh->level = IPPROTO_IPV6;
43911042SErik.Nordmark@Sun.COM toh->name = IPV6_TCLASS;
44011042SErik.Nordmark@Sun.COM toh->len = sizeof (struct T_opthdr) + sizeof (uint_t);
44111042SErik.Nordmark@Sun.COM toh->status = 0;
44211042SErik.Nordmark@Sun.COM ancil_buf += sizeof (struct T_opthdr);
44311042SErik.Nordmark@Sun.COM
44411042SErik.Nordmark@Sun.COM if (ira->ira_flags & IRAF_IS_IPV4)
44511042SErik.Nordmark@Sun.COM *(uint_t *)ancil_buf = ipp->ipp_type_of_service;
44611042SErik.Nordmark@Sun.COM else
44711042SErik.Nordmark@Sun.COM *(uint_t *)ancil_buf = ipp->ipp_tclass;
44811042SErik.Nordmark@Sun.COM ancil_buf += sizeof (uint_t);
44911042SErik.Nordmark@Sun.COM ancil_size -= toh->len;
45011042SErik.Nordmark@Sun.COM }
45111042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_ipv6_recvhopopts &&
45211042SErik.Nordmark@Sun.COM (ipp->ipp_fields & IPPF_HOPOPTS)) {
45311042SErik.Nordmark@Sun.COM struct T_opthdr *toh;
45411042SErik.Nordmark@Sun.COM
45511042SErik.Nordmark@Sun.COM toh = (struct T_opthdr *)ancil_buf;
45611042SErik.Nordmark@Sun.COM toh->level = IPPROTO_IPV6;
45711042SErik.Nordmark@Sun.COM toh->name = IPV6_HOPOPTS;
45811042SErik.Nordmark@Sun.COM toh->len = sizeof (struct T_opthdr) + ipp->ipp_hopoptslen;
45911042SErik.Nordmark@Sun.COM toh->status = 0;
46011042SErik.Nordmark@Sun.COM ancil_buf += sizeof (struct T_opthdr);
46111042SErik.Nordmark@Sun.COM bcopy(ipp->ipp_hopopts, ancil_buf, ipp->ipp_hopoptslen);
46211042SErik.Nordmark@Sun.COM ancil_buf += ipp->ipp_hopoptslen;
46311042SErik.Nordmark@Sun.COM ancil_size -= toh->len;
46411042SErik.Nordmark@Sun.COM }
46511042SErik.Nordmark@Sun.COM /*
46611042SErik.Nordmark@Sun.COM * To honor RFC3542 when an application asks for both IPV6_RECVDSTOPTS
46711042SErik.Nordmark@Sun.COM * and IPV6_RECVRTHDR, we pass up the item rthdrdstopts (the destination
46811042SErik.Nordmark@Sun.COM * options that appear before a routing header.
46911042SErik.Nordmark@Sun.COM * We also pass them up if IPV6_RECVRTHDRDSTOPTS is set.
47011042SErik.Nordmark@Sun.COM */
47111042SErik.Nordmark@Sun.COM if (ipp->ipp_fields & IPPF_RTHDRDSTOPTS) {
47211042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_ipv6_recvrthdrdstopts ||
47311042SErik.Nordmark@Sun.COM (recv_ancillary.crb_ipv6_recvdstopts &&
47411042SErik.Nordmark@Sun.COM recv_ancillary.crb_ipv6_recvrthdr)) {
47511042SErik.Nordmark@Sun.COM struct T_opthdr *toh;
47611042SErik.Nordmark@Sun.COM
47711042SErik.Nordmark@Sun.COM toh = (struct T_opthdr *)ancil_buf;
47811042SErik.Nordmark@Sun.COM toh->level = IPPROTO_IPV6;
47911042SErik.Nordmark@Sun.COM toh->name = IPV6_DSTOPTS;
48011042SErik.Nordmark@Sun.COM toh->len = sizeof (struct T_opthdr) +
48111042SErik.Nordmark@Sun.COM ipp->ipp_rthdrdstoptslen;
48211042SErik.Nordmark@Sun.COM toh->status = 0;
48311042SErik.Nordmark@Sun.COM ancil_buf += sizeof (struct T_opthdr);
48411042SErik.Nordmark@Sun.COM bcopy(ipp->ipp_rthdrdstopts, ancil_buf,
48511042SErik.Nordmark@Sun.COM ipp->ipp_rthdrdstoptslen);
48611042SErik.Nordmark@Sun.COM ancil_buf += ipp->ipp_rthdrdstoptslen;
48711042SErik.Nordmark@Sun.COM ancil_size -= toh->len;
48811042SErik.Nordmark@Sun.COM }
48911042SErik.Nordmark@Sun.COM }
49011042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_ipv6_recvrthdr &&
49111042SErik.Nordmark@Sun.COM (ipp->ipp_fields & IPPF_RTHDR)) {
49211042SErik.Nordmark@Sun.COM struct T_opthdr *toh;
49311042SErik.Nordmark@Sun.COM
49411042SErik.Nordmark@Sun.COM toh = (struct T_opthdr *)ancil_buf;
49511042SErik.Nordmark@Sun.COM toh->level = IPPROTO_IPV6;
49611042SErik.Nordmark@Sun.COM toh->name = IPV6_RTHDR;
49711042SErik.Nordmark@Sun.COM toh->len = sizeof (struct T_opthdr) + ipp->ipp_rthdrlen;
49811042SErik.Nordmark@Sun.COM toh->status = 0;
49911042SErik.Nordmark@Sun.COM ancil_buf += sizeof (struct T_opthdr);
50011042SErik.Nordmark@Sun.COM bcopy(ipp->ipp_rthdr, ancil_buf, ipp->ipp_rthdrlen);
50111042SErik.Nordmark@Sun.COM ancil_buf += ipp->ipp_rthdrlen;
50211042SErik.Nordmark@Sun.COM ancil_size -= toh->len;
50311042SErik.Nordmark@Sun.COM }
50411042SErik.Nordmark@Sun.COM if ((recv_ancillary.crb_ipv6_recvdstopts ||
50511042SErik.Nordmark@Sun.COM recv_ancillary.crb_old_ipv6_recvdstopts) &&
50611042SErik.Nordmark@Sun.COM (ipp->ipp_fields & IPPF_DSTOPTS)) {
50711042SErik.Nordmark@Sun.COM struct T_opthdr *toh;
50811042SErik.Nordmark@Sun.COM
50911042SErik.Nordmark@Sun.COM toh = (struct T_opthdr *)ancil_buf;
51011042SErik.Nordmark@Sun.COM toh->level = IPPROTO_IPV6;
51111042SErik.Nordmark@Sun.COM toh->name = IPV6_DSTOPTS;
51211042SErik.Nordmark@Sun.COM toh->len = sizeof (struct T_opthdr) + ipp->ipp_dstoptslen;
51311042SErik.Nordmark@Sun.COM toh->status = 0;
51411042SErik.Nordmark@Sun.COM ancil_buf += sizeof (struct T_opthdr);
51511042SErik.Nordmark@Sun.COM bcopy(ipp->ipp_dstopts, ancil_buf, ipp->ipp_dstoptslen);
51611042SErik.Nordmark@Sun.COM ancil_buf += ipp->ipp_dstoptslen;
51711042SErik.Nordmark@Sun.COM ancil_size -= toh->len;
51811042SErik.Nordmark@Sun.COM }
51911042SErik.Nordmark@Sun.COM
52011042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_recvucred && ira->ira_cred != NULL) {
52111042SErik.Nordmark@Sun.COM struct T_opthdr *toh;
52211042SErik.Nordmark@Sun.COM cred_t *rcr = connp->conn_cred;
52311042SErik.Nordmark@Sun.COM
52411042SErik.Nordmark@Sun.COM toh = (struct T_opthdr *)ancil_buf;
52511042SErik.Nordmark@Sun.COM toh->level = SOL_SOCKET;
52611042SErik.Nordmark@Sun.COM toh->name = SCM_UCRED;
52711134SCasper.Dik@Sun.COM toh->len = sizeof (struct T_opthdr) +
52811134SCasper.Dik@Sun.COM ucredminsize(ira->ira_cred);
52911042SErik.Nordmark@Sun.COM toh->status = 0;
53011042SErik.Nordmark@Sun.COM (void) cred2ucred(ira->ira_cred, ira->ira_cpid, &toh[1], rcr);
53111042SErik.Nordmark@Sun.COM ancil_buf += toh->len;
53211042SErik.Nordmark@Sun.COM ancil_size -= toh->len;
53311042SErik.Nordmark@Sun.COM }
53411042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_timestamp) {
53511042SErik.Nordmark@Sun.COM struct T_opthdr *toh;
53611042SErik.Nordmark@Sun.COM
53711042SErik.Nordmark@Sun.COM toh = (struct T_opthdr *)ancil_buf;
53811042SErik.Nordmark@Sun.COM toh->level = SOL_SOCKET;
53911042SErik.Nordmark@Sun.COM toh->name = SCM_TIMESTAMP;
54011042SErik.Nordmark@Sun.COM toh->len = sizeof (struct T_opthdr) +
54111042SErik.Nordmark@Sun.COM sizeof (timestruc_t) + _POINTER_ALIGNMENT;
54211042SErik.Nordmark@Sun.COM toh->status = 0;
54311042SErik.Nordmark@Sun.COM ancil_buf += sizeof (struct T_opthdr);
54411042SErik.Nordmark@Sun.COM /* Align for gethrestime() */
54511042SErik.Nordmark@Sun.COM ancil_buf = (uchar_t *)P2ROUNDUP((intptr_t)ancil_buf,
54611042SErik.Nordmark@Sun.COM sizeof (intptr_t));
54711042SErik.Nordmark@Sun.COM gethrestime((timestruc_t *)ancil_buf);
54811042SErik.Nordmark@Sun.COM ancil_buf = (uchar_t *)toh + toh->len;
54911042SErik.Nordmark@Sun.COM ancil_size -= toh->len;
55011042SErik.Nordmark@Sun.COM }
55111042SErik.Nordmark@Sun.COM
55211042SErik.Nordmark@Sun.COM /*
55311042SErik.Nordmark@Sun.COM * CAUTION:
55411042SErik.Nordmark@Sun.COM * Due to aligment issues
55511042SErik.Nordmark@Sun.COM * Processing of IP_RECVTTL option
55611042SErik.Nordmark@Sun.COM * should always be the last. Adding
55711042SErik.Nordmark@Sun.COM * any option processing after this will
55811042SErik.Nordmark@Sun.COM * cause alignment panic.
55911042SErik.Nordmark@Sun.COM */
56011042SErik.Nordmark@Sun.COM if (recv_ancillary.crb_recvttl &&
56111042SErik.Nordmark@Sun.COM (ira->ira_flags & IRAF_IS_IPV4)) {
56211042SErik.Nordmark@Sun.COM struct T_opthdr *toh;
56311042SErik.Nordmark@Sun.COM uint8_t *dstptr;
56411042SErik.Nordmark@Sun.COM
56511042SErik.Nordmark@Sun.COM toh = (struct T_opthdr *)ancil_buf;
56611042SErik.Nordmark@Sun.COM toh->level = IPPROTO_IP;
56711042SErik.Nordmark@Sun.COM toh->name = IP_RECVTTL;
56811042SErik.Nordmark@Sun.COM toh->len = sizeof (struct T_opthdr) + sizeof (uint8_t);
56911042SErik.Nordmark@Sun.COM toh->status = 0;
57011042SErik.Nordmark@Sun.COM ancil_buf += sizeof (struct T_opthdr);
57111042SErik.Nordmark@Sun.COM dstptr = (uint8_t *)ancil_buf;
57211042SErik.Nordmark@Sun.COM *dstptr = ipp->ipp_hoplimit;
57311042SErik.Nordmark@Sun.COM ancil_buf += sizeof (uint8_t);
57411042SErik.Nordmark@Sun.COM ancil_size -= toh->len;
57511042SErik.Nordmark@Sun.COM }
57611042SErik.Nordmark@Sun.COM
57711042SErik.Nordmark@Sun.COM /* Consumed all of allocated space */
57811042SErik.Nordmark@Sun.COM ASSERT(ancil_size == 0);
57911042SErik.Nordmark@Sun.COM
58011042SErik.Nordmark@Sun.COM }
58111042SErik.Nordmark@Sun.COM
58211042SErik.Nordmark@Sun.COM /*
58311042SErik.Nordmark@Sun.COM * This routine retrieves the current status of socket options.
58411042SErik.Nordmark@Sun.COM * It returns the size of the option retrieved, or -1.
58511042SErik.Nordmark@Sun.COM */
58611042SErik.Nordmark@Sun.COM int
conn_opt_get(conn_opt_arg_t * coa,t_scalar_t level,t_scalar_t name,uchar_t * ptr)58711042SErik.Nordmark@Sun.COM conn_opt_get(conn_opt_arg_t *coa, t_scalar_t level, t_scalar_t name,
58811042SErik.Nordmark@Sun.COM uchar_t *ptr)
58911042SErik.Nordmark@Sun.COM {
59011042SErik.Nordmark@Sun.COM int *i1 = (int *)ptr;
59111042SErik.Nordmark@Sun.COM conn_t *connp = coa->coa_connp;
59211042SErik.Nordmark@Sun.COM ip_xmit_attr_t *ixa = coa->coa_ixa;
59311042SErik.Nordmark@Sun.COM ip_pkt_t *ipp = coa->coa_ipp;
59411042SErik.Nordmark@Sun.COM ip_stack_t *ipst = ixa->ixa_ipst;
59511042SErik.Nordmark@Sun.COM uint_t len;
59611042SErik.Nordmark@Sun.COM
59711042SErik.Nordmark@Sun.COM ASSERT(MUTEX_HELD(&coa->coa_connp->conn_lock));
59811042SErik.Nordmark@Sun.COM
59911042SErik.Nordmark@Sun.COM switch (level) {
60011042SErik.Nordmark@Sun.COM case SOL_SOCKET:
60111042SErik.Nordmark@Sun.COM switch (name) {
60211042SErik.Nordmark@Sun.COM case SO_DEBUG:
60311042SErik.Nordmark@Sun.COM *i1 = connp->conn_debug ? SO_DEBUG : 0;
60411042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
60511042SErik.Nordmark@Sun.COM case SO_KEEPALIVE:
60611042SErik.Nordmark@Sun.COM *i1 = connp->conn_keepalive ? SO_KEEPALIVE : 0;
60711042SErik.Nordmark@Sun.COM break;
60811042SErik.Nordmark@Sun.COM case SO_LINGER: {
60911042SErik.Nordmark@Sun.COM struct linger *lgr = (struct linger *)ptr;
61011042SErik.Nordmark@Sun.COM
61111042SErik.Nordmark@Sun.COM lgr->l_onoff = connp->conn_linger ? SO_LINGER : 0;
61211042SErik.Nordmark@Sun.COM lgr->l_linger = connp->conn_lingertime;
61311042SErik.Nordmark@Sun.COM }
61411042SErik.Nordmark@Sun.COM return (sizeof (struct linger));
61511042SErik.Nordmark@Sun.COM
61611042SErik.Nordmark@Sun.COM case SO_OOBINLINE:
61711042SErik.Nordmark@Sun.COM *i1 = connp->conn_oobinline ? SO_OOBINLINE : 0;
61811042SErik.Nordmark@Sun.COM break;
61911042SErik.Nordmark@Sun.COM case SO_REUSEADDR:
62011042SErik.Nordmark@Sun.COM *i1 = connp->conn_reuseaddr ? SO_REUSEADDR : 0;
62111042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
62211042SErik.Nordmark@Sun.COM case SO_TYPE:
62311042SErik.Nordmark@Sun.COM *i1 = connp->conn_so_type;
62411042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
62511042SErik.Nordmark@Sun.COM case SO_DONTROUTE:
62611042SErik.Nordmark@Sun.COM *i1 = (ixa->ixa_flags & IXAF_DONTROUTE) ?
62711042SErik.Nordmark@Sun.COM SO_DONTROUTE : 0;
62811042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
62911042SErik.Nordmark@Sun.COM case SO_USELOOPBACK:
63011042SErik.Nordmark@Sun.COM *i1 = connp->conn_useloopback ? SO_USELOOPBACK : 0;
63111042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
63211042SErik.Nordmark@Sun.COM case SO_BROADCAST:
63311042SErik.Nordmark@Sun.COM *i1 = connp->conn_broadcast ? SO_BROADCAST : 0;
63411042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
63511042SErik.Nordmark@Sun.COM
63611042SErik.Nordmark@Sun.COM case SO_SNDBUF:
63711042SErik.Nordmark@Sun.COM *i1 = connp->conn_sndbuf;
63811042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
63911042SErik.Nordmark@Sun.COM case SO_RCVBUF:
64011042SErik.Nordmark@Sun.COM *i1 = connp->conn_rcvbuf;
64111042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
64211042SErik.Nordmark@Sun.COM case SO_RCVTIMEO:
64311042SErik.Nordmark@Sun.COM case SO_SNDTIMEO:
64411042SErik.Nordmark@Sun.COM /*
64511042SErik.Nordmark@Sun.COM * Pass these two options in order for third part
64611042SErik.Nordmark@Sun.COM * protocol usage. Here just return directly.
64711042SErik.Nordmark@Sun.COM */
64811042SErik.Nordmark@Sun.COM *i1 = 0;
64911042SErik.Nordmark@Sun.COM break;
65011042SErik.Nordmark@Sun.COM case SO_DGRAM_ERRIND:
65111042SErik.Nordmark@Sun.COM *i1 = connp->conn_dgram_errind ? SO_DGRAM_ERRIND : 0;
65211042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
65311042SErik.Nordmark@Sun.COM case SO_RECVUCRED:
65411042SErik.Nordmark@Sun.COM *i1 = connp->conn_recv_ancillary.crb_recvucred;
65511042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
65611042SErik.Nordmark@Sun.COM case SO_TIMESTAMP:
65711042SErik.Nordmark@Sun.COM *i1 = connp->conn_recv_ancillary.crb_timestamp;
65811042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
65911042SErik.Nordmark@Sun.COM case SO_VRRP:
66011042SErik.Nordmark@Sun.COM *i1 = connp->conn_isvrrp;
66111042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
66211042SErik.Nordmark@Sun.COM case SO_ANON_MLP:
66311042SErik.Nordmark@Sun.COM *i1 = connp->conn_anon_mlp;
66411042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
66511042SErik.Nordmark@Sun.COM case SO_MAC_EXEMPT:
66611042SErik.Nordmark@Sun.COM *i1 = (connp->conn_mac_mode == CONN_MAC_AWARE);
66711042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
66811042SErik.Nordmark@Sun.COM case SO_MAC_IMPLICIT:
66911042SErik.Nordmark@Sun.COM *i1 = (connp->conn_mac_mode == CONN_MAC_IMPLICIT);
67011042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
67111042SErik.Nordmark@Sun.COM case SO_ALLZONES:
67211042SErik.Nordmark@Sun.COM *i1 = connp->conn_allzones;
67311042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
67411042SErik.Nordmark@Sun.COM case SO_EXCLBIND:
67511042SErik.Nordmark@Sun.COM *i1 = connp->conn_exclbind ? SO_EXCLBIND : 0;
67611042SErik.Nordmark@Sun.COM break;
67711042SErik.Nordmark@Sun.COM case SO_PROTOTYPE:
67811042SErik.Nordmark@Sun.COM *i1 = connp->conn_proto;
67911042SErik.Nordmark@Sun.COM break;
68011042SErik.Nordmark@Sun.COM
68111042SErik.Nordmark@Sun.COM case SO_DOMAIN:
68211042SErik.Nordmark@Sun.COM *i1 = connp->conn_family;
68311042SErik.Nordmark@Sun.COM break;
68411042SErik.Nordmark@Sun.COM default:
68511042SErik.Nordmark@Sun.COM return (-1);
68611042SErik.Nordmark@Sun.COM }
68711042SErik.Nordmark@Sun.COM break;
68811042SErik.Nordmark@Sun.COM case IPPROTO_IP:
68911042SErik.Nordmark@Sun.COM if (connp->conn_family != AF_INET)
69011042SErik.Nordmark@Sun.COM return (-1);
69111042SErik.Nordmark@Sun.COM switch (name) {
69211042SErik.Nordmark@Sun.COM case IP_OPTIONS:
69311042SErik.Nordmark@Sun.COM case T_IP_OPTIONS:
69411042SErik.Nordmark@Sun.COM if (!(ipp->ipp_fields & IPPF_IPV4_OPTIONS))
69511042SErik.Nordmark@Sun.COM return (0);
69611042SErik.Nordmark@Sun.COM
69711042SErik.Nordmark@Sun.COM len = ipp->ipp_ipv4_options_len;
69811042SErik.Nordmark@Sun.COM if (len > 0) {
69911042SErik.Nordmark@Sun.COM bcopy(ipp->ipp_ipv4_options, ptr, len);
70011042SErik.Nordmark@Sun.COM }
70111042SErik.Nordmark@Sun.COM return (len);
70211042SErik.Nordmark@Sun.COM
70311042SErik.Nordmark@Sun.COM case IP_PKTINFO: {
70411042SErik.Nordmark@Sun.COM /*
70511042SErik.Nordmark@Sun.COM * This also handles IP_RECVPKTINFO.
70611042SErik.Nordmark@Sun.COM * IP_PKTINFO and IP_RECVPKTINFO have same value.
70711042SErik.Nordmark@Sun.COM * Differentiation is based on the size of the
70811042SErik.Nordmark@Sun.COM * argument passed in.
70911042SErik.Nordmark@Sun.COM */
71011042SErik.Nordmark@Sun.COM struct in_pktinfo *pktinfo;
71111042SErik.Nordmark@Sun.COM
71211042SErik.Nordmark@Sun.COM #ifdef notdef
71311042SErik.Nordmark@Sun.COM /* optcom doesn't provide a length with "get" */
71411042SErik.Nordmark@Sun.COM if (inlen == sizeof (int)) {
71511042SErik.Nordmark@Sun.COM /* This is IP_RECVPKTINFO option. */
71611042SErik.Nordmark@Sun.COM *i1 = connp->conn_recv_ancillary.
71711042SErik.Nordmark@Sun.COM crb_ip_recvpktinfo;
71811042SErik.Nordmark@Sun.COM return (sizeof (int));
71911042SErik.Nordmark@Sun.COM }
72011042SErik.Nordmark@Sun.COM #endif
72111042SErik.Nordmark@Sun.COM /* XXX assumes that caller has room for max size! */
72211042SErik.Nordmark@Sun.COM
72311042SErik.Nordmark@Sun.COM pktinfo = (struct in_pktinfo *)ptr;
72411042SErik.Nordmark@Sun.COM pktinfo->ipi_ifindex = ixa->ixa_ifindex;
72511042SErik.Nordmark@Sun.COM if (ipp->ipp_fields & IPPF_ADDR)
72611042SErik.Nordmark@Sun.COM pktinfo->ipi_spec_dst.s_addr = ipp->ipp_addr_v4;
72711042SErik.Nordmark@Sun.COM else
72811042SErik.Nordmark@Sun.COM pktinfo->ipi_spec_dst.s_addr = INADDR_ANY;
72911042SErik.Nordmark@Sun.COM return (sizeof (struct in_pktinfo));
73011042SErik.Nordmark@Sun.COM }
73111042SErik.Nordmark@Sun.COM case IP_DONTFRAG:
73211042SErik.Nordmark@Sun.COM *i1 = (ixa->ixa_flags & IXAF_DONTFRAG) != 0;
73311042SErik.Nordmark@Sun.COM return (sizeof (int));
73411042SErik.Nordmark@Sun.COM case IP_TOS:
73511042SErik.Nordmark@Sun.COM case T_IP_TOS:
73611042SErik.Nordmark@Sun.COM *i1 = (int)ipp->ipp_type_of_service;
73711042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
73811042SErik.Nordmark@Sun.COM case IP_TTL:
73911042SErik.Nordmark@Sun.COM *i1 = (int)ipp->ipp_unicast_hops;
74011042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
74111042SErik.Nordmark@Sun.COM case IP_DHCPINIT_IF:
74211042SErik.Nordmark@Sun.COM return (-1);
74311042SErik.Nordmark@Sun.COM case IP_NEXTHOP:
74411042SErik.Nordmark@Sun.COM if (ixa->ixa_flags & IXAF_NEXTHOP_SET) {
74511042SErik.Nordmark@Sun.COM *(ipaddr_t *)ptr = ixa->ixa_nexthop_v4;
74611042SErik.Nordmark@Sun.COM return (sizeof (ipaddr_t));
74711042SErik.Nordmark@Sun.COM } else {
74811042SErik.Nordmark@Sun.COM return (0);
74911042SErik.Nordmark@Sun.COM }
75011042SErik.Nordmark@Sun.COM
75111042SErik.Nordmark@Sun.COM case IP_MULTICAST_IF:
75211042SErik.Nordmark@Sun.COM /* 0 address if not set */
75311042SErik.Nordmark@Sun.COM *(ipaddr_t *)ptr = ixa->ixa_multicast_ifaddr;
75411042SErik.Nordmark@Sun.COM return (sizeof (ipaddr_t));
75511042SErik.Nordmark@Sun.COM case IP_MULTICAST_TTL:
75611042SErik.Nordmark@Sun.COM *(uchar_t *)ptr = ixa->ixa_multicast_ttl;
75711042SErik.Nordmark@Sun.COM return (sizeof (uchar_t));
75811042SErik.Nordmark@Sun.COM case IP_MULTICAST_LOOP:
75911042SErik.Nordmark@Sun.COM *ptr = (ixa->ixa_flags & IXAF_MULTICAST_LOOP) ? 1 : 0;
76011042SErik.Nordmark@Sun.COM return (sizeof (uint8_t));
76111042SErik.Nordmark@Sun.COM case IP_RECVOPTS:
76211042SErik.Nordmark@Sun.COM *i1 = connp->conn_recv_ancillary.crb_recvopts;
76311042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
76411042SErik.Nordmark@Sun.COM case IP_RECVDSTADDR:
76511042SErik.Nordmark@Sun.COM *i1 = connp->conn_recv_ancillary.crb_recvdstaddr;
76611042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
76711042SErik.Nordmark@Sun.COM case IP_RECVIF:
76811042SErik.Nordmark@Sun.COM *i1 = connp->conn_recv_ancillary.crb_recvif;
76911042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
77011042SErik.Nordmark@Sun.COM case IP_RECVSLLA:
77111042SErik.Nordmark@Sun.COM *i1 = connp->conn_recv_ancillary.crb_recvslla;
77211042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
77311042SErik.Nordmark@Sun.COM case IP_RECVTTL:
77411042SErik.Nordmark@Sun.COM *i1 = connp->conn_recv_ancillary.crb_recvttl;
77511042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
77611042SErik.Nordmark@Sun.COM case IP_ADD_MEMBERSHIP:
77711042SErik.Nordmark@Sun.COM case IP_DROP_MEMBERSHIP:
77811042SErik.Nordmark@Sun.COM case MCAST_JOIN_GROUP:
77911042SErik.Nordmark@Sun.COM case MCAST_LEAVE_GROUP:
78011042SErik.Nordmark@Sun.COM case IP_BLOCK_SOURCE:
78111042SErik.Nordmark@Sun.COM case IP_UNBLOCK_SOURCE:
78211042SErik.Nordmark@Sun.COM case IP_ADD_SOURCE_MEMBERSHIP:
78311042SErik.Nordmark@Sun.COM case IP_DROP_SOURCE_MEMBERSHIP:
78411042SErik.Nordmark@Sun.COM case MCAST_BLOCK_SOURCE:
78511042SErik.Nordmark@Sun.COM case MCAST_UNBLOCK_SOURCE:
78611042SErik.Nordmark@Sun.COM case MCAST_JOIN_SOURCE_GROUP:
78711042SErik.Nordmark@Sun.COM case MCAST_LEAVE_SOURCE_GROUP:
78811042SErik.Nordmark@Sun.COM case MRT_INIT:
78911042SErik.Nordmark@Sun.COM case MRT_DONE:
79011042SErik.Nordmark@Sun.COM case MRT_ADD_VIF:
79111042SErik.Nordmark@Sun.COM case MRT_DEL_VIF:
79211042SErik.Nordmark@Sun.COM case MRT_ADD_MFC:
79311042SErik.Nordmark@Sun.COM case MRT_DEL_MFC:
79411042SErik.Nordmark@Sun.COM /* cannot "get" the value for these */
79511042SErik.Nordmark@Sun.COM return (-1);
79611042SErik.Nordmark@Sun.COM case MRT_VERSION:
79711042SErik.Nordmark@Sun.COM case MRT_ASSERT:
79811042SErik.Nordmark@Sun.COM (void) ip_mrouter_get(name, connp, ptr);
79911042SErik.Nordmark@Sun.COM return (sizeof (int));
80011042SErik.Nordmark@Sun.COM case IP_SEC_OPT:
80111042SErik.Nordmark@Sun.COM return (ipsec_req_from_conn(connp, (ipsec_req_t *)ptr,
80211042SErik.Nordmark@Sun.COM IPSEC_AF_V4));
80311042SErik.Nordmark@Sun.COM case IP_BOUND_IF:
80411042SErik.Nordmark@Sun.COM /* Zero if not set */
80511042SErik.Nordmark@Sun.COM *i1 = connp->conn_bound_if;
80611042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
80711042SErik.Nordmark@Sun.COM case IP_UNSPEC_SRC:
80811042SErik.Nordmark@Sun.COM *i1 = connp->conn_unspec_src;
80911042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
81011042SErik.Nordmark@Sun.COM case IP_BROADCAST_TTL:
81111042SErik.Nordmark@Sun.COM if (ixa->ixa_flags & IXAF_BROADCAST_TTL_SET)
81211042SErik.Nordmark@Sun.COM *(uchar_t *)ptr = ixa->ixa_broadcast_ttl;
81311042SErik.Nordmark@Sun.COM else
81411042SErik.Nordmark@Sun.COM *(uchar_t *)ptr = ipst->ips_ip_broadcast_ttl;
81511042SErik.Nordmark@Sun.COM return (sizeof (uchar_t));
81611042SErik.Nordmark@Sun.COM default:
81711042SErik.Nordmark@Sun.COM return (-1);
81811042SErik.Nordmark@Sun.COM }
81911042SErik.Nordmark@Sun.COM break;
82011042SErik.Nordmark@Sun.COM case IPPROTO_IPV6:
82111042SErik.Nordmark@Sun.COM if (connp->conn_family != AF_INET6)
82211042SErik.Nordmark@Sun.COM return (-1);
82311042SErik.Nordmark@Sun.COM switch (name) {
82411042SErik.Nordmark@Sun.COM case IPV6_UNICAST_HOPS:
82511042SErik.Nordmark@Sun.COM *i1 = (int)ipp->ipp_unicast_hops;
82611042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
82711042SErik.Nordmark@Sun.COM case IPV6_MULTICAST_IF:
82811042SErik.Nordmark@Sun.COM /* 0 index if not set */
82911042SErik.Nordmark@Sun.COM *i1 = ixa->ixa_multicast_ifindex;
83011042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
83111042SErik.Nordmark@Sun.COM case IPV6_MULTICAST_HOPS:
83211042SErik.Nordmark@Sun.COM *i1 = ixa->ixa_multicast_ttl;
83311042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
83411042SErik.Nordmark@Sun.COM case IPV6_MULTICAST_LOOP:
83511042SErik.Nordmark@Sun.COM *i1 = (ixa->ixa_flags & IXAF_MULTICAST_LOOP) ? 1 : 0;
83611042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
83711042SErik.Nordmark@Sun.COM case IPV6_JOIN_GROUP:
83811042SErik.Nordmark@Sun.COM case IPV6_LEAVE_GROUP:
83911042SErik.Nordmark@Sun.COM case MCAST_JOIN_GROUP:
84011042SErik.Nordmark@Sun.COM case MCAST_LEAVE_GROUP:
84111042SErik.Nordmark@Sun.COM case MCAST_BLOCK_SOURCE:
84211042SErik.Nordmark@Sun.COM case MCAST_UNBLOCK_SOURCE:
84311042SErik.Nordmark@Sun.COM case MCAST_JOIN_SOURCE_GROUP:
84411042SErik.Nordmark@Sun.COM case MCAST_LEAVE_SOURCE_GROUP:
84511042SErik.Nordmark@Sun.COM /* cannot "get" the value for these */
84611042SErik.Nordmark@Sun.COM return (-1);
84711042SErik.Nordmark@Sun.COM case IPV6_BOUND_IF:
84811042SErik.Nordmark@Sun.COM /* Zero if not set */
84911042SErik.Nordmark@Sun.COM *i1 = connp->conn_bound_if;
85011042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
85111042SErik.Nordmark@Sun.COM case IPV6_UNSPEC_SRC:
85211042SErik.Nordmark@Sun.COM *i1 = connp->conn_unspec_src;
85311042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
85411042SErik.Nordmark@Sun.COM case IPV6_RECVPKTINFO:
85511042SErik.Nordmark@Sun.COM *i1 = connp->conn_recv_ancillary.crb_ip_recvpktinfo;
85611042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
85711042SErik.Nordmark@Sun.COM case IPV6_RECVTCLASS:
85811042SErik.Nordmark@Sun.COM *i1 = connp->conn_recv_ancillary.crb_ipv6_recvtclass;
85911042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
86011042SErik.Nordmark@Sun.COM case IPV6_RECVPATHMTU:
86111042SErik.Nordmark@Sun.COM *i1 = connp->conn_ipv6_recvpathmtu;
86211042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
86311042SErik.Nordmark@Sun.COM case IPV6_RECVHOPLIMIT:
86411042SErik.Nordmark@Sun.COM *i1 = connp->conn_recv_ancillary.crb_ipv6_recvhoplimit;
86511042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
86611042SErik.Nordmark@Sun.COM case IPV6_RECVHOPOPTS:
86711042SErik.Nordmark@Sun.COM *i1 = connp->conn_recv_ancillary.crb_ipv6_recvhopopts;
86811042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
86911042SErik.Nordmark@Sun.COM case IPV6_RECVDSTOPTS:
87011042SErik.Nordmark@Sun.COM *i1 = connp->conn_recv_ancillary.crb_ipv6_recvdstopts;
87111042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
87211042SErik.Nordmark@Sun.COM case _OLD_IPV6_RECVDSTOPTS:
87311042SErik.Nordmark@Sun.COM *i1 =
87411042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_old_ipv6_recvdstopts;
87511042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
87611042SErik.Nordmark@Sun.COM case IPV6_RECVRTHDRDSTOPTS:
87711042SErik.Nordmark@Sun.COM *i1 = connp->conn_recv_ancillary.
87811042SErik.Nordmark@Sun.COM crb_ipv6_recvrthdrdstopts;
87911042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
88011042SErik.Nordmark@Sun.COM case IPV6_RECVRTHDR:
88111042SErik.Nordmark@Sun.COM *i1 = connp->conn_recv_ancillary.crb_ipv6_recvrthdr;
88211042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
88311042SErik.Nordmark@Sun.COM case IPV6_PKTINFO: {
88411042SErik.Nordmark@Sun.COM /* XXX assumes that caller has room for max size! */
88511042SErik.Nordmark@Sun.COM struct in6_pktinfo *pkti;
88611042SErik.Nordmark@Sun.COM
88711042SErik.Nordmark@Sun.COM pkti = (struct in6_pktinfo *)ptr;
88811042SErik.Nordmark@Sun.COM pkti->ipi6_ifindex = ixa->ixa_ifindex;
88911042SErik.Nordmark@Sun.COM if (ipp->ipp_fields & IPPF_ADDR)
89011042SErik.Nordmark@Sun.COM pkti->ipi6_addr = ipp->ipp_addr;
89111042SErik.Nordmark@Sun.COM else
89211042SErik.Nordmark@Sun.COM pkti->ipi6_addr = ipv6_all_zeros;
89311042SErik.Nordmark@Sun.COM return (sizeof (struct in6_pktinfo));
89411042SErik.Nordmark@Sun.COM }
89511042SErik.Nordmark@Sun.COM case IPV6_TCLASS:
89611042SErik.Nordmark@Sun.COM *i1 = ipp->ipp_tclass;
89711042SErik.Nordmark@Sun.COM break; /* goto sizeof (int) option return */
89811042SErik.Nordmark@Sun.COM case IPV6_NEXTHOP: {
89911042SErik.Nordmark@Sun.COM sin6_t *sin6 = (sin6_t *)ptr;
90011042SErik.Nordmark@Sun.COM
90111042SErik.Nordmark@Sun.COM if (ixa->ixa_flags & IXAF_NEXTHOP_SET)
90211042SErik.Nordmark@Sun.COM return (0);
90311042SErik.Nordmark@Sun.COM
90411042SErik.Nordmark@Sun.COM *sin6 = sin6_null;
90511042SErik.Nordmark@Sun.COM sin6->sin6_family = AF_INET6;
90611042SErik.Nordmark@Sun.COM sin6->sin6_addr = ixa->ixa_nexthop_v6;
90711042SErik.Nordmark@Sun.COM
90811042SErik.Nordmark@Sun.COM return (sizeof (sin6_t));
90911042SErik.Nordmark@Sun.COM }
91011042SErik.Nordmark@Sun.COM case IPV6_HOPOPTS:
91111042SErik.Nordmark@Sun.COM if (!(ipp->ipp_fields & IPPF_HOPOPTS))
91211042SErik.Nordmark@Sun.COM return (0);
91311042SErik.Nordmark@Sun.COM bcopy(ipp->ipp_hopopts, ptr,
91411042SErik.Nordmark@Sun.COM ipp->ipp_hopoptslen);
91511042SErik.Nordmark@Sun.COM return (ipp->ipp_hopoptslen);
91611042SErik.Nordmark@Sun.COM case IPV6_RTHDRDSTOPTS:
91711042SErik.Nordmark@Sun.COM if (!(ipp->ipp_fields & IPPF_RTHDRDSTOPTS))
91811042SErik.Nordmark@Sun.COM return (0);
91911042SErik.Nordmark@Sun.COM bcopy(ipp->ipp_rthdrdstopts, ptr,
92011042SErik.Nordmark@Sun.COM ipp->ipp_rthdrdstoptslen);
92111042SErik.Nordmark@Sun.COM return (ipp->ipp_rthdrdstoptslen);
92211042SErik.Nordmark@Sun.COM case IPV6_RTHDR:
92311042SErik.Nordmark@Sun.COM if (!(ipp->ipp_fields & IPPF_RTHDR))
92411042SErik.Nordmark@Sun.COM return (0);
92511042SErik.Nordmark@Sun.COM bcopy(ipp->ipp_rthdr, ptr, ipp->ipp_rthdrlen);
92611042SErik.Nordmark@Sun.COM return (ipp->ipp_rthdrlen);
92711042SErik.Nordmark@Sun.COM case IPV6_DSTOPTS:
92811042SErik.Nordmark@Sun.COM if (!(ipp->ipp_fields & IPPF_DSTOPTS))
92911042SErik.Nordmark@Sun.COM return (0);
93011042SErik.Nordmark@Sun.COM bcopy(ipp->ipp_dstopts, ptr, ipp->ipp_dstoptslen);
93111042SErik.Nordmark@Sun.COM return (ipp->ipp_dstoptslen);
93211042SErik.Nordmark@Sun.COM case IPV6_PATHMTU:
93311042SErik.Nordmark@Sun.COM return (ip_fill_mtuinfo(connp, ixa,
93411042SErik.Nordmark@Sun.COM (struct ip6_mtuinfo *)ptr));
93511042SErik.Nordmark@Sun.COM case IPV6_SEC_OPT:
93611042SErik.Nordmark@Sun.COM return (ipsec_req_from_conn(connp, (ipsec_req_t *)ptr,
93711042SErik.Nordmark@Sun.COM IPSEC_AF_V6));
93811042SErik.Nordmark@Sun.COM case IPV6_SRC_PREFERENCES:
93911042SErik.Nordmark@Sun.COM return (ip6_get_src_preferences(ixa, (uint32_t *)ptr));
94011042SErik.Nordmark@Sun.COM case IPV6_DONTFRAG:
94111042SErik.Nordmark@Sun.COM *i1 = (ixa->ixa_flags & IXAF_DONTFRAG) != 0;
94211042SErik.Nordmark@Sun.COM return (sizeof (int));
94311042SErik.Nordmark@Sun.COM case IPV6_USE_MIN_MTU:
94411042SErik.Nordmark@Sun.COM if (ixa->ixa_flags & IXAF_USE_MIN_MTU)
94511042SErik.Nordmark@Sun.COM *i1 = ixa->ixa_use_min_mtu;
94611042SErik.Nordmark@Sun.COM else
94711042SErik.Nordmark@Sun.COM *i1 = IPV6_USE_MIN_MTU_MULTICAST;
94811042SErik.Nordmark@Sun.COM break;
94911042SErik.Nordmark@Sun.COM case IPV6_V6ONLY:
95011042SErik.Nordmark@Sun.COM *i1 = connp->conn_ipv6_v6only;
95111042SErik.Nordmark@Sun.COM return (sizeof (int));
95211042SErik.Nordmark@Sun.COM default:
95311042SErik.Nordmark@Sun.COM return (-1);
95411042SErik.Nordmark@Sun.COM }
95511042SErik.Nordmark@Sun.COM break;
95611042SErik.Nordmark@Sun.COM case IPPROTO_UDP:
95711042SErik.Nordmark@Sun.COM switch (name) {
95811042SErik.Nordmark@Sun.COM case UDP_ANONPRIVBIND:
95911042SErik.Nordmark@Sun.COM *i1 = connp->conn_anon_priv_bind;
96011042SErik.Nordmark@Sun.COM break;
96111042SErik.Nordmark@Sun.COM case UDP_EXCLBIND:
96211042SErik.Nordmark@Sun.COM *i1 = connp->conn_exclbind ? UDP_EXCLBIND : 0;
96311042SErik.Nordmark@Sun.COM break;
96411042SErik.Nordmark@Sun.COM default:
96511042SErik.Nordmark@Sun.COM return (-1);
96611042SErik.Nordmark@Sun.COM }
96711042SErik.Nordmark@Sun.COM break;
96811042SErik.Nordmark@Sun.COM case IPPROTO_TCP:
96911042SErik.Nordmark@Sun.COM switch (name) {
97011042SErik.Nordmark@Sun.COM case TCP_RECVDSTADDR:
97111042SErik.Nordmark@Sun.COM *i1 = connp->conn_recv_ancillary.crb_recvdstaddr;
97211042SErik.Nordmark@Sun.COM break;
97311042SErik.Nordmark@Sun.COM case TCP_ANONPRIVBIND:
97411042SErik.Nordmark@Sun.COM *i1 = connp->conn_anon_priv_bind;
97511042SErik.Nordmark@Sun.COM break;
97611042SErik.Nordmark@Sun.COM case TCP_EXCLBIND:
97711042SErik.Nordmark@Sun.COM *i1 = connp->conn_exclbind ? TCP_EXCLBIND : 0;
97811042SErik.Nordmark@Sun.COM break;
97911042SErik.Nordmark@Sun.COM default:
98011042SErik.Nordmark@Sun.COM return (-1);
98111042SErik.Nordmark@Sun.COM }
98211042SErik.Nordmark@Sun.COM break;
98311042SErik.Nordmark@Sun.COM default:
98411042SErik.Nordmark@Sun.COM return (-1);
98511042SErik.Nordmark@Sun.COM }
98611042SErik.Nordmark@Sun.COM return (sizeof (int));
98711042SErik.Nordmark@Sun.COM }
98811042SErik.Nordmark@Sun.COM
98911042SErik.Nordmark@Sun.COM static int conn_opt_set_socket(conn_opt_arg_t *coa, t_scalar_t name,
99011042SErik.Nordmark@Sun.COM uint_t inlen, uchar_t *invalp, boolean_t checkonly, cred_t *cr);
99111042SErik.Nordmark@Sun.COM static int conn_opt_set_ip(conn_opt_arg_t *coa, t_scalar_t name,
99211042SErik.Nordmark@Sun.COM uint_t inlen, uchar_t *invalp, boolean_t checkonly, cred_t *cr);
99311042SErik.Nordmark@Sun.COM static int conn_opt_set_ipv6(conn_opt_arg_t *coa, t_scalar_t name,
99411042SErik.Nordmark@Sun.COM uint_t inlen, uchar_t *invalp, boolean_t checkonly, cred_t *cr);
99511042SErik.Nordmark@Sun.COM static int conn_opt_set_udp(conn_opt_arg_t *coa, t_scalar_t name,
99611042SErik.Nordmark@Sun.COM uint_t inlen, uchar_t *invalp, boolean_t checkonly, cred_t *cr);
99711042SErik.Nordmark@Sun.COM static int conn_opt_set_tcp(conn_opt_arg_t *coa, t_scalar_t name,
99811042SErik.Nordmark@Sun.COM uint_t inlen, uchar_t *invalp, boolean_t checkonly, cred_t *cr);
99911042SErik.Nordmark@Sun.COM
100011042SErik.Nordmark@Sun.COM /*
100111042SErik.Nordmark@Sun.COM * This routine sets the most common socket options including some
100211042SErik.Nordmark@Sun.COM * that are transport/ULP specific.
100311042SErik.Nordmark@Sun.COM * It returns errno or zero.
100411042SErik.Nordmark@Sun.COM *
100511042SErik.Nordmark@Sun.COM * For fixed length options, there is no sanity check
100611042SErik.Nordmark@Sun.COM * of passed in length is done. It is assumed *_optcom_req()
100711042SErik.Nordmark@Sun.COM * routines do the right thing.
100811042SErik.Nordmark@Sun.COM */
100911042SErik.Nordmark@Sun.COM int
conn_opt_set(conn_opt_arg_t * coa,t_scalar_t level,t_scalar_t name,uint_t inlen,uchar_t * invalp,boolean_t checkonly,cred_t * cr)101011042SErik.Nordmark@Sun.COM conn_opt_set(conn_opt_arg_t *coa, t_scalar_t level, t_scalar_t name,
101111042SErik.Nordmark@Sun.COM uint_t inlen, uchar_t *invalp, boolean_t checkonly, cred_t *cr)
101211042SErik.Nordmark@Sun.COM {
101311042SErik.Nordmark@Sun.COM ASSERT(MUTEX_NOT_HELD(&coa->coa_connp->conn_lock));
101411042SErik.Nordmark@Sun.COM
101511042SErik.Nordmark@Sun.COM /* We have different functions for different levels */
101611042SErik.Nordmark@Sun.COM switch (level) {
101711042SErik.Nordmark@Sun.COM case SOL_SOCKET:
101811042SErik.Nordmark@Sun.COM return (conn_opt_set_socket(coa, name, inlen, invalp,
101911042SErik.Nordmark@Sun.COM checkonly, cr));
102011042SErik.Nordmark@Sun.COM case IPPROTO_IP:
102111042SErik.Nordmark@Sun.COM return (conn_opt_set_ip(coa, name, inlen, invalp,
102211042SErik.Nordmark@Sun.COM checkonly, cr));
102311042SErik.Nordmark@Sun.COM case IPPROTO_IPV6:
102411042SErik.Nordmark@Sun.COM return (conn_opt_set_ipv6(coa, name, inlen, invalp,
102511042SErik.Nordmark@Sun.COM checkonly, cr));
102611042SErik.Nordmark@Sun.COM case IPPROTO_UDP:
102711042SErik.Nordmark@Sun.COM return (conn_opt_set_udp(coa, name, inlen, invalp,
102811042SErik.Nordmark@Sun.COM checkonly, cr));
102911042SErik.Nordmark@Sun.COM case IPPROTO_TCP:
103011042SErik.Nordmark@Sun.COM return (conn_opt_set_tcp(coa, name, inlen, invalp,
103111042SErik.Nordmark@Sun.COM checkonly, cr));
103211042SErik.Nordmark@Sun.COM default:
103311042SErik.Nordmark@Sun.COM return (0);
103411042SErik.Nordmark@Sun.COM }
103511042SErik.Nordmark@Sun.COM }
103611042SErik.Nordmark@Sun.COM
103711042SErik.Nordmark@Sun.COM /*
103811042SErik.Nordmark@Sun.COM * Handle SOL_SOCKET
103911042SErik.Nordmark@Sun.COM * Note that we do not handle SO_PROTOTYPE here. The ULPs that support
104011042SErik.Nordmark@Sun.COM * it implement their own checks and setting of conn_proto.
104111042SErik.Nordmark@Sun.COM */
104211042SErik.Nordmark@Sun.COM /* ARGSUSED1 */
104311042SErik.Nordmark@Sun.COM static int
conn_opt_set_socket(conn_opt_arg_t * coa,t_scalar_t name,uint_t inlen,uchar_t * invalp,boolean_t checkonly,cred_t * cr)104411042SErik.Nordmark@Sun.COM conn_opt_set_socket(conn_opt_arg_t *coa, t_scalar_t name, uint_t inlen,
104511042SErik.Nordmark@Sun.COM uchar_t *invalp, boolean_t checkonly, cred_t *cr)
104611042SErik.Nordmark@Sun.COM {
104711042SErik.Nordmark@Sun.COM conn_t *connp = coa->coa_connp;
104811042SErik.Nordmark@Sun.COM ip_xmit_attr_t *ixa = coa->coa_ixa;
104911042SErik.Nordmark@Sun.COM int *i1 = (int *)invalp;
105011042SErik.Nordmark@Sun.COM boolean_t onoff = (*i1 == 0) ? 0 : 1;
105111042SErik.Nordmark@Sun.COM
105211042SErik.Nordmark@Sun.COM switch (name) {
105311042SErik.Nordmark@Sun.COM case SO_ALLZONES:
105411042SErik.Nordmark@Sun.COM if (IPCL_IS_BOUND(connp))
105511042SErik.Nordmark@Sun.COM return (EINVAL);
105611042SErik.Nordmark@Sun.COM break;
105711042SErik.Nordmark@Sun.COM case SO_VRRP:
105811042SErik.Nordmark@Sun.COM if (secpolicy_ip_config(cr, checkonly) != 0)
105911042SErik.Nordmark@Sun.COM return (EACCES);
106011042SErik.Nordmark@Sun.COM break;
106111042SErik.Nordmark@Sun.COM case SO_MAC_EXEMPT:
106211042SErik.Nordmark@Sun.COM if (secpolicy_net_mac_aware(cr) != 0)
106311042SErik.Nordmark@Sun.COM return (EACCES);
106411042SErik.Nordmark@Sun.COM if (IPCL_IS_BOUND(connp))
106511042SErik.Nordmark@Sun.COM return (EINVAL);
106611042SErik.Nordmark@Sun.COM break;
106711042SErik.Nordmark@Sun.COM case SO_MAC_IMPLICIT:
106811042SErik.Nordmark@Sun.COM if (secpolicy_net_mac_implicit(cr) != 0)
106911042SErik.Nordmark@Sun.COM return (EACCES);
107011042SErik.Nordmark@Sun.COM break;
107111042SErik.Nordmark@Sun.COM }
107211042SErik.Nordmark@Sun.COM if (checkonly)
107311042SErik.Nordmark@Sun.COM return (0);
107411042SErik.Nordmark@Sun.COM
107511042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
107611042SErik.Nordmark@Sun.COM /* Here we set the actual option value */
107711042SErik.Nordmark@Sun.COM switch (name) {
107811042SErik.Nordmark@Sun.COM case SO_DEBUG:
107911042SErik.Nordmark@Sun.COM connp->conn_debug = onoff;
108011042SErik.Nordmark@Sun.COM break;
108111042SErik.Nordmark@Sun.COM case SO_KEEPALIVE:
108211042SErik.Nordmark@Sun.COM connp->conn_keepalive = onoff;
108311042SErik.Nordmark@Sun.COM break;
108411042SErik.Nordmark@Sun.COM case SO_LINGER: {
108511042SErik.Nordmark@Sun.COM struct linger *lgr = (struct linger *)invalp;
108611042SErik.Nordmark@Sun.COM
108711042SErik.Nordmark@Sun.COM if (lgr->l_onoff) {
108811042SErik.Nordmark@Sun.COM connp->conn_linger = 1;
108911042SErik.Nordmark@Sun.COM connp->conn_lingertime = lgr->l_linger;
109011042SErik.Nordmark@Sun.COM } else {
109111042SErik.Nordmark@Sun.COM connp->conn_linger = 0;
109211042SErik.Nordmark@Sun.COM connp->conn_lingertime = 0;
109311042SErik.Nordmark@Sun.COM }
109411042SErik.Nordmark@Sun.COM break;
109511042SErik.Nordmark@Sun.COM }
109611042SErik.Nordmark@Sun.COM case SO_OOBINLINE:
109711042SErik.Nordmark@Sun.COM connp->conn_oobinline = onoff;
109811042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_OOBINLINE_CHANGED;
109911042SErik.Nordmark@Sun.COM break;
110011042SErik.Nordmark@Sun.COM case SO_REUSEADDR:
110111042SErik.Nordmark@Sun.COM connp->conn_reuseaddr = onoff;
110211042SErik.Nordmark@Sun.COM break;
110311042SErik.Nordmark@Sun.COM case SO_DONTROUTE:
110411042SErik.Nordmark@Sun.COM if (onoff)
110511042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_DONTROUTE;
110611042SErik.Nordmark@Sun.COM else
110711042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~IXAF_DONTROUTE;
110811042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_ROUTE_CHANGED;
110911042SErik.Nordmark@Sun.COM break;
111011042SErik.Nordmark@Sun.COM case SO_USELOOPBACK:
111111042SErik.Nordmark@Sun.COM connp->conn_useloopback = onoff;
111211042SErik.Nordmark@Sun.COM break;
111311042SErik.Nordmark@Sun.COM case SO_BROADCAST:
111411042SErik.Nordmark@Sun.COM connp->conn_broadcast = onoff;
111511042SErik.Nordmark@Sun.COM break;
111611042SErik.Nordmark@Sun.COM case SO_SNDBUF:
111711042SErik.Nordmark@Sun.COM /* ULP has range checked the value */
111811042SErik.Nordmark@Sun.COM connp->conn_sndbuf = *i1;
111911042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_SNDBUF_CHANGED;
112011042SErik.Nordmark@Sun.COM break;
112111042SErik.Nordmark@Sun.COM case SO_RCVBUF:
112211042SErik.Nordmark@Sun.COM /* ULP has range checked the value */
112311042SErik.Nordmark@Sun.COM connp->conn_rcvbuf = *i1;
112411042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_RCVBUF_CHANGED;
112511042SErik.Nordmark@Sun.COM break;
112611042SErik.Nordmark@Sun.COM case SO_RCVTIMEO:
112711042SErik.Nordmark@Sun.COM case SO_SNDTIMEO:
112811042SErik.Nordmark@Sun.COM /*
112911042SErik.Nordmark@Sun.COM * Pass these two options in order for third part
113011042SErik.Nordmark@Sun.COM * protocol usage.
113111042SErik.Nordmark@Sun.COM */
113211042SErik.Nordmark@Sun.COM break;
113311042SErik.Nordmark@Sun.COM case SO_DGRAM_ERRIND:
113411042SErik.Nordmark@Sun.COM connp->conn_dgram_errind = onoff;
113511042SErik.Nordmark@Sun.COM break;
113611042SErik.Nordmark@Sun.COM case SO_RECVUCRED:
113711042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_recvucred = onoff;
113811042SErik.Nordmark@Sun.COM break;
113911042SErik.Nordmark@Sun.COM case SO_ALLZONES:
114011042SErik.Nordmark@Sun.COM connp->conn_allzones = onoff;
114111042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_ROUTE_CHANGED;
114211042SErik.Nordmark@Sun.COM if (onoff)
114311042SErik.Nordmark@Sun.COM ixa->ixa_zoneid = ALL_ZONES;
114411042SErik.Nordmark@Sun.COM else
114511042SErik.Nordmark@Sun.COM ixa->ixa_zoneid = connp->conn_zoneid;
114611042SErik.Nordmark@Sun.COM break;
114711042SErik.Nordmark@Sun.COM case SO_TIMESTAMP:
114811042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_timestamp = onoff;
114911042SErik.Nordmark@Sun.COM break;
115011042SErik.Nordmark@Sun.COM case SO_VRRP:
115111042SErik.Nordmark@Sun.COM connp->conn_isvrrp = onoff;
115211042SErik.Nordmark@Sun.COM break;
115311042SErik.Nordmark@Sun.COM case SO_ANON_MLP:
115411042SErik.Nordmark@Sun.COM connp->conn_anon_mlp = onoff;
115511042SErik.Nordmark@Sun.COM break;
115611042SErik.Nordmark@Sun.COM case SO_MAC_EXEMPT:
115711042SErik.Nordmark@Sun.COM connp->conn_mac_mode = onoff ?
115811042SErik.Nordmark@Sun.COM CONN_MAC_AWARE : CONN_MAC_DEFAULT;
115911042SErik.Nordmark@Sun.COM break;
116011042SErik.Nordmark@Sun.COM case SO_MAC_IMPLICIT:
116111042SErik.Nordmark@Sun.COM connp->conn_mac_mode = onoff ?
116211042SErik.Nordmark@Sun.COM CONN_MAC_IMPLICIT : CONN_MAC_DEFAULT;
116311042SErik.Nordmark@Sun.COM break;
116411042SErik.Nordmark@Sun.COM case SO_EXCLBIND:
116511042SErik.Nordmark@Sun.COM connp->conn_exclbind = onoff;
116611042SErik.Nordmark@Sun.COM break;
116711042SErik.Nordmark@Sun.COM }
116811042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
116911042SErik.Nordmark@Sun.COM return (0);
117011042SErik.Nordmark@Sun.COM }
117111042SErik.Nordmark@Sun.COM
117211042SErik.Nordmark@Sun.COM /* Handle IPPROTO_IP */
117311042SErik.Nordmark@Sun.COM static int
conn_opt_set_ip(conn_opt_arg_t * coa,t_scalar_t name,uint_t inlen,uchar_t * invalp,boolean_t checkonly,cred_t * cr)117411042SErik.Nordmark@Sun.COM conn_opt_set_ip(conn_opt_arg_t *coa, t_scalar_t name, uint_t inlen,
117511042SErik.Nordmark@Sun.COM uchar_t *invalp, boolean_t checkonly, cred_t *cr)
117611042SErik.Nordmark@Sun.COM {
117711042SErik.Nordmark@Sun.COM conn_t *connp = coa->coa_connp;
117811042SErik.Nordmark@Sun.COM ip_xmit_attr_t *ixa = coa->coa_ixa;
117911042SErik.Nordmark@Sun.COM ip_pkt_t *ipp = coa->coa_ipp;
118011042SErik.Nordmark@Sun.COM int *i1 = (int *)invalp;
118111042SErik.Nordmark@Sun.COM boolean_t onoff = (*i1 == 0) ? 0 : 1;
118211042SErik.Nordmark@Sun.COM ipaddr_t addr = (ipaddr_t)*i1;
118311042SErik.Nordmark@Sun.COM uint_t ifindex;
118411042SErik.Nordmark@Sun.COM zoneid_t zoneid = IPCL_ZONEID(connp);
118511042SErik.Nordmark@Sun.COM ipif_t *ipif;
118611042SErik.Nordmark@Sun.COM ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
118711042SErik.Nordmark@Sun.COM int error;
118811042SErik.Nordmark@Sun.COM
118911042SErik.Nordmark@Sun.COM if (connp->conn_family != AF_INET)
119011042SErik.Nordmark@Sun.COM return (EINVAL);
119111042SErik.Nordmark@Sun.COM
119211042SErik.Nordmark@Sun.COM switch (name) {
119311042SErik.Nordmark@Sun.COM case IP_TTL:
119411042SErik.Nordmark@Sun.COM /* Don't allow zero */
119511042SErik.Nordmark@Sun.COM if (*i1 < 1 || *i1 > 255)
119611042SErik.Nordmark@Sun.COM return (EINVAL);
119711042SErik.Nordmark@Sun.COM break;
119811042SErik.Nordmark@Sun.COM case IP_MULTICAST_IF:
119911042SErik.Nordmark@Sun.COM if (addr == INADDR_ANY) {
120011042SErik.Nordmark@Sun.COM /* Clear */
120111042SErik.Nordmark@Sun.COM ifindex = 0;
120211042SErik.Nordmark@Sun.COM break;
120311042SErik.Nordmark@Sun.COM }
120411042SErik.Nordmark@Sun.COM ipif = ipif_lookup_addr(addr, NULL, zoneid, ipst);
120511042SErik.Nordmark@Sun.COM if (ipif == NULL)
120611042SErik.Nordmark@Sun.COM return (EHOSTUNREACH);
120711042SErik.Nordmark@Sun.COM /* not supported by the virtual network iface */
120811042SErik.Nordmark@Sun.COM if (IS_VNI(ipif->ipif_ill)) {
120911042SErik.Nordmark@Sun.COM ipif_refrele(ipif);
121011042SErik.Nordmark@Sun.COM return (EINVAL);
121111042SErik.Nordmark@Sun.COM }
121211042SErik.Nordmark@Sun.COM ifindex = ipif->ipif_ill->ill_phyint->phyint_ifindex;
121311042SErik.Nordmark@Sun.COM ipif_refrele(ipif);
121411042SErik.Nordmark@Sun.COM break;
121511042SErik.Nordmark@Sun.COM case IP_NEXTHOP: {
121611042SErik.Nordmark@Sun.COM ire_t *ire;
121711042SErik.Nordmark@Sun.COM
121811042SErik.Nordmark@Sun.COM if (addr == INADDR_ANY) {
121911042SErik.Nordmark@Sun.COM /* Clear */
122011042SErik.Nordmark@Sun.COM break;
122111042SErik.Nordmark@Sun.COM }
122211042SErik.Nordmark@Sun.COM /* Verify that the next-hop is on-link */
122311042SErik.Nordmark@Sun.COM ire = ire_ftable_lookup_v4(addr, 0, 0, IRE_ONLINK, NULL, zoneid,
122411042SErik.Nordmark@Sun.COM NULL, MATCH_IRE_TYPE, 0, ipst, NULL);
122511042SErik.Nordmark@Sun.COM if (ire == NULL)
122611042SErik.Nordmark@Sun.COM return (EHOSTUNREACH);
122711042SErik.Nordmark@Sun.COM ire_refrele(ire);
122811042SErik.Nordmark@Sun.COM break;
122911042SErik.Nordmark@Sun.COM }
123011042SErik.Nordmark@Sun.COM case IP_OPTIONS:
123111042SErik.Nordmark@Sun.COM case T_IP_OPTIONS: {
123211042SErik.Nordmark@Sun.COM uint_t newlen;
123311042SErik.Nordmark@Sun.COM
123411042SErik.Nordmark@Sun.COM if (ipp->ipp_fields & IPPF_LABEL_V4)
123511042SErik.Nordmark@Sun.COM newlen = inlen + (ipp->ipp_label_len_v4 + 3) & ~3;
123611042SErik.Nordmark@Sun.COM else
123711042SErik.Nordmark@Sun.COM newlen = inlen;
123811042SErik.Nordmark@Sun.COM if ((inlen & 0x3) || newlen > IP_MAX_OPT_LENGTH) {
123911042SErik.Nordmark@Sun.COM return (EINVAL);
124011042SErik.Nordmark@Sun.COM }
124111042SErik.Nordmark@Sun.COM break;
124211042SErik.Nordmark@Sun.COM }
124311042SErik.Nordmark@Sun.COM case IP_PKTINFO: {
124411042SErik.Nordmark@Sun.COM struct in_pktinfo *pktinfo;
124511042SErik.Nordmark@Sun.COM
124611042SErik.Nordmark@Sun.COM /* Two different valid lengths */
124711042SErik.Nordmark@Sun.COM if (inlen != sizeof (int) &&
124811042SErik.Nordmark@Sun.COM inlen != sizeof (struct in_pktinfo))
124911042SErik.Nordmark@Sun.COM return (EINVAL);
125011042SErik.Nordmark@Sun.COM if (inlen == sizeof (int))
125111042SErik.Nordmark@Sun.COM break;
125211042SErik.Nordmark@Sun.COM
125311042SErik.Nordmark@Sun.COM pktinfo = (struct in_pktinfo *)invalp;
125411042SErik.Nordmark@Sun.COM if (pktinfo->ipi_spec_dst.s_addr != INADDR_ANY) {
125511042SErik.Nordmark@Sun.COM switch (ip_laddr_verify_v4(pktinfo->ipi_spec_dst.s_addr,
125611042SErik.Nordmark@Sun.COM zoneid, ipst, B_FALSE)) {
125711042SErik.Nordmark@Sun.COM case IPVL_UNICAST_UP:
125811042SErik.Nordmark@Sun.COM case IPVL_UNICAST_DOWN:
125911042SErik.Nordmark@Sun.COM break;
126011042SErik.Nordmark@Sun.COM default:
126111042SErik.Nordmark@Sun.COM return (EADDRNOTAVAIL);
126211042SErik.Nordmark@Sun.COM }
126311042SErik.Nordmark@Sun.COM }
126411430SErik.Nordmark@Sun.COM if (!ip_xmit_ifindex_valid(pktinfo->ipi_ifindex, zoneid,
126511430SErik.Nordmark@Sun.COM B_FALSE, ipst))
126611042SErik.Nordmark@Sun.COM return (ENXIO);
126711042SErik.Nordmark@Sun.COM break;
126811042SErik.Nordmark@Sun.COM }
126911042SErik.Nordmark@Sun.COM case IP_BOUND_IF:
127011042SErik.Nordmark@Sun.COM ifindex = *(uint_t *)i1;
127111042SErik.Nordmark@Sun.COM
127211042SErik.Nordmark@Sun.COM /* Just check it is ok. */
127311430SErik.Nordmark@Sun.COM if (!ip_xmit_ifindex_valid(ifindex, zoneid, B_FALSE, ipst))
127411042SErik.Nordmark@Sun.COM return (ENXIO);
127511042SErik.Nordmark@Sun.COM break;
127611042SErik.Nordmark@Sun.COM }
127711042SErik.Nordmark@Sun.COM if (checkonly)
127811042SErik.Nordmark@Sun.COM return (0);
127911042SErik.Nordmark@Sun.COM
128011042SErik.Nordmark@Sun.COM /* Here we set the actual option value */
128111042SErik.Nordmark@Sun.COM /*
128211042SErik.Nordmark@Sun.COM * conn_lock protects the bitfields, and is used to
128311042SErik.Nordmark@Sun.COM * set the fields atomically. Not needed for ixa settings since
128411042SErik.Nordmark@Sun.COM * the caller has an exclusive copy of the ixa.
128511042SErik.Nordmark@Sun.COM * We can not hold conn_lock across the multicast options though.
128611042SErik.Nordmark@Sun.COM */
128711042SErik.Nordmark@Sun.COM switch (name) {
128811042SErik.Nordmark@Sun.COM case IP_OPTIONS:
128911042SErik.Nordmark@Sun.COM case T_IP_OPTIONS:
129011042SErik.Nordmark@Sun.COM /* Save options for use by IP. */
129111042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
129211042SErik.Nordmark@Sun.COM error = optcom_pkt_set(invalp, inlen,
129311042SErik.Nordmark@Sun.COM (uchar_t **)&ipp->ipp_ipv4_options,
129411042SErik.Nordmark@Sun.COM &ipp->ipp_ipv4_options_len);
129511042SErik.Nordmark@Sun.COM if (error != 0) {
129611042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
129711042SErik.Nordmark@Sun.COM return (error);
129811042SErik.Nordmark@Sun.COM }
129911042SErik.Nordmark@Sun.COM if (ipp->ipp_ipv4_options_len == 0) {
130011042SErik.Nordmark@Sun.COM ipp->ipp_fields &= ~IPPF_IPV4_OPTIONS;
130111042SErik.Nordmark@Sun.COM } else {
130211042SErik.Nordmark@Sun.COM ipp->ipp_fields |= IPPF_IPV4_OPTIONS;
130311042SErik.Nordmark@Sun.COM }
130411042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
130511042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_HEADER_CHANGED;
130611042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_WROFF_CHANGED;
130711042SErik.Nordmark@Sun.COM break;
130811042SErik.Nordmark@Sun.COM
130911042SErik.Nordmark@Sun.COM case IP_TTL:
131011042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
131111042SErik.Nordmark@Sun.COM ipp->ipp_unicast_hops = *i1;
131211042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
131311042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_HEADER_CHANGED;
131411042SErik.Nordmark@Sun.COM break;
131511042SErik.Nordmark@Sun.COM case IP_TOS:
131611042SErik.Nordmark@Sun.COM case T_IP_TOS:
131711042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
131811042SErik.Nordmark@Sun.COM if (*i1 == -1) {
131911042SErik.Nordmark@Sun.COM ipp->ipp_type_of_service = 0;
132011042SErik.Nordmark@Sun.COM } else {
132111042SErik.Nordmark@Sun.COM ipp->ipp_type_of_service = *i1;
132211042SErik.Nordmark@Sun.COM }
132311042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
132411042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_HEADER_CHANGED;
132511042SErik.Nordmark@Sun.COM break;
132611042SErik.Nordmark@Sun.COM case IP_MULTICAST_IF:
132711042SErik.Nordmark@Sun.COM ixa->ixa_multicast_ifindex = ifindex;
132811042SErik.Nordmark@Sun.COM ixa->ixa_multicast_ifaddr = addr;
132911042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_ROUTE_CHANGED;
133011042SErik.Nordmark@Sun.COM break;
133111042SErik.Nordmark@Sun.COM case IP_MULTICAST_TTL:
133211042SErik.Nordmark@Sun.COM ixa->ixa_multicast_ttl = *invalp;
133311042SErik.Nordmark@Sun.COM /* Handled automatically by ip_output */
133411042SErik.Nordmark@Sun.COM break;
133511042SErik.Nordmark@Sun.COM case IP_MULTICAST_LOOP:
133611042SErik.Nordmark@Sun.COM if (*invalp != 0)
133711042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_MULTICAST_LOOP;
133811042SErik.Nordmark@Sun.COM else
133911042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~IXAF_MULTICAST_LOOP;
134011042SErik.Nordmark@Sun.COM /* Handled automatically by ip_output */
134111042SErik.Nordmark@Sun.COM break;
134211042SErik.Nordmark@Sun.COM case IP_RECVOPTS:
134311042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
134411042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_recvopts = onoff;
134511042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
134611042SErik.Nordmark@Sun.COM break;
134711042SErik.Nordmark@Sun.COM case IP_RECVDSTADDR:
134811042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
134911042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_recvdstaddr = onoff;
135011042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
135111042SErik.Nordmark@Sun.COM break;
135211042SErik.Nordmark@Sun.COM case IP_RECVIF:
135311042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
135411042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_recvif = onoff;
135511042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
135611042SErik.Nordmark@Sun.COM break;
135711042SErik.Nordmark@Sun.COM case IP_RECVSLLA:
135811042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
135911042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_recvslla = onoff;
136011042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
136111042SErik.Nordmark@Sun.COM break;
136211042SErik.Nordmark@Sun.COM case IP_RECVTTL:
136311042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
136411042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_recvttl = onoff;
136511042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
136611042SErik.Nordmark@Sun.COM break;
136711042SErik.Nordmark@Sun.COM case IP_PKTINFO: {
136811042SErik.Nordmark@Sun.COM /*
136911042SErik.Nordmark@Sun.COM * This also handles IP_RECVPKTINFO.
137011042SErik.Nordmark@Sun.COM * IP_PKTINFO and IP_RECVPKTINFO have same value.
137111042SErik.Nordmark@Sun.COM * Differentiation is based on the size of the
137211042SErik.Nordmark@Sun.COM * argument passed in.
137311042SErik.Nordmark@Sun.COM */
137411042SErik.Nordmark@Sun.COM struct in_pktinfo *pktinfo;
137511042SErik.Nordmark@Sun.COM
137611042SErik.Nordmark@Sun.COM if (inlen == sizeof (int)) {
137711042SErik.Nordmark@Sun.COM /* This is IP_RECVPKTINFO option. */
137811042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
137911042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_ip_recvpktinfo =
138011042SErik.Nordmark@Sun.COM onoff;
138111042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
138211042SErik.Nordmark@Sun.COM break;
138311042SErik.Nordmark@Sun.COM }
138411042SErik.Nordmark@Sun.COM
138511042SErik.Nordmark@Sun.COM /* This is IP_PKTINFO option. */
138611042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
138711042SErik.Nordmark@Sun.COM pktinfo = (struct in_pktinfo *)invalp;
1388*12595SMarcel.Telka@Sun.COM if (pktinfo->ipi_spec_dst.s_addr != INADDR_ANY) {
138911042SErik.Nordmark@Sun.COM ipp->ipp_fields |= IPPF_ADDR;
139011042SErik.Nordmark@Sun.COM IN6_INADDR_TO_V4MAPPED(&pktinfo->ipi_spec_dst,
139111042SErik.Nordmark@Sun.COM &ipp->ipp_addr);
139211042SErik.Nordmark@Sun.COM } else {
139311042SErik.Nordmark@Sun.COM ipp->ipp_fields &= ~IPPF_ADDR;
139411042SErik.Nordmark@Sun.COM ipp->ipp_addr = ipv6_all_zeros;
139511042SErik.Nordmark@Sun.COM }
139611042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
139711042SErik.Nordmark@Sun.COM ixa->ixa_ifindex = pktinfo->ipi_ifindex;
139811042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_ROUTE_CHANGED;
139911042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_HEADER_CHANGED;
140011042SErik.Nordmark@Sun.COM break;
140111042SErik.Nordmark@Sun.COM }
140211042SErik.Nordmark@Sun.COM case IP_DONTFRAG:
140311042SErik.Nordmark@Sun.COM if (onoff) {
140411042SErik.Nordmark@Sun.COM ixa->ixa_flags |= (IXAF_DONTFRAG | IXAF_PMTU_IPV4_DF);
140511042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~IXAF_PMTU_DISCOVERY;
140611042SErik.Nordmark@Sun.COM } else {
140711042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~(IXAF_DONTFRAG | IXAF_PMTU_IPV4_DF);
140811042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_PMTU_DISCOVERY;
140911042SErik.Nordmark@Sun.COM }
141011042SErik.Nordmark@Sun.COM /* Need to redo ip_attr_connect */
141111042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_ROUTE_CHANGED;
141211042SErik.Nordmark@Sun.COM break;
141311042SErik.Nordmark@Sun.COM case IP_ADD_MEMBERSHIP:
141411042SErik.Nordmark@Sun.COM case IP_DROP_MEMBERSHIP:
141511042SErik.Nordmark@Sun.COM case MCAST_JOIN_GROUP:
141611042SErik.Nordmark@Sun.COM case MCAST_LEAVE_GROUP:
141711042SErik.Nordmark@Sun.COM return (ip_opt_set_multicast_group(connp, name,
141811042SErik.Nordmark@Sun.COM invalp, B_FALSE, checkonly));
141911042SErik.Nordmark@Sun.COM
142011042SErik.Nordmark@Sun.COM case IP_BLOCK_SOURCE:
142111042SErik.Nordmark@Sun.COM case IP_UNBLOCK_SOURCE:
142211042SErik.Nordmark@Sun.COM case IP_ADD_SOURCE_MEMBERSHIP:
142311042SErik.Nordmark@Sun.COM case IP_DROP_SOURCE_MEMBERSHIP:
142411042SErik.Nordmark@Sun.COM case MCAST_BLOCK_SOURCE:
142511042SErik.Nordmark@Sun.COM case MCAST_UNBLOCK_SOURCE:
142611042SErik.Nordmark@Sun.COM case MCAST_JOIN_SOURCE_GROUP:
142711042SErik.Nordmark@Sun.COM case MCAST_LEAVE_SOURCE_GROUP:
142811042SErik.Nordmark@Sun.COM return (ip_opt_set_multicast_sources(connp, name,
142911042SErik.Nordmark@Sun.COM invalp, B_FALSE, checkonly));
143011042SErik.Nordmark@Sun.COM
143111042SErik.Nordmark@Sun.COM case IP_SEC_OPT:
143211042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
143311042SErik.Nordmark@Sun.COM error = ipsec_set_req(cr, connp, (ipsec_req_t *)invalp);
143411042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
143511042SErik.Nordmark@Sun.COM if (error != 0) {
143611042SErik.Nordmark@Sun.COM return (error);
143711042SErik.Nordmark@Sun.COM }
143811042SErik.Nordmark@Sun.COM /* This is an IPsec policy change - redo ip_attr_connect */
143911042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_ROUTE_CHANGED;
144011042SErik.Nordmark@Sun.COM break;
144111042SErik.Nordmark@Sun.COM case IP_NEXTHOP:
144211042SErik.Nordmark@Sun.COM ixa->ixa_nexthop_v4 = addr;
144311042SErik.Nordmark@Sun.COM if (addr != INADDR_ANY)
144411042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_NEXTHOP_SET;
144511042SErik.Nordmark@Sun.COM else
144611042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~IXAF_NEXTHOP_SET;
144711042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_ROUTE_CHANGED;
144811042SErik.Nordmark@Sun.COM break;
144911042SErik.Nordmark@Sun.COM
145011042SErik.Nordmark@Sun.COM case IP_BOUND_IF:
145111042SErik.Nordmark@Sun.COM ixa->ixa_ifindex = ifindex; /* Send */
145211042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
145311042SErik.Nordmark@Sun.COM connp->conn_incoming_ifindex = ifindex; /* Receive */
145411042SErik.Nordmark@Sun.COM connp->conn_bound_if = ifindex; /* getsockopt */
145511042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
145611042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_ROUTE_CHANGED;
145711042SErik.Nordmark@Sun.COM break;
145811042SErik.Nordmark@Sun.COM case IP_UNSPEC_SRC:
145911042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
146011042SErik.Nordmark@Sun.COM connp->conn_unspec_src = onoff;
146111042SErik.Nordmark@Sun.COM if (onoff)
146211042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~IXAF_VERIFY_SOURCE;
146311042SErik.Nordmark@Sun.COM else
146411042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_VERIFY_SOURCE;
146511042SErik.Nordmark@Sun.COM
146611042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
146711042SErik.Nordmark@Sun.COM break;
146811042SErik.Nordmark@Sun.COM case IP_BROADCAST_TTL:
146911042SErik.Nordmark@Sun.COM ixa->ixa_broadcast_ttl = *invalp;
147011042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_BROADCAST_TTL_SET;
147111042SErik.Nordmark@Sun.COM /* Handled automatically by ip_output */
147211042SErik.Nordmark@Sun.COM break;
147311042SErik.Nordmark@Sun.COM case MRT_INIT:
147411042SErik.Nordmark@Sun.COM case MRT_DONE:
147511042SErik.Nordmark@Sun.COM case MRT_ADD_VIF:
147611042SErik.Nordmark@Sun.COM case MRT_DEL_VIF:
147711042SErik.Nordmark@Sun.COM case MRT_ADD_MFC:
147811042SErik.Nordmark@Sun.COM case MRT_DEL_MFC:
147911042SErik.Nordmark@Sun.COM case MRT_ASSERT:
148011042SErik.Nordmark@Sun.COM if ((error = secpolicy_ip_config(cr, B_FALSE)) != 0) {
148111042SErik.Nordmark@Sun.COM return (error);
148211042SErik.Nordmark@Sun.COM }
148311042SErik.Nordmark@Sun.COM error = ip_mrouter_set((int)name, connp, checkonly,
148411042SErik.Nordmark@Sun.COM (uchar_t *)invalp, inlen);
148511042SErik.Nordmark@Sun.COM if (error) {
148611042SErik.Nordmark@Sun.COM return (error);
148711042SErik.Nordmark@Sun.COM }
148811042SErik.Nordmark@Sun.COM return (0);
148911042SErik.Nordmark@Sun.COM
149011042SErik.Nordmark@Sun.COM }
149111042SErik.Nordmark@Sun.COM return (0);
149211042SErik.Nordmark@Sun.COM }
149311042SErik.Nordmark@Sun.COM
149411042SErik.Nordmark@Sun.COM /* Handle IPPROTO_IPV6 */
149511042SErik.Nordmark@Sun.COM static int
conn_opt_set_ipv6(conn_opt_arg_t * coa,t_scalar_t name,uint_t inlen,uchar_t * invalp,boolean_t checkonly,cred_t * cr)149611042SErik.Nordmark@Sun.COM conn_opt_set_ipv6(conn_opt_arg_t *coa, t_scalar_t name, uint_t inlen,
149711042SErik.Nordmark@Sun.COM uchar_t *invalp, boolean_t checkonly, cred_t *cr)
149811042SErik.Nordmark@Sun.COM {
149911042SErik.Nordmark@Sun.COM conn_t *connp = coa->coa_connp;
150011042SErik.Nordmark@Sun.COM ip_xmit_attr_t *ixa = coa->coa_ixa;
150111042SErik.Nordmark@Sun.COM ip_pkt_t *ipp = coa->coa_ipp;
150211042SErik.Nordmark@Sun.COM int *i1 = (int *)invalp;
150311042SErik.Nordmark@Sun.COM boolean_t onoff = (*i1 == 0) ? 0 : 1;
150411042SErik.Nordmark@Sun.COM uint_t ifindex;
150511042SErik.Nordmark@Sun.COM zoneid_t zoneid = IPCL_ZONEID(connp);
150611042SErik.Nordmark@Sun.COM ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
150711042SErik.Nordmark@Sun.COM int error;
150811042SErik.Nordmark@Sun.COM
150911042SErik.Nordmark@Sun.COM if (connp->conn_family != AF_INET6)
151011042SErik.Nordmark@Sun.COM return (EINVAL);
151111042SErik.Nordmark@Sun.COM
151211042SErik.Nordmark@Sun.COM switch (name) {
151311042SErik.Nordmark@Sun.COM case IPV6_MULTICAST_IF:
151411042SErik.Nordmark@Sun.COM /*
151511042SErik.Nordmark@Sun.COM * The only possible error is EINVAL.
151611042SErik.Nordmark@Sun.COM * We call this option on both V4 and V6
151711042SErik.Nordmark@Sun.COM * If both fail, then this call returns
151811042SErik.Nordmark@Sun.COM * EINVAL. If at least one of them succeeds we
151911042SErik.Nordmark@Sun.COM * return success.
152011042SErik.Nordmark@Sun.COM */
152111042SErik.Nordmark@Sun.COM ifindex = *(uint_t *)i1;
152211042SErik.Nordmark@Sun.COM
152311430SErik.Nordmark@Sun.COM if (!ip_xmit_ifindex_valid(ifindex, zoneid, B_TRUE, ipst) &&
152411430SErik.Nordmark@Sun.COM !ip_xmit_ifindex_valid(ifindex, zoneid, B_FALSE, ipst))
152511042SErik.Nordmark@Sun.COM return (EINVAL);
152611042SErik.Nordmark@Sun.COM break;
152711042SErik.Nordmark@Sun.COM case IPV6_UNICAST_HOPS:
152811042SErik.Nordmark@Sun.COM /* Don't allow zero. -1 means to use default */
152911042SErik.Nordmark@Sun.COM if (*i1 < -1 || *i1 == 0 || *i1 > IPV6_MAX_HOPS)
153011042SErik.Nordmark@Sun.COM return (EINVAL);
153111042SErik.Nordmark@Sun.COM break;
153211042SErik.Nordmark@Sun.COM case IPV6_MULTICAST_HOPS:
153311042SErik.Nordmark@Sun.COM /* -1 means use default */
153411042SErik.Nordmark@Sun.COM if (*i1 < -1 || *i1 > IPV6_MAX_HOPS)
153511042SErik.Nordmark@Sun.COM return (EINVAL);
153611042SErik.Nordmark@Sun.COM break;
153711042SErik.Nordmark@Sun.COM case IPV6_MULTICAST_LOOP:
153811042SErik.Nordmark@Sun.COM if (*i1 != 0 && *i1 != 1)
153911042SErik.Nordmark@Sun.COM return (EINVAL);
154011042SErik.Nordmark@Sun.COM break;
154111042SErik.Nordmark@Sun.COM case IPV6_BOUND_IF:
154211042SErik.Nordmark@Sun.COM ifindex = *(uint_t *)i1;
154311042SErik.Nordmark@Sun.COM
154411430SErik.Nordmark@Sun.COM if (!ip_xmit_ifindex_valid(ifindex, zoneid, B_TRUE, ipst))
154511042SErik.Nordmark@Sun.COM return (ENXIO);
154611042SErik.Nordmark@Sun.COM break;
154711042SErik.Nordmark@Sun.COM case IPV6_PKTINFO: {
154811042SErik.Nordmark@Sun.COM struct in6_pktinfo *pkti;
154911042SErik.Nordmark@Sun.COM boolean_t isv6;
155011042SErik.Nordmark@Sun.COM
155111042SErik.Nordmark@Sun.COM if (inlen != 0 && inlen != sizeof (struct in6_pktinfo))
155211042SErik.Nordmark@Sun.COM return (EINVAL);
155311042SErik.Nordmark@Sun.COM if (inlen == 0)
155411042SErik.Nordmark@Sun.COM break; /* Clear values below */
155511042SErik.Nordmark@Sun.COM
155611042SErik.Nordmark@Sun.COM /*
155711042SErik.Nordmark@Sun.COM * Verify the source address and ifindex. Privileged users
155811042SErik.Nordmark@Sun.COM * can use any source address.
155911042SErik.Nordmark@Sun.COM */
156011042SErik.Nordmark@Sun.COM pkti = (struct in6_pktinfo *)invalp;
156111042SErik.Nordmark@Sun.COM
156211042SErik.Nordmark@Sun.COM /*
156311042SErik.Nordmark@Sun.COM * For link-local addresses we use the ipi6_ifindex when
156411042SErik.Nordmark@Sun.COM * we verify the local address.
156511042SErik.Nordmark@Sun.COM * If net_rawaccess then any source address can be used.
156611042SErik.Nordmark@Sun.COM */
156711042SErik.Nordmark@Sun.COM if (!IN6_IS_ADDR_UNSPECIFIED(&pkti->ipi6_addr) &&
156811042SErik.Nordmark@Sun.COM secpolicy_net_rawaccess(cr) != 0) {
156911042SErik.Nordmark@Sun.COM uint_t scopeid = 0;
157011042SErik.Nordmark@Sun.COM in6_addr_t *v6src = &pkti->ipi6_addr;
157111042SErik.Nordmark@Sun.COM ipaddr_t v4src;
157211042SErik.Nordmark@Sun.COM ip_laddr_t laddr_type = IPVL_UNICAST_UP;
157311042SErik.Nordmark@Sun.COM
157411042SErik.Nordmark@Sun.COM if (IN6_IS_ADDR_V4MAPPED(v6src)) {
157511042SErik.Nordmark@Sun.COM IN6_V4MAPPED_TO_IPADDR(v6src, v4src);
157611042SErik.Nordmark@Sun.COM if (v4src != INADDR_ANY) {
157711042SErik.Nordmark@Sun.COM laddr_type = ip_laddr_verify_v4(v4src,
157811042SErik.Nordmark@Sun.COM zoneid, ipst, B_FALSE);
157911042SErik.Nordmark@Sun.COM }
158011042SErik.Nordmark@Sun.COM } else {
158111042SErik.Nordmark@Sun.COM if (IN6_IS_ADDR_LINKSCOPE(v6src))
158211042SErik.Nordmark@Sun.COM scopeid = pkti->ipi6_ifindex;
158311042SErik.Nordmark@Sun.COM
158411042SErik.Nordmark@Sun.COM laddr_type = ip_laddr_verify_v6(v6src, zoneid,
158511042SErik.Nordmark@Sun.COM ipst, B_FALSE, scopeid);
158611042SErik.Nordmark@Sun.COM }
158711042SErik.Nordmark@Sun.COM switch (laddr_type) {
158811042SErik.Nordmark@Sun.COM case IPVL_UNICAST_UP:
158911042SErik.Nordmark@Sun.COM case IPVL_UNICAST_DOWN:
159011042SErik.Nordmark@Sun.COM break;
159111042SErik.Nordmark@Sun.COM default:
159211042SErik.Nordmark@Sun.COM return (EADDRNOTAVAIL);
159311042SErik.Nordmark@Sun.COM }
159411042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_VERIFY_SOURCE;
159511042SErik.Nordmark@Sun.COM } else if (!IN6_IS_ADDR_UNSPECIFIED(&pkti->ipi6_addr)) {
159611042SErik.Nordmark@Sun.COM /* Allow any source */
159711042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~IXAF_VERIFY_SOURCE;
159811042SErik.Nordmark@Sun.COM }
159911042SErik.Nordmark@Sun.COM isv6 = !(IN6_IS_ADDR_V4MAPPED(&pkti->ipi6_addr));
160011430SErik.Nordmark@Sun.COM if (!ip_xmit_ifindex_valid(pkti->ipi6_ifindex, zoneid, isv6,
160111430SErik.Nordmark@Sun.COM ipst))
160211042SErik.Nordmark@Sun.COM return (ENXIO);
160311042SErik.Nordmark@Sun.COM break;
160411042SErik.Nordmark@Sun.COM }
160511042SErik.Nordmark@Sun.COM case IPV6_HOPLIMIT:
160611042SErik.Nordmark@Sun.COM /* It is only allowed as ancilary data */
160711042SErik.Nordmark@Sun.COM if (!coa->coa_ancillary)
160811042SErik.Nordmark@Sun.COM return (EINVAL);
160911042SErik.Nordmark@Sun.COM
161011042SErik.Nordmark@Sun.COM if (inlen != 0 && inlen != sizeof (int))
161111042SErik.Nordmark@Sun.COM return (EINVAL);
161211042SErik.Nordmark@Sun.COM if (inlen == sizeof (int)) {
161311042SErik.Nordmark@Sun.COM if (*i1 > 255 || *i1 < -1 || *i1 == 0)
161411042SErik.Nordmark@Sun.COM return (EINVAL);
161511042SErik.Nordmark@Sun.COM }
161611042SErik.Nordmark@Sun.COM break;
161711042SErik.Nordmark@Sun.COM case IPV6_TCLASS:
161811042SErik.Nordmark@Sun.COM if (inlen != 0 && inlen != sizeof (int))
161911042SErik.Nordmark@Sun.COM return (EINVAL);
162011042SErik.Nordmark@Sun.COM if (inlen == sizeof (int)) {
162111042SErik.Nordmark@Sun.COM if (*i1 > 255 || *i1 < -1)
162211042SErik.Nordmark@Sun.COM return (EINVAL);
162311042SErik.Nordmark@Sun.COM }
162411042SErik.Nordmark@Sun.COM break;
162511042SErik.Nordmark@Sun.COM case IPV6_NEXTHOP:
162611042SErik.Nordmark@Sun.COM if (inlen != 0 && inlen != sizeof (sin6_t))
162711042SErik.Nordmark@Sun.COM return (EINVAL);
162811042SErik.Nordmark@Sun.COM if (inlen == sizeof (sin6_t)) {
162911042SErik.Nordmark@Sun.COM sin6_t *sin6 = (sin6_t *)invalp;
163011042SErik.Nordmark@Sun.COM ire_t *ire;
163111042SErik.Nordmark@Sun.COM
163211042SErik.Nordmark@Sun.COM if (sin6->sin6_family != AF_INET6)
163311042SErik.Nordmark@Sun.COM return (EAFNOSUPPORT);
163411042SErik.Nordmark@Sun.COM if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
163511042SErik.Nordmark@Sun.COM return (EADDRNOTAVAIL);
163611042SErik.Nordmark@Sun.COM
163711042SErik.Nordmark@Sun.COM /* Verify that the next-hop is on-link */
163811042SErik.Nordmark@Sun.COM ire = ire_ftable_lookup_v6(&sin6->sin6_addr,
163911042SErik.Nordmark@Sun.COM 0, 0, IRE_ONLINK, NULL, zoneid,
164011042SErik.Nordmark@Sun.COM NULL, MATCH_IRE_TYPE, 0, ipst, NULL);
164111042SErik.Nordmark@Sun.COM if (ire == NULL)
164211042SErik.Nordmark@Sun.COM return (EHOSTUNREACH);
164311042SErik.Nordmark@Sun.COM ire_refrele(ire);
164411042SErik.Nordmark@Sun.COM break;
164511042SErik.Nordmark@Sun.COM }
164611042SErik.Nordmark@Sun.COM break;
164711042SErik.Nordmark@Sun.COM case IPV6_RTHDR:
164811042SErik.Nordmark@Sun.COM case IPV6_DSTOPTS:
164911042SErik.Nordmark@Sun.COM case IPV6_RTHDRDSTOPTS:
165011042SErik.Nordmark@Sun.COM case IPV6_HOPOPTS: {
165111042SErik.Nordmark@Sun.COM /* All have the length field in the same place */
165211042SErik.Nordmark@Sun.COM ip6_hbh_t *hopts = (ip6_hbh_t *)invalp;
165311042SErik.Nordmark@Sun.COM /*
165411042SErik.Nordmark@Sun.COM * Sanity checks - minimum size, size a multiple of
165511042SErik.Nordmark@Sun.COM * eight bytes, and matching size passed in.
165611042SErik.Nordmark@Sun.COM */
165711042SErik.Nordmark@Sun.COM if (inlen != 0 &&
165811042SErik.Nordmark@Sun.COM inlen != (8 * (hopts->ip6h_len + 1)))
165911042SErik.Nordmark@Sun.COM return (EINVAL);
166011042SErik.Nordmark@Sun.COM break;
166111042SErik.Nordmark@Sun.COM }
166211042SErik.Nordmark@Sun.COM case IPV6_PATHMTU:
166311042SErik.Nordmark@Sun.COM /* Can't be set */
166411042SErik.Nordmark@Sun.COM return (EINVAL);
166511042SErik.Nordmark@Sun.COM
166611042SErik.Nordmark@Sun.COM case IPV6_USE_MIN_MTU:
166711042SErik.Nordmark@Sun.COM if (inlen != sizeof (int))
166811042SErik.Nordmark@Sun.COM return (EINVAL);
166911042SErik.Nordmark@Sun.COM if (*i1 < -1 || *i1 > 1)
167011042SErik.Nordmark@Sun.COM return (EINVAL);
167111042SErik.Nordmark@Sun.COM break;
167211042SErik.Nordmark@Sun.COM case IPV6_SRC_PREFERENCES:
167311042SErik.Nordmark@Sun.COM if (inlen != sizeof (uint32_t))
167411042SErik.Nordmark@Sun.COM return (EINVAL);
167511042SErik.Nordmark@Sun.COM break;
167611042SErik.Nordmark@Sun.COM case IPV6_V6ONLY:
167711042SErik.Nordmark@Sun.COM if (*i1 < 0 || *i1 > 1) {
167811042SErik.Nordmark@Sun.COM return (EINVAL);
167911042SErik.Nordmark@Sun.COM }
168011042SErik.Nordmark@Sun.COM break;
168111042SErik.Nordmark@Sun.COM }
168211042SErik.Nordmark@Sun.COM if (checkonly)
168311042SErik.Nordmark@Sun.COM return (0);
168411042SErik.Nordmark@Sun.COM
168511042SErik.Nordmark@Sun.COM /* Here we set the actual option value */
168611042SErik.Nordmark@Sun.COM /*
168711042SErik.Nordmark@Sun.COM * conn_lock protects the bitfields, and is used to
168811042SErik.Nordmark@Sun.COM * set the fields atomically. Not needed for ixa settings since
168911042SErik.Nordmark@Sun.COM * the caller has an exclusive copy of the ixa.
169011042SErik.Nordmark@Sun.COM * We can not hold conn_lock across the multicast options though.
169111042SErik.Nordmark@Sun.COM */
169211042SErik.Nordmark@Sun.COM ASSERT(MUTEX_NOT_HELD(&coa->coa_connp->conn_lock));
169311042SErik.Nordmark@Sun.COM switch (name) {
169411042SErik.Nordmark@Sun.COM case IPV6_MULTICAST_IF:
169511042SErik.Nordmark@Sun.COM ixa->ixa_multicast_ifindex = ifindex;
169611042SErik.Nordmark@Sun.COM /* Need to redo ip_attr_connect */
169711042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_ROUTE_CHANGED;
169811042SErik.Nordmark@Sun.COM break;
169911042SErik.Nordmark@Sun.COM case IPV6_UNICAST_HOPS:
170011042SErik.Nordmark@Sun.COM /* -1 means use default */
170111042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
170211042SErik.Nordmark@Sun.COM if (*i1 == -1) {
170311042SErik.Nordmark@Sun.COM ipp->ipp_unicast_hops = connp->conn_default_ttl;
170411042SErik.Nordmark@Sun.COM } else {
170511042SErik.Nordmark@Sun.COM ipp->ipp_unicast_hops = (uint8_t)*i1;
170611042SErik.Nordmark@Sun.COM }
170711042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
170811042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_HEADER_CHANGED;
170911042SErik.Nordmark@Sun.COM break;
171011042SErik.Nordmark@Sun.COM case IPV6_MULTICAST_HOPS:
171111042SErik.Nordmark@Sun.COM /* -1 means use default */
171211042SErik.Nordmark@Sun.COM if (*i1 == -1) {
171311042SErik.Nordmark@Sun.COM ixa->ixa_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
171411042SErik.Nordmark@Sun.COM } else {
171511042SErik.Nordmark@Sun.COM ixa->ixa_multicast_ttl = (uint8_t)*i1;
171611042SErik.Nordmark@Sun.COM }
171711042SErik.Nordmark@Sun.COM /* Handled automatically by ip_output */
171811042SErik.Nordmark@Sun.COM break;
171911042SErik.Nordmark@Sun.COM case IPV6_MULTICAST_LOOP:
172011042SErik.Nordmark@Sun.COM if (*i1 != 0)
172111042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_MULTICAST_LOOP;
172211042SErik.Nordmark@Sun.COM else
172311042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~IXAF_MULTICAST_LOOP;
172411042SErik.Nordmark@Sun.COM /* Handled automatically by ip_output */
172511042SErik.Nordmark@Sun.COM break;
172611042SErik.Nordmark@Sun.COM case IPV6_JOIN_GROUP:
172711042SErik.Nordmark@Sun.COM case IPV6_LEAVE_GROUP:
172811042SErik.Nordmark@Sun.COM case MCAST_JOIN_GROUP:
172911042SErik.Nordmark@Sun.COM case MCAST_LEAVE_GROUP:
173011042SErik.Nordmark@Sun.COM return (ip_opt_set_multicast_group(connp, name,
173111042SErik.Nordmark@Sun.COM invalp, B_TRUE, checkonly));
173211042SErik.Nordmark@Sun.COM
173311042SErik.Nordmark@Sun.COM case MCAST_BLOCK_SOURCE:
173411042SErik.Nordmark@Sun.COM case MCAST_UNBLOCK_SOURCE:
173511042SErik.Nordmark@Sun.COM case MCAST_JOIN_SOURCE_GROUP:
173611042SErik.Nordmark@Sun.COM case MCAST_LEAVE_SOURCE_GROUP:
173711042SErik.Nordmark@Sun.COM return (ip_opt_set_multicast_sources(connp, name,
173811042SErik.Nordmark@Sun.COM invalp, B_TRUE, checkonly));
173911042SErik.Nordmark@Sun.COM
174011042SErik.Nordmark@Sun.COM case IPV6_BOUND_IF:
174111042SErik.Nordmark@Sun.COM ixa->ixa_ifindex = ifindex; /* Send */
174211042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
174311042SErik.Nordmark@Sun.COM connp->conn_incoming_ifindex = ifindex; /* Receive */
174411042SErik.Nordmark@Sun.COM connp->conn_bound_if = ifindex; /* getsockopt */
174511042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
174611042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_ROUTE_CHANGED;
174711042SErik.Nordmark@Sun.COM break;
174811042SErik.Nordmark@Sun.COM case IPV6_UNSPEC_SRC:
174911042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
175011042SErik.Nordmark@Sun.COM connp->conn_unspec_src = onoff;
175111042SErik.Nordmark@Sun.COM if (onoff)
175211042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~IXAF_VERIFY_SOURCE;
175311042SErik.Nordmark@Sun.COM else
175411042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_VERIFY_SOURCE;
175511042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
175611042SErik.Nordmark@Sun.COM break;
175711042SErik.Nordmark@Sun.COM case IPV6_RECVPKTINFO:
175811042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
175911042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_ip_recvpktinfo = onoff;
176011042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
176111042SErik.Nordmark@Sun.COM break;
176211042SErik.Nordmark@Sun.COM case IPV6_RECVTCLASS:
176311042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
176411042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_ipv6_recvtclass = onoff;
176511042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
176611042SErik.Nordmark@Sun.COM break;
176711042SErik.Nordmark@Sun.COM case IPV6_RECVPATHMTU:
176811042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
176911042SErik.Nordmark@Sun.COM connp->conn_ipv6_recvpathmtu = onoff;
177011042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
177111042SErik.Nordmark@Sun.COM break;
177211042SErik.Nordmark@Sun.COM case IPV6_RECVHOPLIMIT:
177311042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
177411042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_ipv6_recvhoplimit =
177511042SErik.Nordmark@Sun.COM onoff;
177611042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
177711042SErik.Nordmark@Sun.COM break;
177811042SErik.Nordmark@Sun.COM case IPV6_RECVHOPOPTS:
177911042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
178011042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_ipv6_recvhopopts = onoff;
178111042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
178211042SErik.Nordmark@Sun.COM break;
178311042SErik.Nordmark@Sun.COM case IPV6_RECVDSTOPTS:
178411042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
178511042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_ipv6_recvdstopts = onoff;
178611042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
178711042SErik.Nordmark@Sun.COM break;
178811042SErik.Nordmark@Sun.COM case _OLD_IPV6_RECVDSTOPTS:
178911042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
179011042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_old_ipv6_recvdstopts =
179111042SErik.Nordmark@Sun.COM onoff;
179211042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
179311042SErik.Nordmark@Sun.COM break;
179411042SErik.Nordmark@Sun.COM case IPV6_RECVRTHDRDSTOPTS:
179511042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
179611042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_ipv6_recvrthdrdstopts =
179711042SErik.Nordmark@Sun.COM onoff;
179811042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
179911042SErik.Nordmark@Sun.COM break;
180011042SErik.Nordmark@Sun.COM case IPV6_RECVRTHDR:
180111042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
180211042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_ipv6_recvrthdr = onoff;
180311042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
180411042SErik.Nordmark@Sun.COM break;
180511042SErik.Nordmark@Sun.COM case IPV6_PKTINFO:
180611042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
180711042SErik.Nordmark@Sun.COM if (inlen == 0) {
180811042SErik.Nordmark@Sun.COM ipp->ipp_fields &= ~IPPF_ADDR;
180911042SErik.Nordmark@Sun.COM ipp->ipp_addr = ipv6_all_zeros;
181011042SErik.Nordmark@Sun.COM ixa->ixa_ifindex = 0;
181111042SErik.Nordmark@Sun.COM } else {
181211042SErik.Nordmark@Sun.COM struct in6_pktinfo *pkti;
181311042SErik.Nordmark@Sun.COM
181411042SErik.Nordmark@Sun.COM pkti = (struct in6_pktinfo *)invalp;
181511042SErik.Nordmark@Sun.COM ipp->ipp_addr = pkti->ipi6_addr;
181611042SErik.Nordmark@Sun.COM if (!IN6_IS_ADDR_UNSPECIFIED(&ipp->ipp_addr))
181711042SErik.Nordmark@Sun.COM ipp->ipp_fields |= IPPF_ADDR;
181811042SErik.Nordmark@Sun.COM else
181911042SErik.Nordmark@Sun.COM ipp->ipp_fields &= ~IPPF_ADDR;
182011042SErik.Nordmark@Sun.COM ixa->ixa_ifindex = pkti->ipi6_ifindex;
182111042SErik.Nordmark@Sun.COM }
182211042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
182311042SErik.Nordmark@Sun.COM /* Source and ifindex might have changed */
182411042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_HEADER_CHANGED;
182511042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_ROUTE_CHANGED;
182611042SErik.Nordmark@Sun.COM break;
182711042SErik.Nordmark@Sun.COM case IPV6_HOPLIMIT:
182811042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
182911042SErik.Nordmark@Sun.COM if (inlen == 0 || *i1 == -1) {
183011042SErik.Nordmark@Sun.COM /* Revert to default */
183111042SErik.Nordmark@Sun.COM ipp->ipp_fields &= ~IPPF_HOPLIMIT;
183211042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~IXAF_NO_TTL_CHANGE;
183311042SErik.Nordmark@Sun.COM } else {
183411042SErik.Nordmark@Sun.COM ipp->ipp_hoplimit = *i1;
183511042SErik.Nordmark@Sun.COM ipp->ipp_fields |= IPPF_HOPLIMIT;
183611042SErik.Nordmark@Sun.COM /* Ensure that it sticks for multicast packets */
183711042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_NO_TTL_CHANGE;
183811042SErik.Nordmark@Sun.COM }
183911042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
184011042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_HEADER_CHANGED;
184111042SErik.Nordmark@Sun.COM break;
184211042SErik.Nordmark@Sun.COM case IPV6_TCLASS:
184311042SErik.Nordmark@Sun.COM /*
184411042SErik.Nordmark@Sun.COM * IPV6_TCLASS accepts -1 as use kernel default
184511042SErik.Nordmark@Sun.COM * and [0, 255] as the actualy traffic class.
184611042SErik.Nordmark@Sun.COM */
184711042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
184811042SErik.Nordmark@Sun.COM if (inlen == 0 || *i1 == -1) {
184911042SErik.Nordmark@Sun.COM ipp->ipp_tclass = 0;
185011042SErik.Nordmark@Sun.COM ipp->ipp_fields &= ~IPPF_TCLASS;
185111042SErik.Nordmark@Sun.COM } else {
185211042SErik.Nordmark@Sun.COM ipp->ipp_tclass = *i1;
185311042SErik.Nordmark@Sun.COM ipp->ipp_fields |= IPPF_TCLASS;
185411042SErik.Nordmark@Sun.COM }
185511042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
185611042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_HEADER_CHANGED;
185711042SErik.Nordmark@Sun.COM break;
185811042SErik.Nordmark@Sun.COM case IPV6_NEXTHOP:
185911042SErik.Nordmark@Sun.COM if (inlen == 0) {
186011042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~IXAF_NEXTHOP_SET;
186111042SErik.Nordmark@Sun.COM } else {
186211042SErik.Nordmark@Sun.COM sin6_t *sin6 = (sin6_t *)invalp;
186311042SErik.Nordmark@Sun.COM
186411042SErik.Nordmark@Sun.COM ixa->ixa_nexthop_v6 = sin6->sin6_addr;
186511042SErik.Nordmark@Sun.COM if (!IN6_IS_ADDR_UNSPECIFIED(&ixa->ixa_nexthop_v6))
186611042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_NEXTHOP_SET;
186711042SErik.Nordmark@Sun.COM else
186811042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~IXAF_NEXTHOP_SET;
186911042SErik.Nordmark@Sun.COM }
187011042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_ROUTE_CHANGED;
187111042SErik.Nordmark@Sun.COM break;
187211042SErik.Nordmark@Sun.COM case IPV6_HOPOPTS:
187311042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
187411042SErik.Nordmark@Sun.COM error = optcom_pkt_set(invalp, inlen,
187511042SErik.Nordmark@Sun.COM (uchar_t **)&ipp->ipp_hopopts, &ipp->ipp_hopoptslen);
187611042SErik.Nordmark@Sun.COM if (error != 0) {
187711042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
187811042SErik.Nordmark@Sun.COM return (error);
187911042SErik.Nordmark@Sun.COM }
188011042SErik.Nordmark@Sun.COM if (ipp->ipp_hopoptslen == 0) {
188111042SErik.Nordmark@Sun.COM ipp->ipp_fields &= ~IPPF_HOPOPTS;
188211042SErik.Nordmark@Sun.COM } else {
188311042SErik.Nordmark@Sun.COM ipp->ipp_fields |= IPPF_HOPOPTS;
188411042SErik.Nordmark@Sun.COM }
188511042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
188611042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_HEADER_CHANGED;
188711042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_WROFF_CHANGED;
188811042SErik.Nordmark@Sun.COM break;
188911042SErik.Nordmark@Sun.COM case IPV6_RTHDRDSTOPTS:
189011042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
189111042SErik.Nordmark@Sun.COM error = optcom_pkt_set(invalp, inlen,
189211042SErik.Nordmark@Sun.COM (uchar_t **)&ipp->ipp_rthdrdstopts,
189311042SErik.Nordmark@Sun.COM &ipp->ipp_rthdrdstoptslen);
189411042SErik.Nordmark@Sun.COM if (error != 0) {
189511042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
189611042SErik.Nordmark@Sun.COM return (error);
189711042SErik.Nordmark@Sun.COM }
189811042SErik.Nordmark@Sun.COM if (ipp->ipp_rthdrdstoptslen == 0) {
189911042SErik.Nordmark@Sun.COM ipp->ipp_fields &= ~IPPF_RTHDRDSTOPTS;
190011042SErik.Nordmark@Sun.COM } else {
190111042SErik.Nordmark@Sun.COM ipp->ipp_fields |= IPPF_RTHDRDSTOPTS;
190211042SErik.Nordmark@Sun.COM }
190311042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
190411042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_HEADER_CHANGED;
190511042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_WROFF_CHANGED;
190611042SErik.Nordmark@Sun.COM break;
190711042SErik.Nordmark@Sun.COM case IPV6_DSTOPTS:
190811042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
190911042SErik.Nordmark@Sun.COM error = optcom_pkt_set(invalp, inlen,
191011042SErik.Nordmark@Sun.COM (uchar_t **)&ipp->ipp_dstopts, &ipp->ipp_dstoptslen);
191111042SErik.Nordmark@Sun.COM if (error != 0) {
191211042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
191311042SErik.Nordmark@Sun.COM return (error);
191411042SErik.Nordmark@Sun.COM }
191511042SErik.Nordmark@Sun.COM if (ipp->ipp_dstoptslen == 0) {
191611042SErik.Nordmark@Sun.COM ipp->ipp_fields &= ~IPPF_DSTOPTS;
191711042SErik.Nordmark@Sun.COM } else {
191811042SErik.Nordmark@Sun.COM ipp->ipp_fields |= IPPF_DSTOPTS;
191911042SErik.Nordmark@Sun.COM }
192011042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
192111042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_HEADER_CHANGED;
192211042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_WROFF_CHANGED;
192311042SErik.Nordmark@Sun.COM break;
192411042SErik.Nordmark@Sun.COM case IPV6_RTHDR:
192511042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
192611042SErik.Nordmark@Sun.COM error = optcom_pkt_set(invalp, inlen,
192711042SErik.Nordmark@Sun.COM (uchar_t **)&ipp->ipp_rthdr, &ipp->ipp_rthdrlen);
192811042SErik.Nordmark@Sun.COM if (error != 0) {
192911042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
193011042SErik.Nordmark@Sun.COM return (error);
193111042SErik.Nordmark@Sun.COM }
193211042SErik.Nordmark@Sun.COM if (ipp->ipp_rthdrlen == 0) {
193311042SErik.Nordmark@Sun.COM ipp->ipp_fields &= ~IPPF_RTHDR;
193411042SErik.Nordmark@Sun.COM } else {
193511042SErik.Nordmark@Sun.COM ipp->ipp_fields |= IPPF_RTHDR;
193611042SErik.Nordmark@Sun.COM }
193711042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
193811042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_HEADER_CHANGED;
193911042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_WROFF_CHANGED;
194011042SErik.Nordmark@Sun.COM break;
194111042SErik.Nordmark@Sun.COM
194211042SErik.Nordmark@Sun.COM case IPV6_DONTFRAG:
194311042SErik.Nordmark@Sun.COM if (onoff) {
194411042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_DONTFRAG;
194511042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~IXAF_PMTU_DISCOVERY;
194611042SErik.Nordmark@Sun.COM } else {
194711042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~IXAF_DONTFRAG;
194811042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_PMTU_DISCOVERY;
194911042SErik.Nordmark@Sun.COM }
195011042SErik.Nordmark@Sun.COM /* Need to redo ip_attr_connect */
195111042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_ROUTE_CHANGED;
195211042SErik.Nordmark@Sun.COM break;
195311042SErik.Nordmark@Sun.COM
195411042SErik.Nordmark@Sun.COM case IPV6_USE_MIN_MTU:
195511042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_USE_MIN_MTU;
195611042SErik.Nordmark@Sun.COM ixa->ixa_use_min_mtu = *i1;
195711042SErik.Nordmark@Sun.COM /* Need to redo ip_attr_connect */
195811042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_ROUTE_CHANGED;
195911042SErik.Nordmark@Sun.COM break;
196011042SErik.Nordmark@Sun.COM
196111042SErik.Nordmark@Sun.COM case IPV6_SEC_OPT:
196211042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
196311042SErik.Nordmark@Sun.COM error = ipsec_set_req(cr, connp, (ipsec_req_t *)invalp);
196411042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
196511042SErik.Nordmark@Sun.COM if (error != 0) {
196611042SErik.Nordmark@Sun.COM return (error);
196711042SErik.Nordmark@Sun.COM }
196811042SErik.Nordmark@Sun.COM /* This is an IPsec policy change - redo ip_attr_connect */
196911042SErik.Nordmark@Sun.COM coa->coa_changed |= COA_ROUTE_CHANGED;
197011042SErik.Nordmark@Sun.COM break;
197111042SErik.Nordmark@Sun.COM case IPV6_SRC_PREFERENCES:
197211042SErik.Nordmark@Sun.COM /*
197311042SErik.Nordmark@Sun.COM * This socket option only affects connected
197411042SErik.Nordmark@Sun.COM * sockets that haven't already bound to a specific
197511042SErik.Nordmark@Sun.COM * IPv6 address. In other words, sockets that
197611042SErik.Nordmark@Sun.COM * don't call bind() with an address other than the
197711042SErik.Nordmark@Sun.COM * unspecified address and that call connect().
197811042SErik.Nordmark@Sun.COM * ip_set_destination_v6() passes these preferences
197911042SErik.Nordmark@Sun.COM * to the ipif_select_source_v6() function.
198011042SErik.Nordmark@Sun.COM */
198111042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
198211042SErik.Nordmark@Sun.COM error = ip6_set_src_preferences(ixa, *(uint32_t *)invalp);
198311042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
198411042SErik.Nordmark@Sun.COM if (error != 0) {
198511042SErik.Nordmark@Sun.COM return (error);
198611042SErik.Nordmark@Sun.COM }
198711042SErik.Nordmark@Sun.COM break;
198811042SErik.Nordmark@Sun.COM case IPV6_V6ONLY:
198911042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
199011042SErik.Nordmark@Sun.COM connp->conn_ipv6_v6only = onoff;
199111042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
199211042SErik.Nordmark@Sun.COM break;
199311042SErik.Nordmark@Sun.COM }
199411042SErik.Nordmark@Sun.COM return (0);
199511042SErik.Nordmark@Sun.COM }
199611042SErik.Nordmark@Sun.COM
199711042SErik.Nordmark@Sun.COM /* Handle IPPROTO_UDP */
199811042SErik.Nordmark@Sun.COM /* ARGSUSED1 */
199911042SErik.Nordmark@Sun.COM static int
conn_opt_set_udp(conn_opt_arg_t * coa,t_scalar_t name,uint_t inlen,uchar_t * invalp,boolean_t checkonly,cred_t * cr)200011042SErik.Nordmark@Sun.COM conn_opt_set_udp(conn_opt_arg_t *coa, t_scalar_t name, uint_t inlen,
200111042SErik.Nordmark@Sun.COM uchar_t *invalp, boolean_t checkonly, cred_t *cr)
200211042SErik.Nordmark@Sun.COM {
200311042SErik.Nordmark@Sun.COM conn_t *connp = coa->coa_connp;
200411042SErik.Nordmark@Sun.COM int *i1 = (int *)invalp;
200511042SErik.Nordmark@Sun.COM boolean_t onoff = (*i1 == 0) ? 0 : 1;
200611042SErik.Nordmark@Sun.COM int error;
200711042SErik.Nordmark@Sun.COM
200811042SErik.Nordmark@Sun.COM switch (name) {
200911042SErik.Nordmark@Sun.COM case UDP_ANONPRIVBIND:
201011042SErik.Nordmark@Sun.COM if ((error = secpolicy_net_privaddr(cr, 0, IPPROTO_UDP)) != 0) {
201111042SErik.Nordmark@Sun.COM return (error);
201211042SErik.Nordmark@Sun.COM }
201311042SErik.Nordmark@Sun.COM break;
201411042SErik.Nordmark@Sun.COM }
201511042SErik.Nordmark@Sun.COM if (checkonly)
201611042SErik.Nordmark@Sun.COM return (0);
201711042SErik.Nordmark@Sun.COM
201811042SErik.Nordmark@Sun.COM /* Here we set the actual option value */
201911042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
202011042SErik.Nordmark@Sun.COM switch (name) {
202111042SErik.Nordmark@Sun.COM case UDP_ANONPRIVBIND:
202211042SErik.Nordmark@Sun.COM connp->conn_anon_priv_bind = onoff;
202311042SErik.Nordmark@Sun.COM break;
202411042SErik.Nordmark@Sun.COM case UDP_EXCLBIND:
202511042SErik.Nordmark@Sun.COM connp->conn_exclbind = onoff;
202611042SErik.Nordmark@Sun.COM break;
202711042SErik.Nordmark@Sun.COM }
202811042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
202911042SErik.Nordmark@Sun.COM return (0);
203011042SErik.Nordmark@Sun.COM }
203111042SErik.Nordmark@Sun.COM
203211042SErik.Nordmark@Sun.COM /* Handle IPPROTO_TCP */
203311042SErik.Nordmark@Sun.COM /* ARGSUSED1 */
203411042SErik.Nordmark@Sun.COM static int
conn_opt_set_tcp(conn_opt_arg_t * coa,t_scalar_t name,uint_t inlen,uchar_t * invalp,boolean_t checkonly,cred_t * cr)203511042SErik.Nordmark@Sun.COM conn_opt_set_tcp(conn_opt_arg_t *coa, t_scalar_t name, uint_t inlen,
203611042SErik.Nordmark@Sun.COM uchar_t *invalp, boolean_t checkonly, cred_t *cr)
203711042SErik.Nordmark@Sun.COM {
203811042SErik.Nordmark@Sun.COM conn_t *connp = coa->coa_connp;
203911042SErik.Nordmark@Sun.COM int *i1 = (int *)invalp;
204011042SErik.Nordmark@Sun.COM boolean_t onoff = (*i1 == 0) ? 0 : 1;
204111042SErik.Nordmark@Sun.COM int error;
204211042SErik.Nordmark@Sun.COM
204311042SErik.Nordmark@Sun.COM switch (name) {
204411042SErik.Nordmark@Sun.COM case TCP_ANONPRIVBIND:
204511042SErik.Nordmark@Sun.COM if ((error = secpolicy_net_privaddr(cr, 0, IPPROTO_TCP)) != 0) {
204611042SErik.Nordmark@Sun.COM return (error);
204711042SErik.Nordmark@Sun.COM }
204811042SErik.Nordmark@Sun.COM break;
204911042SErik.Nordmark@Sun.COM }
205011042SErik.Nordmark@Sun.COM if (checkonly)
205111042SErik.Nordmark@Sun.COM return (0);
205211042SErik.Nordmark@Sun.COM
205311042SErik.Nordmark@Sun.COM /* Here we set the actual option value */
205411042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
205511042SErik.Nordmark@Sun.COM switch (name) {
205611042SErik.Nordmark@Sun.COM case TCP_ANONPRIVBIND:
205711042SErik.Nordmark@Sun.COM connp->conn_anon_priv_bind = onoff;
205811042SErik.Nordmark@Sun.COM break;
205911042SErik.Nordmark@Sun.COM case TCP_EXCLBIND:
206011042SErik.Nordmark@Sun.COM connp->conn_exclbind = onoff;
206111042SErik.Nordmark@Sun.COM break;
206211042SErik.Nordmark@Sun.COM case TCP_RECVDSTADDR:
206311042SErik.Nordmark@Sun.COM connp->conn_recv_ancillary.crb_recvdstaddr = onoff;
206411042SErik.Nordmark@Sun.COM break;
206511042SErik.Nordmark@Sun.COM }
206611042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
206711042SErik.Nordmark@Sun.COM return (0);
206811042SErik.Nordmark@Sun.COM }
206911042SErik.Nordmark@Sun.COM
207011042SErik.Nordmark@Sun.COM int
conn_getsockname(conn_t * connp,struct sockaddr * sa,uint_t * salenp)207111042SErik.Nordmark@Sun.COM conn_getsockname(conn_t *connp, struct sockaddr *sa, uint_t *salenp)
207211042SErik.Nordmark@Sun.COM {
207311042SErik.Nordmark@Sun.COM sin_t *sin;
207411042SErik.Nordmark@Sun.COM sin6_t *sin6;
207511042SErik.Nordmark@Sun.COM
207611042SErik.Nordmark@Sun.COM if (connp->conn_family == AF_INET) {
207711042SErik.Nordmark@Sun.COM if (*salenp < sizeof (sin_t))
207811042SErik.Nordmark@Sun.COM return (EINVAL);
207911042SErik.Nordmark@Sun.COM
208011042SErik.Nordmark@Sun.COM *salenp = sizeof (sin_t);
208111042SErik.Nordmark@Sun.COM /* Fill zeroes and then initialize non-zero fields */
208211042SErik.Nordmark@Sun.COM sin = (sin_t *)sa;
208311042SErik.Nordmark@Sun.COM *sin = sin_null;
208411042SErik.Nordmark@Sun.COM sin->sin_family = AF_INET;
208511042SErik.Nordmark@Sun.COM if (!IN6_IS_ADDR_V4MAPPED_ANY(&connp->conn_saddr_v6) &&
208611042SErik.Nordmark@Sun.COM !IN6_IS_ADDR_UNSPECIFIED(&connp->conn_saddr_v6)) {
208711042SErik.Nordmark@Sun.COM sin->sin_addr.s_addr = connp->conn_saddr_v4;
208811042SErik.Nordmark@Sun.COM } else {
208911042SErik.Nordmark@Sun.COM /*
209011042SErik.Nordmark@Sun.COM * INADDR_ANY
209111042SErik.Nordmark@Sun.COM * conn_saddr is not set, we might be bound to
209211042SErik.Nordmark@Sun.COM * broadcast/multicast. Use conn_bound_addr as
209311042SErik.Nordmark@Sun.COM * local address instead (that could
209411042SErik.Nordmark@Sun.COM * also still be INADDR_ANY)
209511042SErik.Nordmark@Sun.COM */
209611042SErik.Nordmark@Sun.COM sin->sin_addr.s_addr = connp->conn_bound_addr_v4;
209711042SErik.Nordmark@Sun.COM }
209811042SErik.Nordmark@Sun.COM sin->sin_port = connp->conn_lport;
209911042SErik.Nordmark@Sun.COM } else {
210011042SErik.Nordmark@Sun.COM if (*salenp < sizeof (sin6_t))
210111042SErik.Nordmark@Sun.COM return (EINVAL);
210211042SErik.Nordmark@Sun.COM
210311042SErik.Nordmark@Sun.COM *salenp = sizeof (sin6_t);
210411042SErik.Nordmark@Sun.COM /* Fill zeroes and then initialize non-zero fields */
210511042SErik.Nordmark@Sun.COM sin6 = (sin6_t *)sa;
210611042SErik.Nordmark@Sun.COM *sin6 = sin6_null;
210711042SErik.Nordmark@Sun.COM sin6->sin6_family = AF_INET6;
210811042SErik.Nordmark@Sun.COM if (!IN6_IS_ADDR_UNSPECIFIED(&connp->conn_saddr_v6)) {
210911042SErik.Nordmark@Sun.COM sin6->sin6_addr = connp->conn_saddr_v6;
211011042SErik.Nordmark@Sun.COM } else {
211111042SErik.Nordmark@Sun.COM /*
211211042SErik.Nordmark@Sun.COM * conn_saddr is not set, we might be bound to
211311042SErik.Nordmark@Sun.COM * broadcast/multicast. Use conn_bound_addr as
211411042SErik.Nordmark@Sun.COM * local address instead (which could
211511042SErik.Nordmark@Sun.COM * also still be unspecified)
211611042SErik.Nordmark@Sun.COM */
211711042SErik.Nordmark@Sun.COM sin6->sin6_addr = connp->conn_bound_addr_v6;
211811042SErik.Nordmark@Sun.COM }
211911042SErik.Nordmark@Sun.COM sin6->sin6_port = connp->conn_lport;
212011042SErik.Nordmark@Sun.COM if (IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr) &&
212111042SErik.Nordmark@Sun.COM (connp->conn_ixa->ixa_flags & IXAF_SCOPEID_SET))
212211042SErik.Nordmark@Sun.COM sin6->sin6_scope_id = connp->conn_ixa->ixa_scopeid;
212311042SErik.Nordmark@Sun.COM }
212411042SErik.Nordmark@Sun.COM return (0);
212511042SErik.Nordmark@Sun.COM }
212611042SErik.Nordmark@Sun.COM
212711042SErik.Nordmark@Sun.COM int
conn_getpeername(conn_t * connp,struct sockaddr * sa,uint_t * salenp)212811042SErik.Nordmark@Sun.COM conn_getpeername(conn_t *connp, struct sockaddr *sa, uint_t *salenp)
212911042SErik.Nordmark@Sun.COM {
213011042SErik.Nordmark@Sun.COM struct sockaddr_in *sin;
213111042SErik.Nordmark@Sun.COM struct sockaddr_in6 *sin6;
213211042SErik.Nordmark@Sun.COM
213311042SErik.Nordmark@Sun.COM if (connp->conn_family == AF_INET) {
213411042SErik.Nordmark@Sun.COM if (*salenp < sizeof (sin_t))
213511042SErik.Nordmark@Sun.COM return (EINVAL);
213611042SErik.Nordmark@Sun.COM
213711042SErik.Nordmark@Sun.COM *salenp = sizeof (sin_t);
213811042SErik.Nordmark@Sun.COM /* initialize */
213911042SErik.Nordmark@Sun.COM sin = (sin_t *)sa;
214011042SErik.Nordmark@Sun.COM *sin = sin_null;
214111042SErik.Nordmark@Sun.COM sin->sin_family = AF_INET;
214211042SErik.Nordmark@Sun.COM sin->sin_addr.s_addr = connp->conn_faddr_v4;
214311042SErik.Nordmark@Sun.COM sin->sin_port = connp->conn_fport;
214411042SErik.Nordmark@Sun.COM } else {
214511042SErik.Nordmark@Sun.COM if (*salenp < sizeof (sin6_t))
214611042SErik.Nordmark@Sun.COM return (EINVAL);
214711042SErik.Nordmark@Sun.COM
214811042SErik.Nordmark@Sun.COM *salenp = sizeof (sin6_t);
214911042SErik.Nordmark@Sun.COM /* initialize */
215011042SErik.Nordmark@Sun.COM sin6 = (sin6_t *)sa;
215111042SErik.Nordmark@Sun.COM *sin6 = sin6_null;
215211042SErik.Nordmark@Sun.COM sin6->sin6_family = AF_INET6;
215311042SErik.Nordmark@Sun.COM sin6->sin6_addr = connp->conn_faddr_v6;
215411042SErik.Nordmark@Sun.COM sin6->sin6_port = connp->conn_fport;
215511042SErik.Nordmark@Sun.COM sin6->sin6_flowinfo = connp->conn_flowinfo;
215611042SErik.Nordmark@Sun.COM if (IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr) &&
215711042SErik.Nordmark@Sun.COM (connp->conn_ixa->ixa_flags & IXAF_SCOPEID_SET))
215811042SErik.Nordmark@Sun.COM sin6->sin6_scope_id = connp->conn_ixa->ixa_scopeid;
215911042SErik.Nordmark@Sun.COM }
216011042SErik.Nordmark@Sun.COM return (0);
216111042SErik.Nordmark@Sun.COM }
216211042SErik.Nordmark@Sun.COM
216311042SErik.Nordmark@Sun.COM static uint32_t cksum_massage_options_v4(ipha_t *, netstack_t *);
216411042SErik.Nordmark@Sun.COM static uint32_t cksum_massage_options_v6(ip6_t *, uint_t, netstack_t *);
216511042SErik.Nordmark@Sun.COM
216611042SErik.Nordmark@Sun.COM /*
216711042SErik.Nordmark@Sun.COM * Allocate and fill in conn_ht_iphc based on the current information
216811042SErik.Nordmark@Sun.COM * in the conn.
216911042SErik.Nordmark@Sun.COM * Normally used when we bind() and connect().
217011042SErik.Nordmark@Sun.COM * Returns failure if can't allocate memory, or if there is a problem
217111042SErik.Nordmark@Sun.COM * with a routing header/option.
217211042SErik.Nordmark@Sun.COM *
217311042SErik.Nordmark@Sun.COM * We allocate space for the transport header (ulp_hdr_len + extra) and
217411042SErik.Nordmark@Sun.COM * indicate the offset of the ulp header by setting ixa_ip_hdr_length.
217511042SErik.Nordmark@Sun.COM * The extra is there for transports that want some spare room for future
217611042SErik.Nordmark@Sun.COM * options. conn_ht_iphc_allocated is what was allocated; conn_ht_iphc_len
217711042SErik.Nordmark@Sun.COM * excludes the extra part.
217811042SErik.Nordmark@Sun.COM *
217911042SErik.Nordmark@Sun.COM * We massage an routing option/header and store the ckecksum difference
218011042SErik.Nordmark@Sun.COM * in conn_sum.
218111042SErik.Nordmark@Sun.COM *
218211042SErik.Nordmark@Sun.COM * Caller needs to update conn_wroff if desired.
218311042SErik.Nordmark@Sun.COM */
218411042SErik.Nordmark@Sun.COM int
conn_build_hdr_template(conn_t * connp,uint_t ulp_hdr_length,uint_t extra,const in6_addr_t * v6src,const in6_addr_t * v6dst,uint32_t flowinfo)218511042SErik.Nordmark@Sun.COM conn_build_hdr_template(conn_t *connp, uint_t ulp_hdr_length, uint_t extra,
218611042SErik.Nordmark@Sun.COM const in6_addr_t *v6src, const in6_addr_t *v6dst, uint32_t flowinfo)
218711042SErik.Nordmark@Sun.COM {
218811042SErik.Nordmark@Sun.COM ip_xmit_attr_t *ixa = connp->conn_ixa;
218911042SErik.Nordmark@Sun.COM ip_pkt_t *ipp = &connp->conn_xmit_ipp;
219011042SErik.Nordmark@Sun.COM uint_t ip_hdr_length;
219111042SErik.Nordmark@Sun.COM uchar_t *hdrs;
219211042SErik.Nordmark@Sun.COM uint_t hdrs_len;
219311042SErik.Nordmark@Sun.COM
219411042SErik.Nordmark@Sun.COM ASSERT(MUTEX_HELD(&connp->conn_lock));
219511042SErik.Nordmark@Sun.COM
219611042SErik.Nordmark@Sun.COM if (ixa->ixa_flags & IXAF_IS_IPV4) {
219711042SErik.Nordmark@Sun.COM ip_hdr_length = ip_total_hdrs_len_v4(ipp);
219811042SErik.Nordmark@Sun.COM /* In case of TX label and IP options it can be too much */
219911042SErik.Nordmark@Sun.COM if (ip_hdr_length > IP_MAX_HDR_LENGTH) {
220011042SErik.Nordmark@Sun.COM /* Preserves existing TX errno for this */
220111042SErik.Nordmark@Sun.COM return (EHOSTUNREACH);
220211042SErik.Nordmark@Sun.COM }
220311042SErik.Nordmark@Sun.COM } else {
220411042SErik.Nordmark@Sun.COM ip_hdr_length = ip_total_hdrs_len_v6(ipp);
220511042SErik.Nordmark@Sun.COM }
220611042SErik.Nordmark@Sun.COM ixa->ixa_ip_hdr_length = ip_hdr_length;
220711042SErik.Nordmark@Sun.COM hdrs_len = ip_hdr_length + ulp_hdr_length + extra;
220811042SErik.Nordmark@Sun.COM ASSERT(hdrs_len != 0);
220911042SErik.Nordmark@Sun.COM
221011042SErik.Nordmark@Sun.COM if (hdrs_len != connp->conn_ht_iphc_allocated) {
221111042SErik.Nordmark@Sun.COM /* Allocate new before we free any old */
221211042SErik.Nordmark@Sun.COM hdrs = kmem_alloc(hdrs_len, KM_NOSLEEP);
221311042SErik.Nordmark@Sun.COM if (hdrs == NULL)
221411042SErik.Nordmark@Sun.COM return (ENOMEM);
221511042SErik.Nordmark@Sun.COM
221611042SErik.Nordmark@Sun.COM if (connp->conn_ht_iphc != NULL) {
221711042SErik.Nordmark@Sun.COM kmem_free(connp->conn_ht_iphc,
221811042SErik.Nordmark@Sun.COM connp->conn_ht_iphc_allocated);
221911042SErik.Nordmark@Sun.COM }
222011042SErik.Nordmark@Sun.COM connp->conn_ht_iphc = hdrs;
222111042SErik.Nordmark@Sun.COM connp->conn_ht_iphc_allocated = hdrs_len;
222211042SErik.Nordmark@Sun.COM } else {
222311042SErik.Nordmark@Sun.COM hdrs = connp->conn_ht_iphc;
222411042SErik.Nordmark@Sun.COM }
222511042SErik.Nordmark@Sun.COM hdrs_len -= extra;
222611042SErik.Nordmark@Sun.COM connp->conn_ht_iphc_len = hdrs_len;
222711042SErik.Nordmark@Sun.COM
222811042SErik.Nordmark@Sun.COM connp->conn_ht_ulp = hdrs + ip_hdr_length;
222911042SErik.Nordmark@Sun.COM connp->conn_ht_ulp_len = ulp_hdr_length;
223011042SErik.Nordmark@Sun.COM
223111042SErik.Nordmark@Sun.COM if (ixa->ixa_flags & IXAF_IS_IPV4) {
223211042SErik.Nordmark@Sun.COM ipha_t *ipha = (ipha_t *)hdrs;
223311042SErik.Nordmark@Sun.COM
223411042SErik.Nordmark@Sun.COM IN6_V4MAPPED_TO_IPADDR(v6src, ipha->ipha_src);
223511042SErik.Nordmark@Sun.COM IN6_V4MAPPED_TO_IPADDR(v6dst, ipha->ipha_dst);
223611042SErik.Nordmark@Sun.COM ip_build_hdrs_v4(hdrs, ip_hdr_length, ipp, connp->conn_proto);
223711042SErik.Nordmark@Sun.COM ipha->ipha_length = htons(hdrs_len);
223811042SErik.Nordmark@Sun.COM if (ixa->ixa_flags & IXAF_PMTU_IPV4_DF)
223911042SErik.Nordmark@Sun.COM ipha->ipha_fragment_offset_and_flags |= IPH_DF_HTONS;
224011042SErik.Nordmark@Sun.COM else
224111042SErik.Nordmark@Sun.COM ipha->ipha_fragment_offset_and_flags &= ~IPH_DF_HTONS;
224211042SErik.Nordmark@Sun.COM
224311042SErik.Nordmark@Sun.COM if (ipp->ipp_fields & IPPF_IPV4_OPTIONS) {
224411042SErik.Nordmark@Sun.COM connp->conn_sum = cksum_massage_options_v4(ipha,
224511042SErik.Nordmark@Sun.COM connp->conn_netstack);
224611042SErik.Nordmark@Sun.COM } else {
224711042SErik.Nordmark@Sun.COM connp->conn_sum = 0;
224811042SErik.Nordmark@Sun.COM }
224911042SErik.Nordmark@Sun.COM } else {
225011042SErik.Nordmark@Sun.COM ip6_t *ip6h = (ip6_t *)hdrs;
225111042SErik.Nordmark@Sun.COM
225211042SErik.Nordmark@Sun.COM ip6h->ip6_src = *v6src;
225311042SErik.Nordmark@Sun.COM ip6h->ip6_dst = *v6dst;
225411042SErik.Nordmark@Sun.COM ip_build_hdrs_v6(hdrs, ip_hdr_length, ipp, connp->conn_proto,
225511042SErik.Nordmark@Sun.COM flowinfo);
225611042SErik.Nordmark@Sun.COM ip6h->ip6_plen = htons(hdrs_len - IPV6_HDR_LEN);
225711042SErik.Nordmark@Sun.COM
225811042SErik.Nordmark@Sun.COM if (ipp->ipp_fields & IPPF_RTHDR) {
225911042SErik.Nordmark@Sun.COM connp->conn_sum = cksum_massage_options_v6(ip6h,
226011042SErik.Nordmark@Sun.COM ip_hdr_length, connp->conn_netstack);
226111042SErik.Nordmark@Sun.COM
226211042SErik.Nordmark@Sun.COM /*
226311042SErik.Nordmark@Sun.COM * Verify that the first hop isn't a mapped address.
226411042SErik.Nordmark@Sun.COM * Routers along the path need to do this verification
226511042SErik.Nordmark@Sun.COM * for subsequent hops.
226611042SErik.Nordmark@Sun.COM */
226711042SErik.Nordmark@Sun.COM if (IN6_IS_ADDR_V4MAPPED(&ip6h->ip6_dst))
226811042SErik.Nordmark@Sun.COM return (EADDRNOTAVAIL);
226911042SErik.Nordmark@Sun.COM
227011042SErik.Nordmark@Sun.COM } else {
227111042SErik.Nordmark@Sun.COM connp->conn_sum = 0;
227211042SErik.Nordmark@Sun.COM }
227311042SErik.Nordmark@Sun.COM }
227411042SErik.Nordmark@Sun.COM return (0);
227511042SErik.Nordmark@Sun.COM }
227611042SErik.Nordmark@Sun.COM
227711042SErik.Nordmark@Sun.COM /*
227811042SErik.Nordmark@Sun.COM * Prepend a header template to data_mp based on the ip_pkt_t
227911042SErik.Nordmark@Sun.COM * and the passed in source, destination and protocol.
228011042SErik.Nordmark@Sun.COM *
228111042SErik.Nordmark@Sun.COM * Returns failure if can't allocate memory, in which case data_mp is freed.
228211042SErik.Nordmark@Sun.COM * We allocate space for the transport header (ulp_hdr_len) and
228311042SErik.Nordmark@Sun.COM * indicate the offset of the ulp header by setting ixa_ip_hdr_length.
228411042SErik.Nordmark@Sun.COM *
228511042SErik.Nordmark@Sun.COM * We massage an routing option/header and return the ckecksum difference
228611042SErik.Nordmark@Sun.COM * in *sump. This is in host byte order.
228711042SErik.Nordmark@Sun.COM *
228811042SErik.Nordmark@Sun.COM * Caller needs to update conn_wroff if desired.
228911042SErik.Nordmark@Sun.COM */
229011042SErik.Nordmark@Sun.COM mblk_t *
conn_prepend_hdr(ip_xmit_attr_t * ixa,const ip_pkt_t * ipp,const in6_addr_t * v6src,const in6_addr_t * v6dst,uint8_t protocol,uint32_t flowinfo,uint_t ulp_hdr_length,mblk_t * data_mp,uint_t data_length,uint_t wroff_extra,uint32_t * sump,int * errorp)229111042SErik.Nordmark@Sun.COM conn_prepend_hdr(ip_xmit_attr_t *ixa, const ip_pkt_t *ipp,
229211042SErik.Nordmark@Sun.COM const in6_addr_t *v6src, const in6_addr_t *v6dst,
229311042SErik.Nordmark@Sun.COM uint8_t protocol, uint32_t flowinfo, uint_t ulp_hdr_length, mblk_t *data_mp,
229411042SErik.Nordmark@Sun.COM uint_t data_length, uint_t wroff_extra, uint32_t *sump, int *errorp)
229511042SErik.Nordmark@Sun.COM {
229611042SErik.Nordmark@Sun.COM uint_t ip_hdr_length;
229711042SErik.Nordmark@Sun.COM uchar_t *hdrs;
229811042SErik.Nordmark@Sun.COM uint_t hdrs_len;
229911042SErik.Nordmark@Sun.COM mblk_t *mp;
230011042SErik.Nordmark@Sun.COM
230111042SErik.Nordmark@Sun.COM if (ixa->ixa_flags & IXAF_IS_IPV4) {
230211042SErik.Nordmark@Sun.COM ip_hdr_length = ip_total_hdrs_len_v4(ipp);
230311042SErik.Nordmark@Sun.COM ASSERT(ip_hdr_length <= IP_MAX_HDR_LENGTH);
230411042SErik.Nordmark@Sun.COM } else {
230511042SErik.Nordmark@Sun.COM ip_hdr_length = ip_total_hdrs_len_v6(ipp);
230611042SErik.Nordmark@Sun.COM }
230711042SErik.Nordmark@Sun.COM hdrs_len = ip_hdr_length + ulp_hdr_length;
230811042SErik.Nordmark@Sun.COM ASSERT(hdrs_len != 0);
230911042SErik.Nordmark@Sun.COM
231011042SErik.Nordmark@Sun.COM ixa->ixa_ip_hdr_length = ip_hdr_length;
231111042SErik.Nordmark@Sun.COM
231211042SErik.Nordmark@Sun.COM /* Can we prepend to data_mp? */
231311042SErik.Nordmark@Sun.COM if (data_mp != NULL &&
231411042SErik.Nordmark@Sun.COM data_mp->b_rptr - data_mp->b_datap->db_base >= hdrs_len &&
231511042SErik.Nordmark@Sun.COM data_mp->b_datap->db_ref == 1) {
231611042SErik.Nordmark@Sun.COM hdrs = data_mp->b_rptr - hdrs_len;
231711042SErik.Nordmark@Sun.COM data_mp->b_rptr = hdrs;
231811042SErik.Nordmark@Sun.COM mp = data_mp;
231911042SErik.Nordmark@Sun.COM } else {
232011042SErik.Nordmark@Sun.COM mp = allocb(hdrs_len + wroff_extra, BPRI_MED);
232111042SErik.Nordmark@Sun.COM if (mp == NULL) {
232211042SErik.Nordmark@Sun.COM freemsg(data_mp);
232311042SErik.Nordmark@Sun.COM *errorp = ENOMEM;
232411042SErik.Nordmark@Sun.COM return (NULL);
232511042SErik.Nordmark@Sun.COM }
232611042SErik.Nordmark@Sun.COM mp->b_wptr = mp->b_datap->db_lim;
232711042SErik.Nordmark@Sun.COM hdrs = mp->b_rptr = mp->b_wptr - hdrs_len;
232811042SErik.Nordmark@Sun.COM mp->b_cont = data_mp;
232911042SErik.Nordmark@Sun.COM }
233011042SErik.Nordmark@Sun.COM
233111042SErik.Nordmark@Sun.COM /*
233211042SErik.Nordmark@Sun.COM * Set the source in the header. ip_build_hdrs_v4/v6 will overwrite it
233311042SErik.Nordmark@Sun.COM * if PKTINFO (aka IPPF_ADDR) was set.
233411042SErik.Nordmark@Sun.COM */
233511042SErik.Nordmark@Sun.COM if (ixa->ixa_flags & IXAF_IS_IPV4) {
233611042SErik.Nordmark@Sun.COM ipha_t *ipha = (ipha_t *)hdrs;
233711042SErik.Nordmark@Sun.COM
233811042SErik.Nordmark@Sun.COM ASSERT(IN6_IS_ADDR_V4MAPPED(v6dst));
233911042SErik.Nordmark@Sun.COM IN6_V4MAPPED_TO_IPADDR(v6src, ipha->ipha_src);
234011042SErik.Nordmark@Sun.COM IN6_V4MAPPED_TO_IPADDR(v6dst, ipha->ipha_dst);
234111042SErik.Nordmark@Sun.COM ip_build_hdrs_v4(hdrs, ip_hdr_length, ipp, protocol);
234211042SErik.Nordmark@Sun.COM ipha->ipha_length = htons(hdrs_len + data_length);
234311042SErik.Nordmark@Sun.COM if (ixa->ixa_flags & IXAF_PMTU_IPV4_DF)
234411042SErik.Nordmark@Sun.COM ipha->ipha_fragment_offset_and_flags |= IPH_DF_HTONS;
234511042SErik.Nordmark@Sun.COM else
234611042SErik.Nordmark@Sun.COM ipha->ipha_fragment_offset_and_flags &= ~IPH_DF_HTONS;
234711042SErik.Nordmark@Sun.COM
234811042SErik.Nordmark@Sun.COM if (ipp->ipp_fields & IPPF_IPV4_OPTIONS) {
234911042SErik.Nordmark@Sun.COM *sump = cksum_massage_options_v4(ipha,
235011042SErik.Nordmark@Sun.COM ixa->ixa_ipst->ips_netstack);
235111042SErik.Nordmark@Sun.COM } else {
235211042SErik.Nordmark@Sun.COM *sump = 0;
235311042SErik.Nordmark@Sun.COM }
235411042SErik.Nordmark@Sun.COM } else {
235511042SErik.Nordmark@Sun.COM ip6_t *ip6h = (ip6_t *)hdrs;
235611042SErik.Nordmark@Sun.COM
235711042SErik.Nordmark@Sun.COM ip6h->ip6_src = *v6src;
235811042SErik.Nordmark@Sun.COM ip6h->ip6_dst = *v6dst;
235911042SErik.Nordmark@Sun.COM ip_build_hdrs_v6(hdrs, ip_hdr_length, ipp, protocol, flowinfo);
236011042SErik.Nordmark@Sun.COM ip6h->ip6_plen = htons(hdrs_len + data_length - IPV6_HDR_LEN);
236111042SErik.Nordmark@Sun.COM
236211042SErik.Nordmark@Sun.COM if (ipp->ipp_fields & IPPF_RTHDR) {
236311042SErik.Nordmark@Sun.COM *sump = cksum_massage_options_v6(ip6h,
236411042SErik.Nordmark@Sun.COM ip_hdr_length, ixa->ixa_ipst->ips_netstack);
236511042SErik.Nordmark@Sun.COM
236611042SErik.Nordmark@Sun.COM /*
236711042SErik.Nordmark@Sun.COM * Verify that the first hop isn't a mapped address.
236811042SErik.Nordmark@Sun.COM * Routers along the path need to do this verification
236911042SErik.Nordmark@Sun.COM * for subsequent hops.
237011042SErik.Nordmark@Sun.COM */
237111042SErik.Nordmark@Sun.COM if (IN6_IS_ADDR_V4MAPPED(&ip6h->ip6_dst)) {
237211042SErik.Nordmark@Sun.COM *errorp = EADDRNOTAVAIL;
237311042SErik.Nordmark@Sun.COM freemsg(mp);
237411042SErik.Nordmark@Sun.COM return (NULL);
237511042SErik.Nordmark@Sun.COM }
237611042SErik.Nordmark@Sun.COM } else {
237711042SErik.Nordmark@Sun.COM *sump = 0;
237811042SErik.Nordmark@Sun.COM }
237911042SErik.Nordmark@Sun.COM }
238011042SErik.Nordmark@Sun.COM return (mp);
238111042SErik.Nordmark@Sun.COM }
238211042SErik.Nordmark@Sun.COM
238311042SErik.Nordmark@Sun.COM /*
238411042SErik.Nordmark@Sun.COM * Massage a source route if any putting the first hop
238511042SErik.Nordmark@Sun.COM * in ipha_dst. Compute a starting value for the checksum which
238611042SErik.Nordmark@Sun.COM * takes into account that the original ipha_dst should be
238711042SErik.Nordmark@Sun.COM * included in the checksum but that IP will include the
238811042SErik.Nordmark@Sun.COM * first hop from the source route in the tcp checksum.
238911042SErik.Nordmark@Sun.COM */
239011042SErik.Nordmark@Sun.COM static uint32_t
cksum_massage_options_v4(ipha_t * ipha,netstack_t * ns)239111042SErik.Nordmark@Sun.COM cksum_massage_options_v4(ipha_t *ipha, netstack_t *ns)
239211042SErik.Nordmark@Sun.COM {
239311042SErik.Nordmark@Sun.COM in_addr_t dst;
239411042SErik.Nordmark@Sun.COM uint32_t cksum;
239511042SErik.Nordmark@Sun.COM
239611042SErik.Nordmark@Sun.COM /* Get last hop then diff against first hop */
239711042SErik.Nordmark@Sun.COM cksum = ip_massage_options(ipha, ns);
239811042SErik.Nordmark@Sun.COM cksum = (cksum & 0xFFFF) + (cksum >> 16);
239911042SErik.Nordmark@Sun.COM dst = ipha->ipha_dst;
240011042SErik.Nordmark@Sun.COM cksum -= ((dst >> 16) + (dst & 0xffff));
240111042SErik.Nordmark@Sun.COM if ((int)cksum < 0)
240211042SErik.Nordmark@Sun.COM cksum--;
240311042SErik.Nordmark@Sun.COM cksum = (cksum & 0xFFFF) + (cksum >> 16);
240411042SErik.Nordmark@Sun.COM cksum = (cksum & 0xFFFF) + (cksum >> 16);
240511042SErik.Nordmark@Sun.COM ASSERT(cksum < 0x10000);
240611042SErik.Nordmark@Sun.COM return (ntohs(cksum));
240711042SErik.Nordmark@Sun.COM }
240811042SErik.Nordmark@Sun.COM
240911042SErik.Nordmark@Sun.COM static uint32_t
cksum_massage_options_v6(ip6_t * ip6h,uint_t ip_hdr_len,netstack_t * ns)241011042SErik.Nordmark@Sun.COM cksum_massage_options_v6(ip6_t *ip6h, uint_t ip_hdr_len, netstack_t *ns)
241111042SErik.Nordmark@Sun.COM {
241211042SErik.Nordmark@Sun.COM uint8_t *end;
241311042SErik.Nordmark@Sun.COM ip6_rthdr_t *rth;
241411042SErik.Nordmark@Sun.COM uint32_t cksum;
241511042SErik.Nordmark@Sun.COM
241611042SErik.Nordmark@Sun.COM end = (uint8_t *)ip6h + ip_hdr_len;
241711042SErik.Nordmark@Sun.COM rth = ip_find_rthdr_v6(ip6h, end);
241811042SErik.Nordmark@Sun.COM if (rth == NULL)
241911042SErik.Nordmark@Sun.COM return (0);
242011042SErik.Nordmark@Sun.COM
242111042SErik.Nordmark@Sun.COM cksum = ip_massage_options_v6(ip6h, rth, ns);
242211042SErik.Nordmark@Sun.COM cksum = (cksum & 0xFFFF) + (cksum >> 16);
242311042SErik.Nordmark@Sun.COM ASSERT(cksum < 0x10000);
242411042SErik.Nordmark@Sun.COM return (ntohs(cksum));
242511042SErik.Nordmark@Sun.COM }
242611042SErik.Nordmark@Sun.COM
242711042SErik.Nordmark@Sun.COM /*
242811042SErik.Nordmark@Sun.COM * ULPs that change the destination address need to call this for each
242911042SErik.Nordmark@Sun.COM * change to discard any state about a previous destination that might
243011042SErik.Nordmark@Sun.COM * have been multicast or multirt.
243111042SErik.Nordmark@Sun.COM */
243211042SErik.Nordmark@Sun.COM void
ip_attr_newdst(ip_xmit_attr_t * ixa)243311042SErik.Nordmark@Sun.COM ip_attr_newdst(ip_xmit_attr_t *ixa)
243411042SErik.Nordmark@Sun.COM {
243511042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~(IXAF_LOOPBACK_COPY | IXAF_NO_HW_CKSUM |
243611042SErik.Nordmark@Sun.COM IXAF_NO_TTL_CHANGE | IXAF_IPV6_ADD_FRAGHDR |
243711042SErik.Nordmark@Sun.COM IXAF_NO_LOOP_ZONEID_SET);
243811042SErik.Nordmark@Sun.COM }
243911042SErik.Nordmark@Sun.COM
244011042SErik.Nordmark@Sun.COM /*
244111042SErik.Nordmark@Sun.COM * Determine the nexthop which will be used.
244211042SErik.Nordmark@Sun.COM * Normally this is just the destination, but if a IPv4 source route, or
244311042SErik.Nordmark@Sun.COM * IPv6 routing header, is in the ip_pkt_t then we extract the nexthop from
244411042SErik.Nordmark@Sun.COM * there.
244511042SErik.Nordmark@Sun.COM */
244611042SErik.Nordmark@Sun.COM void
ip_attr_nexthop(const ip_pkt_t * ipp,const ip_xmit_attr_t * ixa,const in6_addr_t * dst,in6_addr_t * nexthop)244711042SErik.Nordmark@Sun.COM ip_attr_nexthop(const ip_pkt_t *ipp, const ip_xmit_attr_t *ixa,
244811042SErik.Nordmark@Sun.COM const in6_addr_t *dst, in6_addr_t *nexthop)
244911042SErik.Nordmark@Sun.COM {
245011131SErik.Nordmark@Sun.COM if (!(ipp->ipp_fields & (IPPF_IPV4_OPTIONS|IPPF_RTHDR))) {
245111131SErik.Nordmark@Sun.COM *nexthop = *dst;
245211131SErik.Nordmark@Sun.COM return;
245311131SErik.Nordmark@Sun.COM }
245411042SErik.Nordmark@Sun.COM if (ixa->ixa_flags & IXAF_IS_IPV4) {
245511042SErik.Nordmark@Sun.COM ipaddr_t v4dst;
245611042SErik.Nordmark@Sun.COM ipaddr_t v4nexthop;
245711042SErik.Nordmark@Sun.COM
245811042SErik.Nordmark@Sun.COM IN6_V4MAPPED_TO_IPADDR(dst, v4dst);
245911042SErik.Nordmark@Sun.COM v4nexthop = ip_pkt_source_route_v4(ipp);
246011042SErik.Nordmark@Sun.COM if (v4nexthop == INADDR_ANY)
246111042SErik.Nordmark@Sun.COM v4nexthop = v4dst;
246211042SErik.Nordmark@Sun.COM
246311042SErik.Nordmark@Sun.COM IN6_IPADDR_TO_V4MAPPED(v4nexthop, nexthop);
246411042SErik.Nordmark@Sun.COM } else {
246511042SErik.Nordmark@Sun.COM const in6_addr_t *v6nexthop;
246611042SErik.Nordmark@Sun.COM
246711042SErik.Nordmark@Sun.COM v6nexthop = ip_pkt_source_route_v6(ipp);
246811042SErik.Nordmark@Sun.COM if (v6nexthop == NULL)
246911042SErik.Nordmark@Sun.COM v6nexthop = dst;
247011042SErik.Nordmark@Sun.COM
247111042SErik.Nordmark@Sun.COM *nexthop = *v6nexthop;
247211042SErik.Nordmark@Sun.COM }
247311042SErik.Nordmark@Sun.COM }
247411042SErik.Nordmark@Sun.COM
247511042SErik.Nordmark@Sun.COM /*
247611042SErik.Nordmark@Sun.COM * Update the ip_xmit_attr_t based the addresses, conn_xmit_ipp and conn_ixa.
247711042SErik.Nordmark@Sun.COM * If IPDF_IPSEC is set we cache the IPsec policy to handle the unconnected
247811042SErik.Nordmark@Sun.COM * case (connected latching is done in conn_connect).
247911042SErik.Nordmark@Sun.COM * Note that IPsec policy lookup requires conn_proto and conn_laddr to be
248011042SErik.Nordmark@Sun.COM * set, but doesn't otherwise use the conn_t.
248111042SErik.Nordmark@Sun.COM *
248211042SErik.Nordmark@Sun.COM * Caller must set/clear IXAF_IS_IPV4 as appropriately.
248311042SErik.Nordmark@Sun.COM * Caller must use ip_attr_nexthop() to determine the nexthop argument.
248411042SErik.Nordmark@Sun.COM *
248511042SErik.Nordmark@Sun.COM * The caller must NOT hold conn_lock (to avoid problems with ill_refrele
248611042SErik.Nordmark@Sun.COM * causing the squeue to run doing ipcl_walk grabbing conn_lock.)
248711042SErik.Nordmark@Sun.COM *
248811042SErik.Nordmark@Sun.COM * Updates laddrp and uinfo if they are non-NULL.
248911042SErik.Nordmark@Sun.COM *
249011042SErik.Nordmark@Sun.COM * TSOL notes: The callers if ip_attr_connect must check if the destination
249111042SErik.Nordmark@Sun.COM * is different than before and in that case redo conn_update_label.
249211042SErik.Nordmark@Sun.COM * The callers of conn_connect do not need that since conn_connect
249311042SErik.Nordmark@Sun.COM * performs the conn_update_label.
249411042SErik.Nordmark@Sun.COM */
249511042SErik.Nordmark@Sun.COM int
ip_attr_connect(const conn_t * connp,ip_xmit_attr_t * ixa,const in6_addr_t * v6src,const in6_addr_t * v6dst,const in6_addr_t * v6nexthop,in_port_t dstport,in6_addr_t * laddrp,iulp_t * uinfo,uint32_t flags)249611042SErik.Nordmark@Sun.COM ip_attr_connect(const conn_t *connp, ip_xmit_attr_t *ixa,
249711042SErik.Nordmark@Sun.COM const in6_addr_t *v6src, const in6_addr_t *v6dst,
249811042SErik.Nordmark@Sun.COM const in6_addr_t *v6nexthop, in_port_t dstport, in6_addr_t *laddrp,
249911042SErik.Nordmark@Sun.COM iulp_t *uinfo, uint32_t flags)
250011042SErik.Nordmark@Sun.COM {
250111042SErik.Nordmark@Sun.COM in6_addr_t laddr = *v6src;
250211042SErik.Nordmark@Sun.COM int error;
250311042SErik.Nordmark@Sun.COM
250411042SErik.Nordmark@Sun.COM ASSERT(MUTEX_NOT_HELD(&connp->conn_lock));
250511042SErik.Nordmark@Sun.COM
250611042SErik.Nordmark@Sun.COM if (connp->conn_zone_is_global)
250711042SErik.Nordmark@Sun.COM flags |= IPDF_ZONE_IS_GLOBAL;
250811042SErik.Nordmark@Sun.COM else
250911042SErik.Nordmark@Sun.COM flags &= ~IPDF_ZONE_IS_GLOBAL;
251011042SErik.Nordmark@Sun.COM
251111042SErik.Nordmark@Sun.COM /*
251211042SErik.Nordmark@Sun.COM * Lookup the route to determine a source address and the uinfo.
251311042SErik.Nordmark@Sun.COM * If the ULP has a source route option then the caller will
251411042SErik.Nordmark@Sun.COM * have set v6nexthop to be the first hop.
251511042SErik.Nordmark@Sun.COM */
251611042SErik.Nordmark@Sun.COM if (ixa->ixa_flags & IXAF_IS_IPV4) {
251711042SErik.Nordmark@Sun.COM ipaddr_t v4dst;
251811042SErik.Nordmark@Sun.COM ipaddr_t v4src, v4nexthop;
251911042SErik.Nordmark@Sun.COM
252011042SErik.Nordmark@Sun.COM IN6_V4MAPPED_TO_IPADDR(v6dst, v4dst);
252111042SErik.Nordmark@Sun.COM IN6_V4MAPPED_TO_IPADDR(v6nexthop, v4nexthop);
252211042SErik.Nordmark@Sun.COM IN6_V4MAPPED_TO_IPADDR(v6src, v4src);
252311042SErik.Nordmark@Sun.COM
252411042SErik.Nordmark@Sun.COM if (connp->conn_unspec_src || v4src != INADDR_ANY)
252511042SErik.Nordmark@Sun.COM flags &= ~IPDF_SELECT_SRC;
252611042SErik.Nordmark@Sun.COM else
252711042SErik.Nordmark@Sun.COM flags |= IPDF_SELECT_SRC;
252811042SErik.Nordmark@Sun.COM
252911042SErik.Nordmark@Sun.COM error = ip_set_destination_v4(&v4src, v4dst, v4nexthop, ixa,
253011042SErik.Nordmark@Sun.COM uinfo, flags, connp->conn_mac_mode);
253111042SErik.Nordmark@Sun.COM IN6_IPADDR_TO_V4MAPPED(v4src, &laddr);
253211042SErik.Nordmark@Sun.COM } else {
253311042SErik.Nordmark@Sun.COM if (connp->conn_unspec_src || !IN6_IS_ADDR_UNSPECIFIED(v6src))
253411042SErik.Nordmark@Sun.COM flags &= ~IPDF_SELECT_SRC;
253511042SErik.Nordmark@Sun.COM else
253611042SErik.Nordmark@Sun.COM flags |= IPDF_SELECT_SRC;
253711042SErik.Nordmark@Sun.COM
253811042SErik.Nordmark@Sun.COM error = ip_set_destination_v6(&laddr, v6dst, v6nexthop, ixa,
253911042SErik.Nordmark@Sun.COM uinfo, flags, connp->conn_mac_mode);
254011042SErik.Nordmark@Sun.COM }
254111042SErik.Nordmark@Sun.COM /* Pass out some address even if we hit a RTF_REJECT etc */
254211042SErik.Nordmark@Sun.COM if (laddrp != NULL)
254311042SErik.Nordmark@Sun.COM *laddrp = laddr;
254411042SErik.Nordmark@Sun.COM
254511042SErik.Nordmark@Sun.COM if (error != 0)
254611042SErik.Nordmark@Sun.COM return (error);
254711042SErik.Nordmark@Sun.COM
254811042SErik.Nordmark@Sun.COM if (flags & IPDF_IPSEC) {
254911042SErik.Nordmark@Sun.COM /*
255011042SErik.Nordmark@Sun.COM * Set any IPsec policy in ixa. Routine also looks at ULP
255111042SErik.Nordmark@Sun.COM * ports.
255211042SErik.Nordmark@Sun.COM */
255311042SErik.Nordmark@Sun.COM ipsec_cache_outbound_policy(connp, v6src, v6dst, dstport, ixa);
255411042SErik.Nordmark@Sun.COM }
255511042SErik.Nordmark@Sun.COM return (0);
255611042SErik.Nordmark@Sun.COM }
255711042SErik.Nordmark@Sun.COM
255811042SErik.Nordmark@Sun.COM /*
255911042SErik.Nordmark@Sun.COM * Connect the conn based on the addresses, conn_xmit_ipp and conn_ixa.
256011042SErik.Nordmark@Sun.COM * Assumes that conn_faddr and conn_fport are already set. As such it is not
256111042SErik.Nordmark@Sun.COM * usable for SCTP, since SCTP has multiple faddrs.
256211042SErik.Nordmark@Sun.COM *
256311042SErik.Nordmark@Sun.COM * Caller must hold conn_lock to provide atomic constency between the
256411042SErik.Nordmark@Sun.COM * conn_t's addresses and the ixa.
256511042SErik.Nordmark@Sun.COM * NOTE: this function drops and reaquires conn_lock since it can't be
256611042SErik.Nordmark@Sun.COM * held across ip_attr_connect/ip_set_destination.
256711042SErik.Nordmark@Sun.COM *
256811042SErik.Nordmark@Sun.COM * The caller needs to handle inserting in the receive-side fanout when
256911042SErik.Nordmark@Sun.COM * appropriate after conn_connect returns.
257011042SErik.Nordmark@Sun.COM */
257111042SErik.Nordmark@Sun.COM int
conn_connect(conn_t * connp,iulp_t * uinfo,uint32_t flags)257211042SErik.Nordmark@Sun.COM conn_connect(conn_t *connp, iulp_t *uinfo, uint32_t flags)
257311042SErik.Nordmark@Sun.COM {
257411042SErik.Nordmark@Sun.COM ip_xmit_attr_t *ixa = connp->conn_ixa;
257511042SErik.Nordmark@Sun.COM in6_addr_t nexthop;
257611042SErik.Nordmark@Sun.COM in6_addr_t saddr, faddr;
257711042SErik.Nordmark@Sun.COM in_port_t fport;
257811042SErik.Nordmark@Sun.COM int error;
257911042SErik.Nordmark@Sun.COM
258011042SErik.Nordmark@Sun.COM ASSERT(MUTEX_HELD(&connp->conn_lock));
258111042SErik.Nordmark@Sun.COM
258211042SErik.Nordmark@Sun.COM if (connp->conn_ipversion == IPV4_VERSION)
258311042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_IS_IPV4;
258411042SErik.Nordmark@Sun.COM else
258511042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~IXAF_IS_IPV4;
258611042SErik.Nordmark@Sun.COM
258711042SErik.Nordmark@Sun.COM /* We do IPsec latching below - hence no caching in ip_attr_connect */
258811042SErik.Nordmark@Sun.COM flags &= ~IPDF_IPSEC;
258911042SErik.Nordmark@Sun.COM
259011042SErik.Nordmark@Sun.COM /* In case we had previously done an ip_attr_connect */
259111042SErik.Nordmark@Sun.COM ip_attr_newdst(ixa);
259211042SErik.Nordmark@Sun.COM
259311042SErik.Nordmark@Sun.COM /*
259411042SErik.Nordmark@Sun.COM * Determine the nexthop and copy the addresses before dropping
259511042SErik.Nordmark@Sun.COM * conn_lock.
259611042SErik.Nordmark@Sun.COM */
259711042SErik.Nordmark@Sun.COM ip_attr_nexthop(&connp->conn_xmit_ipp, connp->conn_ixa,
259811042SErik.Nordmark@Sun.COM &connp->conn_faddr_v6, &nexthop);
259911042SErik.Nordmark@Sun.COM saddr = connp->conn_saddr_v6;
260011042SErik.Nordmark@Sun.COM faddr = connp->conn_faddr_v6;
260111042SErik.Nordmark@Sun.COM fport = connp->conn_fport;
260211042SErik.Nordmark@Sun.COM
260311042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock);
260411042SErik.Nordmark@Sun.COM error = ip_attr_connect(connp, ixa, &saddr, &faddr, &nexthop, fport,
260511042SErik.Nordmark@Sun.COM &saddr, uinfo, flags | IPDF_VERIFY_DST);
260611042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock);
260711042SErik.Nordmark@Sun.COM
260811042SErik.Nordmark@Sun.COM /* Could have changed even if an error */
260911042SErik.Nordmark@Sun.COM connp->conn_saddr_v6 = saddr;
261011042SErik.Nordmark@Sun.COM if (error != 0)
261111042SErik.Nordmark@Sun.COM return (error);
261211042SErik.Nordmark@Sun.COM
261311042SErik.Nordmark@Sun.COM /*
261411042SErik.Nordmark@Sun.COM * Check whether Trusted Solaris policy allows communication with this
261511042SErik.Nordmark@Sun.COM * host, and pretend that the destination is unreachable if not.
261611042SErik.Nordmark@Sun.COM * Compute any needed label and place it in ipp_label_v4/v6.
261711042SErik.Nordmark@Sun.COM *
261811042SErik.Nordmark@Sun.COM * Later conn_build_hdr_template() takes ipp_label_v4/v6 to form
261911042SErik.Nordmark@Sun.COM * the packet.
262011042SErik.Nordmark@Sun.COM *
262111042SErik.Nordmark@Sun.COM * TSOL Note: Any concurrent threads would pick a different ixa
262211042SErik.Nordmark@Sun.COM * (and ipp if they are to change the ipp) so we
262311042SErik.Nordmark@Sun.COM * don't have to worry about concurrent threads.
262411042SErik.Nordmark@Sun.COM */
262511042SErik.Nordmark@Sun.COM if (is_system_labeled()) {
262611042SErik.Nordmark@Sun.COM if (connp->conn_mlp_type != mlptSingle)
262711042SErik.Nordmark@Sun.COM return (ECONNREFUSED);
262811042SErik.Nordmark@Sun.COM
262911042SErik.Nordmark@Sun.COM /*
263011042SErik.Nordmark@Sun.COM * conn_update_label will set ipp_label* which will later
263111042SErik.Nordmark@Sun.COM * be used by conn_build_hdr_template.
263211042SErik.Nordmark@Sun.COM */
263311042SErik.Nordmark@Sun.COM error = conn_update_label(connp, ixa,
263411042SErik.Nordmark@Sun.COM &connp->conn_faddr_v6, &connp->conn_xmit_ipp);
263511042SErik.Nordmark@Sun.COM if (error != 0)
263611042SErik.Nordmark@Sun.COM return (error);
263711042SErik.Nordmark@Sun.COM }
263811042SErik.Nordmark@Sun.COM
263911042SErik.Nordmark@Sun.COM /*
264011042SErik.Nordmark@Sun.COM * Ensure that we match on the selected local address.
264111042SErik.Nordmark@Sun.COM * This overrides conn_laddr in the case we had earlier bound to a
264211042SErik.Nordmark@Sun.COM * multicast or broadcast address.
264311042SErik.Nordmark@Sun.COM */
264411042SErik.Nordmark@Sun.COM connp->conn_laddr_v6 = connp->conn_saddr_v6;
264511042SErik.Nordmark@Sun.COM
264611042SErik.Nordmark@Sun.COM /*
264711042SErik.Nordmark@Sun.COM * Allow setting new policies.
264811042SErik.Nordmark@Sun.COM * The addresses/ports are already set, thus the IPsec policy calls
264911042SErik.Nordmark@Sun.COM * can handle their passed-in conn's.
265011042SErik.Nordmark@Sun.COM */
265111042SErik.Nordmark@Sun.COM connp->conn_policy_cached = B_FALSE;
265211042SErik.Nordmark@Sun.COM
265311042SErik.Nordmark@Sun.COM /*
265411042SErik.Nordmark@Sun.COM * Cache IPsec policy in this conn. If we have per-socket policy,
265511042SErik.Nordmark@Sun.COM * we'll cache that. If we don't, we'll inherit global policy.
265611042SErik.Nordmark@Sun.COM *
265711042SErik.Nordmark@Sun.COM * This is done before the caller inserts in the receive-side fanout.
265811042SErik.Nordmark@Sun.COM * Note that conn_policy_cached is set by ipsec_conn_cache_policy() even
265911042SErik.Nordmark@Sun.COM * for connections where we don't have a policy. This is to prevent
266011042SErik.Nordmark@Sun.COM * global policy lookups in the inbound path.
266111042SErik.Nordmark@Sun.COM *
266211042SErik.Nordmark@Sun.COM * If we insert before we set conn_policy_cached,
266311042SErik.Nordmark@Sun.COM * CONN_INBOUND_POLICY_PRESENT() check can still evaluate true
266411042SErik.Nordmark@Sun.COM * because global policy cound be non-empty. We normally call
266511042SErik.Nordmark@Sun.COM * ipsec_check_policy() for conn_policy_cached connections only if
266611042SErik.Nordmark@Sun.COM * conn_in_enforce_policy is set. But in this case,
266711042SErik.Nordmark@Sun.COM * conn_policy_cached can get set anytime since we made the
266811042SErik.Nordmark@Sun.COM * CONN_INBOUND_POLICY_PRESENT() check and ipsec_check_policy() is
266911042SErik.Nordmark@Sun.COM * called, which will make the above assumption false. Thus, we
267011042SErik.Nordmark@Sun.COM * need to insert after we set conn_policy_cached.
267111042SErik.Nordmark@Sun.COM */
267211042SErik.Nordmark@Sun.COM error = ipsec_conn_cache_policy(connp,
267311042SErik.Nordmark@Sun.COM connp->conn_ipversion == IPV4_VERSION);
267411042SErik.Nordmark@Sun.COM if (error != 0)
267511042SErik.Nordmark@Sun.COM return (error);
267611042SErik.Nordmark@Sun.COM
267711042SErik.Nordmark@Sun.COM /*
267811042SErik.Nordmark@Sun.COM * We defer to do LSO check until here since now we have better idea
267911042SErik.Nordmark@Sun.COM * whether IPsec is present. If the underlying ill is LSO capable,
268011042SErik.Nordmark@Sun.COM * copy its capability in so the ULP can decide whether to enable LSO
268111042SErik.Nordmark@Sun.COM * on this connection. So far, only TCP/IPv4 is implemented, so won't
268211042SErik.Nordmark@Sun.COM * claim LSO for IPv6.
268311042SErik.Nordmark@Sun.COM *
268411042SErik.Nordmark@Sun.COM * Currently, won't enable LSO for IRE_LOOPBACK or IRE_LOCAL, because
268511042SErik.Nordmark@Sun.COM * the receiver can not handle it. Also not to enable LSO for MULTIRT.
268611042SErik.Nordmark@Sun.COM */
268711042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~IXAF_LSO_CAPAB;
268811042SErik.Nordmark@Sun.COM
268911042SErik.Nordmark@Sun.COM ASSERT(ixa->ixa_ire != NULL);
269011042SErik.Nordmark@Sun.COM if (ixa->ixa_ipst->ips_ip_lso_outbound && (flags & IPDF_LSO) &&
269111042SErik.Nordmark@Sun.COM !(ixa->ixa_flags & IXAF_IPSEC_SECURE) &&
269211042SErik.Nordmark@Sun.COM !(ixa->ixa_ire->ire_type & (IRE_LOCAL | IRE_LOOPBACK)) &&
269311042SErik.Nordmark@Sun.COM !(ixa->ixa_ire->ire_flags & RTF_MULTIRT) &&
269411042SErik.Nordmark@Sun.COM (ixa->ixa_nce != NULL) &&
269511042SErik.Nordmark@Sun.COM ((ixa->ixa_flags & IXAF_IS_IPV4) ?
269611042SErik.Nordmark@Sun.COM ILL_LSO_TCP_IPV4_USABLE(ixa->ixa_nce->nce_ill) :
269711042SErik.Nordmark@Sun.COM ILL_LSO_TCP_IPV6_USABLE(ixa->ixa_nce->nce_ill))) {
269811042SErik.Nordmark@Sun.COM ixa->ixa_lso_capab = *ixa->ixa_nce->nce_ill->ill_lso_capab;
269911042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_LSO_CAPAB;
270011042SErik.Nordmark@Sun.COM }
270111042SErik.Nordmark@Sun.COM
270211042SErik.Nordmark@Sun.COM /* Check whether ZEROCOPY capability is usable for this connection. */
270311042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~IXAF_ZCOPY_CAPAB;
270411042SErik.Nordmark@Sun.COM
270511042SErik.Nordmark@Sun.COM if ((flags & IPDF_ZCOPY) &&
270611042SErik.Nordmark@Sun.COM !(ixa->ixa_flags & IXAF_IPSEC_SECURE) &&
270711042SErik.Nordmark@Sun.COM !(ixa->ixa_ire->ire_type & (IRE_LOCAL | IRE_LOOPBACK)) &&
270811042SErik.Nordmark@Sun.COM !(ixa->ixa_ire->ire_flags & RTF_MULTIRT) &&
270911042SErik.Nordmark@Sun.COM (ixa->ixa_nce != NULL) &&
271011042SErik.Nordmark@Sun.COM ILL_ZCOPY_USABLE(ixa->ixa_nce->nce_ill)) {
271111042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_ZCOPY_CAPAB;
271211042SErik.Nordmark@Sun.COM }
271311042SErik.Nordmark@Sun.COM return (0);
271411042SErik.Nordmark@Sun.COM }
271511042SErik.Nordmark@Sun.COM
271611042SErik.Nordmark@Sun.COM /*
271711042SErik.Nordmark@Sun.COM * Predicates to check if the addresses match conn_last*
271811042SErik.Nordmark@Sun.COM */
271911042SErik.Nordmark@Sun.COM
272011042SErik.Nordmark@Sun.COM /*
272111042SErik.Nordmark@Sun.COM * Compare the conn against an address.
272211042SErik.Nordmark@Sun.COM * If using mapped addresses on AF_INET6 sockets, use the _v6 function
272311042SErik.Nordmark@Sun.COM */
272411042SErik.Nordmark@Sun.COM boolean_t
conn_same_as_last_v4(conn_t * connp,sin_t * sin)272511042SErik.Nordmark@Sun.COM conn_same_as_last_v4(conn_t *connp, sin_t *sin)
272611042SErik.Nordmark@Sun.COM {
272711042SErik.Nordmark@Sun.COM ASSERT(connp->conn_family == AF_INET);
272811042SErik.Nordmark@Sun.COM return (sin->sin_addr.s_addr == connp->conn_v4lastdst &&
272911042SErik.Nordmark@Sun.COM sin->sin_port == connp->conn_lastdstport);
273011042SErik.Nordmark@Sun.COM }
273111042SErik.Nordmark@Sun.COM
273211042SErik.Nordmark@Sun.COM /*
273311042SErik.Nordmark@Sun.COM * Compare, including for mapped addresses
273411042SErik.Nordmark@Sun.COM */
273511042SErik.Nordmark@Sun.COM boolean_t
conn_same_as_last_v6(conn_t * connp,sin6_t * sin6)273611042SErik.Nordmark@Sun.COM conn_same_as_last_v6(conn_t *connp, sin6_t *sin6)
273711042SErik.Nordmark@Sun.COM {
273811042SErik.Nordmark@Sun.COM return (IN6_ARE_ADDR_EQUAL(&connp->conn_v6lastdst, &sin6->sin6_addr) &&
273911042SErik.Nordmark@Sun.COM sin6->sin6_port == connp->conn_lastdstport &&
274011042SErik.Nordmark@Sun.COM sin6->sin6_flowinfo == connp->conn_lastflowinfo &&
274111042SErik.Nordmark@Sun.COM sin6->sin6_scope_id == connp->conn_lastscopeid);
274211042SErik.Nordmark@Sun.COM }
274311042SErik.Nordmark@Sun.COM
274411042SErik.Nordmark@Sun.COM /*
274511042SErik.Nordmark@Sun.COM * Compute a label and place it in the ip_packet_t.
274611042SErik.Nordmark@Sun.COM * Handles IPv4 and IPv6.
274711042SErik.Nordmark@Sun.COM * The caller should have a correct ixa_tsl and ixa_zoneid and have
274811042SErik.Nordmark@Sun.COM * already called conn_connect or ip_attr_connect to ensure that tsol_check_dest
274911042SErik.Nordmark@Sun.COM * has been called.
275011042SErik.Nordmark@Sun.COM */
275111042SErik.Nordmark@Sun.COM int
conn_update_label(const conn_t * connp,const ip_xmit_attr_t * ixa,const in6_addr_t * v6dst,ip_pkt_t * ipp)275211042SErik.Nordmark@Sun.COM conn_update_label(const conn_t *connp, const ip_xmit_attr_t *ixa,
275311042SErik.Nordmark@Sun.COM const in6_addr_t *v6dst, ip_pkt_t *ipp)
275411042SErik.Nordmark@Sun.COM {
275511042SErik.Nordmark@Sun.COM int err;
275611042SErik.Nordmark@Sun.COM ipaddr_t v4dst;
275711042SErik.Nordmark@Sun.COM
275811042SErik.Nordmark@Sun.COM if (IN6_IS_ADDR_V4MAPPED(v6dst)) {
275911042SErik.Nordmark@Sun.COM uchar_t opt_storage[IP_MAX_OPT_LENGTH];
276011042SErik.Nordmark@Sun.COM
276111042SErik.Nordmark@Sun.COM IN6_V4MAPPED_TO_IPADDR(v6dst, v4dst);
276211042SErik.Nordmark@Sun.COM
276311042SErik.Nordmark@Sun.COM err = tsol_compute_label_v4(ixa->ixa_tsl, ixa->ixa_zoneid,
276411042SErik.Nordmark@Sun.COM v4dst, opt_storage, ixa->ixa_ipst);
276511042SErik.Nordmark@Sun.COM if (err == 0) {
276611042SErik.Nordmark@Sun.COM /* Length contained in opt_storage[IPOPT_OLEN] */
276711042SErik.Nordmark@Sun.COM err = optcom_pkt_set(opt_storage,
276811042SErik.Nordmark@Sun.COM opt_storage[IPOPT_OLEN],
276911042SErik.Nordmark@Sun.COM (uchar_t **)&ipp->ipp_label_v4,
277011042SErik.Nordmark@Sun.COM &ipp->ipp_label_len_v4);
277111042SErik.Nordmark@Sun.COM }
277211042SErik.Nordmark@Sun.COM if (err != 0) {
277311042SErik.Nordmark@Sun.COM DTRACE_PROBE4(tx__ip__log__info__updatelabel,
277411042SErik.Nordmark@Sun.COM char *, "conn(1) failed to update options(2) "
277511042SErik.Nordmark@Sun.COM "on ixa(3)",
277611042SErik.Nordmark@Sun.COM conn_t *, connp, char *, opt_storage,
277711042SErik.Nordmark@Sun.COM ip_xmit_attr_t *, ixa);
277811042SErik.Nordmark@Sun.COM }
277911042SErik.Nordmark@Sun.COM if (ipp->ipp_label_len_v4 != 0)
278011042SErik.Nordmark@Sun.COM ipp->ipp_fields |= IPPF_LABEL_V4;
278111042SErik.Nordmark@Sun.COM else
278211042SErik.Nordmark@Sun.COM ipp->ipp_fields &= ~IPPF_LABEL_V4;
278311042SErik.Nordmark@Sun.COM } else {
278411042SErik.Nordmark@Sun.COM uchar_t opt_storage[TSOL_MAX_IPV6_OPTION];
278511042SErik.Nordmark@Sun.COM uint_t optlen;
278611042SErik.Nordmark@Sun.COM
278711042SErik.Nordmark@Sun.COM err = tsol_compute_label_v6(ixa->ixa_tsl, ixa->ixa_zoneid,
278811042SErik.Nordmark@Sun.COM v6dst, opt_storage, ixa->ixa_ipst);
278911042SErik.Nordmark@Sun.COM if (err == 0) {
279011042SErik.Nordmark@Sun.COM /*
279111042SErik.Nordmark@Sun.COM * Note that ipp_label_v6 is just the option - not
279211042SErik.Nordmark@Sun.COM * the hopopts extension header.
279311042SErik.Nordmark@Sun.COM *
279411042SErik.Nordmark@Sun.COM * Length contained in opt_storage[IPOPT_OLEN], but
279511042SErik.Nordmark@Sun.COM * that doesn't include the two byte options header.
279611042SErik.Nordmark@Sun.COM */
279711042SErik.Nordmark@Sun.COM optlen = opt_storage[IPOPT_OLEN];
279811042SErik.Nordmark@Sun.COM if (optlen != 0)
279911042SErik.Nordmark@Sun.COM optlen += 2;
280011042SErik.Nordmark@Sun.COM
280111042SErik.Nordmark@Sun.COM err = optcom_pkt_set(opt_storage, optlen,
280211042SErik.Nordmark@Sun.COM (uchar_t **)&ipp->ipp_label_v6,
280311042SErik.Nordmark@Sun.COM &ipp->ipp_label_len_v6);
280411042SErik.Nordmark@Sun.COM }
280511042SErik.Nordmark@Sun.COM if (err != 0) {
280611042SErik.Nordmark@Sun.COM DTRACE_PROBE4(tx__ip__log__info__updatelabel,
280711042SErik.Nordmark@Sun.COM char *, "conn(1) failed to update options(2) "
280811042SErik.Nordmark@Sun.COM "on ixa(3)",
280911042SErik.Nordmark@Sun.COM conn_t *, connp, char *, opt_storage,
281011042SErik.Nordmark@Sun.COM ip_xmit_attr_t *, ixa);
281111042SErik.Nordmark@Sun.COM }
281211042SErik.Nordmark@Sun.COM if (ipp->ipp_label_len_v6 != 0)
281311042SErik.Nordmark@Sun.COM ipp->ipp_fields |= IPPF_LABEL_V6;
281411042SErik.Nordmark@Sun.COM else
281511042SErik.Nordmark@Sun.COM ipp->ipp_fields &= ~IPPF_LABEL_V6;
281611042SErik.Nordmark@Sun.COM }
281711042SErik.Nordmark@Sun.COM return (err);
281811042SErik.Nordmark@Sun.COM }
281911042SErik.Nordmark@Sun.COM
282011042SErik.Nordmark@Sun.COM /*
282111042SErik.Nordmark@Sun.COM * Inherit all options settings from the parent/listener to the eager.
282211042SErik.Nordmark@Sun.COM * Returns zero on success; ENOMEM if memory allocation failed.
282311042SErik.Nordmark@Sun.COM *
282411042SErik.Nordmark@Sun.COM * We assume that the eager has not had any work done i.e., the conn_ixa
282511042SErik.Nordmark@Sun.COM * and conn_xmit_ipp are all zero.
282611042SErik.Nordmark@Sun.COM * Furthermore we assume that no other thread can access the eager (because
282711042SErik.Nordmark@Sun.COM * it isn't inserted in any fanout list).
282811042SErik.Nordmark@Sun.COM */
282911042SErik.Nordmark@Sun.COM int
conn_inherit_parent(conn_t * lconnp,conn_t * econnp)283011042SErik.Nordmark@Sun.COM conn_inherit_parent(conn_t *lconnp, conn_t *econnp)
283111042SErik.Nordmark@Sun.COM {
283211042SErik.Nordmark@Sun.COM cred_t *credp;
283311042SErik.Nordmark@Sun.COM int err;
283411042SErik.Nordmark@Sun.COM void *notify_cookie;
283511352SRao.Shoaib@Sun.COM uint32_t xmit_hint;
283611042SErik.Nordmark@Sun.COM
283711042SErik.Nordmark@Sun.COM econnp->conn_family = lconnp->conn_family;
283811042SErik.Nordmark@Sun.COM econnp->conn_ipv6_v6only = lconnp->conn_ipv6_v6only;
283911042SErik.Nordmark@Sun.COM econnp->conn_wq = lconnp->conn_wq;
284011042SErik.Nordmark@Sun.COM econnp->conn_rq = lconnp->conn_rq;
284111042SErik.Nordmark@Sun.COM
284211042SErik.Nordmark@Sun.COM /*
284311042SErik.Nordmark@Sun.COM * Make a safe copy of the transmit attributes.
284411042SErik.Nordmark@Sun.COM * conn_connect will later be used by the caller to setup the ire etc.
284511042SErik.Nordmark@Sun.COM */
284611042SErik.Nordmark@Sun.COM ASSERT(econnp->conn_ixa->ixa_refcnt == 1);
284711042SErik.Nordmark@Sun.COM ASSERT(econnp->conn_ixa->ixa_ire == NULL);
284811042SErik.Nordmark@Sun.COM ASSERT(econnp->conn_ixa->ixa_dce == NULL);
284911042SErik.Nordmark@Sun.COM ASSERT(econnp->conn_ixa->ixa_nce == NULL);
285011042SErik.Nordmark@Sun.COM
285111352SRao.Shoaib@Sun.COM /* Preserve ixa_notify_cookie and xmit_hint */
285211042SErik.Nordmark@Sun.COM notify_cookie = econnp->conn_ixa->ixa_notify_cookie;
285311352SRao.Shoaib@Sun.COM xmit_hint = econnp->conn_ixa->ixa_xmit_hint;
285411042SErik.Nordmark@Sun.COM ixa_safe_copy(lconnp->conn_ixa, econnp->conn_ixa);
285511042SErik.Nordmark@Sun.COM econnp->conn_ixa->ixa_notify_cookie = notify_cookie;
285611352SRao.Shoaib@Sun.COM econnp->conn_ixa->ixa_xmit_hint = xmit_hint;
285711042SErik.Nordmark@Sun.COM
285811042SErik.Nordmark@Sun.COM econnp->conn_bound_if = lconnp->conn_bound_if;
285911042SErik.Nordmark@Sun.COM econnp->conn_incoming_ifindex = lconnp->conn_incoming_ifindex;
286011042SErik.Nordmark@Sun.COM
286111042SErik.Nordmark@Sun.COM /* Inherit all RECV options */
286211042SErik.Nordmark@Sun.COM econnp->conn_recv_ancillary = lconnp->conn_recv_ancillary;
286311042SErik.Nordmark@Sun.COM
286411042SErik.Nordmark@Sun.COM err = ip_pkt_copy(&lconnp->conn_xmit_ipp, &econnp->conn_xmit_ipp,
286511042SErik.Nordmark@Sun.COM KM_NOSLEEP);
286611042SErik.Nordmark@Sun.COM if (err != 0)
286711042SErik.Nordmark@Sun.COM return (err);
286811042SErik.Nordmark@Sun.COM
286911042SErik.Nordmark@Sun.COM econnp->conn_zoneid = lconnp->conn_zoneid;
287011042SErik.Nordmark@Sun.COM econnp->conn_allzones = lconnp->conn_allzones;
287111042SErik.Nordmark@Sun.COM
287211042SErik.Nordmark@Sun.COM /* This is odd. Pick a flowlabel for each connection instead? */
287311042SErik.Nordmark@Sun.COM econnp->conn_flowinfo = lconnp->conn_flowinfo;
287411042SErik.Nordmark@Sun.COM
287511042SErik.Nordmark@Sun.COM econnp->conn_default_ttl = lconnp->conn_default_ttl;
287611042SErik.Nordmark@Sun.COM
287711042SErik.Nordmark@Sun.COM /*
287811042SErik.Nordmark@Sun.COM * TSOL: tsol_input_proc() needs the eager's cred before the
287911042SErik.Nordmark@Sun.COM * eager is accepted
288011042SErik.Nordmark@Sun.COM */
288111042SErik.Nordmark@Sun.COM ASSERT(lconnp->conn_cred != NULL);
288211042SErik.Nordmark@Sun.COM econnp->conn_cred = credp = lconnp->conn_cred;
288311042SErik.Nordmark@Sun.COM crhold(credp);
288411042SErik.Nordmark@Sun.COM econnp->conn_cpid = lconnp->conn_cpid;
288511066Srafael.vanoni@sun.com econnp->conn_open_time = ddi_get_lbolt64();
288611042SErik.Nordmark@Sun.COM
288711042SErik.Nordmark@Sun.COM /*
288811042SErik.Nordmark@Sun.COM * Cache things in the ixa without any refhold.
288911042SErik.Nordmark@Sun.COM * Listener might not have set up ixa_cred
289011042SErik.Nordmark@Sun.COM */
289111849SErik.Nordmark@Sun.COM ASSERT(!(econnp->conn_ixa->ixa_free_flags & IXA_FREE_CRED));
289211042SErik.Nordmark@Sun.COM econnp->conn_ixa->ixa_cred = econnp->conn_cred;
289311042SErik.Nordmark@Sun.COM econnp->conn_ixa->ixa_cpid = econnp->conn_cpid;
289411042SErik.Nordmark@Sun.COM if (is_system_labeled())
289511042SErik.Nordmark@Sun.COM econnp->conn_ixa->ixa_tsl = crgetlabel(econnp->conn_cred);
289611042SErik.Nordmark@Sun.COM
289711042SErik.Nordmark@Sun.COM /*
289811042SErik.Nordmark@Sun.COM * If the caller has the process-wide flag set, then default to MAC
289911042SErik.Nordmark@Sun.COM * exempt mode. This allows read-down to unlabeled hosts.
290011042SErik.Nordmark@Sun.COM */
290111042SErik.Nordmark@Sun.COM if (getpflags(NET_MAC_AWARE, credp) != 0)
290211042SErik.Nordmark@Sun.COM econnp->conn_mac_mode = CONN_MAC_AWARE;
290311042SErik.Nordmark@Sun.COM
290411042SErik.Nordmark@Sun.COM econnp->conn_zone_is_global = lconnp->conn_zone_is_global;
290511042SErik.Nordmark@Sun.COM
290611042SErik.Nordmark@Sun.COM /*
290711042SErik.Nordmark@Sun.COM * We eliminate the need for sockfs to send down a T_SVR4_OPTMGMT_REQ
290811042SErik.Nordmark@Sun.COM * via soaccept()->soinheritoptions() which essentially applies
290911042SErik.Nordmark@Sun.COM * all the listener options to the new connection. The options that we
291011042SErik.Nordmark@Sun.COM * need to take care of are:
291111042SErik.Nordmark@Sun.COM * SO_DEBUG, SO_REUSEADDR, SO_KEEPALIVE, SO_DONTROUTE, SO_BROADCAST,
291211042SErik.Nordmark@Sun.COM * SO_USELOOPBACK, SO_OOBINLINE, SO_DGRAM_ERRIND, SO_LINGER,
291311042SErik.Nordmark@Sun.COM * SO_SNDBUF, SO_RCVBUF.
291411042SErik.Nordmark@Sun.COM *
291511042SErik.Nordmark@Sun.COM * SO_RCVBUF: conn_rcvbuf is set.
291611042SErik.Nordmark@Sun.COM * SO_SNDBUF: conn_sndbuf is set.
291711042SErik.Nordmark@Sun.COM */
291811042SErik.Nordmark@Sun.COM
291911131SErik.Nordmark@Sun.COM /* Could we define a struct and use a struct copy for this? */
292011042SErik.Nordmark@Sun.COM econnp->conn_sndbuf = lconnp->conn_sndbuf;
292111042SErik.Nordmark@Sun.COM econnp->conn_rcvbuf = lconnp->conn_rcvbuf;
292211042SErik.Nordmark@Sun.COM econnp->conn_sndlowat = lconnp->conn_sndlowat;
292311042SErik.Nordmark@Sun.COM econnp->conn_rcvlowat = lconnp->conn_rcvlowat;
292411042SErik.Nordmark@Sun.COM econnp->conn_dgram_errind = lconnp->conn_dgram_errind;
292511042SErik.Nordmark@Sun.COM econnp->conn_oobinline = lconnp->conn_oobinline;
292611042SErik.Nordmark@Sun.COM econnp->conn_debug = lconnp->conn_debug;
292711042SErik.Nordmark@Sun.COM econnp->conn_keepalive = lconnp->conn_keepalive;
292811042SErik.Nordmark@Sun.COM econnp->conn_linger = lconnp->conn_linger;
292911042SErik.Nordmark@Sun.COM econnp->conn_lingertime = lconnp->conn_lingertime;
293011042SErik.Nordmark@Sun.COM
293111042SErik.Nordmark@Sun.COM /* Set the IP options */
293211042SErik.Nordmark@Sun.COM econnp->conn_broadcast = lconnp->conn_broadcast;
293311042SErik.Nordmark@Sun.COM econnp->conn_useloopback = lconnp->conn_useloopback;
293411042SErik.Nordmark@Sun.COM econnp->conn_reuseaddr = lconnp->conn_reuseaddr;
293511042SErik.Nordmark@Sun.COM return (0);
293611042SErik.Nordmark@Sun.COM }
2937