xref: /onnv-gate/usr/src/uts/common/inet/sctp/sctp_opt_data.c (revision 13054:feaeaa778d1c)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51676Sjpk  * Common Development and Distribution License (the "License").
61676Sjpk  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211735Skcpoon 
220Sstevel@tonic-gate /*
2312474SGeorge.Shepherd@Sun.COM  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/stream.h>
280Sstevel@tonic-gate #define	_SUN_TPI_VERSION 2
290Sstevel@tonic-gate #include <sys/tihdr.h>
300Sstevel@tonic-gate #include <sys/socket.h>
310Sstevel@tonic-gate #include <sys/xti_inet.h>
320Sstevel@tonic-gate #include <sys/systm.h>
330Sstevel@tonic-gate #include <sys/ddi.h>
340Sstevel@tonic-gate #include <sys/sunddi.h>
350Sstevel@tonic-gate #include <sys/kmem.h>
360Sstevel@tonic-gate #include <sys/strsubr.h>
370Sstevel@tonic-gate #include <sys/strsun.h>
380Sstevel@tonic-gate #include <sys/policy.h>
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #include <inet/common.h>
410Sstevel@tonic-gate #include <netinet/ip6.h>
420Sstevel@tonic-gate #include <inet/ip.h>
430Sstevel@tonic-gate #include <inet/ip_ire.h>
441095Spriyanka #include <inet/ip_if.h>
4511042SErik.Nordmark@Sun.COM #include <inet/proto_set.h>
460Sstevel@tonic-gate #include <inet/ipclassifier.h>
470Sstevel@tonic-gate #include <inet/ipsec_impl.h>
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #include <netinet/in.h>
500Sstevel@tonic-gate #include <netinet/ip.h>
510Sstevel@tonic-gate #include <netinet/tcp.h>
520Sstevel@tonic-gate 
530Sstevel@tonic-gate #include <inet/common.h>
540Sstevel@tonic-gate #include <inet/ip.h>
550Sstevel@tonic-gate #include <inet/ip6.h>
560Sstevel@tonic-gate #include <inet/sctp_itf.h>
570Sstevel@tonic-gate #include "sctp_impl.h"
580Sstevel@tonic-gate #include "sctp_asconf.h"
590Sstevel@tonic-gate #include "sctp_addr.h"
600Sstevel@tonic-gate 
610Sstevel@tonic-gate static int	sctp_getpeeraddrs(sctp_t *, void *, int *);
620Sstevel@tonic-gate 
630Sstevel@tonic-gate static int
sctp_get_status(sctp_t * sctp,void * ptr)640Sstevel@tonic-gate sctp_get_status(sctp_t *sctp, void *ptr)
650Sstevel@tonic-gate {
660Sstevel@tonic-gate 	struct sctp_status *sstat = ptr;
670Sstevel@tonic-gate 	sctp_faddr_t *fp;
680Sstevel@tonic-gate 	struct sockaddr_in *sin;
690Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
700Sstevel@tonic-gate 	struct sctp_paddrinfo *sp;
710Sstevel@tonic-gate 	mblk_t *meta, *mp;
720Sstevel@tonic-gate 	int i;
7311042SErik.Nordmark@Sun.COM 	conn_t	*connp = sctp->sctp_connp;
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	sstat->sstat_state = sctp->sctp_state;
760Sstevel@tonic-gate 	sstat->sstat_rwnd = sctp->sctp_frwnd;
770Sstevel@tonic-gate 
780Sstevel@tonic-gate 	sp = &sstat->sstat_primary;
790Sstevel@tonic-gate 	if (!sctp->sctp_primary) {
800Sstevel@tonic-gate 		bzero(sp, sizeof (*sp));
810Sstevel@tonic-gate 		goto noprim;
820Sstevel@tonic-gate 	}
830Sstevel@tonic-gate 	fp = sctp->sctp_primary;
840Sstevel@tonic-gate 
8513009SChandrasekar.Marimuthu@Sun.COM 	if (fp->sf_isv4) {
860Sstevel@tonic-gate 		sin = (struct sockaddr_in *)&sp->spinfo_address;
870Sstevel@tonic-gate 		sin->sin_family = AF_INET;
8811042SErik.Nordmark@Sun.COM 		sin->sin_port = connp->conn_fport;
8913009SChandrasekar.Marimuthu@Sun.COM 		IN6_V4MAPPED_TO_INADDR(&fp->sf_faddr, &sin->sin_addr);
900Sstevel@tonic-gate 		sp->spinfo_mtu = sctp->sctp_hdr_len;
910Sstevel@tonic-gate 	} else {
920Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)&sp->spinfo_address;
930Sstevel@tonic-gate 		sin6->sin6_family = AF_INET6;
9411042SErik.Nordmark@Sun.COM 		sin6->sin6_port = connp->conn_fport;
9513009SChandrasekar.Marimuthu@Sun.COM 		sin6->sin6_addr = fp->sf_faddr;
960Sstevel@tonic-gate 		sp->spinfo_mtu = sctp->sctp_hdr6_len;
970Sstevel@tonic-gate 	}
9813009SChandrasekar.Marimuthu@Sun.COM 	sp->spinfo_state = fp->sf_state == SCTP_FADDRS_ALIVE ? SCTP_ACTIVE :
990Sstevel@tonic-gate 	    SCTP_INACTIVE;
10013009SChandrasekar.Marimuthu@Sun.COM 	sp->spinfo_cwnd = fp->sf_cwnd;
10113009SChandrasekar.Marimuthu@Sun.COM 	sp->spinfo_srtt = fp->sf_srtt;
10213009SChandrasekar.Marimuthu@Sun.COM 	sp->spinfo_rto = fp->sf_rto;
10313009SChandrasekar.Marimuthu@Sun.COM 	sp->spinfo_mtu += fp->sf_pmss;
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate noprim:
1060Sstevel@tonic-gate 	sstat->sstat_unackdata = 0;
1070Sstevel@tonic-gate 	sstat->sstat_penddata = 0;
1080Sstevel@tonic-gate 	sstat->sstat_instrms = sctp->sctp_num_istr;
1090Sstevel@tonic-gate 	sstat->sstat_outstrms = sctp->sctp_num_ostr;
1100Sstevel@tonic-gate 	sstat->sstat_fragmentation_point = sctp->sctp_mss -
1110Sstevel@tonic-gate 	    sizeof (sctp_data_hdr_t);
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 	/* count unack'd */
1140Sstevel@tonic-gate 	for (meta = sctp->sctp_xmit_head; meta; meta = meta->b_next) {
1150Sstevel@tonic-gate 		for (mp = meta->b_cont; mp; mp = mp->b_next) {
1160Sstevel@tonic-gate 			if (!SCTP_CHUNK_ISSENT(mp)) {
1170Sstevel@tonic-gate 				break;
1180Sstevel@tonic-gate 			}
1190Sstevel@tonic-gate 			if (!SCTP_CHUNK_ISACKED(mp)) {
1200Sstevel@tonic-gate 				sstat->sstat_unackdata++;
1210Sstevel@tonic-gate 			}
1220Sstevel@tonic-gate 		}
1230Sstevel@tonic-gate 	}
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	/*
1260Sstevel@tonic-gate 	 * Count penddata chunks. We can only count chunks in SCTP (not
1270Sstevel@tonic-gate 	 * data already delivered to socket layer).
1280Sstevel@tonic-gate 	 */
1290Sstevel@tonic-gate 	if (sctp->sctp_instr != NULL) {
1300Sstevel@tonic-gate 		for (i = 0; i < sctp->sctp_num_istr; i++) {
1310Sstevel@tonic-gate 			for (meta = sctp->sctp_instr[i].istr_reass;
1320Sstevel@tonic-gate 			    meta != NULL; meta = meta->b_next) {
1330Sstevel@tonic-gate 				for (mp = meta->b_cont; mp; mp = mp->b_cont) {
1340Sstevel@tonic-gate 					if (DB_TYPE(mp) != M_CTL) {
1350Sstevel@tonic-gate 						sstat->sstat_penddata++;
1360Sstevel@tonic-gate 					}
1370Sstevel@tonic-gate 				}
1380Sstevel@tonic-gate 			}
1390Sstevel@tonic-gate 		}
1400Sstevel@tonic-gate 	}
1410Sstevel@tonic-gate 	/* Un-Ordered Frag list */
1420Sstevel@tonic-gate 	for (meta = sctp->sctp_uo_frags; meta != NULL; meta = meta->b_next)
1430Sstevel@tonic-gate 		sstat->sstat_penddata++;
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	return (sizeof (*sstat));
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate /*
1490Sstevel@tonic-gate  * SCTP_GET_PEER_ADDR_INFO
1500Sstevel@tonic-gate  */
1510Sstevel@tonic-gate static int
sctp_get_paddrinfo(sctp_t * sctp,void * ptr,socklen_t * optlen)1520Sstevel@tonic-gate sctp_get_paddrinfo(sctp_t *sctp, void *ptr, socklen_t *optlen)
1530Sstevel@tonic-gate {
1540Sstevel@tonic-gate 	struct sctp_paddrinfo	*infop = ptr;
1550Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
1560Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
1570Sstevel@tonic-gate 	in6_addr_t		faddr;
1580Sstevel@tonic-gate 	sctp_faddr_t		*fp;
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	switch (infop->spinfo_address.ss_family) {
1610Sstevel@tonic-gate 	case AF_INET:
1620Sstevel@tonic-gate 		sin4 = (struct sockaddr_in *)&infop->spinfo_address;
1630Sstevel@tonic-gate 		IN6_INADDR_TO_V4MAPPED(&sin4->sin_addr, &faddr);
1640Sstevel@tonic-gate 		break;
1650Sstevel@tonic-gate 	case AF_INET6:
1660Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)&infop->spinfo_address;
1670Sstevel@tonic-gate 		faddr = sin6->sin6_addr;
1680Sstevel@tonic-gate 		break;
1690Sstevel@tonic-gate 	default:
1700Sstevel@tonic-gate 		return (EAFNOSUPPORT);
1710Sstevel@tonic-gate 	}
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	if ((fp = sctp_lookup_faddr(sctp, &faddr)) == NULL)
1740Sstevel@tonic-gate 		return (EINVAL);
1750Sstevel@tonic-gate 
17613009SChandrasekar.Marimuthu@Sun.COM 	infop->spinfo_state = (fp->sf_state == SCTP_FADDRS_ALIVE) ?
17713009SChandrasekar.Marimuthu@Sun.COM 	    SCTP_ACTIVE : SCTP_INACTIVE;
17813009SChandrasekar.Marimuthu@Sun.COM 	infop->spinfo_cwnd = fp->sf_cwnd;
17913009SChandrasekar.Marimuthu@Sun.COM 	infop->spinfo_srtt = TICK_TO_MSEC(fp->sf_srtt);
18013009SChandrasekar.Marimuthu@Sun.COM 	infop->spinfo_rto = TICK_TO_MSEC(fp->sf_rto);
18113009SChandrasekar.Marimuthu@Sun.COM 	infop->spinfo_mtu = fp->sf_pmss;
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	*optlen = sizeof (struct sctp_paddrinfo);
1840Sstevel@tonic-gate 	return (0);
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate /*
1880Sstevel@tonic-gate  * SCTP_RTOINFO
1890Sstevel@tonic-gate  */
1900Sstevel@tonic-gate static int
sctp_get_rtoinfo(sctp_t * sctp,void * ptr)1910Sstevel@tonic-gate sctp_get_rtoinfo(sctp_t *sctp, void *ptr)
1920Sstevel@tonic-gate {
1930Sstevel@tonic-gate 	struct sctp_rtoinfo *srto = ptr;
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	srto->srto_initial = TICK_TO_MSEC(sctp->sctp_rto_initial);
1960Sstevel@tonic-gate 	srto->srto_max = TICK_TO_MSEC(sctp->sctp_rto_max);
1970Sstevel@tonic-gate 	srto->srto_min = TICK_TO_MSEC(sctp->sctp_rto_min);
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	return (sizeof (*srto));
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate static int
sctp_set_rtoinfo(sctp_t * sctp,const void * invalp)20311042SErik.Nordmark@Sun.COM sctp_set_rtoinfo(sctp_t *sctp, const void *invalp)
2040Sstevel@tonic-gate {
2050Sstevel@tonic-gate 	const struct sctp_rtoinfo *srto;
2060Sstevel@tonic-gate 	boolean_t ispriv;
2073448Sdh155122 	sctp_stack_t	*sctps = sctp->sctp_sctps;
20811042SErik.Nordmark@Sun.COM 	conn_t		*connp = sctp->sctp_connp;
20911322SChandrasekar.Marimuthu@Sun.COM 	uint32_t	new_min, new_max;
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	srto = invalp;
2120Sstevel@tonic-gate 
21311042SErik.Nordmark@Sun.COM 	ispriv = secpolicy_ip_config(connp->conn_cred, B_TRUE) == 0;
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	/*
2160Sstevel@tonic-gate 	 * Bounds checking.  Priviledged user can set the RTO initial
2170Sstevel@tonic-gate 	 * outside the ndd boundary.
2180Sstevel@tonic-gate 	 */
2190Sstevel@tonic-gate 	if (srto->srto_initial != 0 &&
2203448Sdh155122 	    (!ispriv && (srto->srto_initial < sctps->sctps_rto_initialg_low ||
2214505Skcpoon 	    srto->srto_initial > sctps->sctps_rto_initialg_high))) {
2220Sstevel@tonic-gate 		return (EINVAL);
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate 	if (srto->srto_max != 0 &&
2253448Sdh155122 	    (!ispriv && (srto->srto_max < sctps->sctps_rto_maxg_low ||
2264505Skcpoon 	    srto->srto_max > sctps->sctps_rto_maxg_high))) {
2270Sstevel@tonic-gate 		return (EINVAL);
2280Sstevel@tonic-gate 	}
2290Sstevel@tonic-gate 	if (srto->srto_min != 0 &&
2303448Sdh155122 	    (!ispriv && (srto->srto_min < sctps->sctps_rto_ming_low ||
2314505Skcpoon 	    srto->srto_min > sctps->sctps_rto_ming_high))) {
2320Sstevel@tonic-gate 		return (EINVAL);
2330Sstevel@tonic-gate 	}
2340Sstevel@tonic-gate 
23511322SChandrasekar.Marimuthu@Sun.COM 	new_min = (srto->srto_min != 0) ? srto->srto_min : sctp->sctp_rto_min;
23611322SChandrasekar.Marimuthu@Sun.COM 	new_max = (srto->srto_max != 0) ? srto->srto_max : sctp->sctp_rto_max;
23711322SChandrasekar.Marimuthu@Sun.COM 	if (new_max < new_min) {
23811322SChandrasekar.Marimuthu@Sun.COM 		return (EINVAL);
23911322SChandrasekar.Marimuthu@Sun.COM 	}
24011322SChandrasekar.Marimuthu@Sun.COM 
2410Sstevel@tonic-gate 	if (srto->srto_initial != 0) {
2420Sstevel@tonic-gate 		sctp->sctp_rto_initial = MSEC_TO_TICK(srto->srto_initial);
2430Sstevel@tonic-gate 	}
24411322SChandrasekar.Marimuthu@Sun.COM 
24511322SChandrasekar.Marimuthu@Sun.COM 	/* Ensure that sctp_rto_max will never be zero. */
2460Sstevel@tonic-gate 	if (srto->srto_max != 0) {
24711322SChandrasekar.Marimuthu@Sun.COM 		sctp->sctp_rto_max = MAX(MSEC_TO_TICK(srto->srto_max), 1);
2480Sstevel@tonic-gate 	}
2490Sstevel@tonic-gate 	if (srto->srto_min != 0) {
2500Sstevel@tonic-gate 		sctp->sctp_rto_min = MSEC_TO_TICK(srto->srto_min);
2510Sstevel@tonic-gate 	}
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	return (0);
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate /*
2570Sstevel@tonic-gate  * SCTP_ASSOCINFO
2580Sstevel@tonic-gate  */
2590Sstevel@tonic-gate static int
sctp_get_assocparams(sctp_t * sctp,void * ptr)2600Sstevel@tonic-gate sctp_get_assocparams(sctp_t *sctp, void *ptr)
2610Sstevel@tonic-gate {
2620Sstevel@tonic-gate 	struct sctp_assocparams *sap = ptr;
2630Sstevel@tonic-gate 	sctp_faddr_t *fp;
2640Sstevel@tonic-gate 	uint16_t i;
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	sap->sasoc_asocmaxrxt = sctp->sctp_pa_max_rxt;
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	/*
2690Sstevel@tonic-gate 	 * Count the number of peer addresses
2700Sstevel@tonic-gate 	 */
27113009SChandrasekar.Marimuthu@Sun.COM 	for (i = 0, fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) {
2720Sstevel@tonic-gate 		i++;
2730Sstevel@tonic-gate 	}
2740Sstevel@tonic-gate 	sap->sasoc_number_peer_destinations = i;
2750Sstevel@tonic-gate 	sap->sasoc_peer_rwnd = sctp->sctp_frwnd;
2760Sstevel@tonic-gate 	sap->sasoc_local_rwnd = sctp->sctp_rwnd;
2770Sstevel@tonic-gate 	sap->sasoc_cookie_life = TICK_TO_MSEC(sctp->sctp_cookie_lifetime);
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	return (sizeof (*sap));
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate static int
sctp_set_assocparams(sctp_t * sctp,const void * invalp)28311042SErik.Nordmark@Sun.COM sctp_set_assocparams(sctp_t *sctp, const void *invalp)
2840Sstevel@tonic-gate {
2850Sstevel@tonic-gate 	const struct sctp_assocparams *sap = invalp;
2860Sstevel@tonic-gate 	uint32_t sum = 0;
2870Sstevel@tonic-gate 	sctp_faddr_t *fp;
2883448Sdh155122 	sctp_stack_t	*sctps = sctp->sctp_sctps;
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 	if (sap->sasoc_asocmaxrxt) {
2910Sstevel@tonic-gate 		if (sctp->sctp_faddrs) {
2920Sstevel@tonic-gate 			/*
2930Sstevel@tonic-gate 			 * Bounds check: as per rfc2960, assoc max retr cannot
2940Sstevel@tonic-gate 			 * exceed the sum of all individual path max retr's.
2950Sstevel@tonic-gate 			 */
29613009SChandrasekar.Marimuthu@Sun.COM 			for (fp = sctp->sctp_faddrs; fp; fp = fp->sf_next) {
29713009SChandrasekar.Marimuthu@Sun.COM 				sum += fp->sf_max_retr;
2980Sstevel@tonic-gate 			}
2990Sstevel@tonic-gate 			if (sap->sasoc_asocmaxrxt > sum) {
3000Sstevel@tonic-gate 				return (EINVAL);
3010Sstevel@tonic-gate 			}
3020Sstevel@tonic-gate 		}
3033448Sdh155122 		if (sap->sasoc_asocmaxrxt < sctps->sctps_pa_max_retr_low ||
3043448Sdh155122 		    sap->sasoc_asocmaxrxt > sctps->sctps_pa_max_retr_high) {
3050Sstevel@tonic-gate 			/*
3060Sstevel@tonic-gate 			 * Out of bounds.
3070Sstevel@tonic-gate 			 */
3080Sstevel@tonic-gate 			return (EINVAL);
3090Sstevel@tonic-gate 		}
3100Sstevel@tonic-gate 	}
3110Sstevel@tonic-gate 	if (sap->sasoc_cookie_life != 0 &&
3123448Sdh155122 	    (sap->sasoc_cookie_life < sctps->sctps_cookie_life_low ||
3134505Skcpoon 	    sap->sasoc_cookie_life > sctps->sctps_cookie_life_high)) {
3144505Skcpoon 		return (EINVAL);
3150Sstevel@tonic-gate 	}
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	if (sap->sasoc_asocmaxrxt > 0) {
3180Sstevel@tonic-gate 		sctp->sctp_pa_max_rxt = sap->sasoc_asocmaxrxt;
3190Sstevel@tonic-gate 	}
3200Sstevel@tonic-gate 	if (sap->sasoc_cookie_life > 0) {
3210Sstevel@tonic-gate 		sctp->sctp_cookie_lifetime = MSEC_TO_TICK(
3220Sstevel@tonic-gate 		    sap->sasoc_cookie_life);
3230Sstevel@tonic-gate 	}
3240Sstevel@tonic-gate 	return (0);
3250Sstevel@tonic-gate }
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate /*
3280Sstevel@tonic-gate  * SCTP_INITMSG
3290Sstevel@tonic-gate  */
3300Sstevel@tonic-gate static int
sctp_get_initmsg(sctp_t * sctp,void * ptr)3310Sstevel@tonic-gate sctp_get_initmsg(sctp_t *sctp, void *ptr)
3320Sstevel@tonic-gate {
3330Sstevel@tonic-gate 	struct sctp_initmsg *si = ptr;
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	si->sinit_num_ostreams = sctp->sctp_num_ostr;
3360Sstevel@tonic-gate 	si->sinit_max_instreams = sctp->sctp_num_istr;
3370Sstevel@tonic-gate 	si->sinit_max_attempts = sctp->sctp_max_init_rxt;
33812474SGeorge.Shepherd@Sun.COM 	si->sinit_max_init_timeo = TICK_TO_MSEC(sctp->sctp_rto_max_init);
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	return (sizeof (*si));
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate static int
sctp_set_initmsg(sctp_t * sctp,const void * invalp,uint_t inlen)3440Sstevel@tonic-gate sctp_set_initmsg(sctp_t *sctp, const void *invalp, uint_t inlen)
3450Sstevel@tonic-gate {
3460Sstevel@tonic-gate 	const struct sctp_initmsg *si = invalp;
3473448Sdh155122 	sctp_stack_t	*sctps = sctp->sctp_sctps;
34811042SErik.Nordmark@Sun.COM 	conn_t		*connp = sctp->sctp_connp;
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	if (sctp->sctp_state > SCTPS_LISTEN) {
3510Sstevel@tonic-gate 		return (EINVAL);
3520Sstevel@tonic-gate 	}
3530Sstevel@tonic-gate 	if (inlen < sizeof (*si)) {
3540Sstevel@tonic-gate 		return (EINVAL);
3550Sstevel@tonic-gate 	}
3560Sstevel@tonic-gate 	if (si->sinit_num_ostreams != 0 &&
3573448Sdh155122 	    (si->sinit_num_ostreams < sctps->sctps_initial_out_streams_low ||
3583448Sdh155122 	    si->sinit_num_ostreams >
3593448Sdh155122 	    sctps->sctps_initial_out_streams_high)) {
3600Sstevel@tonic-gate 		/*
3610Sstevel@tonic-gate 		 * Out of bounds.
3620Sstevel@tonic-gate 		 */
3630Sstevel@tonic-gate 		return (EINVAL);
3640Sstevel@tonic-gate 	}
3650Sstevel@tonic-gate 	if (si->sinit_max_instreams != 0 &&
3663448Sdh155122 	    (si->sinit_max_instreams < sctps->sctps_max_in_streams_low ||
3674505Skcpoon 	    si->sinit_max_instreams > sctps->sctps_max_in_streams_high)) {
3680Sstevel@tonic-gate 		return (EINVAL);
3690Sstevel@tonic-gate 	}
3700Sstevel@tonic-gate 	if (si->sinit_max_attempts != 0 &&
3713448Sdh155122 	    (si->sinit_max_attempts < sctps->sctps_max_init_retr_low ||
3724505Skcpoon 	    si->sinit_max_attempts > sctps->sctps_max_init_retr_high)) {
3730Sstevel@tonic-gate 		return (EINVAL);
3740Sstevel@tonic-gate 	}
3750Sstevel@tonic-gate 	if (si->sinit_max_init_timeo != 0 &&
37611042SErik.Nordmark@Sun.COM 	    (secpolicy_ip_config(connp->conn_cred, B_TRUE) != 0 &&
3774505Skcpoon 	    (si->sinit_max_init_timeo < sctps->sctps_rto_maxg_low ||
3784505Skcpoon 	    si->sinit_max_init_timeo > sctps->sctps_rto_maxg_high))) {
3790Sstevel@tonic-gate 		return (EINVAL);
3800Sstevel@tonic-gate 	}
3810Sstevel@tonic-gate 	if (si->sinit_num_ostreams != 0)
3820Sstevel@tonic-gate 		sctp->sctp_num_ostr = si->sinit_num_ostreams;
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	if (si->sinit_max_instreams != 0)
3850Sstevel@tonic-gate 		sctp->sctp_num_istr = si->sinit_max_instreams;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	if (si->sinit_max_attempts != 0)
3880Sstevel@tonic-gate 		sctp->sctp_max_init_rxt = si->sinit_max_attempts;
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	if (si->sinit_max_init_timeo != 0) {
39112474SGeorge.Shepherd@Sun.COM 		sctp->sctp_rto_max_init =
3920Sstevel@tonic-gate 		    MSEC_TO_TICK(si->sinit_max_init_timeo);
3930Sstevel@tonic-gate 	}
3940Sstevel@tonic-gate 	return (0);
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate /*
3980Sstevel@tonic-gate  * SCTP_PEER_ADDR_PARAMS
3990Sstevel@tonic-gate  */
4000Sstevel@tonic-gate static int
sctp_find_peer_fp(sctp_t * sctp,const struct sockaddr_storage * ss,sctp_faddr_t ** fpp)4010Sstevel@tonic-gate sctp_find_peer_fp(sctp_t *sctp, const struct sockaddr_storage *ss,
4020Sstevel@tonic-gate     sctp_faddr_t **fpp)
4030Sstevel@tonic-gate {
4040Sstevel@tonic-gate 	struct sockaddr_in *sin;
4050Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
4060Sstevel@tonic-gate 	in6_addr_t addr;
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	if (ss->ss_family == AF_INET) {
4090Sstevel@tonic-gate 		sin = (struct sockaddr_in *)ss;
4100Sstevel@tonic-gate 		IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &addr);
4110Sstevel@tonic-gate 	} else if (ss->ss_family == AF_INET6) {
4120Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)ss;
4130Sstevel@tonic-gate 		addr = sin6->sin6_addr;
4140Sstevel@tonic-gate 	} else if (ss->ss_family) {
4150Sstevel@tonic-gate 		return (EAFNOSUPPORT);
4160Sstevel@tonic-gate 	}
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	if (!ss->ss_family ||
4190Sstevel@tonic-gate 	    SCTP_IS_ADDR_UNSPEC(IN6_IS_ADDR_V4MAPPED(&addr), addr)) {
4200Sstevel@tonic-gate 		*fpp = NULL;
4210Sstevel@tonic-gate 	} else {
4220Sstevel@tonic-gate 		*fpp = sctp_lookup_faddr(sctp, &addr);
4230Sstevel@tonic-gate 		if (*fpp == NULL) {
4240Sstevel@tonic-gate 			return (EINVAL);
4250Sstevel@tonic-gate 		}
4260Sstevel@tonic-gate 	}
4270Sstevel@tonic-gate 	return (0);
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate static int
sctp_get_peer_addr_params(sctp_t * sctp,void * ptr)4310Sstevel@tonic-gate sctp_get_peer_addr_params(sctp_t *sctp, void *ptr)
4320Sstevel@tonic-gate {
4330Sstevel@tonic-gate 	struct sctp_paddrparams *spp = ptr;
4340Sstevel@tonic-gate 	sctp_faddr_t *fp;
4350Sstevel@tonic-gate 	int retval;
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	retval = sctp_find_peer_fp(sctp, &spp->spp_address, &fp);
4380Sstevel@tonic-gate 	if (retval) {
4390Sstevel@tonic-gate 		return (retval);
4400Sstevel@tonic-gate 	}
4410Sstevel@tonic-gate 	if (fp) {
44213009SChandrasekar.Marimuthu@Sun.COM 		spp->spp_hbinterval = TICK_TO_MSEC(fp->sf_hb_interval);
44313009SChandrasekar.Marimuthu@Sun.COM 		spp->spp_pathmaxrxt = fp->sf_max_retr;
4440Sstevel@tonic-gate 	} else {
4450Sstevel@tonic-gate 		spp->spp_hbinterval = TICK_TO_MSEC(sctp->sctp_hb_interval);
4460Sstevel@tonic-gate 		spp->spp_pathmaxrxt = sctp->sctp_pp_max_rxt;
4470Sstevel@tonic-gate 	}
4480Sstevel@tonic-gate 	return (sizeof (*spp));
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate static int
sctp_set_peer_addr_params(sctp_t * sctp,const void * invalp)45211042SErik.Nordmark@Sun.COM sctp_set_peer_addr_params(sctp_t *sctp, const void *invalp)
4530Sstevel@tonic-gate {
4540Sstevel@tonic-gate 	const struct sctp_paddrparams *spp = invalp;
4550Sstevel@tonic-gate 	sctp_faddr_t *fp, *fp2;
4560Sstevel@tonic-gate 	int retval;
4570Sstevel@tonic-gate 	uint32_t sum = 0;
4580Sstevel@tonic-gate 	int64_t now;
4593448Sdh155122 	sctp_stack_t	*sctps = sctp->sctp_sctps;
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	retval = sctp_find_peer_fp(sctp, &spp->spp_address, &fp);
4620Sstevel@tonic-gate 	if (retval != 0) {
4630Sstevel@tonic-gate 		return (retval);
4640Sstevel@tonic-gate 	}
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	if (spp->spp_hbinterval && spp->spp_hbinterval != UINT32_MAX &&
4673448Sdh155122 	    (spp->spp_hbinterval < sctps->sctps_heartbeat_interval_low ||
4684505Skcpoon 	    spp->spp_hbinterval > sctps->sctps_heartbeat_interval_high)) {
4690Sstevel@tonic-gate 		return (EINVAL);
4700Sstevel@tonic-gate 	}
4710Sstevel@tonic-gate 	if (spp->spp_pathmaxrxt &&
4723448Sdh155122 	    (spp->spp_pathmaxrxt < sctps->sctps_pp_max_retr_low ||
4734505Skcpoon 	    spp->spp_pathmaxrxt > sctps->sctps_pp_max_retr_high)) {
4740Sstevel@tonic-gate 		return (EINVAL);
4750Sstevel@tonic-gate 	}
4760Sstevel@tonic-gate 	if (spp->spp_pathmaxrxt && sctp->sctp_faddrs) {
47713009SChandrasekar.Marimuthu@Sun.COM 		for (fp2 = sctp->sctp_faddrs; fp2; fp2 = fp2->sf_next) {
4780Sstevel@tonic-gate 			if (!fp || fp2 == fp) {
4790Sstevel@tonic-gate 				sum += spp->spp_pathmaxrxt;
4800Sstevel@tonic-gate 			} else {
48113009SChandrasekar.Marimuthu@Sun.COM 				sum += fp2->sf_max_retr;
4820Sstevel@tonic-gate 			}
4830Sstevel@tonic-gate 		}
4840Sstevel@tonic-gate 		if (sctp->sctp_pa_max_rxt > sum) {
4850Sstevel@tonic-gate 			return (EINVAL);
4860Sstevel@tonic-gate 		}
4870Sstevel@tonic-gate 	}
4880Sstevel@tonic-gate 
48911066Srafael.vanoni@sun.com 	now = ddi_get_lbolt64();
4900Sstevel@tonic-gate 	if (fp != NULL) {
4910Sstevel@tonic-gate 		if (spp->spp_hbinterval == UINT32_MAX) {
4920Sstevel@tonic-gate 			/*
4930Sstevel@tonic-gate 			 * Send heartbeat immediatelly, don't modify the
4940Sstevel@tonic-gate 			 * current setting.
4950Sstevel@tonic-gate 			 */
4960Sstevel@tonic-gate 			sctp_send_heartbeat(sctp, fp);
4970Sstevel@tonic-gate 		} else {
49813009SChandrasekar.Marimuthu@Sun.COM 			fp->sf_hb_interval = MSEC_TO_TICK(spp->spp_hbinterval);
49913009SChandrasekar.Marimuthu@Sun.COM 			fp->sf_hb_expiry = now + SET_HB_INTVL(fp);
5000Sstevel@tonic-gate 			/*
5010Sstevel@tonic-gate 			 * Restart the heartbeat timer using the new intrvl.
5020Sstevel@tonic-gate 			 * We need to call sctp_heartbeat_timer() to set
5030Sstevel@tonic-gate 			 * the earliest heartbeat expiry time.
5040Sstevel@tonic-gate 			 */
5050Sstevel@tonic-gate 			sctp_heartbeat_timer(sctp);
5060Sstevel@tonic-gate 		}
5070Sstevel@tonic-gate 		if (spp->spp_pathmaxrxt) {
50813009SChandrasekar.Marimuthu@Sun.COM 			fp->sf_max_retr = spp->spp_pathmaxrxt;
5090Sstevel@tonic-gate 		}
5100Sstevel@tonic-gate 	} else {
51113009SChandrasekar.Marimuthu@Sun.COM 		for (fp2 = sctp->sctp_faddrs; fp2 != NULL; fp2 = fp2->sf_next) {
5120Sstevel@tonic-gate 			if (spp->spp_hbinterval == UINT32_MAX) {
5130Sstevel@tonic-gate 				/*
5140Sstevel@tonic-gate 				 * Send heartbeat immediatelly, don't modify
5150Sstevel@tonic-gate 				 * the current setting.
5160Sstevel@tonic-gate 				 */
5170Sstevel@tonic-gate 				sctp_send_heartbeat(sctp, fp2);
5180Sstevel@tonic-gate 			} else {
51913009SChandrasekar.Marimuthu@Sun.COM 				fp2->sf_hb_interval = MSEC_TO_TICK(
5200Sstevel@tonic-gate 				    spp->spp_hbinterval);
52113009SChandrasekar.Marimuthu@Sun.COM 				fp2->sf_hb_expiry = now + SET_HB_INTVL(fp2);
5220Sstevel@tonic-gate 			}
5230Sstevel@tonic-gate 			if (spp->spp_pathmaxrxt) {
52413009SChandrasekar.Marimuthu@Sun.COM 				fp2->sf_max_retr = spp->spp_pathmaxrxt;
5250Sstevel@tonic-gate 			}
5260Sstevel@tonic-gate 		}
5270Sstevel@tonic-gate 		if (spp->spp_hbinterval != UINT32_MAX) {
5280Sstevel@tonic-gate 			sctp->sctp_hb_interval = MSEC_TO_TICK(
5290Sstevel@tonic-gate 			    spp->spp_hbinterval);
5300Sstevel@tonic-gate 			/* Restart the heartbeat timer using the new intrvl. */
5310Sstevel@tonic-gate 			sctp_timer(sctp, sctp->sctp_heartbeat_mp,
5320Sstevel@tonic-gate 			    sctp->sctp_hb_interval);
5330Sstevel@tonic-gate 		}
5340Sstevel@tonic-gate 		if (spp->spp_pathmaxrxt) {
5350Sstevel@tonic-gate 			sctp->sctp_pp_max_rxt = spp->spp_pathmaxrxt;
5360Sstevel@tonic-gate 		}
5370Sstevel@tonic-gate 	}
5380Sstevel@tonic-gate 	return (0);
5390Sstevel@tonic-gate }
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate /*
5420Sstevel@tonic-gate  * SCTP_DEFAULT_SEND_PARAM
5430Sstevel@tonic-gate  */
5440Sstevel@tonic-gate static int
sctp_get_def_send_params(sctp_t * sctp,void * ptr)5450Sstevel@tonic-gate sctp_get_def_send_params(sctp_t *sctp, void *ptr)
5460Sstevel@tonic-gate {
5470Sstevel@tonic-gate 	struct sctp_sndrcvinfo *sinfo = ptr;
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	sinfo->sinfo_stream = sctp->sctp_def_stream;
5500Sstevel@tonic-gate 	sinfo->sinfo_ssn = 0;
5510Sstevel@tonic-gate 	sinfo->sinfo_flags = sctp->sctp_def_flags;
5520Sstevel@tonic-gate 	sinfo->sinfo_ppid = sctp->sctp_def_ppid;
5530Sstevel@tonic-gate 	sinfo->sinfo_context = sctp->sctp_def_context;
5540Sstevel@tonic-gate 	sinfo->sinfo_timetolive = sctp->sctp_def_timetolive;
5550Sstevel@tonic-gate 	sinfo->sinfo_tsn = 0;
5560Sstevel@tonic-gate 	sinfo->sinfo_cumtsn = 0;
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	return (sizeof (*sinfo));
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate static int
sctp_set_def_send_params(sctp_t * sctp,const void * invalp)56211042SErik.Nordmark@Sun.COM sctp_set_def_send_params(sctp_t *sctp, const void *invalp)
5630Sstevel@tonic-gate {
5640Sstevel@tonic-gate 	const struct sctp_sndrcvinfo *sinfo = invalp;
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	if (sinfo->sinfo_stream >= sctp->sctp_num_ostr) {
5670Sstevel@tonic-gate 		return (EINVAL);
5680Sstevel@tonic-gate 	}
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 	sctp->sctp_def_stream = sinfo->sinfo_stream;
5710Sstevel@tonic-gate 	sctp->sctp_def_flags = sinfo->sinfo_flags;
5720Sstevel@tonic-gate 	sctp->sctp_def_ppid = sinfo->sinfo_ppid;
5730Sstevel@tonic-gate 	sctp->sctp_def_context = sinfo->sinfo_context;
5740Sstevel@tonic-gate 	sctp->sctp_def_timetolive = sinfo->sinfo_timetolive;
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	return (0);
5770Sstevel@tonic-gate }
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate static int
sctp_set_prim(sctp_t * sctp,const void * invalp)58011042SErik.Nordmark@Sun.COM sctp_set_prim(sctp_t *sctp, const void *invalp)
5810Sstevel@tonic-gate {
5820Sstevel@tonic-gate 	const struct	sctp_setpeerprim *pp = invalp;
5830Sstevel@tonic-gate 	int		retval;
5840Sstevel@tonic-gate 	sctp_faddr_t	*fp;
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	retval = sctp_find_peer_fp(sctp, &pp->sspp_addr, &fp);
5870Sstevel@tonic-gate 	if (retval)
5880Sstevel@tonic-gate 		return (retval);
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	if (fp == NULL)
5910Sstevel@tonic-gate 		return (EINVAL);
5920Sstevel@tonic-gate 	if (fp == sctp->sctp_primary)
5930Sstevel@tonic-gate 		return (0);
5940Sstevel@tonic-gate 	sctp->sctp_primary = fp;
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	/* Only switch current if fp is alive */
59713009SChandrasekar.Marimuthu@Sun.COM 	if (fp->sf_state != SCTP_FADDRS_ALIVE || fp == sctp->sctp_current) {
5980Sstevel@tonic-gate 		return (0);
5990Sstevel@tonic-gate 	}
6001735Skcpoon 	sctp_set_faddr_current(sctp, fp);
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	return (0);
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate 
60511042SErik.Nordmark@Sun.COM /*
60611042SErik.Nordmark@Sun.COM  * Table of all known options handled on a SCTP protocol stack.
60711042SErik.Nordmark@Sun.COM  *
60811042SErik.Nordmark@Sun.COM  * Note: This table contains options processed by both SCTP and IP levels
60911042SErik.Nordmark@Sun.COM  *       and is the superset of options that can be performed on a SCTP and IP
61011042SErik.Nordmark@Sun.COM  *       stack.
61111042SErik.Nordmark@Sun.COM  */
61211042SErik.Nordmark@Sun.COM opdes_t	sctp_opt_arr[] = {
61311042SErik.Nordmark@Sun.COM 
61411042SErik.Nordmark@Sun.COM { SO_LINGER,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0,
61511042SErik.Nordmark@Sun.COM 	sizeof (struct linger), 0 },
61611042SErik.Nordmark@Sun.COM 
61711042SErik.Nordmark@Sun.COM { SO_DEBUG,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
61811042SErik.Nordmark@Sun.COM { SO_KEEPALIVE,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
61911042SErik.Nordmark@Sun.COM { SO_DONTROUTE,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
62011042SErik.Nordmark@Sun.COM { SO_USELOOPBACK, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0
62111042SErik.Nordmark@Sun.COM 	},
62211042SErik.Nordmark@Sun.COM { SO_BROADCAST,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
62311042SErik.Nordmark@Sun.COM { SO_REUSEADDR, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
62411042SErik.Nordmark@Sun.COM { SO_OOBINLINE, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
62511042SErik.Nordmark@Sun.COM { SO_TYPE,	SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
62611042SErik.Nordmark@Sun.COM { SO_SNDBUF,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
62711042SErik.Nordmark@Sun.COM { SO_RCVBUF,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
62811042SErik.Nordmark@Sun.COM { SO_DGRAM_ERRIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0
62911042SErik.Nordmark@Sun.COM 	},
63011042SErik.Nordmark@Sun.COM { SO_SND_COPYAVOID, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
63111042SErik.Nordmark@Sun.COM { SO_ANON_MLP, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int),
63211042SErik.Nordmark@Sun.COM 	0 },
63311042SErik.Nordmark@Sun.COM { SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int),
63411042SErik.Nordmark@Sun.COM 	0 },
63511042SErik.Nordmark@Sun.COM { SO_ALLZONES, SOL_SOCKET, OA_R, OA_RW, OP_CONFIG, 0, sizeof (int),
63611042SErik.Nordmark@Sun.COM 	0 },
63711042SErik.Nordmark@Sun.COM { SO_EXCLBIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
63811042SErik.Nordmark@Sun.COM 
63911042SErik.Nordmark@Sun.COM { SO_DOMAIN,	SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
64011042SErik.Nordmark@Sun.COM 
64111042SErik.Nordmark@Sun.COM { SO_PROTOTYPE,	SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
64211042SErik.Nordmark@Sun.COM 
64311042SErik.Nordmark@Sun.COM { SCTP_ADAPTATION_LAYER, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
64411042SErik.Nordmark@Sun.COM 	sizeof (struct sctp_setadaptation), 0 },
64511042SErik.Nordmark@Sun.COM { SCTP_ADD_ADDR, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, OP_VARLEN,
64611042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
64711042SErik.Nordmark@Sun.COM { SCTP_ASSOCINFO, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
64811042SErik.Nordmark@Sun.COM 	sizeof (struct sctp_assocparams), 0 },
64911042SErik.Nordmark@Sun.COM { SCTP_AUTOCLOSE, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
65011042SErik.Nordmark@Sun.COM { SCTP_DEFAULT_SEND_PARAM, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
65111042SErik.Nordmark@Sun.COM 	sizeof (struct sctp_sndrcvinfo), 0 },
65211042SErik.Nordmark@Sun.COM { SCTP_DISABLE_FRAGMENTS, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
65311042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
65411042SErik.Nordmark@Sun.COM { SCTP_EVENTS, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
65511042SErik.Nordmark@Sun.COM 	sizeof (struct sctp_event_subscribe), 0 },
65611042SErik.Nordmark@Sun.COM { SCTP_GET_LADDRS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, OP_VARLEN,
65711042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
65811042SErik.Nordmark@Sun.COM { SCTP_GET_NLADDRS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
65911042SErik.Nordmark@Sun.COM { SCTP_GET_NPADDRS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
66011042SErik.Nordmark@Sun.COM { SCTP_GET_PADDRS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, OP_VARLEN,
66111042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
66211042SErik.Nordmark@Sun.COM { SCTP_GET_PEER_ADDR_INFO, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0,
66311042SErik.Nordmark@Sun.COM 	sizeof (struct sctp_paddrinfo), 0 },
66411042SErik.Nordmark@Sun.COM { SCTP_INITMSG, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
66511042SErik.Nordmark@Sun.COM 	sizeof (struct sctp_initmsg), 0 },
66611042SErik.Nordmark@Sun.COM { SCTP_I_WANT_MAPPED_V4_ADDR, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
66711042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
66811042SErik.Nordmark@Sun.COM { SCTP_MAXSEG, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
66911042SErik.Nordmark@Sun.COM { SCTP_NODELAY, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
67011042SErik.Nordmark@Sun.COM { SCTP_PEER_ADDR_PARAMS, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
67111042SErik.Nordmark@Sun.COM 	sizeof (struct sctp_paddrparams), 0 },
67211042SErik.Nordmark@Sun.COM { SCTP_PRIMARY_ADDR, IPPROTO_SCTP, OA_W, OA_W, OP_NP, 0,
67311042SErik.Nordmark@Sun.COM 	sizeof (struct sctp_setpeerprim), 0 },
67411042SErik.Nordmark@Sun.COM { SCTP_PRSCTP, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
67511042SErik.Nordmark@Sun.COM { SCTP_GET_ASSOC_STATS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0,
67611042SErik.Nordmark@Sun.COM 	sizeof (sctp_assoc_stats_t), 0 },
67711042SErik.Nordmark@Sun.COM { SCTP_REM_ADDR, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, OP_VARLEN,
67811042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
67911042SErik.Nordmark@Sun.COM { SCTP_RTOINFO, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
68011042SErik.Nordmark@Sun.COM 	sizeof (struct sctp_rtoinfo), 0 },
68111042SErik.Nordmark@Sun.COM { SCTP_SET_PEER_PRIMARY_ADDR, IPPROTO_SCTP, OA_W, OA_W, OP_NP, 0,
68211042SErik.Nordmark@Sun.COM 	sizeof (struct sctp_setprim), 0 },
68311042SErik.Nordmark@Sun.COM { SCTP_STATUS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0,
68411042SErik.Nordmark@Sun.COM 	sizeof (struct sctp_status), 0 },
68511042SErik.Nordmark@Sun.COM { SCTP_UC_SWAP, IPPROTO_SCTP, OA_W, OA_W, OP_NP, 0,
68611042SErik.Nordmark@Sun.COM 	sizeof (struct sctp_uc_swap), 0 },
68711042SErik.Nordmark@Sun.COM 
68811042SErik.Nordmark@Sun.COM { IP_OPTIONS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP,
68911042SErik.Nordmark@Sun.COM 	(OP_VARLEN|OP_NODEFAULT),
69011042SErik.Nordmark@Sun.COM 	40, -1 /* not initialized */ },
69111042SErik.Nordmark@Sun.COM { T_IP_OPTIONS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP,
69211042SErik.Nordmark@Sun.COM 	(OP_VARLEN|OP_NODEFAULT),
69311042SErik.Nordmark@Sun.COM 	40, -1 /* not initialized */ },
69411042SErik.Nordmark@Sun.COM 
69511042SErik.Nordmark@Sun.COM { IP_TOS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
69611042SErik.Nordmark@Sun.COM { T_IP_TOS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
69711042SErik.Nordmark@Sun.COM { IP_TTL,	IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_DEF_FN,
69811042SErik.Nordmark@Sun.COM 	sizeof (int), -1 /* not initialized */ },
69911042SErik.Nordmark@Sun.COM 
70011042SErik.Nordmark@Sun.COM { IP_SEC_OPT, IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_NODEFAULT,
70111042SErik.Nordmark@Sun.COM 	sizeof (ipsec_req_t), -1 /* not initialized */ },
70211042SErik.Nordmark@Sun.COM 
70311042SErik.Nordmark@Sun.COM { IP_BOUND_IF, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0,
70411042SErik.Nordmark@Sun.COM 	sizeof (int),	0 /* no ifindex */ },
70511042SErik.Nordmark@Sun.COM 
70611042SErik.Nordmark@Sun.COM { IP_UNSPEC_SRC, IPPROTO_IP, OA_R, OA_RW, OP_RAW, 0,
70711042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
70811042SErik.Nordmark@Sun.COM 
70911042SErik.Nordmark@Sun.COM { IPV6_UNICAST_HOPS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, OP_DEF_FN,
71011042SErik.Nordmark@Sun.COM 	sizeof (int), -1 /* not initialized */ },
71111042SErik.Nordmark@Sun.COM 
71211042SErik.Nordmark@Sun.COM { IPV6_BOUND_IF, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
71311042SErik.Nordmark@Sun.COM 	sizeof (int),	0 /* no ifindex */ },
71411042SErik.Nordmark@Sun.COM 
71511042SErik.Nordmark@Sun.COM { IP_DONTFRAG, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
71611042SErik.Nordmark@Sun.COM 
71711042SErik.Nordmark@Sun.COM { IP_NEXTHOP, IPPROTO_IP, OA_R, OA_RW, OP_CONFIG, 0,
71811042SErik.Nordmark@Sun.COM 	sizeof (in_addr_t),	-1 /* not initialized  */ },
71911042SErik.Nordmark@Sun.COM 
72011042SErik.Nordmark@Sun.COM { IPV6_UNSPEC_SRC, IPPROTO_IPV6, OA_R, OA_RW, OP_RAW, 0,
72111042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
72211042SErik.Nordmark@Sun.COM 
72311042SErik.Nordmark@Sun.COM { IPV6_PKTINFO, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
72411042SErik.Nordmark@Sun.COM 	(OP_NODEFAULT|OP_VARLEN),
72511042SErik.Nordmark@Sun.COM 	sizeof (struct in6_pktinfo), -1 /* not initialized */ },
72611042SErik.Nordmark@Sun.COM { IPV6_NEXTHOP, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
72711042SErik.Nordmark@Sun.COM 	OP_NODEFAULT,
72811042SErik.Nordmark@Sun.COM 	sizeof (sin6_t), -1 /* not initialized */ },
72911042SErik.Nordmark@Sun.COM { IPV6_HOPOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
73011042SErik.Nordmark@Sun.COM 	(OP_VARLEN|OP_NODEFAULT), 255*8,
73111042SErik.Nordmark@Sun.COM 	-1 /* not initialized */ },
73211042SErik.Nordmark@Sun.COM { IPV6_DSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
73311042SErik.Nordmark@Sun.COM 	(OP_VARLEN|OP_NODEFAULT), 255*8,
73411042SErik.Nordmark@Sun.COM 	-1 /* not initialized */ },
73511042SErik.Nordmark@Sun.COM { IPV6_RTHDRDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
73611042SErik.Nordmark@Sun.COM 	(OP_VARLEN|OP_NODEFAULT), 255*8,
73711042SErik.Nordmark@Sun.COM 	-1 /* not initialized */ },
73811042SErik.Nordmark@Sun.COM { IPV6_RTHDR, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
73911042SErik.Nordmark@Sun.COM 	(OP_VARLEN|OP_NODEFAULT), 255*8,
74011042SErik.Nordmark@Sun.COM 	-1 /* not initialized */ },
74111042SErik.Nordmark@Sun.COM { IPV6_TCLASS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
74211042SErik.Nordmark@Sun.COM 	OP_NODEFAULT,
74311042SErik.Nordmark@Sun.COM 	sizeof (int), -1 /* not initialized */ },
74411042SErik.Nordmark@Sun.COM { IPV6_PATHMTU, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
74511042SErik.Nordmark@Sun.COM 	OP_NODEFAULT,
74611042SErik.Nordmark@Sun.COM 	sizeof (struct ip6_mtuinfo), -1 /* not initialized */ },
74711042SErik.Nordmark@Sun.COM { IPV6_DONTFRAG, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
74811042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
74911042SErik.Nordmark@Sun.COM { IPV6_USE_MIN_MTU, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
75011042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
75111042SErik.Nordmark@Sun.COM { IPV6_V6ONLY, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
75211042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
75311042SErik.Nordmark@Sun.COM 
75411042SErik.Nordmark@Sun.COM /* Enable receipt of ancillary data */
75511042SErik.Nordmark@Sun.COM { IPV6_RECVPKTINFO, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
75611042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
75711042SErik.Nordmark@Sun.COM { IPV6_RECVHOPLIMIT, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
75811042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
75911042SErik.Nordmark@Sun.COM { IPV6_RECVTCLASS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
76011042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
76111042SErik.Nordmark@Sun.COM { IPV6_RECVHOPOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
76211042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
76311042SErik.Nordmark@Sun.COM { _OLD_IPV6_RECVDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
76411042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
76511042SErik.Nordmark@Sun.COM { IPV6_RECVDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
76611042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
76711042SErik.Nordmark@Sun.COM { IPV6_RECVRTHDR, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
76811042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
76911042SErik.Nordmark@Sun.COM { IPV6_RECVRTHDRDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
77011042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
77111042SErik.Nordmark@Sun.COM { IPV6_RECVTCLASS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
77211042SErik.Nordmark@Sun.COM 	sizeof (int), 0 },
77311042SErik.Nordmark@Sun.COM 
77411042SErik.Nordmark@Sun.COM { IPV6_SEC_OPT, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, OP_NODEFAULT,
77511042SErik.Nordmark@Sun.COM 	sizeof (ipsec_req_t), -1 /* not initialized */ },
77611042SErik.Nordmark@Sun.COM { IPV6_SRC_PREFERENCES, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
77711042SErik.Nordmark@Sun.COM 	sizeof (uint32_t), IPV6_PREFER_SRC_DEFAULT },
77811042SErik.Nordmark@Sun.COM };
77911042SErik.Nordmark@Sun.COM 
78011042SErik.Nordmark@Sun.COM uint_t sctp_opt_arr_size = A_CNT(sctp_opt_arr);
78111042SErik.Nordmark@Sun.COM 
7820Sstevel@tonic-gate /* Handy on off switch for socket option processing. */
7830Sstevel@tonic-gate #define	ONOFF(x)	((x) == 0 ? 0 : 1)
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate /*
7860Sstevel@tonic-gate  * SCTP routine to get the values of options.
7870Sstevel@tonic-gate  */
7880Sstevel@tonic-gate int
sctp_get_opt(sctp_t * sctp,int level,int name,void * ptr,socklen_t * optlen)7890Sstevel@tonic-gate sctp_get_opt(sctp_t *sctp, int level, int name, void *ptr, socklen_t *optlen)
7900Sstevel@tonic-gate {
7910Sstevel@tonic-gate 	int	*i1 = (int *)ptr;
7920Sstevel@tonic-gate 	int	retval = 0;
7930Sstevel@tonic-gate 	int	buflen = *optlen;
79411042SErik.Nordmark@Sun.COM 	conn_t	*connp = sctp->sctp_connp;
79511042SErik.Nordmark@Sun.COM 	conn_opt_arg_t	coas;
79611042SErik.Nordmark@Sun.COM 
79711042SErik.Nordmark@Sun.COM 	coas.coa_connp = connp;
79811042SErik.Nordmark@Sun.COM 	coas.coa_ixa = connp->conn_ixa;
79911042SErik.Nordmark@Sun.COM 	coas.coa_ipp = &connp->conn_xmit_ipp;
8003388Skcpoon 
8010Sstevel@tonic-gate 	/* In most cases, the return buffer is just an int */
8020Sstevel@tonic-gate 	*optlen = sizeof (int32_t);
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	RUN_SCTP(sctp);
8050Sstevel@tonic-gate 
8064505Skcpoon 	if (connp->conn_state_flags & CONN_CLOSING) {
8074505Skcpoon 		WAKE_SCTP(sctp);
8084505Skcpoon 		return (EINVAL);
8094505Skcpoon 	}
8104505Skcpoon 
81111042SErik.Nordmark@Sun.COM 	/*
81211042SErik.Nordmark@Sun.COM 	 * Check that the level and name are supported by SCTP, and that
81311042SErik.Nordmark@Sun.COM 	 * the length and credentials are ok.
81411042SErik.Nordmark@Sun.COM 	 */
81511042SErik.Nordmark@Sun.COM 	retval = proto_opt_check(level, name, buflen, NULL, sctp_opt_arr,
81611042SErik.Nordmark@Sun.COM 	    sctp_opt_arr_size, B_FALSE, B_TRUE, connp->conn_cred);
81711042SErik.Nordmark@Sun.COM 	if (retval != 0) {
81811042SErik.Nordmark@Sun.COM 		WAKE_SCTP(sctp);
81911042SErik.Nordmark@Sun.COM 		if (retval < 0) {
82011042SErik.Nordmark@Sun.COM 			retval = proto_tlitosyserr(-retval);
8210Sstevel@tonic-gate 		}
82211042SErik.Nordmark@Sun.COM 		return (retval);
82311042SErik.Nordmark@Sun.COM 	}
8240Sstevel@tonic-gate 
82511042SErik.Nordmark@Sun.COM 	switch (level) {
8260Sstevel@tonic-gate 	case IPPROTO_SCTP:
8270Sstevel@tonic-gate 		switch (name) {
8280Sstevel@tonic-gate 		case SCTP_RTOINFO:
8290Sstevel@tonic-gate 			*optlen = sctp_get_rtoinfo(sctp, ptr);
8300Sstevel@tonic-gate 			break;
8310Sstevel@tonic-gate 		case SCTP_ASSOCINFO:
8320Sstevel@tonic-gate 			*optlen = sctp_get_assocparams(sctp, ptr);
8330Sstevel@tonic-gate 			break;
8340Sstevel@tonic-gate 		case SCTP_INITMSG:
8350Sstevel@tonic-gate 			*optlen = sctp_get_initmsg(sctp, ptr);
8360Sstevel@tonic-gate 			break;
8370Sstevel@tonic-gate 		case SCTP_NODELAY:
8380Sstevel@tonic-gate 			*i1 = sctp->sctp_ndelay;
8390Sstevel@tonic-gate 			break;
8400Sstevel@tonic-gate 		case SCTP_AUTOCLOSE:
8410Sstevel@tonic-gate 			*i1 = TICK_TO_SEC(sctp->sctp_autoclose);
8420Sstevel@tonic-gate 			break;
8435586Skcpoon 		case SCTP_ADAPTATION_LAYER:
8445586Skcpoon 			((struct sctp_setadaptation *)ptr)->ssb_adaptation_ind =
8455586Skcpoon 			    sctp->sctp_tx_adaptation_code;
8460Sstevel@tonic-gate 			break;
8470Sstevel@tonic-gate 		case SCTP_PEER_ADDR_PARAMS:
8480Sstevel@tonic-gate 			*optlen = sctp_get_peer_addr_params(sctp, ptr);
8490Sstevel@tonic-gate 			break;
8500Sstevel@tonic-gate 		case SCTP_DEFAULT_SEND_PARAM:
8510Sstevel@tonic-gate 			*optlen = sctp_get_def_send_params(sctp, ptr);
8520Sstevel@tonic-gate 			break;
8530Sstevel@tonic-gate 		case SCTP_EVENTS: {
8540Sstevel@tonic-gate 			struct sctp_event_subscribe *ev;
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 			ev = (struct sctp_event_subscribe *)ptr;
8570Sstevel@tonic-gate 			ev->sctp_data_io_event =
8580Sstevel@tonic-gate 			    ONOFF(sctp->sctp_recvsndrcvinfo);
8590Sstevel@tonic-gate 			ev->sctp_association_event =
8600Sstevel@tonic-gate 			    ONOFF(sctp->sctp_recvassocevnt);
8610Sstevel@tonic-gate 			ev->sctp_address_event =
8620Sstevel@tonic-gate 			    ONOFF(sctp->sctp_recvpathevnt);
8630Sstevel@tonic-gate 			ev->sctp_send_failure_event =
8640Sstevel@tonic-gate 			    ONOFF(sctp->sctp_recvsendfailevnt);
8650Sstevel@tonic-gate 			ev->sctp_peer_error_event =
8660Sstevel@tonic-gate 			    ONOFF(sctp->sctp_recvpeererr);
8670Sstevel@tonic-gate 			ev->sctp_shutdown_event =
8680Sstevel@tonic-gate 			    ONOFF(sctp->sctp_recvshutdownevnt);
8690Sstevel@tonic-gate 			ev->sctp_partial_delivery_event =
8700Sstevel@tonic-gate 			    ONOFF(sctp->sctp_recvpdevnt);
8715586Skcpoon 			ev->sctp_adaptation_layer_event =
8724505Skcpoon 			    ONOFF(sctp->sctp_recvalevnt);
8730Sstevel@tonic-gate 			*optlen = sizeof (struct sctp_event_subscribe);
8740Sstevel@tonic-gate 			break;
8750Sstevel@tonic-gate 		}
8760Sstevel@tonic-gate 		case SCTP_STATUS:
8770Sstevel@tonic-gate 			*optlen = sctp_get_status(sctp, ptr);
8780Sstevel@tonic-gate 			break;
8790Sstevel@tonic-gate 		case SCTP_GET_PEER_ADDR_INFO:
8800Sstevel@tonic-gate 			retval = sctp_get_paddrinfo(sctp, ptr, optlen);
8810Sstevel@tonic-gate 			break;
8820Sstevel@tonic-gate 		case SCTP_GET_NLADDRS:
8830Sstevel@tonic-gate 			*(int32_t *)ptr = sctp->sctp_nsaddrs;
8840Sstevel@tonic-gate 			break;
8850Sstevel@tonic-gate 		case SCTP_GET_LADDRS: {
8860Sstevel@tonic-gate 			int addr_cnt;
8870Sstevel@tonic-gate 			int addr_size;
8880Sstevel@tonic-gate 
88911042SErik.Nordmark@Sun.COM 			if (connp->conn_family == AF_INET)
8900Sstevel@tonic-gate 				addr_size = sizeof (struct sockaddr_in);
8910Sstevel@tonic-gate 			else
8920Sstevel@tonic-gate 				addr_size = sizeof (struct sockaddr_in6);
8930Sstevel@tonic-gate 			addr_cnt = buflen / addr_size;
8940Sstevel@tonic-gate 			retval = sctp_getmyaddrs(sctp, ptr, &addr_cnt);
8950Sstevel@tonic-gate 			if (retval == 0)
8960Sstevel@tonic-gate 				*optlen = addr_cnt * addr_size;
8970Sstevel@tonic-gate 			break;
8980Sstevel@tonic-gate 		}
8990Sstevel@tonic-gate 		case SCTP_GET_NPADDRS: {
9000Sstevel@tonic-gate 			int i;
9010Sstevel@tonic-gate 			sctp_faddr_t *fp;
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 			for (i = 0, fp = sctp->sctp_faddrs; fp != NULL;
90413009SChandrasekar.Marimuthu@Sun.COM 			    i++, fp = fp->sf_next)
9050Sstevel@tonic-gate 				;
9060Sstevel@tonic-gate 			*(int32_t *)ptr = i;
9070Sstevel@tonic-gate 			break;
9080Sstevel@tonic-gate 		}
9090Sstevel@tonic-gate 		case SCTP_GET_PADDRS: {
9100Sstevel@tonic-gate 			int addr_cnt;
9110Sstevel@tonic-gate 			int addr_size;
9120Sstevel@tonic-gate 
91311042SErik.Nordmark@Sun.COM 			if (connp->conn_family == AF_INET)
9140Sstevel@tonic-gate 				addr_size = sizeof (struct sockaddr_in);
9150Sstevel@tonic-gate 			else
9160Sstevel@tonic-gate 				addr_size = sizeof (struct sockaddr_in6);
9170Sstevel@tonic-gate 			addr_cnt = buflen / addr_size;
9180Sstevel@tonic-gate 			retval = sctp_getpeeraddrs(sctp, ptr, &addr_cnt);
9190Sstevel@tonic-gate 			if (retval == 0)
9200Sstevel@tonic-gate 				*optlen = addr_cnt * addr_size;
9210Sstevel@tonic-gate 			break;
9220Sstevel@tonic-gate 		}
9230Sstevel@tonic-gate 		case SCTP_PRSCTP:
9240Sstevel@tonic-gate 			*i1 = sctp->sctp_prsctp_aware ? 1 : 0;
9250Sstevel@tonic-gate 			break;
92610212SGeorge.Shepherd@Sun.COM 
92710212SGeorge.Shepherd@Sun.COM 		case SCTP_GET_ASSOC_STATS: {
92810212SGeorge.Shepherd@Sun.COM 			sctp_assoc_stats_t *sas;
92910212SGeorge.Shepherd@Sun.COM 
93010212SGeorge.Shepherd@Sun.COM 			sas = (sctp_assoc_stats_t *)ptr;
93110212SGeorge.Shepherd@Sun.COM 
93210212SGeorge.Shepherd@Sun.COM 			/*
93310212SGeorge.Shepherd@Sun.COM 			 * Copy the current stats to the stats struct.
93410751SGeorge.Shepherd@Sun.COM 			 * For stats which can be reset by snmp users
93510751SGeorge.Shepherd@Sun.COM 			 * add the cumulative and current stats for
93610751SGeorge.Shepherd@Sun.COM 			 * the raw totals to output to the user.
93710212SGeorge.Shepherd@Sun.COM 			 */
93810212SGeorge.Shepherd@Sun.COM 			sas->sas_gapcnt = sctp->sctp_gapcnt;
93910212SGeorge.Shepherd@Sun.COM 			sas->sas_outseqtsns = sctp->sctp_outseqtsns;
94010212SGeorge.Shepherd@Sun.COM 			sas->sas_osacks = sctp->sctp_osacks;
94110212SGeorge.Shepherd@Sun.COM 			sas->sas_isacks = sctp->sctp_isacks;
94210212SGeorge.Shepherd@Sun.COM 			sas->sas_idupchunks = sctp->sctp_idupchunks;
94310751SGeorge.Shepherd@Sun.COM 			sas->sas_rtxchunks =  sctp->sctp_rxtchunks +
94410751SGeorge.Shepherd@Sun.COM 			    sctp->sctp_cum_rxtchunks;
94510751SGeorge.Shepherd@Sun.COM 			sas->sas_octrlchunks = sctp->sctp_obchunks +
94610751SGeorge.Shepherd@Sun.COM 			    sctp->sctp_cum_obchunks;
94710751SGeorge.Shepherd@Sun.COM 			sas->sas_ictrlchunks = sctp->sctp_ibchunks +
94810751SGeorge.Shepherd@Sun.COM 			    sctp->sctp_cum_ibchunks;
94910751SGeorge.Shepherd@Sun.COM 			sas->sas_oodchunks = sctp->sctp_odchunks +
95010751SGeorge.Shepherd@Sun.COM 			    sctp->sctp_cum_odchunks;
95110751SGeorge.Shepherd@Sun.COM 			sas->sas_iodchunks = sctp->sctp_idchunks +
95210751SGeorge.Shepherd@Sun.COM 			    sctp->sctp_cum_idchunks;
95310751SGeorge.Shepherd@Sun.COM 			sas->sas_ouodchunks = sctp->sctp_oudchunks +
95410751SGeorge.Shepherd@Sun.COM 			    sctp->sctp_cum_oudchunks;
95510751SGeorge.Shepherd@Sun.COM 			sas->sas_iuodchunks = sctp->sctp_iudchunks +
95610751SGeorge.Shepherd@Sun.COM 			    sctp->sctp_cum_iudchunks;
95710212SGeorge.Shepherd@Sun.COM 
95810212SGeorge.Shepherd@Sun.COM 			/*
95910212SGeorge.Shepherd@Sun.COM 			 * Copy out the maximum observed RTO since the
96010212SGeorge.Shepherd@Sun.COM 			 * time this data was last requested
96110212SGeorge.Shepherd@Sun.COM 			 */
96210212SGeorge.Shepherd@Sun.COM 			if (sctp->sctp_maxrto == 0) {
96310212SGeorge.Shepherd@Sun.COM 				/* unchanged during obervation period */
96410212SGeorge.Shepherd@Sun.COM 				sas->sas_maxrto = sctp->sctp_prev_maxrto;
96510212SGeorge.Shepherd@Sun.COM 			} else {
96610212SGeorge.Shepherd@Sun.COM 				/* record new period maximum */
96710212SGeorge.Shepherd@Sun.COM 				sas->sas_maxrto = sctp->sctp_maxrto;
96810212SGeorge.Shepherd@Sun.COM 			}
96910212SGeorge.Shepherd@Sun.COM 			/* Record the value sent to the user this period */
97010212SGeorge.Shepherd@Sun.COM 			sctp->sctp_prev_maxrto = sas->sas_maxrto;
97110212SGeorge.Shepherd@Sun.COM 
97210212SGeorge.Shepherd@Sun.COM 			/* Mark beginning of a new observation period */
97310212SGeorge.Shepherd@Sun.COM 			sctp->sctp_maxrto = 0;
97410212SGeorge.Shepherd@Sun.COM 
97510212SGeorge.Shepherd@Sun.COM 			*optlen = sizeof (sctp_assoc_stats_t);
97610212SGeorge.Shepherd@Sun.COM 			break;
97710212SGeorge.Shepherd@Sun.COM 		}
9780Sstevel@tonic-gate 		case SCTP_I_WANT_MAPPED_V4_ADDR:
9790Sstevel@tonic-gate 		case SCTP_MAXSEG:
9800Sstevel@tonic-gate 		case SCTP_DISABLE_FRAGMENTS:
98111042SErik.Nordmark@Sun.COM 		default:
9820Sstevel@tonic-gate 			/* Not yet supported. */
9833388Skcpoon 			retval = ENOPROTOOPT;
9840Sstevel@tonic-gate 			break;
9850Sstevel@tonic-gate 		}
98611042SErik.Nordmark@Sun.COM 		WAKE_SCTP(sctp);
98711042SErik.Nordmark@Sun.COM 		return (retval);
9880Sstevel@tonic-gate 	case IPPROTO_IP:
98911042SErik.Nordmark@Sun.COM 		if (connp->conn_family != AF_INET) {
9900Sstevel@tonic-gate 			retval = EINVAL;
9910Sstevel@tonic-gate 			break;
9920Sstevel@tonic-gate 		}
9930Sstevel@tonic-gate 		switch (name) {
9940Sstevel@tonic-gate 		case IP_OPTIONS:
9950Sstevel@tonic-gate 		case T_IP_OPTIONS: {
9960Sstevel@tonic-gate 			/*
9970Sstevel@tonic-gate 			 * This is compatible with BSD in that in only return
9980Sstevel@tonic-gate 			 * the reverse source route with the final destination
9990Sstevel@tonic-gate 			 * as the last entry. The first 4 bytes of the option
10000Sstevel@tonic-gate 			 * will contain the final destination. Allocate a
10010Sstevel@tonic-gate 			 * buffer large enough to hold all the options, we
10020Sstevel@tonic-gate 			 * add IP_ADDR_LEN to SCTP_MAX_IP_OPTIONS_LENGTH since
10031676Sjpk 			 * ip_opt_get_user() adds the final destination
10040Sstevel@tonic-gate 			 * at the start.
10050Sstevel@tonic-gate 			 */
10060Sstevel@tonic-gate 			int	opt_len;
10070Sstevel@tonic-gate 			uchar_t	obuf[SCTP_MAX_IP_OPTIONS_LENGTH + IP_ADDR_LEN];
10080Sstevel@tonic-gate 
100911042SErik.Nordmark@Sun.COM 			opt_len = ip_opt_get_user(connp, obuf);
101011042SErik.Nordmark@Sun.COM 			ASSERT(opt_len <= sizeof (obuf));
101111042SErik.Nordmark@Sun.COM 
10120Sstevel@tonic-gate 			if (buflen < opt_len) {
10130Sstevel@tonic-gate 				/* Silently truncate */
10140Sstevel@tonic-gate 				opt_len = buflen;
10150Sstevel@tonic-gate 			}
10160Sstevel@tonic-gate 			*optlen = opt_len;
10170Sstevel@tonic-gate 			bcopy(obuf, ptr, opt_len);
101811042SErik.Nordmark@Sun.COM 			WAKE_SCTP(sctp);
101911042SErik.Nordmark@Sun.COM 			return (0);
10200Sstevel@tonic-gate 		}
10210Sstevel@tonic-gate 		default:
10220Sstevel@tonic-gate 			break;
10230Sstevel@tonic-gate 		}
10240Sstevel@tonic-gate 		break;
10250Sstevel@tonic-gate 	}
102611042SErik.Nordmark@Sun.COM 	mutex_enter(&connp->conn_lock);
102711042SErik.Nordmark@Sun.COM 	retval = conn_opt_get(&coas, level, name, ptr);
102811042SErik.Nordmark@Sun.COM 	mutex_exit(&connp->conn_lock);
10290Sstevel@tonic-gate 	WAKE_SCTP(sctp);
103011042SErik.Nordmark@Sun.COM 	if (retval == -1)
103111042SErik.Nordmark@Sun.COM 		return (EINVAL);
103211042SErik.Nordmark@Sun.COM 	*optlen = retval;
103311042SErik.Nordmark@Sun.COM 	return (0);
10340Sstevel@tonic-gate }
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate int
sctp_set_opt(sctp_t * sctp,int level,int name,const void * invalp,socklen_t inlen)10370Sstevel@tonic-gate sctp_set_opt(sctp_t *sctp, int level, int name, const void *invalp,
10380Sstevel@tonic-gate     socklen_t inlen)
10390Sstevel@tonic-gate {
10400Sstevel@tonic-gate 	int		*i1 = (int *)invalp;
10410Sstevel@tonic-gate 	boolean_t	onoff;
10420Sstevel@tonic-gate 	int		retval = 0, addrcnt;
10430Sstevel@tonic-gate 	conn_t		*connp = sctp->sctp_connp;
10443448Sdh155122 	sctp_stack_t	*sctps = sctp->sctp_sctps;
104511042SErik.Nordmark@Sun.COM 	conn_opt_arg_t	coas;
104611042SErik.Nordmark@Sun.COM 
104711042SErik.Nordmark@Sun.COM 	coas.coa_connp = connp;
104811042SErik.Nordmark@Sun.COM 	coas.coa_ixa = connp->conn_ixa;
104911042SErik.Nordmark@Sun.COM 	coas.coa_ipp = &connp->conn_xmit_ipp;
105011042SErik.Nordmark@Sun.COM 	coas.coa_ancillary = B_FALSE;
105111042SErik.Nordmark@Sun.COM 	coas.coa_changed = 0;
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 	/* In all cases, the size of the option must be bigger than int */
10540Sstevel@tonic-gate 	if (inlen >= sizeof (int32_t)) {
10550Sstevel@tonic-gate 		onoff = ONOFF(*i1);
10560Sstevel@tonic-gate 	}
10570Sstevel@tonic-gate 	retval = 0;
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 	RUN_SCTP(sctp);
10600Sstevel@tonic-gate 
10614505Skcpoon 	if (connp->conn_state_flags & CONN_CLOSING) {
10624505Skcpoon 		WAKE_SCTP(sctp);
10634505Skcpoon 		return (EINVAL);
10644505Skcpoon 	}
10654505Skcpoon 
106611042SErik.Nordmark@Sun.COM 	/*
106711042SErik.Nordmark@Sun.COM 	 * Check that the level and name are supported by SCTP, and that
106811042SErik.Nordmark@Sun.COM 	 * the length an credentials are ok.
106911042SErik.Nordmark@Sun.COM 	 */
107011042SErik.Nordmark@Sun.COM 	retval = proto_opt_check(level, name, inlen, NULL, sctp_opt_arr,
107111042SErik.Nordmark@Sun.COM 	    sctp_opt_arr_size, B_TRUE, B_FALSE, connp->conn_cred);
107211042SErik.Nordmark@Sun.COM 	if (retval != 0) {
107311042SErik.Nordmark@Sun.COM 		if (retval < 0) {
107411042SErik.Nordmark@Sun.COM 			retval = proto_tlitosyserr(-retval);
107511042SErik.Nordmark@Sun.COM 		}
107611042SErik.Nordmark@Sun.COM 		goto done;
107711042SErik.Nordmark@Sun.COM 	}
107811042SErik.Nordmark@Sun.COM 
107911042SErik.Nordmark@Sun.COM 	/* Note: both SCTP and TCP interpret l_linger as being in seconds */
10800Sstevel@tonic-gate 	switch (level) {
10810Sstevel@tonic-gate 	case SOL_SOCKET:
10820Sstevel@tonic-gate 		switch (name) {
10830Sstevel@tonic-gate 		case SO_SNDBUF:
10843448Sdh155122 			if (*i1 > sctps->sctps_max_buf) {
10850Sstevel@tonic-gate 				retval = ENOBUFS;
108611042SErik.Nordmark@Sun.COM 				goto done;
10870Sstevel@tonic-gate 			}
10880Sstevel@tonic-gate 			if (*i1 < 0) {
10890Sstevel@tonic-gate 				retval = EINVAL;
109011042SErik.Nordmark@Sun.COM 				goto done;
10910Sstevel@tonic-gate 			}
109211042SErik.Nordmark@Sun.COM 			connp->conn_sndbuf = *i1;
109311042SErik.Nordmark@Sun.COM 			if (sctps->sctps_snd_lowat_fraction != 0) {
109411042SErik.Nordmark@Sun.COM 				connp->conn_sndlowat = connp->conn_sndbuf /
10953448Sdh155122 				    sctps->sctps_snd_lowat_fraction;
109611042SErik.Nordmark@Sun.COM 			}
109711042SErik.Nordmark@Sun.COM 			goto done;
10980Sstevel@tonic-gate 		case SO_RCVBUF:
10993448Sdh155122 			if (*i1 > sctps->sctps_max_buf) {
11000Sstevel@tonic-gate 				retval = ENOBUFS;
110111042SErik.Nordmark@Sun.COM 				goto done;
11020Sstevel@tonic-gate 			}
11030Sstevel@tonic-gate 			/* Silently ignore zero */
11040Sstevel@tonic-gate 			if (*i1 != 0) {
11058682SAnders.Persson@Sun.COM 				struct sock_proto_props sopp;
11068682SAnders.Persson@Sun.COM 
11070Sstevel@tonic-gate 				/*
11080Sstevel@tonic-gate 				 * Insist on a receive window that is at least
11090Sstevel@tonic-gate 				 * sctp_recv_hiwat_minmss * MSS (default 4*MSS)
11100Sstevel@tonic-gate 				 * to avoid funny interactions of Nagle
11110Sstevel@tonic-gate 				 * algorithm, SWS avoidance and delayed
11120Sstevel@tonic-gate 				 * acknowledgement.
11130Sstevel@tonic-gate 				 */
11140Sstevel@tonic-gate 				*i1 = MAX(*i1,
11153448Sdh155122 				    sctps->sctps_recv_hiwat_minmss *
11163448Sdh155122 				    sctp->sctp_mss);
111711042SErik.Nordmark@Sun.COM 				/*
111811042SErik.Nordmark@Sun.COM 				 * Note that sctp_rwnd is modified by the
111911042SErik.Nordmark@Sun.COM 				 * protocol and here we just whack it.
112011042SErik.Nordmark@Sun.COM 				 */
112111042SErik.Nordmark@Sun.COM 				connp->conn_rcvbuf = sctp->sctp_rwnd = *i1;
1122*13054SKacheong.Poon@Sun.COM 				sctp->sctp_arwnd = sctp->sctp_rwnd;
11233845Svi117747 				sctp->sctp_pd_point = sctp->sctp_rwnd;
11248682SAnders.Persson@Sun.COM 
11258682SAnders.Persson@Sun.COM 				sopp.sopp_flags = SOCKOPT_RCVHIWAT;
112611042SErik.Nordmark@Sun.COM 				sopp.sopp_rxhiwat = connp->conn_rcvbuf;
11278682SAnders.Persson@Sun.COM 				sctp->sctp_ulp_prop(sctp->sctp_ulpd, &sopp);
11288682SAnders.Persson@Sun.COM 
11290Sstevel@tonic-gate 			}
11300Sstevel@tonic-gate 			/*
11310Sstevel@tonic-gate 			 * XXX should we return the rwnd here
11320Sstevel@tonic-gate 			 * and sctp_opt_get ?
11330Sstevel@tonic-gate 			 */
113411042SErik.Nordmark@Sun.COM 			goto done;
11352263Ssommerfe 		case SO_ALLZONES:
11362263Ssommerfe 			if (sctp->sctp_state >= SCTPS_BOUND) {
11372263Ssommerfe 				retval = EINVAL;
113811042SErik.Nordmark@Sun.COM 				goto done;
11392263Ssommerfe 			}
114010934Ssommerfeld@sun.com 			break;
114111042SErik.Nordmark@Sun.COM 		case SO_MAC_EXEMPT:
114210934Ssommerfeld@sun.com 			if (sctp->sctp_state >= SCTPS_BOUND) {
114310934Ssommerfeld@sun.com 				retval = EINVAL;
114411042SErik.Nordmark@Sun.COM 				goto done;
114510934Ssommerfeld@sun.com 			}
11460Sstevel@tonic-gate 			break;
11470Sstevel@tonic-gate 		}
11480Sstevel@tonic-gate 		break;
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	case IPPROTO_SCTP:
11510Sstevel@tonic-gate 		switch (name) {
11520Sstevel@tonic-gate 		case SCTP_RTOINFO:
115311042SErik.Nordmark@Sun.COM 			retval = sctp_set_rtoinfo(sctp, invalp);
11540Sstevel@tonic-gate 			break;
11550Sstevel@tonic-gate 		case SCTP_ASSOCINFO:
115611042SErik.Nordmark@Sun.COM 			retval = sctp_set_assocparams(sctp, invalp);
11570Sstevel@tonic-gate 			break;
11580Sstevel@tonic-gate 		case SCTP_INITMSG:
11590Sstevel@tonic-gate 			retval = sctp_set_initmsg(sctp, invalp, inlen);
11600Sstevel@tonic-gate 			break;
11610Sstevel@tonic-gate 		case SCTP_NODELAY:
11620Sstevel@tonic-gate 			sctp->sctp_ndelay = ONOFF(*i1);
11630Sstevel@tonic-gate 			break;
11640Sstevel@tonic-gate 		case SCTP_AUTOCLOSE:
11650Sstevel@tonic-gate 			if (SEC_TO_TICK(*i1) < 0) {
11660Sstevel@tonic-gate 				retval = EINVAL;
11670Sstevel@tonic-gate 				break;
11680Sstevel@tonic-gate 			}
11690Sstevel@tonic-gate 			/* Convert the number of seconds to ticks. */
11700Sstevel@tonic-gate 			sctp->sctp_autoclose = SEC_TO_TICK(*i1);
11710Sstevel@tonic-gate 			sctp_heartbeat_timer(sctp);
11720Sstevel@tonic-gate 			break;
11730Sstevel@tonic-gate 		case SCTP_SET_PEER_PRIMARY_ADDR:
117411042SErik.Nordmark@Sun.COM 			retval = sctp_set_peerprim(sctp, invalp);
11750Sstevel@tonic-gate 			break;
11760Sstevel@tonic-gate 		case SCTP_PRIMARY_ADDR:
117711042SErik.Nordmark@Sun.COM 			retval = sctp_set_prim(sctp, invalp);
11780Sstevel@tonic-gate 			break;
11795586Skcpoon 		case SCTP_ADAPTATION_LAYER: {
11805586Skcpoon 			struct sctp_setadaptation *ssb;
11810Sstevel@tonic-gate 
11825586Skcpoon 			ssb = (struct sctp_setadaptation *)invalp;
11835586Skcpoon 			sctp->sctp_send_adaptation = 1;
11845586Skcpoon 			sctp->sctp_tx_adaptation_code = ssb->ssb_adaptation_ind;
11850Sstevel@tonic-gate 			break;
11860Sstevel@tonic-gate 		}
11870Sstevel@tonic-gate 		case SCTP_PEER_ADDR_PARAMS:
118811042SErik.Nordmark@Sun.COM 			retval = sctp_set_peer_addr_params(sctp, invalp);
11890Sstevel@tonic-gate 			break;
11900Sstevel@tonic-gate 		case SCTP_DEFAULT_SEND_PARAM:
119111042SErik.Nordmark@Sun.COM 			retval = sctp_set_def_send_params(sctp, invalp);
11920Sstevel@tonic-gate 			break;
11930Sstevel@tonic-gate 		case SCTP_EVENTS: {
11940Sstevel@tonic-gate 			struct sctp_event_subscribe *ev;
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 			ev = (struct sctp_event_subscribe *)invalp;
11970Sstevel@tonic-gate 			sctp->sctp_recvsndrcvinfo =
11980Sstevel@tonic-gate 			    ONOFF(ev->sctp_data_io_event);
11990Sstevel@tonic-gate 			sctp->sctp_recvassocevnt =
12000Sstevel@tonic-gate 			    ONOFF(ev->sctp_association_event);
12010Sstevel@tonic-gate 			sctp->sctp_recvpathevnt =
12020Sstevel@tonic-gate 			    ONOFF(ev->sctp_address_event);
12030Sstevel@tonic-gate 			sctp->sctp_recvsendfailevnt =
12040Sstevel@tonic-gate 			    ONOFF(ev->sctp_send_failure_event);
12050Sstevel@tonic-gate 			sctp->sctp_recvpeererr =
12060Sstevel@tonic-gate 			    ONOFF(ev->sctp_peer_error_event);
12070Sstevel@tonic-gate 			sctp->sctp_recvshutdownevnt =
12080Sstevel@tonic-gate 			    ONOFF(ev->sctp_shutdown_event);
12090Sstevel@tonic-gate 			sctp->sctp_recvpdevnt =
12100Sstevel@tonic-gate 			    ONOFF(ev->sctp_partial_delivery_event);
12110Sstevel@tonic-gate 			sctp->sctp_recvalevnt =
12125586Skcpoon 			    ONOFF(ev->sctp_adaptation_layer_event);
12130Sstevel@tonic-gate 			break;
12140Sstevel@tonic-gate 		}
12150Sstevel@tonic-gate 		case SCTP_ADD_ADDR:
12160Sstevel@tonic-gate 		case SCTP_REM_ADDR:
12170Sstevel@tonic-gate 			/*
12180Sstevel@tonic-gate 			 * The sctp_t has to be bound first before
12190Sstevel@tonic-gate 			 * the address list can be changed.
12200Sstevel@tonic-gate 			 */
12210Sstevel@tonic-gate 			if (sctp->sctp_state < SCTPS_BOUND) {
12220Sstevel@tonic-gate 				retval = EINVAL;
12230Sstevel@tonic-gate 				break;
12240Sstevel@tonic-gate 			}
122511042SErik.Nordmark@Sun.COM 			if (connp->conn_family == AF_INET) {
12260Sstevel@tonic-gate 				addrcnt = inlen / sizeof (struct sockaddr_in);
12270Sstevel@tonic-gate 			} else {
122811042SErik.Nordmark@Sun.COM 				ASSERT(connp->conn_family == AF_INET6);
12290Sstevel@tonic-gate 				addrcnt = inlen / sizeof (struct sockaddr_in6);
12300Sstevel@tonic-gate 			}
12310Sstevel@tonic-gate 			if (name == SCTP_ADD_ADDR) {
12320Sstevel@tonic-gate 				retval = sctp_bind_add(sctp, invalp, addrcnt,
123311042SErik.Nordmark@Sun.COM 				    B_TRUE, connp->conn_lport);
12340Sstevel@tonic-gate 			} else {
12350Sstevel@tonic-gate 				retval = sctp_bind_del(sctp, invalp, addrcnt,
12360Sstevel@tonic-gate 				    B_TRUE);
12370Sstevel@tonic-gate 			}
12380Sstevel@tonic-gate 			break;
12390Sstevel@tonic-gate 		case SCTP_UC_SWAP: {
12400Sstevel@tonic-gate 			struct sctp_uc_swap *us;
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 			/*
12430Sstevel@tonic-gate 			 * Change handle & upcalls.
12440Sstevel@tonic-gate 			 */
12450Sstevel@tonic-gate 			us = (struct sctp_uc_swap *)invalp;
12460Sstevel@tonic-gate 			sctp->sctp_ulpd = us->sus_handle;
12478348SEric.Yu@Sun.COM 			sctp->sctp_upcalls = us->sus_upcalls;
12480Sstevel@tonic-gate 			break;
12490Sstevel@tonic-gate 		}
12500Sstevel@tonic-gate 		case SCTP_PRSCTP:
12510Sstevel@tonic-gate 			sctp->sctp_prsctp_aware = onoff;
12520Sstevel@tonic-gate 			break;
12530Sstevel@tonic-gate 		case SCTP_I_WANT_MAPPED_V4_ADDR:
12540Sstevel@tonic-gate 		case SCTP_MAXSEG:
12550Sstevel@tonic-gate 		case SCTP_DISABLE_FRAGMENTS:
12560Sstevel@tonic-gate 			/* Not yet supported. */
12570Sstevel@tonic-gate 			retval = ENOPROTOOPT;
12580Sstevel@tonic-gate 			break;
12590Sstevel@tonic-gate 		}
126011042SErik.Nordmark@Sun.COM 		goto done;
126111042SErik.Nordmark@Sun.COM 
126211042SErik.Nordmark@Sun.COM 	case IPPROTO_IP:
126311042SErik.Nordmark@Sun.COM 		if (connp->conn_family != AF_INET) {
126411042SErik.Nordmark@Sun.COM 			retval = ENOPROTOOPT;
126511042SErik.Nordmark@Sun.COM 			goto done;
12660Sstevel@tonic-gate 		}
12670Sstevel@tonic-gate 		switch (name) {
12680Sstevel@tonic-gate 		case IP_SEC_OPT:
12690Sstevel@tonic-gate 			/*
12700Sstevel@tonic-gate 			 * We should not allow policy setting after
12710Sstevel@tonic-gate 			 * we start listening for connections.
12720Sstevel@tonic-gate 			 */
12730Sstevel@tonic-gate 			if (sctp->sctp_state >= SCTPS_LISTEN) {
12740Sstevel@tonic-gate 				retval = EINVAL;
127511042SErik.Nordmark@Sun.COM 				goto done;
12761095Spriyanka 			}
12771095Spriyanka 			break;
12781095Spriyanka 		}
12790Sstevel@tonic-gate 		break;
128011042SErik.Nordmark@Sun.COM 	case IPPROTO_IPV6:
128111042SErik.Nordmark@Sun.COM 		if (connp->conn_family != AF_INET6) {
128211042SErik.Nordmark@Sun.COM 			retval = EINVAL;
128311042SErik.Nordmark@Sun.COM 			goto done;
12840Sstevel@tonic-gate 		}
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 		switch (name) {
12870Sstevel@tonic-gate 		case IPV6_RECVPKTINFO:
12880Sstevel@tonic-gate 			/* Send it with the next msg */
12890Sstevel@tonic-gate 			sctp->sctp_recvifindex = 0;
129011042SErik.Nordmark@Sun.COM 			break;
129111042SErik.Nordmark@Sun.COM 		case IPV6_RECVTCLASS:
129211042SErik.Nordmark@Sun.COM 			/* Force it to be sent up with the next msg */
129311042SErik.Nordmark@Sun.COM 			sctp->sctp_recvtclass = 0xffffffffU;
12940Sstevel@tonic-gate 			break;
12950Sstevel@tonic-gate 		case IPV6_RECVHOPLIMIT:
129611042SErik.Nordmark@Sun.COM 			/* Force it to be sent up with the next msg */
12970Sstevel@tonic-gate 			sctp->sctp_recvhops = 0xffffffffU;
12980Sstevel@tonic-gate 			break;
12990Sstevel@tonic-gate 		case IPV6_SEC_OPT:
13000Sstevel@tonic-gate 			/*
13010Sstevel@tonic-gate 			 * We should not allow policy setting after
13020Sstevel@tonic-gate 			 * we start listening for connections.
13030Sstevel@tonic-gate 			 */
13040Sstevel@tonic-gate 			if (sctp->sctp_state >= SCTPS_LISTEN) {
13050Sstevel@tonic-gate 				retval = EINVAL;
130611042SErik.Nordmark@Sun.COM 				goto done;
13070Sstevel@tonic-gate 			}
13080Sstevel@tonic-gate 			break;
13090Sstevel@tonic-gate 		case IPV6_V6ONLY:
13100Sstevel@tonic-gate 			/*
13110Sstevel@tonic-gate 			 * After the bound state, setting the v6only option
13120Sstevel@tonic-gate 			 * is too late.
13130Sstevel@tonic-gate 			 */
13140Sstevel@tonic-gate 			if (sctp->sctp_state >= SCTPS_BOUND) {
13150Sstevel@tonic-gate 				retval = EINVAL;
131611042SErik.Nordmark@Sun.COM 				goto done;
13170Sstevel@tonic-gate 			}
13180Sstevel@tonic-gate 			break;
13190Sstevel@tonic-gate 		}
13200Sstevel@tonic-gate 		break;
13210Sstevel@tonic-gate 	}
132211042SErik.Nordmark@Sun.COM 
132311042SErik.Nordmark@Sun.COM 	retval = conn_opt_set(&coas, level, name, inlen, (uchar_t *)invalp,
132411042SErik.Nordmark@Sun.COM 	    B_FALSE, connp->conn_cred);
132511042SErik.Nordmark@Sun.COM 	if (retval != 0)
132611042SErik.Nordmark@Sun.COM 		goto done;
132711042SErik.Nordmark@Sun.COM 
132811042SErik.Nordmark@Sun.COM 	if (coas.coa_changed & COA_ROUTE_CHANGED) {
132911042SErik.Nordmark@Sun.COM 		sctp_faddr_t *fp;
133011042SErik.Nordmark@Sun.COM 		/*
133111042SErik.Nordmark@Sun.COM 		 * We recache the information which might pick a different
133211042SErik.Nordmark@Sun.COM 		 * source and redo IPsec as a result.
133311042SErik.Nordmark@Sun.COM 		 */
133413009SChandrasekar.Marimuthu@Sun.COM 		for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next)
133511042SErik.Nordmark@Sun.COM 			sctp_get_dest(sctp, fp);
13360Sstevel@tonic-gate 	}
133711042SErik.Nordmark@Sun.COM 	if (coas.coa_changed & COA_HEADER_CHANGED) {
133811042SErik.Nordmark@Sun.COM 		retval = sctp_build_hdrs(sctp, KM_NOSLEEP);
133911042SErik.Nordmark@Sun.COM 		if (retval != 0)
134011042SErik.Nordmark@Sun.COM 			goto done;
134111042SErik.Nordmark@Sun.COM 	}
134211042SErik.Nordmark@Sun.COM 	if (coas.coa_changed & COA_WROFF_CHANGED) {
134311042SErik.Nordmark@Sun.COM 		connp->conn_wroff = connp->conn_ht_iphc_allocated +
134411042SErik.Nordmark@Sun.COM 		    sctps->sctps_wroff_xtra;
134511042SErik.Nordmark@Sun.COM 		if (sctp->sctp_current != NULL) {
134611042SErik.Nordmark@Sun.COM 			/*
134711042SErik.Nordmark@Sun.COM 			 * Could be setting options before setting up
134811042SErik.Nordmark@Sun.COM 			 * connection.
134911042SErik.Nordmark@Sun.COM 			 */
135011042SErik.Nordmark@Sun.COM 			sctp_set_ulp_prop(sctp);
135111042SErik.Nordmark@Sun.COM 		}
135211042SErik.Nordmark@Sun.COM 	}
135311042SErik.Nordmark@Sun.COM done:
13540Sstevel@tonic-gate 	WAKE_SCTP(sctp);
13550Sstevel@tonic-gate 	return (retval);
13560Sstevel@tonic-gate }
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate /*
13590Sstevel@tonic-gate  * SCTP exported kernel interface for geting the first source address of
13600Sstevel@tonic-gate  * a sctp_t.  The parameter addr is assumed to have enough space to hold
13610Sstevel@tonic-gate  * one socket address.
13620Sstevel@tonic-gate  */
13630Sstevel@tonic-gate int
sctp_getsockname(sctp_t * sctp,struct sockaddr * addr,socklen_t * addrlen)13640Sstevel@tonic-gate sctp_getsockname(sctp_t *sctp, struct sockaddr *addr, socklen_t *addrlen)
13650Sstevel@tonic-gate {
13660Sstevel@tonic-gate 	int	err = 0;
13670Sstevel@tonic-gate 	int	addrcnt = 1;
13680Sstevel@tonic-gate 	sin_t	*sin4;
13690Sstevel@tonic-gate 	sin6_t	*sin6;
137011042SErik.Nordmark@Sun.COM 	conn_t	*connp = sctp->sctp_connp;
13710Sstevel@tonic-gate 
13720Sstevel@tonic-gate 	ASSERT(sctp != NULL);
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate 	RUN_SCTP(sctp);
137511042SErik.Nordmark@Sun.COM 	addr->sa_family = connp->conn_family;
137611042SErik.Nordmark@Sun.COM 	switch (connp->conn_family) {
13770Sstevel@tonic-gate 	case AF_INET:
13780Sstevel@tonic-gate 		sin4 = (sin_t *)addr;
13790Sstevel@tonic-gate 		if ((sctp->sctp_state <= SCTPS_LISTEN) &&
13800Sstevel@tonic-gate 		    sctp->sctp_bound_to_all) {
13810Sstevel@tonic-gate 			sin4->sin_addr.s_addr = INADDR_ANY;
138211042SErik.Nordmark@Sun.COM 			sin4->sin_port = connp->conn_lport;
13830Sstevel@tonic-gate 		} else {
13840Sstevel@tonic-gate 			err = sctp_getmyaddrs(sctp, sin4, &addrcnt);
13850Sstevel@tonic-gate 			if (err != 0) {
13860Sstevel@tonic-gate 				*addrlen = 0;
13870Sstevel@tonic-gate 				break;
13880Sstevel@tonic-gate 			}
13890Sstevel@tonic-gate 		}
13900Sstevel@tonic-gate 		*addrlen = sizeof (struct sockaddr_in);
13910Sstevel@tonic-gate 		break;
13920Sstevel@tonic-gate 	case AF_INET6:
13930Sstevel@tonic-gate 		sin6 = (sin6_t *)addr;
13940Sstevel@tonic-gate 		if ((sctp->sctp_state <= SCTPS_LISTEN) &&
13950Sstevel@tonic-gate 		    sctp->sctp_bound_to_all) {
13960Sstevel@tonic-gate 			bzero(&sin6->sin6_addr, sizeof (sin6->sin6_addr));
139711042SErik.Nordmark@Sun.COM 			sin6->sin6_port = connp->conn_lport;
13980Sstevel@tonic-gate 		} else {
13990Sstevel@tonic-gate 			err = sctp_getmyaddrs(sctp, sin6, &addrcnt);
14000Sstevel@tonic-gate 			if (err != 0) {
14010Sstevel@tonic-gate 				*addrlen = 0;
14020Sstevel@tonic-gate 				break;
14030Sstevel@tonic-gate 			}
14040Sstevel@tonic-gate 		}
14050Sstevel@tonic-gate 		*addrlen = sizeof (struct sockaddr_in6);
140611042SErik.Nordmark@Sun.COM 		/* Note that flowinfo is only returned for getpeername */
14070Sstevel@tonic-gate 		break;
14080Sstevel@tonic-gate 	}
14090Sstevel@tonic-gate 	WAKE_SCTP(sctp);
14100Sstevel@tonic-gate 	return (err);
14110Sstevel@tonic-gate }
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate /*
14140Sstevel@tonic-gate  * SCTP exported kernel interface for geting the primary peer address of
14150Sstevel@tonic-gate  * a sctp_t.  The parameter addr is assumed to have enough space to hold
14160Sstevel@tonic-gate  * one socket address.
14170Sstevel@tonic-gate  */
14180Sstevel@tonic-gate int
sctp_getpeername(sctp_t * sctp,struct sockaddr * addr,socklen_t * addrlen)14190Sstevel@tonic-gate sctp_getpeername(sctp_t *sctp, struct sockaddr *addr, socklen_t *addrlen)
14200Sstevel@tonic-gate {
14210Sstevel@tonic-gate 	int	err = 0;
14220Sstevel@tonic-gate 	int	addrcnt = 1;
14230Sstevel@tonic-gate 	sin6_t	*sin6;
142411042SErik.Nordmark@Sun.COM 	conn_t	*connp = sctp->sctp_connp;
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 	ASSERT(sctp != NULL);
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate 	RUN_SCTP(sctp);
142911042SErik.Nordmark@Sun.COM 	addr->sa_family = connp->conn_family;
143011042SErik.Nordmark@Sun.COM 	switch (connp->conn_family) {
14310Sstevel@tonic-gate 	case AF_INET:
14320Sstevel@tonic-gate 		err = sctp_getpeeraddrs(sctp, addr, &addrcnt);
14330Sstevel@tonic-gate 		if (err != 0) {
14340Sstevel@tonic-gate 			*addrlen = 0;
14350Sstevel@tonic-gate 			break;
14360Sstevel@tonic-gate 		}
14370Sstevel@tonic-gate 		*addrlen = sizeof (struct sockaddr_in);
14380Sstevel@tonic-gate 		break;
14390Sstevel@tonic-gate 	case AF_INET6:
14400Sstevel@tonic-gate 		sin6 = (sin6_t *)addr;
14410Sstevel@tonic-gate 		err = sctp_getpeeraddrs(sctp, sin6, &addrcnt);
14420Sstevel@tonic-gate 		if (err != 0) {
14430Sstevel@tonic-gate 			*addrlen = 0;
14440Sstevel@tonic-gate 			break;
14450Sstevel@tonic-gate 		}
14460Sstevel@tonic-gate 		*addrlen = sizeof (struct sockaddr_in6);
14470Sstevel@tonic-gate 		break;
14480Sstevel@tonic-gate 	}
14490Sstevel@tonic-gate 	WAKE_SCTP(sctp);
14500Sstevel@tonic-gate 	return (err);
14510Sstevel@tonic-gate }
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate /*
14540Sstevel@tonic-gate  * Return a list of IP addresses of the peer endpoint of this sctp_t.
14550Sstevel@tonic-gate  * The parameter paddrs is supposed to be either (struct sockaddr_in *) or
14560Sstevel@tonic-gate  * (struct sockaddr_in6 *) depending on the address family of the sctp_t.
14570Sstevel@tonic-gate  */
14580Sstevel@tonic-gate int
sctp_getpeeraddrs(sctp_t * sctp,void * paddrs,int * addrcnt)14590Sstevel@tonic-gate sctp_getpeeraddrs(sctp_t *sctp, void *paddrs, int *addrcnt)
14600Sstevel@tonic-gate {
14610Sstevel@tonic-gate 	int			family;
14620Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
14630Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
14640Sstevel@tonic-gate 	int			max;
14650Sstevel@tonic-gate 	int			cnt;
14660Sstevel@tonic-gate 	sctp_faddr_t		*fp = sctp->sctp_faddrs;
14670Sstevel@tonic-gate 	in6_addr_t		addr;
146811042SErik.Nordmark@Sun.COM 	conn_t			*connp = sctp->sctp_connp;
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 	ASSERT(sctp != NULL);
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate 	if (sctp->sctp_faddrs == NULL)
14730Sstevel@tonic-gate 		return (ENOTCONN);
14740Sstevel@tonic-gate 
147511042SErik.Nordmark@Sun.COM 	family = connp->conn_family;
14760Sstevel@tonic-gate 	max = *addrcnt;
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 	/* If we want only one, give the primary */
14790Sstevel@tonic-gate 	if (max == 1) {
148013009SChandrasekar.Marimuthu@Sun.COM 		addr = sctp->sctp_primary->sf_faddr;
14810Sstevel@tonic-gate 		switch (family) {
14820Sstevel@tonic-gate 		case AF_INET:
14830Sstevel@tonic-gate 			sin4 = paddrs;
14840Sstevel@tonic-gate 			IN6_V4MAPPED_TO_INADDR(&addr, &sin4->sin_addr);
148511042SErik.Nordmark@Sun.COM 			sin4->sin_port = connp->conn_fport;
14860Sstevel@tonic-gate 			sin4->sin_family = AF_INET;
14870Sstevel@tonic-gate 			break;
14880Sstevel@tonic-gate 
14890Sstevel@tonic-gate 		case AF_INET6:
14900Sstevel@tonic-gate 			sin6 = paddrs;
14910Sstevel@tonic-gate 			sin6->sin6_addr = addr;
149211042SErik.Nordmark@Sun.COM 			sin6->sin6_port = connp->conn_fport;
14930Sstevel@tonic-gate 			sin6->sin6_family = AF_INET6;
149411042SErik.Nordmark@Sun.COM 			sin6->sin6_flowinfo = connp->conn_flowinfo;
149511042SErik.Nordmark@Sun.COM 			if (IN6_IS_ADDR_LINKSCOPE(&addr) &&
149611042SErik.Nordmark@Sun.COM 			    sctp->sctp_primary != NULL &&
149713009SChandrasekar.Marimuthu@Sun.COM 			    (sctp->sctp_primary->sf_ixa->ixa_flags &
149811042SErik.Nordmark@Sun.COM 			    IXAF_SCOPEID_SET)) {
149911042SErik.Nordmark@Sun.COM 				sin6->sin6_scope_id =
150013009SChandrasekar.Marimuthu@Sun.COM 				    sctp->sctp_primary->sf_ixa->ixa_scopeid;
150111042SErik.Nordmark@Sun.COM 			} else {
150211042SErik.Nordmark@Sun.COM 				sin6->sin6_scope_id = 0;
150311042SErik.Nordmark@Sun.COM 			}
150411042SErik.Nordmark@Sun.COM 			sin6->__sin6_src_id = 0;
15050Sstevel@tonic-gate 			break;
15060Sstevel@tonic-gate 		}
15070Sstevel@tonic-gate 		return (0);
15080Sstevel@tonic-gate 	}
15090Sstevel@tonic-gate 
151013009SChandrasekar.Marimuthu@Sun.COM 	for (cnt = 0; cnt < max && fp != NULL; cnt++, fp = fp->sf_next) {
151113009SChandrasekar.Marimuthu@Sun.COM 		addr = fp->sf_faddr;
15120Sstevel@tonic-gate 		switch (family) {
15130Sstevel@tonic-gate 		case AF_INET:
15140Sstevel@tonic-gate 			ASSERT(IN6_IS_ADDR_V4MAPPED(&addr));
15150Sstevel@tonic-gate 			sin4 = (struct sockaddr_in *)paddrs + cnt;
15160Sstevel@tonic-gate 			IN6_V4MAPPED_TO_INADDR(&addr, &sin4->sin_addr);
151711042SErik.Nordmark@Sun.COM 			sin4->sin_port = connp->conn_fport;
15180Sstevel@tonic-gate 			sin4->sin_family = AF_INET;
15190Sstevel@tonic-gate 			break;
15200Sstevel@tonic-gate 		case AF_INET6:
15210Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)paddrs + cnt;
15220Sstevel@tonic-gate 			sin6->sin6_addr = addr;
152311042SErik.Nordmark@Sun.COM 			sin6->sin6_port = connp->conn_fport;
15240Sstevel@tonic-gate 			sin6->sin6_family = AF_INET6;
152511042SErik.Nordmark@Sun.COM 			sin6->sin6_flowinfo = connp->conn_flowinfo;
152611042SErik.Nordmark@Sun.COM 			if (IN6_IS_ADDR_LINKSCOPE(&addr) &&
152713009SChandrasekar.Marimuthu@Sun.COM 			    (fp->sf_ixa->ixa_flags & IXAF_SCOPEID_SET))
152813009SChandrasekar.Marimuthu@Sun.COM 				sin6->sin6_scope_id = fp->sf_ixa->ixa_scopeid;
152911042SErik.Nordmark@Sun.COM 			else
153011042SErik.Nordmark@Sun.COM 				sin6->sin6_scope_id = 0;
153111042SErik.Nordmark@Sun.COM 			sin6->__sin6_src_id = 0;
15320Sstevel@tonic-gate 			break;
15330Sstevel@tonic-gate 		}
15340Sstevel@tonic-gate 	}
15350Sstevel@tonic-gate 	*addrcnt = cnt;
15360Sstevel@tonic-gate 	return (0);
15370Sstevel@tonic-gate }
1538