17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
545916cd2Sjpk  * Common Development and Distribution License (the "License").
645916cd2Sjpk  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2177c67f2fSkcpoon 
227c478bd9Sstevel@tonic-gate /*
23fd7b5aedSGeorge Shepherd  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/stream.h>
287c478bd9Sstevel@tonic-gate #define	_SUN_TPI_VERSION 2
297c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
307c478bd9Sstevel@tonic-gate #include <sys/socket.h>
317c478bd9Sstevel@tonic-gate #include <sys/xti_inet.h>
327c478bd9Sstevel@tonic-gate #include <sys/systm.h>
337c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
347c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
357c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
367c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
377c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
387c478bd9Sstevel@tonic-gate #include <sys/policy.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #include <inet/common.h>
417c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
427c478bd9Sstevel@tonic-gate #include <inet/ip.h>
437c478bd9Sstevel@tonic-gate #include <inet/ip_ire.h>
4443d18f1cSpriyanka #include <inet/ip_if.h>
45bd670b35SErik Nordmark #include <inet/proto_set.h>
467c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h>
477c478bd9Sstevel@tonic-gate #include <inet/ipsec_impl.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #include <netinet/in.h>
507c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
517c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #include <inet/common.h>
547c478bd9Sstevel@tonic-gate #include <inet/ip.h>
557c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
567c478bd9Sstevel@tonic-gate #include <inet/sctp_itf.h>
577c478bd9Sstevel@tonic-gate #include "sctp_impl.h"
587c478bd9Sstevel@tonic-gate #include "sctp_asconf.h"
597c478bd9Sstevel@tonic-gate #include "sctp_addr.h"
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate static int	sctp_getpeeraddrs(sctp_t *, void *, int *);
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate static int
647c478bd9Sstevel@tonic-gate sctp_get_status(sctp_t *sctp, void *ptr)
657c478bd9Sstevel@tonic-gate {
667c478bd9Sstevel@tonic-gate 	struct sctp_status *sstat = ptr;
677c478bd9Sstevel@tonic-gate 	sctp_faddr_t *fp;
687c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin;
697c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
707c478bd9Sstevel@tonic-gate 	struct sctp_paddrinfo *sp;
717c478bd9Sstevel@tonic-gate 	mblk_t *meta, *mp;
727c478bd9Sstevel@tonic-gate 	int i;
73bd670b35SErik Nordmark 	conn_t	*connp = sctp->sctp_connp;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate 	sstat->sstat_state = sctp->sctp_state;
767c478bd9Sstevel@tonic-gate 	sstat->sstat_rwnd = sctp->sctp_frwnd;
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 	sp = &sstat->sstat_primary;
797c478bd9Sstevel@tonic-gate 	if (!sctp->sctp_primary) {
807c478bd9Sstevel@tonic-gate 		bzero(sp, sizeof (*sp));
817c478bd9Sstevel@tonic-gate 		goto noprim;
827c478bd9Sstevel@tonic-gate 	}
837c478bd9Sstevel@tonic-gate 	fp = sctp->sctp_primary;
847c478bd9Sstevel@tonic-gate 
85*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	if (fp->sf_isv4) {
867c478bd9Sstevel@tonic-gate 		sin = (struct sockaddr_in *)&sp->spinfo_address;
877c478bd9Sstevel@tonic-gate 		sin->sin_family = AF_INET;
88bd670b35SErik Nordmark 		sin->sin_port = connp->conn_fport;
89*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		IN6_V4MAPPED_TO_INADDR(&fp->sf_faddr, &sin->sin_addr);
907c478bd9Sstevel@tonic-gate 		sp->spinfo_mtu = sctp->sctp_hdr_len;
917c478bd9Sstevel@tonic-gate 	} else {
927c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)&sp->spinfo_address;
937c478bd9Sstevel@tonic-gate 		sin6->sin6_family = AF_INET6;
94bd670b35SErik Nordmark 		sin6->sin6_port = connp->conn_fport;
95*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		sin6->sin6_addr = fp->sf_faddr;
967c478bd9Sstevel@tonic-gate 		sp->spinfo_mtu = sctp->sctp_hdr6_len;
977c478bd9Sstevel@tonic-gate 	}
98*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	sp->spinfo_state = fp->sf_state == SCTP_FADDRS_ALIVE ? SCTP_ACTIVE :
997c478bd9Sstevel@tonic-gate 	    SCTP_INACTIVE;
100*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	sp->spinfo_cwnd = fp->sf_cwnd;
101*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	sp->spinfo_srtt = fp->sf_srtt;
102*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	sp->spinfo_rto = fp->sf_rto;
103*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	sp->spinfo_mtu += fp->sf_pmss;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate noprim:
1067c478bd9Sstevel@tonic-gate 	sstat->sstat_unackdata = 0;
1077c478bd9Sstevel@tonic-gate 	sstat->sstat_penddata = 0;
1087c478bd9Sstevel@tonic-gate 	sstat->sstat_instrms = sctp->sctp_num_istr;
1097c478bd9Sstevel@tonic-gate 	sstat->sstat_outstrms = sctp->sctp_num_ostr;
1107c478bd9Sstevel@tonic-gate 	sstat->sstat_fragmentation_point = sctp->sctp_mss -
1117c478bd9Sstevel@tonic-gate 	    sizeof (sctp_data_hdr_t);
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	/* count unack'd */
1147c478bd9Sstevel@tonic-gate 	for (meta = sctp->sctp_xmit_head; meta; meta = meta->b_next) {
1157c478bd9Sstevel@tonic-gate 		for (mp = meta->b_cont; mp; mp = mp->b_next) {
1167c478bd9Sstevel@tonic-gate 			if (!SCTP_CHUNK_ISSENT(mp)) {
1177c478bd9Sstevel@tonic-gate 				break;
1187c478bd9Sstevel@tonic-gate 			}
1197c478bd9Sstevel@tonic-gate 			if (!SCTP_CHUNK_ISACKED(mp)) {
1207c478bd9Sstevel@tonic-gate 				sstat->sstat_unackdata++;
1217c478bd9Sstevel@tonic-gate 			}
1227c478bd9Sstevel@tonic-gate 		}
1237c478bd9Sstevel@tonic-gate 	}
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	/*
1267c478bd9Sstevel@tonic-gate 	 * Count penddata chunks. We can only count chunks in SCTP (not
1277c478bd9Sstevel@tonic-gate 	 * data already delivered to socket layer).
1287c478bd9Sstevel@tonic-gate 	 */
1297c478bd9Sstevel@tonic-gate 	if (sctp->sctp_instr != NULL) {
1307c478bd9Sstevel@tonic-gate 		for (i = 0; i < sctp->sctp_num_istr; i++) {
1317c478bd9Sstevel@tonic-gate 			for (meta = sctp->sctp_instr[i].istr_reass;
1327c478bd9Sstevel@tonic-gate 			    meta != NULL; meta = meta->b_next) {
1337c478bd9Sstevel@tonic-gate 				for (mp = meta->b_cont; mp; mp = mp->b_cont) {
1347c478bd9Sstevel@tonic-gate 					if (DB_TYPE(mp) != M_CTL) {
1357c478bd9Sstevel@tonic-gate 						sstat->sstat_penddata++;
1367c478bd9Sstevel@tonic-gate 					}
1377c478bd9Sstevel@tonic-gate 				}
1387c478bd9Sstevel@tonic-gate 			}
1397c478bd9Sstevel@tonic-gate 		}
1407c478bd9Sstevel@tonic-gate 	}
1417c478bd9Sstevel@tonic-gate 	/* Un-Ordered Frag list */
1427c478bd9Sstevel@tonic-gate 	for (meta = sctp->sctp_uo_frags; meta != NULL; meta = meta->b_next)
1437c478bd9Sstevel@tonic-gate 		sstat->sstat_penddata++;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	return (sizeof (*sstat));
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate  * SCTP_GET_PEER_ADDR_INFO
1507c478bd9Sstevel@tonic-gate  */
1517c478bd9Sstevel@tonic-gate static int
1527c478bd9Sstevel@tonic-gate sctp_get_paddrinfo(sctp_t *sctp, void *ptr, socklen_t *optlen)
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate 	struct sctp_paddrinfo	*infop = ptr;
1557c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
1567c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
1577c478bd9Sstevel@tonic-gate 	in6_addr_t		faddr;
1587c478bd9Sstevel@tonic-gate 	sctp_faddr_t		*fp;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	switch (infop->spinfo_address.ss_family) {
1617c478bd9Sstevel@tonic-gate 	case AF_INET:
1627c478bd9Sstevel@tonic-gate 		sin4 = (struct sockaddr_in *)&infop->spinfo_address;
1637c478bd9Sstevel@tonic-gate 		IN6_INADDR_TO_V4MAPPED(&sin4->sin_addr, &faddr);
1647c478bd9Sstevel@tonic-gate 		break;
1657c478bd9Sstevel@tonic-gate 	case AF_INET6:
1667c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)&infop->spinfo_address;
1677c478bd9Sstevel@tonic-gate 		faddr = sin6->sin6_addr;
1687c478bd9Sstevel@tonic-gate 		break;
1697c478bd9Sstevel@tonic-gate 	default:
1707c478bd9Sstevel@tonic-gate 		return (EAFNOSUPPORT);
1717c478bd9Sstevel@tonic-gate 	}
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	if ((fp = sctp_lookup_faddr(sctp, &faddr)) == NULL)
1747c478bd9Sstevel@tonic-gate 		return (EINVAL);
1757c478bd9Sstevel@tonic-gate 
176*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	infop->spinfo_state = (fp->sf_state == SCTP_FADDRS_ALIVE) ?
177*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	    SCTP_ACTIVE : SCTP_INACTIVE;
178*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	infop->spinfo_cwnd = fp->sf_cwnd;
179*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	infop->spinfo_srtt = TICK_TO_MSEC(fp->sf_srtt);
180*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	infop->spinfo_rto = TICK_TO_MSEC(fp->sf_rto);
181*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	infop->spinfo_mtu = fp->sf_pmss;
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	*optlen = sizeof (struct sctp_paddrinfo);
1847c478bd9Sstevel@tonic-gate 	return (0);
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate /*
1887c478bd9Sstevel@tonic-gate  * SCTP_RTOINFO
1897c478bd9Sstevel@tonic-gate  */
1907c478bd9Sstevel@tonic-gate static int
1917c478bd9Sstevel@tonic-gate sctp_get_rtoinfo(sctp_t *sctp, void *ptr)
1927c478bd9Sstevel@tonic-gate {
1937c478bd9Sstevel@tonic-gate 	struct sctp_rtoinfo *srto = ptr;
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	srto->srto_initial = TICK_TO_MSEC(sctp->sctp_rto_initial);
1967c478bd9Sstevel@tonic-gate 	srto->srto_max = TICK_TO_MSEC(sctp->sctp_rto_max);
1977c478bd9Sstevel@tonic-gate 	srto->srto_min = TICK_TO_MSEC(sctp->sctp_rto_min);
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	return (sizeof (*srto));
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate static int
203bd670b35SErik Nordmark sctp_set_rtoinfo(sctp_t *sctp, const void *invalp)
2047c478bd9Sstevel@tonic-gate {
2057c478bd9Sstevel@tonic-gate 	const struct sctp_rtoinfo *srto;
2067c478bd9Sstevel@tonic-gate 	boolean_t ispriv;
207f4b3ec61Sdh 	sctp_stack_t	*sctps = sctp->sctp_sctps;
208bd670b35SErik Nordmark 	conn_t		*connp = sctp->sctp_connp;
20905cdb43cSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	uint32_t	new_min, new_max;
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	srto = invalp;
2127c478bd9Sstevel@tonic-gate 
213bd670b35SErik Nordmark 	ispriv = secpolicy_ip_config(connp->conn_cred, B_TRUE) == 0;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	/*
2167c478bd9Sstevel@tonic-gate 	 * Bounds checking.  Priviledged user can set the RTO initial
2177c478bd9Sstevel@tonic-gate 	 * outside the ndd boundary.
2187c478bd9Sstevel@tonic-gate 	 */
2197c478bd9Sstevel@tonic-gate 	if (srto->srto_initial != 0 &&
220f4b3ec61Sdh 	    (!ispriv && (srto->srto_initial < sctps->sctps_rto_initialg_low ||
221b34b8d1aSkcpoon 	    srto->srto_initial > sctps->sctps_rto_initialg_high))) {
2227c478bd9Sstevel@tonic-gate 		return (EINVAL);
2237c478bd9Sstevel@tonic-gate 	}
2247c478bd9Sstevel@tonic-gate 	if (srto->srto_max != 0 &&
225f4b3ec61Sdh 	    (!ispriv && (srto->srto_max < sctps->sctps_rto_maxg_low ||
226b34b8d1aSkcpoon 	    srto->srto_max > sctps->sctps_rto_maxg_high))) {
2277c478bd9Sstevel@tonic-gate 		return (EINVAL);
2287c478bd9Sstevel@tonic-gate 	}
2297c478bd9Sstevel@tonic-gate 	if (srto->srto_min != 0 &&
230f4b3ec61Sdh 	    (!ispriv && (srto->srto_min < sctps->sctps_rto_ming_low ||
231b34b8d1aSkcpoon 	    srto->srto_min > sctps->sctps_rto_ming_high))) {
2327c478bd9Sstevel@tonic-gate 		return (EINVAL);
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 
23505cdb43cSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	new_min = (srto->srto_min != 0) ? srto->srto_min : sctp->sctp_rto_min;
23605cdb43cSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	new_max = (srto->srto_max != 0) ? srto->srto_max : sctp->sctp_rto_max;
23705cdb43cSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	if (new_max < new_min) {
23805cdb43cSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		return (EINVAL);
23905cdb43cSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	}
24005cdb43cSchandrasekar marimuthu - Sun Microsystems - Bangalore India 
2417c478bd9Sstevel@tonic-gate 	if (srto->srto_initial != 0) {
2427c478bd9Sstevel@tonic-gate 		sctp->sctp_rto_initial = MSEC_TO_TICK(srto->srto_initial);
2437c478bd9Sstevel@tonic-gate 	}
24405cdb43cSchandrasekar marimuthu - Sun Microsystems - Bangalore India 
24505cdb43cSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	/* Ensure that sctp_rto_max will never be zero. */
2467c478bd9Sstevel@tonic-gate 	if (srto->srto_max != 0) {
24705cdb43cSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		sctp->sctp_rto_max = MAX(MSEC_TO_TICK(srto->srto_max), 1);
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 	if (srto->srto_min != 0) {
2507c478bd9Sstevel@tonic-gate 		sctp->sctp_rto_min = MSEC_TO_TICK(srto->srto_min);
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	return (0);
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate /*
2577c478bd9Sstevel@tonic-gate  * SCTP_ASSOCINFO
2587c478bd9Sstevel@tonic-gate  */
2597c478bd9Sstevel@tonic-gate static int
2607c478bd9Sstevel@tonic-gate sctp_get_assocparams(sctp_t *sctp, void *ptr)
2617c478bd9Sstevel@tonic-gate {
2627c478bd9Sstevel@tonic-gate 	struct sctp_assocparams *sap = ptr;
2637c478bd9Sstevel@tonic-gate 	sctp_faddr_t *fp;
2647c478bd9Sstevel@tonic-gate 	uint16_t i;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	sap->sasoc_asocmaxrxt = sctp->sctp_pa_max_rxt;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	/*
2697c478bd9Sstevel@tonic-gate 	 * Count the number of peer addresses
2707c478bd9Sstevel@tonic-gate 	 */
271*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	for (i = 0, fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) {
2727c478bd9Sstevel@tonic-gate 		i++;
2737c478bd9Sstevel@tonic-gate 	}
2747c478bd9Sstevel@tonic-gate 	sap->sasoc_number_peer_destinations = i;
2757c478bd9Sstevel@tonic-gate 	sap->sasoc_peer_rwnd = sctp->sctp_frwnd;
2767c478bd9Sstevel@tonic-gate 	sap->sasoc_local_rwnd = sctp->sctp_rwnd;
2777c478bd9Sstevel@tonic-gate 	sap->sasoc_cookie_life = TICK_TO_MSEC(sctp->sctp_cookie_lifetime);
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	return (sizeof (*sap));
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate static int
283bd670b35SErik Nordmark sctp_set_assocparams(sctp_t *sctp, const void *invalp)
2847c478bd9Sstevel@tonic-gate {
2857c478bd9Sstevel@tonic-gate 	const struct sctp_assocparams *sap = invalp;
2867c478bd9Sstevel@tonic-gate 	uint32_t sum = 0;
2877c478bd9Sstevel@tonic-gate 	sctp_faddr_t *fp;
288f4b3ec61Sdh 	sctp_stack_t	*sctps = sctp->sctp_sctps;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	if (sap->sasoc_asocmaxrxt) {
2917c478bd9Sstevel@tonic-gate 		if (sctp->sctp_faddrs) {
2927c478bd9Sstevel@tonic-gate 			/*
2937c478bd9Sstevel@tonic-gate 			 * Bounds check: as per rfc2960, assoc max retr cannot
2947c478bd9Sstevel@tonic-gate 			 * exceed the sum of all individual path max retr's.
2957c478bd9Sstevel@tonic-gate 			 */
296*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			for (fp = sctp->sctp_faddrs; fp; fp = fp->sf_next) {
297*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 				sum += fp->sf_max_retr;
2987c478bd9Sstevel@tonic-gate 			}
2997c478bd9Sstevel@tonic-gate 			if (sap->sasoc_asocmaxrxt > sum) {
3007c478bd9Sstevel@tonic-gate 				return (EINVAL);
3017c478bd9Sstevel@tonic-gate 			}
3027c478bd9Sstevel@tonic-gate 		}
303f4b3ec61Sdh 		if (sap->sasoc_asocmaxrxt < sctps->sctps_pa_max_retr_low ||
304f4b3ec61Sdh 		    sap->sasoc_asocmaxrxt > sctps->sctps_pa_max_retr_high) {
3057c478bd9Sstevel@tonic-gate 			/*
3067c478bd9Sstevel@tonic-gate 			 * Out of bounds.
3077c478bd9Sstevel@tonic-gate 			 */
3087c478bd9Sstevel@tonic-gate 			return (EINVAL);
3097c478bd9Sstevel@tonic-gate 		}
3107c478bd9Sstevel@tonic-gate 	}
3117c478bd9Sstevel@tonic-gate 	if (sap->sasoc_cookie_life != 0 &&
312f4b3ec61Sdh 	    (sap->sasoc_cookie_life < sctps->sctps_cookie_life_low ||
313b34b8d1aSkcpoon 	    sap->sasoc_cookie_life > sctps->sctps_cookie_life_high)) {
314b34b8d1aSkcpoon 		return (EINVAL);
3157c478bd9Sstevel@tonic-gate 	}
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	if (sap->sasoc_asocmaxrxt > 0) {
3187c478bd9Sstevel@tonic-gate 		sctp->sctp_pa_max_rxt = sap->sasoc_asocmaxrxt;
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 	if (sap->sasoc_cookie_life > 0) {
3217c478bd9Sstevel@tonic-gate 		sctp->sctp_cookie_lifetime = MSEC_TO_TICK(
3227c478bd9Sstevel@tonic-gate 		    sap->sasoc_cookie_life);
3237c478bd9Sstevel@tonic-gate 	}
3247c478bd9Sstevel@tonic-gate 	return (0);
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate /*
3287c478bd9Sstevel@tonic-gate  * SCTP_INITMSG
3297c478bd9Sstevel@tonic-gate  */
3307c478bd9Sstevel@tonic-gate static int
3317c478bd9Sstevel@tonic-gate sctp_get_initmsg(sctp_t *sctp, void *ptr)
3327c478bd9Sstevel@tonic-gate {
3337c478bd9Sstevel@tonic-gate 	struct sctp_initmsg *si = ptr;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	si->sinit_num_ostreams = sctp->sctp_num_ostr;
3367c478bd9Sstevel@tonic-gate 	si->sinit_max_instreams = sctp->sctp_num_istr;
3377c478bd9Sstevel@tonic-gate 	si->sinit_max_attempts = sctp->sctp_max_init_rxt;
338fd7b5aedSGeorge Shepherd 	si->sinit_max_init_timeo = TICK_TO_MSEC(sctp->sctp_rto_max_init);
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	return (sizeof (*si));
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate static int
3447c478bd9Sstevel@tonic-gate sctp_set_initmsg(sctp_t *sctp, const void *invalp, uint_t inlen)
3457c478bd9Sstevel@tonic-gate {
3467c478bd9Sstevel@tonic-gate 	const struct sctp_initmsg *si = invalp;
347f4b3ec61Sdh 	sctp_stack_t	*sctps = sctp->sctp_sctps;
348bd670b35SErik Nordmark 	conn_t		*connp = sctp->sctp_connp;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	if (sctp->sctp_state > SCTPS_LISTEN) {
3517c478bd9Sstevel@tonic-gate 		return (EINVAL);
3527c478bd9Sstevel@tonic-gate 	}
3537c478bd9Sstevel@tonic-gate 	if (inlen < sizeof (*si)) {
3547c478bd9Sstevel@tonic-gate 		return (EINVAL);
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 	if (si->sinit_num_ostreams != 0 &&
357f4b3ec61Sdh 	    (si->sinit_num_ostreams < sctps->sctps_initial_out_streams_low ||
358f4b3ec61Sdh 	    si->sinit_num_ostreams >
359f4b3ec61Sdh 	    sctps->sctps_initial_out_streams_high)) {
3607c478bd9Sstevel@tonic-gate 		/*
3617c478bd9Sstevel@tonic-gate 		 * Out of bounds.
3627c478bd9Sstevel@tonic-gate 		 */
3637c478bd9Sstevel@tonic-gate 		return (EINVAL);
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 	if (si->sinit_max_instreams != 0 &&
366f4b3ec61Sdh 	    (si->sinit_max_instreams < sctps->sctps_max_in_streams_low ||
367b34b8d1aSkcpoon 	    si->sinit_max_instreams > sctps->sctps_max_in_streams_high)) {
3687c478bd9Sstevel@tonic-gate 		return (EINVAL);
3697c478bd9Sstevel@tonic-gate 	}
3707c478bd9Sstevel@tonic-gate 	if (si->sinit_max_attempts != 0 &&
371f4b3ec61Sdh 	    (si->sinit_max_attempts < sctps->sctps_max_init_retr_low ||
372b34b8d1aSkcpoon 	    si->sinit_max_attempts > sctps->sctps_max_init_retr_high)) {
3737c478bd9Sstevel@tonic-gate 		return (EINVAL);
3747c478bd9Sstevel@tonic-gate 	}
3757c478bd9Sstevel@tonic-gate 	if (si->sinit_max_init_timeo != 0 &&
376bd670b35SErik Nordmark 	    (secpolicy_ip_config(connp->conn_cred, B_TRUE) != 0 &&
377b34b8d1aSkcpoon 	    (si->sinit_max_init_timeo < sctps->sctps_rto_maxg_low ||
378b34b8d1aSkcpoon 	    si->sinit_max_init_timeo > sctps->sctps_rto_maxg_high))) {
3797c478bd9Sstevel@tonic-gate 		return (EINVAL);
3807c478bd9Sstevel@tonic-gate 	}
3817c478bd9Sstevel@tonic-gate 	if (si->sinit_num_ostreams != 0)
3827c478bd9Sstevel@tonic-gate 		sctp->sctp_num_ostr = si->sinit_num_ostreams;
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	if (si->sinit_max_instreams != 0)
3857c478bd9Sstevel@tonic-gate 		sctp->sctp_num_istr = si->sinit_max_instreams;
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	if (si->sinit_max_attempts != 0)
3887c478bd9Sstevel@tonic-gate 		sctp->sctp_max_init_rxt = si->sinit_max_attempts;
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	if (si->sinit_max_init_timeo != 0) {
391fd7b5aedSGeorge Shepherd 		sctp->sctp_rto_max_init =
3927c478bd9Sstevel@tonic-gate 		    MSEC_TO_TICK(si->sinit_max_init_timeo);
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 	return (0);
3957c478bd9Sstevel@tonic-gate }
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate /*
3987c478bd9Sstevel@tonic-gate  * SCTP_PEER_ADDR_PARAMS
3997c478bd9Sstevel@tonic-gate  */
4007c478bd9Sstevel@tonic-gate static int
4017c478bd9Sstevel@tonic-gate sctp_find_peer_fp(sctp_t *sctp, const struct sockaddr_storage *ss,
4027c478bd9Sstevel@tonic-gate     sctp_faddr_t **fpp)
4037c478bd9Sstevel@tonic-gate {
4047c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin;
4057c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
4067c478bd9Sstevel@tonic-gate 	in6_addr_t addr;
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	if (ss->ss_family == AF_INET) {
4097c478bd9Sstevel@tonic-gate 		sin = (struct sockaddr_in *)ss;
4107c478bd9Sstevel@tonic-gate 		IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &addr);
4117c478bd9Sstevel@tonic-gate 	} else if (ss->ss_family == AF_INET6) {
4127c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)ss;
4137c478bd9Sstevel@tonic-gate 		addr = sin6->sin6_addr;
4147c478bd9Sstevel@tonic-gate 	} else if (ss->ss_family) {
4157c478bd9Sstevel@tonic-gate 		return (EAFNOSUPPORT);
4167c478bd9Sstevel@tonic-gate 	}
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	if (!ss->ss_family ||
4197c478bd9Sstevel@tonic-gate 	    SCTP_IS_ADDR_UNSPEC(IN6_IS_ADDR_V4MAPPED(&addr), addr)) {
4207c478bd9Sstevel@tonic-gate 		*fpp = NULL;
4217c478bd9Sstevel@tonic-gate 	} else {
4227c478bd9Sstevel@tonic-gate 		*fpp = sctp_lookup_faddr(sctp, &addr);
4237c478bd9Sstevel@tonic-gate 		if (*fpp == NULL) {
4247c478bd9Sstevel@tonic-gate 			return (EINVAL);
4257c478bd9Sstevel@tonic-gate 		}
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 	return (0);
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate static int
4317c478bd9Sstevel@tonic-gate sctp_get_peer_addr_params(sctp_t *sctp, void *ptr)
4327c478bd9Sstevel@tonic-gate {
4337c478bd9Sstevel@tonic-gate 	struct sctp_paddrparams *spp = ptr;
4347c478bd9Sstevel@tonic-gate 	sctp_faddr_t *fp;
4357c478bd9Sstevel@tonic-gate 	int retval;
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	retval = sctp_find_peer_fp(sctp, &spp->spp_address, &fp);
4387c478bd9Sstevel@tonic-gate 	if (retval) {
4397c478bd9Sstevel@tonic-gate 		return (retval);
4407c478bd9Sstevel@tonic-gate 	}
4417c478bd9Sstevel@tonic-gate 	if (fp) {
442*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		spp->spp_hbinterval = TICK_TO_MSEC(fp->sf_hb_interval);
443*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		spp->spp_pathmaxrxt = fp->sf_max_retr;
4447c478bd9Sstevel@tonic-gate 	} else {
4457c478bd9Sstevel@tonic-gate 		spp->spp_hbinterval = TICK_TO_MSEC(sctp->sctp_hb_interval);
4467c478bd9Sstevel@tonic-gate 		spp->spp_pathmaxrxt = sctp->sctp_pp_max_rxt;
4477c478bd9Sstevel@tonic-gate 	}
4487c478bd9Sstevel@tonic-gate 	return (sizeof (*spp));
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate static int
452bd670b35SErik Nordmark sctp_set_peer_addr_params(sctp_t *sctp, const void *invalp)
4537c478bd9Sstevel@tonic-gate {
4547c478bd9Sstevel@tonic-gate 	const struct sctp_paddrparams *spp = invalp;
4557c478bd9Sstevel@tonic-gate 	sctp_faddr_t *fp, *fp2;
4567c478bd9Sstevel@tonic-gate 	int retval;
4577c478bd9Sstevel@tonic-gate 	uint32_t sum = 0;
4587c478bd9Sstevel@tonic-gate 	int64_t now;
459f4b3ec61Sdh 	sctp_stack_t	*sctps = sctp->sctp_sctps;
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	retval = sctp_find_peer_fp(sctp, &spp->spp_address, &fp);
4627c478bd9Sstevel@tonic-gate 	if (retval != 0) {
4637c478bd9Sstevel@tonic-gate 		return (retval);
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	if (spp->spp_hbinterval && spp->spp_hbinterval != UINT32_MAX &&
467f4b3ec61Sdh 	    (spp->spp_hbinterval < sctps->sctps_heartbeat_interval_low ||
468b34b8d1aSkcpoon 	    spp->spp_hbinterval > sctps->sctps_heartbeat_interval_high)) {
4697c478bd9Sstevel@tonic-gate 		return (EINVAL);
4707c478bd9Sstevel@tonic-gate 	}
4717c478bd9Sstevel@tonic-gate 	if (spp->spp_pathmaxrxt &&
472f4b3ec61Sdh 	    (spp->spp_pathmaxrxt < sctps->sctps_pp_max_retr_low ||
473b34b8d1aSkcpoon 	    spp->spp_pathmaxrxt > sctps->sctps_pp_max_retr_high)) {
4747c478bd9Sstevel@tonic-gate 		return (EINVAL);
4757c478bd9Sstevel@tonic-gate 	}
4767c478bd9Sstevel@tonic-gate 	if (spp->spp_pathmaxrxt && sctp->sctp_faddrs) {
477*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		for (fp2 = sctp->sctp_faddrs; fp2; fp2 = fp2->sf_next) {
4787c478bd9Sstevel@tonic-gate 			if (!fp || fp2 == fp) {
4797c478bd9Sstevel@tonic-gate 				sum += spp->spp_pathmaxrxt;
4807c478bd9Sstevel@tonic-gate 			} else {
481*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 				sum += fp2->sf_max_retr;
4827c478bd9Sstevel@tonic-gate 			}
4837c478bd9Sstevel@tonic-gate 		}
4847c478bd9Sstevel@tonic-gate 		if (sctp->sctp_pa_max_rxt > sum) {
4857c478bd9Sstevel@tonic-gate 			return (EINVAL);
4867c478bd9Sstevel@tonic-gate 		}
4877c478bd9Sstevel@tonic-gate 	}
4887c478bd9Sstevel@tonic-gate 
489d3d50737SRafael Vanoni 	now = ddi_get_lbolt64();
4907c478bd9Sstevel@tonic-gate 	if (fp != NULL) {
4917c478bd9Sstevel@tonic-gate 		if (spp->spp_hbinterval == UINT32_MAX) {
4927c478bd9Sstevel@tonic-gate 			/*
4937c478bd9Sstevel@tonic-gate 			 * Send heartbeat immediatelly, don't modify the
4947c478bd9Sstevel@tonic-gate 			 * current setting.
4957c478bd9Sstevel@tonic-gate 			 */
4967c478bd9Sstevel@tonic-gate 			sctp_send_heartbeat(sctp, fp);
4977c478bd9Sstevel@tonic-gate 		} else {
498*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			fp->sf_hb_interval = MSEC_TO_TICK(spp->spp_hbinterval);
499*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			fp->sf_hb_expiry = now + SET_HB_INTVL(fp);
5007c478bd9Sstevel@tonic-gate 			/*
5017c478bd9Sstevel@tonic-gate 			 * Restart the heartbeat timer using the new intrvl.
5027c478bd9Sstevel@tonic-gate 			 * We need to call sctp_heartbeat_timer() to set
5037c478bd9Sstevel@tonic-gate 			 * the earliest heartbeat expiry time.
5047c478bd9Sstevel@tonic-gate 			 */
5057c478bd9Sstevel@tonic-gate 			sctp_heartbeat_timer(sctp);
5067c478bd9Sstevel@tonic-gate 		}
5077c478bd9Sstevel@tonic-gate 		if (spp->spp_pathmaxrxt) {
508*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			fp->sf_max_retr = spp->spp_pathmaxrxt;
5097c478bd9Sstevel@tonic-gate 		}
5107c478bd9Sstevel@tonic-gate 	} else {
511*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		for (fp2 = sctp->sctp_faddrs; fp2 != NULL; fp2 = fp2->sf_next) {
5127c478bd9Sstevel@tonic-gate 			if (spp->spp_hbinterval == UINT32_MAX) {
5137c478bd9Sstevel@tonic-gate 				/*
5147c478bd9Sstevel@tonic-gate 				 * Send heartbeat immediatelly, don't modify
5157c478bd9Sstevel@tonic-gate 				 * the current setting.
5167c478bd9Sstevel@tonic-gate 				 */
5177c478bd9Sstevel@tonic-gate 				sctp_send_heartbeat(sctp, fp2);
5187c478bd9Sstevel@tonic-gate 			} else {
519*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 				fp2->sf_hb_interval = MSEC_TO_TICK(
5207c478bd9Sstevel@tonic-gate 				    spp->spp_hbinterval);
521*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 				fp2->sf_hb_expiry = now + SET_HB_INTVL(fp2);
5227c478bd9Sstevel@tonic-gate 			}
5237c478bd9Sstevel@tonic-gate 			if (spp->spp_pathmaxrxt) {
524*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 				fp2->sf_max_retr = spp->spp_pathmaxrxt;
5257c478bd9Sstevel@tonic-gate 			}
5267c478bd9Sstevel@tonic-gate 		}
5277c478bd9Sstevel@tonic-gate 		if (spp->spp_hbinterval != UINT32_MAX) {
5287c478bd9Sstevel@tonic-gate 			sctp->sctp_hb_interval = MSEC_TO_TICK(
5297c478bd9Sstevel@tonic-gate 			    spp->spp_hbinterval);
5307c478bd9Sstevel@tonic-gate 			/* Restart the heartbeat timer using the new intrvl. */
5317c478bd9Sstevel@tonic-gate 			sctp_timer(sctp, sctp->sctp_heartbeat_mp,
5327c478bd9Sstevel@tonic-gate 			    sctp->sctp_hb_interval);
5337c478bd9Sstevel@tonic-gate 		}
5347c478bd9Sstevel@tonic-gate 		if (spp->spp_pathmaxrxt) {
5357c478bd9Sstevel@tonic-gate 			sctp->sctp_pp_max_rxt = spp->spp_pathmaxrxt;
5367c478bd9Sstevel@tonic-gate 		}
5377c478bd9Sstevel@tonic-gate 	}
5387c478bd9Sstevel@tonic-gate 	return (0);
5397c478bd9Sstevel@tonic-gate }
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate /*
5427c478bd9Sstevel@tonic-gate  * SCTP_DEFAULT_SEND_PARAM
5437c478bd9Sstevel@tonic-gate  */
5447c478bd9Sstevel@tonic-gate static int
5457c478bd9Sstevel@tonic-gate sctp_get_def_send_params(sctp_t *sctp, void *ptr)
5467c478bd9Sstevel@tonic-gate {
5477c478bd9Sstevel@tonic-gate 	struct sctp_sndrcvinfo *sinfo = ptr;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	sinfo->sinfo_stream = sctp->sctp_def_stream;
5507c478bd9Sstevel@tonic-gate 	sinfo->sinfo_ssn = 0;
5517c478bd9Sstevel@tonic-gate 	sinfo->sinfo_flags = sctp->sctp_def_flags;
5527c478bd9Sstevel@tonic-gate 	sinfo->sinfo_ppid = sctp->sctp_def_ppid;
5537c478bd9Sstevel@tonic-gate 	sinfo->sinfo_context = sctp->sctp_def_context;
5547c478bd9Sstevel@tonic-gate 	sinfo->sinfo_timetolive = sctp->sctp_def_timetolive;
5557c478bd9Sstevel@tonic-gate 	sinfo->sinfo_tsn = 0;
5567c478bd9Sstevel@tonic-gate 	sinfo->sinfo_cumtsn = 0;
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	return (sizeof (*sinfo));
5597c478bd9Sstevel@tonic-gate }
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate static int
562bd670b35SErik Nordmark sctp_set_def_send_params(sctp_t *sctp, const void *invalp)
5637c478bd9Sstevel@tonic-gate {
5647c478bd9Sstevel@tonic-gate 	const struct sctp_sndrcvinfo *sinfo = invalp;
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	if (sinfo->sinfo_stream >= sctp->sctp_num_ostr) {
5677c478bd9Sstevel@tonic-gate 		return (EINVAL);
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	sctp->sctp_def_stream = sinfo->sinfo_stream;
5717c478bd9Sstevel@tonic-gate 	sctp->sctp_def_flags = sinfo->sinfo_flags;
5727c478bd9Sstevel@tonic-gate 	sctp->sctp_def_ppid = sinfo->sinfo_ppid;
5737c478bd9Sstevel@tonic-gate 	sctp->sctp_def_context = sinfo->sinfo_context;
5747c478bd9Sstevel@tonic-gate 	sctp->sctp_def_timetolive = sinfo->sinfo_timetolive;
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	return (0);
5777c478bd9Sstevel@tonic-gate }
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate static int
580bd670b35SErik Nordmark sctp_set_prim(sctp_t *sctp, const void *invalp)
5817c478bd9Sstevel@tonic-gate {
5827c478bd9Sstevel@tonic-gate 	const struct	sctp_setpeerprim *pp = invalp;
5837c478bd9Sstevel@tonic-gate 	int		retval;
5847c478bd9Sstevel@tonic-gate 	sctp_faddr_t	*fp;
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	retval = sctp_find_peer_fp(sctp, &pp->sspp_addr, &fp);
5877c478bd9Sstevel@tonic-gate 	if (retval)
5887c478bd9Sstevel@tonic-gate 		return (retval);
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	if (fp == NULL)
5917c478bd9Sstevel@tonic-gate 		return (EINVAL);
5927c478bd9Sstevel@tonic-gate 	if (fp == sctp->sctp_primary)
5937c478bd9Sstevel@tonic-gate 		return (0);
5947c478bd9Sstevel@tonic-gate 	sctp->sctp_primary = fp;
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 	/* Only switch current if fp is alive */
597*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	if (fp->sf_state != SCTP_FADDRS_ALIVE || fp == sctp->sctp_current) {
5987c478bd9Sstevel@tonic-gate 		return (0);
5997c478bd9Sstevel@tonic-gate 	}
60077c67f2fSkcpoon 	sctp_set_faddr_current(sctp, fp);
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	return (0);
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate 
605bd670b35SErik Nordmark /*
606bd670b35SErik Nordmark  * Table of all known options handled on a SCTP protocol stack.
607bd670b35SErik Nordmark  *
608bd670b35SErik Nordmark  * Note: This table contains options processed by both SCTP and IP levels
609bd670b35SErik Nordmark  *       and is the superset of options that can be performed on a SCTP and IP
610bd670b35SErik Nordmark  *       stack.
611bd670b35SErik Nordmark  */
612bd670b35SErik Nordmark opdes_t	sctp_opt_arr[] = {
613bd670b35SErik Nordmark 
614bd670b35SErik Nordmark { SO_LINGER,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0,
615bd670b35SErik Nordmark 	sizeof (struct linger), 0 },
616bd670b35SErik Nordmark 
617bd670b35SErik Nordmark { SO_DEBUG,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
618bd670b35SErik Nordmark { SO_KEEPALIVE,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
619bd670b35SErik Nordmark { SO_DONTROUTE,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
620bd670b35SErik Nordmark { SO_USELOOPBACK, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0
621bd670b35SErik Nordmark 	},
622bd670b35SErik Nordmark { SO_BROADCAST,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
623bd670b35SErik Nordmark { SO_REUSEADDR, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
624bd670b35SErik Nordmark { SO_OOBINLINE, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
625bd670b35SErik Nordmark { SO_TYPE,	SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
626bd670b35SErik Nordmark { SO_SNDBUF,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
627bd670b35SErik Nordmark { SO_RCVBUF,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
628bd670b35SErik Nordmark { SO_DGRAM_ERRIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0
629bd670b35SErik Nordmark 	},
630bd670b35SErik Nordmark { SO_SND_COPYAVOID, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
631bd670b35SErik Nordmark { SO_ANON_MLP, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int),
632bd670b35SErik Nordmark 	0 },
633bd670b35SErik Nordmark { SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int),
634bd670b35SErik Nordmark 	0 },
635bd670b35SErik Nordmark { SO_ALLZONES, SOL_SOCKET, OA_R, OA_RW, OP_CONFIG, 0, sizeof (int),
636bd670b35SErik Nordmark 	0 },
637bd670b35SErik Nordmark { SO_EXCLBIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
638bd670b35SErik Nordmark 
639bd670b35SErik Nordmark { SO_DOMAIN,	SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
640bd670b35SErik Nordmark 
641bd670b35SErik Nordmark { SO_PROTOTYPE,	SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
642bd670b35SErik Nordmark 
643bd670b35SErik Nordmark { SCTP_ADAPTATION_LAYER, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
644bd670b35SErik Nordmark 	sizeof (struct sctp_setadaptation), 0 },
645bd670b35SErik Nordmark { SCTP_ADD_ADDR, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, OP_VARLEN,
646bd670b35SErik Nordmark 	sizeof (int), 0 },
647bd670b35SErik Nordmark { SCTP_ASSOCINFO, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
648bd670b35SErik Nordmark 	sizeof (struct sctp_assocparams), 0 },
649bd670b35SErik Nordmark { SCTP_AUTOCLOSE, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
650bd670b35SErik Nordmark { SCTP_DEFAULT_SEND_PARAM, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
651bd670b35SErik Nordmark 	sizeof (struct sctp_sndrcvinfo), 0 },
652bd670b35SErik Nordmark { SCTP_DISABLE_FRAGMENTS, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
653bd670b35SErik Nordmark 	sizeof (int), 0 },
654bd670b35SErik Nordmark { SCTP_EVENTS, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
655bd670b35SErik Nordmark 	sizeof (struct sctp_event_subscribe), 0 },
656bd670b35SErik Nordmark { SCTP_GET_LADDRS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, OP_VARLEN,
657bd670b35SErik Nordmark 	sizeof (int), 0 },
658bd670b35SErik Nordmark { SCTP_GET_NLADDRS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
659bd670b35SErik Nordmark { SCTP_GET_NPADDRS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
660bd670b35SErik Nordmark { SCTP_GET_PADDRS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, OP_VARLEN,
661bd670b35SErik Nordmark 	sizeof (int), 0 },
662bd670b35SErik Nordmark { SCTP_GET_PEER_ADDR_INFO, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0,
663bd670b35SErik Nordmark 	sizeof (struct sctp_paddrinfo), 0 },
664bd670b35SErik Nordmark { SCTP_INITMSG, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
665bd670b35SErik Nordmark 	sizeof (struct sctp_initmsg), 0 },
666bd670b35SErik Nordmark { SCTP_I_WANT_MAPPED_V4_ADDR, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
667bd670b35SErik Nordmark 	sizeof (int), 0 },
668bd670b35SErik Nordmark { SCTP_MAXSEG, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
669bd670b35SErik Nordmark { SCTP_NODELAY, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
670bd670b35SErik Nordmark { SCTP_PEER_ADDR_PARAMS, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
671bd670b35SErik Nordmark 	sizeof (struct sctp_paddrparams), 0 },
672bd670b35SErik Nordmark { SCTP_PRIMARY_ADDR, IPPROTO_SCTP, OA_W, OA_W, OP_NP, 0,
673bd670b35SErik Nordmark 	sizeof (struct sctp_setpeerprim), 0 },
674bd670b35SErik Nordmark { SCTP_PRSCTP, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
675bd670b35SErik Nordmark { SCTP_GET_ASSOC_STATS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0,
676bd670b35SErik Nordmark 	sizeof (sctp_assoc_stats_t), 0 },
677bd670b35SErik Nordmark { SCTP_REM_ADDR, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, OP_VARLEN,
678bd670b35SErik Nordmark 	sizeof (int), 0 },
679bd670b35SErik Nordmark { SCTP_RTOINFO, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
680bd670b35SErik Nordmark 	sizeof (struct sctp_rtoinfo), 0 },
681bd670b35SErik Nordmark { SCTP_SET_PEER_PRIMARY_ADDR, IPPROTO_SCTP, OA_W, OA_W, OP_NP, 0,
682bd670b35SErik Nordmark 	sizeof (struct sctp_setprim), 0 },
683bd670b35SErik Nordmark { SCTP_STATUS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0,
684bd670b35SErik Nordmark 	sizeof (struct sctp_status), 0 },
685bd670b35SErik Nordmark { SCTP_UC_SWAP, IPPROTO_SCTP, OA_W, OA_W, OP_NP, 0,
686bd670b35SErik Nordmark 	sizeof (struct sctp_uc_swap), 0 },
687bd670b35SErik Nordmark 
688bd670b35SErik Nordmark { IP_OPTIONS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP,
689bd670b35SErik Nordmark 	(OP_VARLEN|OP_NODEFAULT),
690bd670b35SErik Nordmark 	40, -1 /* not initialized */ },
691bd670b35SErik Nordmark { T_IP_OPTIONS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP,
692bd670b35SErik Nordmark 	(OP_VARLEN|OP_NODEFAULT),
693bd670b35SErik Nordmark 	40, -1 /* not initialized */ },
694bd670b35SErik Nordmark 
695bd670b35SErik Nordmark { IP_TOS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
696bd670b35SErik Nordmark { T_IP_TOS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
697bd670b35SErik Nordmark { IP_TTL,	IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_DEF_FN,
698bd670b35SErik Nordmark 	sizeof (int), -1 /* not initialized */ },
699bd670b35SErik Nordmark 
700bd670b35SErik Nordmark { IP_SEC_OPT, IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_NODEFAULT,
701bd670b35SErik Nordmark 	sizeof (ipsec_req_t), -1 /* not initialized */ },
702bd670b35SErik Nordmark 
703bd670b35SErik Nordmark { IP_BOUND_IF, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0,
704bd670b35SErik Nordmark 	sizeof (int),	0 /* no ifindex */ },
705bd670b35SErik Nordmark 
706bd670b35SErik Nordmark { IP_UNSPEC_SRC, IPPROTO_IP, OA_R, OA_RW, OP_RAW, 0,
707bd670b35SErik Nordmark 	sizeof (int), 0 },
708bd670b35SErik Nordmark 
709bd670b35SErik Nordmark { IPV6_UNICAST_HOPS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, OP_DEF_FN,
710bd670b35SErik Nordmark 	sizeof (int), -1 /* not initialized */ },
711bd670b35SErik Nordmark 
712bd670b35SErik Nordmark { IPV6_BOUND_IF, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
713bd670b35SErik Nordmark 	sizeof (int),	0 /* no ifindex */ },
714bd670b35SErik Nordmark 
715bd670b35SErik Nordmark { IP_DONTFRAG, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
716bd670b35SErik Nordmark 
717bd670b35SErik Nordmark { IP_NEXTHOP, IPPROTO_IP, OA_R, OA_RW, OP_CONFIG, 0,
718bd670b35SErik Nordmark 	sizeof (in_addr_t),	-1 /* not initialized  */ },
719bd670b35SErik Nordmark 
720bd670b35SErik Nordmark { IPV6_UNSPEC_SRC, IPPROTO_IPV6, OA_R, OA_RW, OP_RAW, 0,
721bd670b35SErik Nordmark 	sizeof (int), 0 },
722bd670b35SErik Nordmark 
723bd670b35SErik Nordmark { IPV6_PKTINFO, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
724bd670b35SErik Nordmark 	(OP_NODEFAULT|OP_VARLEN),
725bd670b35SErik Nordmark 	sizeof (struct in6_pktinfo), -1 /* not initialized */ },
726bd670b35SErik Nordmark { IPV6_NEXTHOP, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
727bd670b35SErik Nordmark 	OP_NODEFAULT,
728bd670b35SErik Nordmark 	sizeof (sin6_t), -1 /* not initialized */ },
729bd670b35SErik Nordmark { IPV6_HOPOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
730bd670b35SErik Nordmark 	(OP_VARLEN|OP_NODEFAULT), 255*8,
731bd670b35SErik Nordmark 	-1 /* not initialized */ },
732bd670b35SErik Nordmark { IPV6_DSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
733bd670b35SErik Nordmark 	(OP_VARLEN|OP_NODEFAULT), 255*8,
734bd670b35SErik Nordmark 	-1 /* not initialized */ },
735bd670b35SErik Nordmark { IPV6_RTHDRDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
736bd670b35SErik Nordmark 	(OP_VARLEN|OP_NODEFAULT), 255*8,
737bd670b35SErik Nordmark 	-1 /* not initialized */ },
738bd670b35SErik Nordmark { IPV6_RTHDR, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
739bd670b35SErik Nordmark 	(OP_VARLEN|OP_NODEFAULT), 255*8,
740bd670b35SErik Nordmark 	-1 /* not initialized */ },
741bd670b35SErik Nordmark { IPV6_TCLASS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
742bd670b35SErik Nordmark 	OP_NODEFAULT,
743bd670b35SErik Nordmark 	sizeof (int), -1 /* not initialized */ },
744bd670b35SErik Nordmark { IPV6_PATHMTU, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
745bd670b35SErik Nordmark 	OP_NODEFAULT,
746bd670b35SErik Nordmark 	sizeof (struct ip6_mtuinfo), -1 /* not initialized */ },
747bd670b35SErik Nordmark { IPV6_DONTFRAG, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
748bd670b35SErik Nordmark 	sizeof (int), 0 },
749bd670b35SErik Nordmark { IPV6_USE_MIN_MTU, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
750bd670b35SErik Nordmark 	sizeof (int), 0 },
751bd670b35SErik Nordmark { IPV6_V6ONLY, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
752bd670b35SErik Nordmark 	sizeof (int), 0 },
753bd670b35SErik Nordmark 
754bd670b35SErik Nordmark /* Enable receipt of ancillary data */
755bd670b35SErik Nordmark { IPV6_RECVPKTINFO, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
756bd670b35SErik Nordmark 	sizeof (int), 0 },
757bd670b35SErik Nordmark { IPV6_RECVHOPLIMIT, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
758bd670b35SErik Nordmark 	sizeof (int), 0 },
759bd670b35SErik Nordmark { IPV6_RECVTCLASS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
760bd670b35SErik Nordmark 	sizeof (int), 0 },
761bd670b35SErik Nordmark { IPV6_RECVHOPOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
762bd670b35SErik Nordmark 	sizeof (int), 0 },
763bd670b35SErik Nordmark { _OLD_IPV6_RECVDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
764bd670b35SErik Nordmark 	sizeof (int), 0 },
765bd670b35SErik Nordmark { IPV6_RECVDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
766bd670b35SErik Nordmark 	sizeof (int), 0 },
767bd670b35SErik Nordmark { IPV6_RECVRTHDR, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
768bd670b35SErik Nordmark 	sizeof (int), 0 },
769bd670b35SErik Nordmark { IPV6_RECVRTHDRDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
770bd670b35SErik Nordmark 	sizeof (int), 0 },
771bd670b35SErik Nordmark { IPV6_RECVTCLASS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
772bd670b35SErik Nordmark 	sizeof (int), 0 },
773bd670b35SErik Nordmark 
774bd670b35SErik Nordmark { IPV6_SEC_OPT, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, OP_NODEFAULT,
775bd670b35SErik Nordmark 	sizeof (ipsec_req_t), -1 /* not initialized */ },
776bd670b35SErik Nordmark { IPV6_SRC_PREFERENCES, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
777bd670b35SErik Nordmark 	sizeof (uint32_t), IPV6_PREFER_SRC_DEFAULT },
778bd670b35SErik Nordmark };
779bd670b35SErik Nordmark 
780bd670b35SErik Nordmark uint_t sctp_opt_arr_size = A_CNT(sctp_opt_arr);
781bd670b35SErik Nordmark 
7827c478bd9Sstevel@tonic-gate /* Handy on off switch for socket option processing. */
7837c478bd9Sstevel@tonic-gate #define	ONOFF(x)	((x) == 0 ? 0 : 1)
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate /*
7867c478bd9Sstevel@tonic-gate  * SCTP routine to get the values of options.
7877c478bd9Sstevel@tonic-gate  */
7887c478bd9Sstevel@tonic-gate int
7897c478bd9Sstevel@tonic-gate sctp_get_opt(sctp_t *sctp, int level, int name, void *ptr, socklen_t *optlen)
7907c478bd9Sstevel@tonic-gate {
7917c478bd9Sstevel@tonic-gate 	int	*i1 = (int *)ptr;
7927c478bd9Sstevel@tonic-gate 	int	retval = 0;
7937c478bd9Sstevel@tonic-gate 	int	buflen = *optlen;
794bd670b35SErik Nordmark 	conn_t	*connp = sctp->sctp_connp;
795bd670b35SErik Nordmark 	conn_opt_arg_t	coas;
796bd670b35SErik Nordmark 
797bd670b35SErik Nordmark 	coas.coa_connp = connp;
798bd670b35SErik Nordmark 	coas.coa_ixa = connp->conn_ixa;
799bd670b35SErik Nordmark 	coas.coa_ipp = &connp->conn_xmit_ipp;
80088cda078Skcpoon 
8017c478bd9Sstevel@tonic-gate 	/* In most cases, the return buffer is just an int */
8027c478bd9Sstevel@tonic-gate 	*optlen = sizeof (int32_t);
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	RUN_SCTP(sctp);
8057c478bd9Sstevel@tonic-gate 
806b34b8d1aSkcpoon 	if (connp->conn_state_flags & CONN_CLOSING) {
807b34b8d1aSkcpoon 		WAKE_SCTP(sctp);
808b34b8d1aSkcpoon 		return (EINVAL);
809b34b8d1aSkcpoon 	}
810b34b8d1aSkcpoon 
811bd670b35SErik Nordmark 	/*
812bd670b35SErik Nordmark 	 * Check that the level and name are supported by SCTP, and that
813bd670b35SErik Nordmark 	 * the length and credentials are ok.
814bd670b35SErik Nordmark 	 */
815bd670b35SErik Nordmark 	retval = proto_opt_check(level, name, buflen, NULL, sctp_opt_arr,
816bd670b35SErik Nordmark 	    sctp_opt_arr_size, B_FALSE, B_TRUE, connp->conn_cred);
817bd670b35SErik Nordmark 	if (retval != 0) {
818bd670b35SErik Nordmark 		WAKE_SCTP(sctp);
819bd670b35SErik Nordmark 		if (retval < 0) {
820bd670b35SErik Nordmark 			retval = proto_tlitosyserr(-retval);
8217c478bd9Sstevel@tonic-gate 		}
822bd670b35SErik Nordmark 		return (retval);
823bd670b35SErik Nordmark 	}
8247c478bd9Sstevel@tonic-gate 
825bd670b35SErik Nordmark 	switch (level) {
8267c478bd9Sstevel@tonic-gate 	case IPPROTO_SCTP:
8277c478bd9Sstevel@tonic-gate 		switch (name) {
8287c478bd9Sstevel@tonic-gate 		case SCTP_RTOINFO:
8297c478bd9Sstevel@tonic-gate 			*optlen = sctp_get_rtoinfo(sctp, ptr);
8307c478bd9Sstevel@tonic-gate 			break;
8317c478bd9Sstevel@tonic-gate 		case SCTP_ASSOCINFO:
8327c478bd9Sstevel@tonic-gate 			*optlen = sctp_get_assocparams(sctp, ptr);
8337c478bd9Sstevel@tonic-gate 			break;
8347c478bd9Sstevel@tonic-gate 		case SCTP_INITMSG:
8357c478bd9Sstevel@tonic-gate 			*optlen = sctp_get_initmsg(sctp, ptr);
8367c478bd9Sstevel@tonic-gate 			break;
8377c478bd9Sstevel@tonic-gate 		case SCTP_NODELAY:
8387c478bd9Sstevel@tonic-gate 			*i1 = sctp->sctp_ndelay;
8397c478bd9Sstevel@tonic-gate 			break;
8407c478bd9Sstevel@tonic-gate 		case SCTP_AUTOCLOSE:
8417c478bd9Sstevel@tonic-gate 			*i1 = TICK_TO_SEC(sctp->sctp_autoclose);
8427c478bd9Sstevel@tonic-gate 			break;
843558fbd03Skcpoon 		case SCTP_ADAPTATION_LAYER:
844558fbd03Skcpoon 			((struct sctp_setadaptation *)ptr)->ssb_adaptation_ind =
845558fbd03Skcpoon 			    sctp->sctp_tx_adaptation_code;
8467c478bd9Sstevel@tonic-gate 			break;
8477c478bd9Sstevel@tonic-gate 		case SCTP_PEER_ADDR_PARAMS:
8487c478bd9Sstevel@tonic-gate 			*optlen = sctp_get_peer_addr_params(sctp, ptr);
8497c478bd9Sstevel@tonic-gate 			break;
8507c478bd9Sstevel@tonic-gate 		case SCTP_DEFAULT_SEND_PARAM:
8517c478bd9Sstevel@tonic-gate 			*optlen = sctp_get_def_send_params(sctp, ptr);
8527c478bd9Sstevel@tonic-gate 			break;
8537c478bd9Sstevel@tonic-gate 		case SCTP_EVENTS: {
8547c478bd9Sstevel@tonic-gate 			struct sctp_event_subscribe *ev;
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 			ev = (struct sctp_event_subscribe *)ptr;
8577c478bd9Sstevel@tonic-gate 			ev->sctp_data_io_event =
8587c478bd9Sstevel@tonic-gate 			    ONOFF(sctp->sctp_recvsndrcvinfo);
8597c478bd9Sstevel@tonic-gate 			ev->sctp_association_event =
8607c478bd9Sstevel@tonic-gate 			    ONOFF(sctp->sctp_recvassocevnt);
8617c478bd9Sstevel@tonic-gate 			ev->sctp_address_event =
8627c478bd9Sstevel@tonic-gate 			    ONOFF(sctp->sctp_recvpathevnt);
8637c478bd9Sstevel@tonic-gate 			ev->sctp_send_failure_event =
8647c478bd9Sstevel@tonic-gate 			    ONOFF(sctp->sctp_recvsendfailevnt);
8657c478bd9Sstevel@tonic-gate 			ev->sctp_peer_error_event =
8667c478bd9Sstevel@tonic-gate 			    ONOFF(sctp->sctp_recvpeererr);
8677c478bd9Sstevel@tonic-gate 			ev->sctp_shutdown_event =
8687c478bd9Sstevel@tonic-gate 			    ONOFF(sctp->sctp_recvshutdownevnt);
8697c478bd9Sstevel@tonic-gate 			ev->sctp_partial_delivery_event =
8707c478bd9Sstevel@tonic-gate 			    ONOFF(sctp->sctp_recvpdevnt);
871558fbd03Skcpoon 			ev->sctp_adaptation_layer_event =
872b34b8d1aSkcpoon 			    ONOFF(sctp->sctp_recvalevnt);
8737c478bd9Sstevel@tonic-gate 			*optlen = sizeof (struct sctp_event_subscribe);
8747c478bd9Sstevel@tonic-gate 			break;
8757c478bd9Sstevel@tonic-gate 		}
8767c478bd9Sstevel@tonic-gate 		case SCTP_STATUS:
8777c478bd9Sstevel@tonic-gate 			*optlen = sctp_get_status(sctp, ptr);
8787c478bd9Sstevel@tonic-gate 			break;
8797c478bd9Sstevel@tonic-gate 		case SCTP_GET_PEER_ADDR_INFO:
8807c478bd9Sstevel@tonic-gate 			retval = sctp_get_paddrinfo(sctp, ptr, optlen);
8817c478bd9Sstevel@tonic-gate 			break;
8827c478bd9Sstevel@tonic-gate 		case SCTP_GET_NLADDRS:
8837c478bd9Sstevel@tonic-gate 			*(int32_t *)ptr = sctp->sctp_nsaddrs;
8847c478bd9Sstevel@tonic-gate 			break;
8857c478bd9Sstevel@tonic-gate 		case SCTP_GET_LADDRS: {
8867c478bd9Sstevel@tonic-gate 			int addr_cnt;
8877c478bd9Sstevel@tonic-gate 			int addr_size;
8887c478bd9Sstevel@tonic-gate 
889bd670b35SErik Nordmark 			if (connp->conn_family == AF_INET)
8907c478bd9Sstevel@tonic-gate 				addr_size = sizeof (struct sockaddr_in);
8917c478bd9Sstevel@tonic-gate 			else
8927c478bd9Sstevel@tonic-gate 				addr_size = sizeof (struct sockaddr_in6);
8937c478bd9Sstevel@tonic-gate 			addr_cnt = buflen / addr_size;
8947c478bd9Sstevel@tonic-gate 			retval = sctp_getmyaddrs(sctp, ptr, &addr_cnt);
8957c478bd9Sstevel@tonic-gate 			if (retval == 0)
8967c478bd9Sstevel@tonic-gate 				*optlen = addr_cnt * addr_size;
8977c478bd9Sstevel@tonic-gate 			break;
8987c478bd9Sstevel@tonic-gate 		}
8997c478bd9Sstevel@tonic-gate 		case SCTP_GET_NPADDRS: {
9007c478bd9Sstevel@tonic-gate 			int i;
9017c478bd9Sstevel@tonic-gate 			sctp_faddr_t *fp;
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 			for (i = 0, fp = sctp->sctp_faddrs; fp != NULL;
904*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			    i++, fp = fp->sf_next)
9057c478bd9Sstevel@tonic-gate 				;
9067c478bd9Sstevel@tonic-gate 			*(int32_t *)ptr = i;
9077c478bd9Sstevel@tonic-gate 			break;
9087c478bd9Sstevel@tonic-gate 		}
9097c478bd9Sstevel@tonic-gate 		case SCTP_GET_PADDRS: {
9107c478bd9Sstevel@tonic-gate 			int addr_cnt;
9117c478bd9Sstevel@tonic-gate 			int addr_size;
9127c478bd9Sstevel@tonic-gate 
913bd670b35SErik Nordmark 			if (connp->conn_family == AF_INET)
9147c478bd9Sstevel@tonic-gate 				addr_size = sizeof (struct sockaddr_in);
9157c478bd9Sstevel@tonic-gate 			else
9167c478bd9Sstevel@tonic-gate 				addr_size = sizeof (struct sockaddr_in6);
9177c478bd9Sstevel@tonic-gate 			addr_cnt = buflen / addr_size;
9187c478bd9Sstevel@tonic-gate 			retval = sctp_getpeeraddrs(sctp, ptr, &addr_cnt);
9197c478bd9Sstevel@tonic-gate 			if (retval == 0)
9207c478bd9Sstevel@tonic-gate 				*optlen = addr_cnt * addr_size;
9217c478bd9Sstevel@tonic-gate 			break;
9227c478bd9Sstevel@tonic-gate 		}
9237c478bd9Sstevel@tonic-gate 		case SCTP_PRSCTP:
9247c478bd9Sstevel@tonic-gate 			*i1 = sctp->sctp_prsctp_aware ? 1 : 0;
9257c478bd9Sstevel@tonic-gate 			break;
9269f13099eSGeorge Shepherd 
9279f13099eSGeorge Shepherd 		case SCTP_GET_ASSOC_STATS: {
9289f13099eSGeorge Shepherd 			sctp_assoc_stats_t *sas;
9299f13099eSGeorge Shepherd 
9309f13099eSGeorge Shepherd 			sas = (sctp_assoc_stats_t *)ptr;
9319f13099eSGeorge Shepherd 
9329f13099eSGeorge Shepherd 			/*
9339f13099eSGeorge Shepherd 			 * Copy the current stats to the stats struct.
93435e12f9cSGeorge Shepherd 			 * For stats which can be reset by snmp users
93535e12f9cSGeorge Shepherd 			 * add the cumulative and current stats for
93635e12f9cSGeorge Shepherd 			 * the raw totals to output to the user.
9379f13099eSGeorge Shepherd 			 */
9389f13099eSGeorge Shepherd 			sas->sas_gapcnt = sctp->sctp_gapcnt;
9399f13099eSGeorge Shepherd 			sas->sas_outseqtsns = sctp->sctp_outseqtsns;
9409f13099eSGeorge Shepherd 			sas->sas_osacks = sctp->sctp_osacks;
9419f13099eSGeorge Shepherd 			sas->sas_isacks = sctp->sctp_isacks;
9429f13099eSGeorge Shepherd 			sas->sas_idupchunks = sctp->sctp_idupchunks;
94335e12f9cSGeorge Shepherd 			sas->sas_rtxchunks =  sctp->sctp_rxtchunks +
94435e12f9cSGeorge Shepherd 			    sctp->sctp_cum_rxtchunks;
94535e12f9cSGeorge Shepherd 			sas->sas_octrlchunks = sctp->sctp_obchunks +
94635e12f9cSGeorge Shepherd 			    sctp->sctp_cum_obchunks;
94735e12f9cSGeorge Shepherd 			sas->sas_ictrlchunks = sctp->sctp_ibchunks +
94835e12f9cSGeorge Shepherd 			    sctp->sctp_cum_ibchunks;
94935e12f9cSGeorge Shepherd 			sas->sas_oodchunks = sctp->sctp_odchunks +
95035e12f9cSGeorge Shepherd 			    sctp->sctp_cum_odchunks;
95135e12f9cSGeorge Shepherd 			sas->sas_iodchunks = sctp->sctp_idchunks +
95235e12f9cSGeorge Shepherd 			    sctp->sctp_cum_idchunks;
95335e12f9cSGeorge Shepherd 			sas->sas_ouodchunks = sctp->sctp_oudchunks +
95435e12f9cSGeorge Shepherd 			    sctp->sctp_cum_oudchunks;
95535e12f9cSGeorge Shepherd 			sas->sas_iuodchunks = sctp->sctp_iudchunks +
95635e12f9cSGeorge Shepherd 			    sctp->sctp_cum_iudchunks;
9579f13099eSGeorge Shepherd 
9589f13099eSGeorge Shepherd 			/*
9599f13099eSGeorge Shepherd 			 * Copy out the maximum observed RTO since the
9609f13099eSGeorge Shepherd 			 * time this data was last requested
9619f13099eSGeorge Shepherd 			 */
9629f13099eSGeorge Shepherd 			if (sctp->sctp_maxrto == 0) {
9639f13099eSGeorge Shepherd 				/* unchanged during obervation period */
9649f13099eSGeorge Shepherd 				sas->sas_maxrto = sctp->sctp_prev_maxrto;
9659f13099eSGeorge Shepherd 			} else {
9669f13099eSGeorge Shepherd 				/* record new period maximum */
9679f13099eSGeorge Shepherd 				sas->sas_maxrto = sctp->sctp_maxrto;
9689f13099eSGeorge Shepherd 			}
9699f13099eSGeorge Shepherd 			/* Record the value sent to the user this period */
9709f13099eSGeorge Shepherd 			sctp->sctp_prev_maxrto = sas->sas_maxrto;
9719f13099eSGeorge Shepherd 
9729f13099eSGeorge Shepherd 			/* Mark beginning of a new observation period */
9739f13099eSGeorge Shepherd 			sctp->sctp_maxrto = 0;
9749f13099eSGeorge Shepherd 
9759f13099eSGeorge Shepherd 			*optlen = sizeof (sctp_assoc_stats_t);
9769f13099eSGeorge Shepherd 			break;
9779f13099eSGeorge Shepherd 		}
9787c478bd9Sstevel@tonic-gate 		case SCTP_I_WANT_MAPPED_V4_ADDR:
9797c478bd9Sstevel@tonic-gate 		case SCTP_MAXSEG:
9807c478bd9Sstevel@tonic-gate 		case SCTP_DISABLE_FRAGMENTS:
9817c478bd9Sstevel@tonic-gate 		default:
982bd670b35SErik Nordmark 			/* Not yet supported. */
98388cda078Skcpoon 			retval = ENOPROTOOPT;
9847c478bd9Sstevel@tonic-gate 			break;
9857c478bd9Sstevel@tonic-gate 		}
986bd670b35SErik Nordmark 		WAKE_SCTP(sctp);
987bd670b35SErik Nordmark 		return (retval);
9887c478bd9Sstevel@tonic-gate 	case IPPROTO_IP:
989bd670b35SErik Nordmark 		if (connp->conn_family != AF_INET) {
9907c478bd9Sstevel@tonic-gate 			retval = EINVAL;
9917c478bd9Sstevel@tonic-gate 			break;
9927c478bd9Sstevel@tonic-gate 		}
9937c478bd9Sstevel@tonic-gate 		switch (name) {
9947c478bd9Sstevel@tonic-gate 		case IP_OPTIONS:
9957c478bd9Sstevel@tonic-gate 		case T_IP_OPTIONS: {
9967c478bd9Sstevel@tonic-gate 			/*
9977c478bd9Sstevel@tonic-gate 			 * This is compatible with BSD in that in only return
9987c478bd9Sstevel@tonic-gate 			 * the reverse source route with the final destination
9997c478bd9Sstevel@tonic-gate 			 * as the last entry. The first 4 bytes of the option
10007c478bd9Sstevel@tonic-gate 			 * will contain the final destination. Allocate a
10017c478bd9Sstevel@tonic-gate 			 * buffer large enough to hold all the options, we
10027c478bd9Sstevel@tonic-gate 			 * add IP_ADDR_LEN to SCTP_MAX_IP_OPTIONS_LENGTH since
100345916cd2Sjpk 			 * ip_opt_get_user() adds the final destination
10047c478bd9Sstevel@tonic-gate 			 * at the start.
10057c478bd9Sstevel@tonic-gate 			 */
10067c478bd9Sstevel@tonic-gate 			int	opt_len;
10077c478bd9Sstevel@tonic-gate 			uchar_t	obuf[SCTP_MAX_IP_OPTIONS_LENGTH + IP_ADDR_LEN];
10087c478bd9Sstevel@tonic-gate 
1009bd670b35SErik Nordmark 			opt_len = ip_opt_get_user(connp, obuf);
1010bd670b35SErik Nordmark 			ASSERT(opt_len <= sizeof (obuf));
1011bd670b35SErik Nordmark 
10127c478bd9Sstevel@tonic-gate 			if (buflen < opt_len) {
10137c478bd9Sstevel@tonic-gate 				/* Silently truncate */
10147c478bd9Sstevel@tonic-gate 				opt_len = buflen;
10157c478bd9Sstevel@tonic-gate 			}
10167c478bd9Sstevel@tonic-gate 			*optlen = opt_len;
10177c478bd9Sstevel@tonic-gate 			bcopy(obuf, ptr, opt_len);
1018bd670b35SErik Nordmark 			WAKE_SCTP(sctp);
1019bd670b35SErik Nordmark 			return (0);
10207c478bd9Sstevel@tonic-gate 		}
10217c478bd9Sstevel@tonic-gate 		default:
10227c478bd9Sstevel@tonic-gate 			break;
10237c478bd9Sstevel@tonic-gate 		}
10247c478bd9Sstevel@tonic-gate 		break;
10257c478bd9Sstevel@tonic-gate 	}
1026bd670b35SErik Nordmark 	mutex_enter(&connp->conn_lock);
1027bd670b35SErik Nordmark 	retval = conn_opt_get(&coas, level, name, ptr);
1028bd670b35SErik Nordmark 	mutex_exit(&connp->conn_lock);
10297c478bd9Sstevel@tonic-gate 	WAKE_SCTP(sctp);
1030bd670b35SErik Nordmark 	if (retval == -1)
1031bd670b35SErik Nordmark 		return (EINVAL);
1032bd670b35SErik Nordmark 	*optlen = retval;
1033bd670b35SErik Nordmark 	return (0);
10347c478bd9Sstevel@tonic-gate }
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate int
10377c478bd9Sstevel@tonic-gate sctp_set_opt(sctp_t *sctp, int level, int name, const void *invalp,
10387c478bd9Sstevel@tonic-gate     socklen_t inlen)
10397c478bd9Sstevel@tonic-gate {
10407c478bd9Sstevel@tonic-gate 	int		*i1 = (int *)invalp;
10417c478bd9Sstevel@tonic-gate 	boolean_t	onoff;
10427c478bd9Sstevel@tonic-gate 	int		retval = 0, addrcnt;
10437c478bd9Sstevel@tonic-gate 	conn_t		*connp = sctp->sctp_connp;
1044f4b3ec61Sdh 	sctp_stack_t	*sctps = sctp->sctp_sctps;
1045bd670b35SErik Nordmark 	conn_opt_arg_t	coas;
1046bd670b35SErik Nordmark 
1047bd670b35SErik Nordmark 	coas.coa_connp = connp;
1048bd670b35SErik Nordmark 	coas.coa_ixa = connp->conn_ixa;
1049bd670b35SErik Nordmark 	coas.coa_ipp = &connp->conn_xmit_ipp;
1050bd670b35SErik Nordmark 	coas.coa_ancillary = B_FALSE;
1051bd670b35SErik Nordmark 	coas.coa_changed = 0;
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 	/* In all cases, the size of the option must be bigger than int */
10547c478bd9Sstevel@tonic-gate 	if (inlen >= sizeof (int32_t)) {
10557c478bd9Sstevel@tonic-gate 		onoff = ONOFF(*i1);
10567c478bd9Sstevel@tonic-gate 	}
10577c478bd9Sstevel@tonic-gate 	retval = 0;
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	RUN_SCTP(sctp);
10607c478bd9Sstevel@tonic-gate 
1061b34b8d1aSkcpoon 	if (connp->conn_state_flags & CONN_CLOSING) {
1062b34b8d1aSkcpoon 		WAKE_SCTP(sctp);
1063b34b8d1aSkcpoon 		return (EINVAL);
1064b34b8d1aSkcpoon 	}
1065b34b8d1aSkcpoon 
1066bd670b35SErik Nordmark 	/*
1067bd670b35SErik Nordmark 	 * Check that the level and name are supported by SCTP, and that
1068bd670b35SErik Nordmark 	 * the length an credentials are ok.
1069bd670b35SErik Nordmark 	 */
1070bd670b35SErik Nordmark 	retval = proto_opt_check(level, name, inlen, NULL, sctp_opt_arr,
1071bd670b35SErik Nordmark 	    sctp_opt_arr_size, B_TRUE, B_FALSE, connp->conn_cred);
1072bd670b35SErik Nordmark 	if (retval != 0) {
1073bd670b35SErik Nordmark 		if (retval < 0) {
1074bd670b35SErik Nordmark 			retval = proto_tlitosyserr(-retval);
1075bd670b35SErik Nordmark 		}
1076bd670b35SErik Nordmark 		goto done;
1077bd670b35SErik Nordmark 	}
1078bd670b35SErik Nordmark 
1079bd670b35SErik Nordmark 	/* Note: both SCTP and TCP interpret l_linger as being in seconds */
10807c478bd9Sstevel@tonic-gate 	switch (level) {
10817c478bd9Sstevel@tonic-gate 	case SOL_SOCKET:
10827c478bd9Sstevel@tonic-gate 		switch (name) {
10837c478bd9Sstevel@tonic-gate 		case SO_SNDBUF:
1084f4b3ec61Sdh 			if (*i1 > sctps->sctps_max_buf) {
10857c478bd9Sstevel@tonic-gate 				retval = ENOBUFS;
1086bd670b35SErik Nordmark 				goto done;
10877c478bd9Sstevel@tonic-gate 			}
10887c478bd9Sstevel@tonic-gate 			if (*i1 < 0) {
10897c478bd9Sstevel@tonic-gate 				retval = EINVAL;
1090bd670b35SErik Nordmark 				goto done;
10917c478bd9Sstevel@tonic-gate 			}
1092bd670b35SErik Nordmark 			connp->conn_sndbuf = *i1;
1093bd670b35SErik Nordmark 			if (sctps->sctps_snd_lowat_fraction != 0) {
1094bd670b35SErik Nordmark 				connp->conn_sndlowat = connp->conn_sndbuf /
1095f4b3ec61Sdh 				    sctps->sctps_snd_lowat_fraction;
1096bd670b35SErik Nordmark 			}
1097bd670b35SErik Nordmark 			goto done;
10987c478bd9Sstevel@tonic-gate 		case SO_RCVBUF:
1099f4b3ec61Sdh 			if (*i1 > sctps->sctps_max_buf) {
11007c478bd9Sstevel@tonic-gate 				retval = ENOBUFS;
1101bd670b35SErik Nordmark 				goto done;
11027c478bd9Sstevel@tonic-gate 			}
11037c478bd9Sstevel@tonic-gate 			/* Silently ignore zero */
11047c478bd9Sstevel@tonic-gate 			if (*i1 != 0) {
11057cae9885SAnders Persson 				struct sock_proto_props sopp;
11067cae9885SAnders Persson 
11077c478bd9Sstevel@tonic-gate 				/*
11087c478bd9Sstevel@tonic-gate 				 * Insist on a receive window that is at least
11097c478bd9Sstevel@tonic-gate 				 * sctp_recv_hiwat_minmss * MSS (default 4*MSS)
11107c478bd9Sstevel@tonic-gate 				 * to avoid funny interactions of Nagle
11117c478bd9Sstevel@tonic-gate 				 * algorithm, SWS avoidance and delayed
11127c478bd9Sstevel@tonic-gate 				 * acknowledgement.
11137c478bd9Sstevel@tonic-gate 				 */
11147c478bd9Sstevel@tonic-gate 				*i1 = MAX(*i1,
1115f4b3ec61Sdh 				    sctps->sctps_recv_hiwat_minmss *
1116f4b3ec61Sdh 				    sctp->sctp_mss);
1117bd670b35SErik Nordmark 				/*
1118bd670b35SErik Nordmark 				 * Note that sctp_rwnd is modified by the
1119bd670b35SErik Nordmark 				 * protocol and here we just whack it.
1120bd670b35SErik Nordmark 				 */
1121bd670b35SErik Nordmark 				connp->conn_rcvbuf = sctp->sctp_rwnd = *i1;
11221d8c4025Svi 				sctp->sctp_irwnd = sctp->sctp_rwnd;
11237d546a59Svi 				sctp->sctp_pd_point = sctp->sctp_rwnd;
11247cae9885SAnders Persson 
11257cae9885SAnders Persson 				sopp.sopp_flags = SOCKOPT_RCVHIWAT;
1126bd670b35SErik Nordmark 				sopp.sopp_rxhiwat = connp->conn_rcvbuf;
11277cae9885SAnders Persson 				sctp->sctp_ulp_prop(sctp->sctp_ulpd, &sopp);
11287cae9885SAnders Persson 
11297c478bd9Sstevel@tonic-gate 			}
11307c478bd9Sstevel@tonic-gate 			/*
11317c478bd9Sstevel@tonic-gate 			 * XXX should we return the rwnd here
11327c478bd9Sstevel@tonic-gate 			 * and sctp_opt_get ?
11337c478bd9Sstevel@tonic-gate 			 */
1134bd670b35SErik Nordmark 			goto done;
11355d0bc3edSsommerfe 		case SO_ALLZONES:
11365d0bc3edSsommerfe 			if (sctp->sctp_state >= SCTPS_BOUND) {
11375d0bc3edSsommerfe 				retval = EINVAL;
1138bd670b35SErik Nordmark 				goto done;
11395d0bc3edSsommerfe 			}
11405d0bc3edSsommerfe 			break;
114145916cd2Sjpk 		case SO_MAC_EXEMPT:
11425d3b8cb7SBill Sommerfeld 			if (sctp->sctp_state >= SCTPS_BOUND) {
11435d3b8cb7SBill Sommerfeld 				retval = EINVAL;
1144bd670b35SErik Nordmark 				goto done;
11455d3b8cb7SBill Sommerfeld 			}
11467c478bd9Sstevel@tonic-gate 			break;
11477c478bd9Sstevel@tonic-gate 		}
11487c478bd9Sstevel@tonic-gate 		break;
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	case IPPROTO_SCTP:
11517c478bd9Sstevel@tonic-gate 		switch (name) {
11527c478bd9Sstevel@tonic-gate 		case SCTP_RTOINFO:
1153bd670b35SErik Nordmark 			retval = sctp_set_rtoinfo(sctp, invalp);
11547c478bd9Sstevel@tonic-gate 			break;
11557c478bd9Sstevel@tonic-gate 		case SCTP_ASSOCINFO:
1156bd670b35SErik Nordmark 			retval = sctp_set_assocparams(sctp, invalp);
11577c478bd9Sstevel@tonic-gate 			break;
11587c478bd9Sstevel@tonic-gate 		case SCTP_INITMSG:
11597c478bd9Sstevel@tonic-gate 			retval = sctp_set_initmsg(sctp, invalp, inlen);
11607c478bd9Sstevel@tonic-gate 			break;
11617c478bd9Sstevel@tonic-gate 		case SCTP_NODELAY:
11627c478bd9Sstevel@tonic-gate 			sctp->sctp_ndelay = ONOFF(*i1);
11637c478bd9Sstevel@tonic-gate 			break;
11647c478bd9Sstevel@tonic-gate 		case SCTP_AUTOCLOSE:
11657c478bd9Sstevel@tonic-gate 			if (SEC_TO_TICK(*i1) < 0) {
11667c478bd9Sstevel@tonic-gate 				retval = EINVAL;
11677c478bd9Sstevel@tonic-gate 				break;
11687c478bd9Sstevel@tonic-gate 			}
11697c478bd9Sstevel@tonic-gate 			/* Convert the number of seconds to ticks. */
11707c478bd9Sstevel@tonic-gate 			sctp->sctp_autoclose = SEC_TO_TICK(*i1);
11717c478bd9Sstevel@tonic-gate 			sctp_heartbeat_timer(sctp);
11727c478bd9Sstevel@tonic-gate 			break;
11737c478bd9Sstevel@tonic-gate 		case SCTP_SET_PEER_PRIMARY_ADDR:
1174bd670b35SErik Nordmark 			retval = sctp_set_peerprim(sctp, invalp);
11757c478bd9Sstevel@tonic-gate 			break;
11767c478bd9Sstevel@tonic-gate 		case SCTP_PRIMARY_ADDR:
1177bd670b35SErik Nordmark 			retval = sctp_set_prim(sctp, invalp);
11787c478bd9Sstevel@tonic-gate 			break;
1179558fbd03Skcpoon 		case SCTP_ADAPTATION_LAYER: {
1180558fbd03Skcpoon 			struct sctp_setadaptation *ssb;
11817c478bd9Sstevel@tonic-gate 
1182558fbd03Skcpoon 			ssb = (struct sctp_setadaptation *)invalp;
1183558fbd03Skcpoon 			sctp->sctp_send_adaptation = 1;
1184558fbd03Skcpoon 			sctp->sctp_tx_adaptation_code = ssb->ssb_adaptation_ind;
11857c478bd9Sstevel@tonic-gate 			break;
11867c478bd9Sstevel@tonic-gate 		}
11877c478bd9Sstevel@tonic-gate 		case SCTP_PEER_ADDR_PARAMS:
1188bd670b35SErik Nordmark 			retval = sctp_set_peer_addr_params(sctp, invalp);
11897c478bd9Sstevel@tonic-gate 			break;
11907c478bd9Sstevel@tonic-gate 		case SCTP_DEFAULT_SEND_PARAM:
1191bd670b35SErik Nordmark 			retval = sctp_set_def_send_params(sctp, invalp);
11927c478bd9Sstevel@tonic-gate 			break;
11937c478bd9Sstevel@tonic-gate 		case SCTP_EVENTS: {
11947c478bd9Sstevel@tonic-gate 			struct sctp_event_subscribe *ev;
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 			ev = (struct sctp_event_subscribe *)invalp;
11977c478bd9Sstevel@tonic-gate 			sctp->sctp_recvsndrcvinfo =
11987c478bd9Sstevel@tonic-gate 			    ONOFF(ev->sctp_data_io_event);
11997c478bd9Sstevel@tonic-gate 			sctp->sctp_recvassocevnt =
12007c478bd9Sstevel@tonic-gate 			    ONOFF(ev->sctp_association_event);
12017c478bd9Sstevel@tonic-gate 			sctp->sctp_recvpathevnt =
12027c478bd9Sstevel@tonic-gate 			    ONOFF(ev->sctp_address_event);
12037c478bd9Sstevel@tonic-gate 			sctp->sctp_recvsendfailevnt =
12047c478bd9Sstevel@tonic-gate 			    ONOFF(ev->sctp_send_failure_event);
12057c478bd9Sstevel@tonic-gate 			sctp->sctp_recvpeererr =
12067c478bd9Sstevel@tonic-gate 			    ONOFF(ev->sctp_peer_error_event);
12077c478bd9Sstevel@tonic-gate 			sctp->sctp_recvshutdownevnt =
12087c478bd9Sstevel@tonic-gate 			    ONOFF(ev->sctp_shutdown_event);
12097c478bd9Sstevel@tonic-gate 			sctp->sctp_recvpdevnt =
12107c478bd9Sstevel@tonic-gate 			    ONOFF(ev->sctp_partial_delivery_event);
12117c478bd9Sstevel@tonic-gate 			sctp->sctp_recvalevnt =
1212558fbd03Skcpoon 			    ONOFF(ev->sctp_adaptation_layer_event);
12137c478bd9Sstevel@tonic-gate 			break;
12147c478bd9Sstevel@tonic-gate 		}
12157c478bd9Sstevel@tonic-gate 		case SCTP_ADD_ADDR:
12167c478bd9Sstevel@tonic-gate 		case SCTP_REM_ADDR:
12177c478bd9Sstevel@tonic-gate 			/*
12187c478bd9Sstevel@tonic-gate 			 * The sctp_t has to be bound first before
12197c478bd9Sstevel@tonic-gate 			 * the address list can be changed.
12207c478bd9Sstevel@tonic-gate 			 */
12217c478bd9Sstevel@tonic-gate 			if (sctp->sctp_state < SCTPS_BOUND) {
12227c478bd9Sstevel@tonic-gate 				retval = EINVAL;
12237c478bd9Sstevel@tonic-gate 				break;
12247c478bd9Sstevel@tonic-gate 			}
1225bd670b35SErik Nordmark 			if (connp->conn_family == AF_INET) {
12267c478bd9Sstevel@tonic-gate 				addrcnt = inlen / sizeof (struct sockaddr_in);
12277c478bd9Sstevel@tonic-gate 			} else {
1228bd670b35SErik Nordmark 				ASSERT(connp->conn_family == AF_INET6);
12297c478bd9Sstevel@tonic-gate 				addrcnt = inlen / sizeof (struct sockaddr_in6);
12307c478bd9Sstevel@tonic-gate 			}
12317c478bd9Sstevel@tonic-gate 			if (name == SCTP_ADD_ADDR) {
12327c478bd9Sstevel@tonic-gate 				retval = sctp_bind_add(sctp, invalp, addrcnt,
1233bd670b35SErik Nordmark 				    B_TRUE, connp->conn_lport);
12347c478bd9Sstevel@tonic-gate 			} else {
12357c478bd9Sstevel@tonic-gate 				retval = sctp_bind_del(sctp, invalp, addrcnt,
12367c478bd9Sstevel@tonic-gate 				    B_TRUE);
12377c478bd9Sstevel@tonic-gate 			}
12387c478bd9Sstevel@tonic-gate 			break;
12397c478bd9Sstevel@tonic-gate 		case SCTP_UC_SWAP: {
12407c478bd9Sstevel@tonic-gate 			struct sctp_uc_swap *us;
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 			/*
12437c478bd9Sstevel@tonic-gate 			 * Change handle & upcalls.
12447c478bd9Sstevel@tonic-gate 			 */
12457c478bd9Sstevel@tonic-gate 			us = (struct sctp_uc_swap *)invalp;
12467c478bd9Sstevel@tonic-gate 			sctp->sctp_ulpd = us->sus_handle;
12470f1702c5SYu Xiangning 			sctp->sctp_upcalls = us->sus_upcalls;
12487c478bd9Sstevel@tonic-gate 			break;
12497c478bd9Sstevel@tonic-gate 		}
12507c478bd9Sstevel@tonic-gate 		case SCTP_PRSCTP:
12517c478bd9Sstevel@tonic-gate 			sctp->sctp_prsctp_aware = onoff;
12527c478bd9Sstevel@tonic-gate 			break;
12537c478bd9Sstevel@tonic-gate 		case SCTP_I_WANT_MAPPED_V4_ADDR:
12547c478bd9Sstevel@tonic-gate 		case SCTP_MAXSEG:
12557c478bd9Sstevel@tonic-gate 		case SCTP_DISABLE_FRAGMENTS:
12567c478bd9Sstevel@tonic-gate 			/* Not yet supported. */
125788cda078Skcpoon 			retval = ENOPROTOOPT;
12587c478bd9Sstevel@tonic-gate 			break;
12597c478bd9Sstevel@tonic-gate 		}
1260bd670b35SErik Nordmark 		goto done;
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 	case IPPROTO_IP:
1263bd670b35SErik Nordmark 		if (connp->conn_family != AF_INET) {
12647c478bd9Sstevel@tonic-gate 			retval = ENOPROTOOPT;
1265bd670b35SErik Nordmark 			goto done;
12667c478bd9Sstevel@tonic-gate 		}
12677c478bd9Sstevel@tonic-gate 		switch (name) {
12687c478bd9Sstevel@tonic-gate 		case IP_SEC_OPT:
12697c478bd9Sstevel@tonic-gate 			/*
12707c478bd9Sstevel@tonic-gate 			 * We should not allow policy setting after
12717c478bd9Sstevel@tonic-gate 			 * we start listening for connections.
12727c478bd9Sstevel@tonic-gate 			 */
12737c478bd9Sstevel@tonic-gate 			if (sctp->sctp_state >= SCTPS_LISTEN) {
12747c478bd9Sstevel@tonic-gate 				retval = EINVAL;
1275bd670b35SErik Nordmark 				goto done;
127643d18f1cSpriyanka 			}
127743d18f1cSpriyanka 			break;
127843d18f1cSpriyanka 		}
12797c478bd9Sstevel@tonic-gate 		break;
1280bd670b35SErik Nordmark 	case IPPROTO_IPV6:
1281bd670b35SErik Nordmark 		if (connp->conn_family != AF_INET6) {
1282bd670b35SErik Nordmark 			retval = EINVAL;
1283bd670b35SErik Nordmark 			goto done;
12847c478bd9Sstevel@tonic-gate 		}
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 		switch (name) {
12877c478bd9Sstevel@tonic-gate 		case IPV6_RECVPKTINFO:
12887c478bd9Sstevel@tonic-gate 			/* Send it with the next msg */
12897c478bd9Sstevel@tonic-gate 			sctp->sctp_recvifindex = 0;
1290bd670b35SErik Nordmark 			break;
1291bd670b35SErik Nordmark 		case IPV6_RECVTCLASS:
1292bd670b35SErik Nordmark 			/* Force it to be sent up with the next msg */
1293bd670b35SErik Nordmark 			sctp->sctp_recvtclass = 0xffffffffU;
12947c478bd9Sstevel@tonic-gate 			break;
12957c478bd9Sstevel@tonic-gate 		case IPV6_RECVHOPLIMIT:
1296bd670b35SErik Nordmark 			/* Force it to be sent up with the next msg */
12977c478bd9Sstevel@tonic-gate 			sctp->sctp_recvhops = 0xffffffffU;
12987c478bd9Sstevel@tonic-gate 			break;
12997c478bd9Sstevel@tonic-gate 		case IPV6_SEC_OPT:
13007c478bd9Sstevel@tonic-gate 			/*
13017c478bd9Sstevel@tonic-gate 			 * We should not allow policy setting after
13027c478bd9Sstevel@tonic-gate 			 * we start listening for connections.
13037c478bd9Sstevel@tonic-gate 			 */
13047c478bd9Sstevel@tonic-gate 			if (sctp->sctp_state >= SCTPS_LISTEN) {
13057c478bd9Sstevel@tonic-gate 				retval = EINVAL;
1306bd670b35SErik Nordmark 				goto done;
13077c478bd9Sstevel@tonic-gate 			}
13087c478bd9Sstevel@tonic-gate 			break;
13097c478bd9Sstevel@tonic-gate 		case IPV6_V6ONLY:
13107c478bd9Sstevel@tonic-gate 			/*
13117c478bd9Sstevel@tonic-gate 			 * After the bound state, setting the v6only option
13127c478bd9Sstevel@tonic-gate 			 * is too late.
13137c478bd9Sstevel@tonic-gate 			 */
13147c478bd9Sstevel@tonic-gate 			if (sctp->sctp_state >= SCTPS_BOUND) {
13157c478bd9Sstevel@tonic-gate 				retval = EINVAL;
1316bd670b35SErik Nordmark 				goto done;
13177c478bd9Sstevel@tonic-gate 			}
13187c478bd9Sstevel@tonic-gate 			break;
13197c478bd9Sstevel@tonic-gate 		}
13207c478bd9Sstevel@tonic-gate 		break;
13217c478bd9Sstevel@tonic-gate 	}
13227c478bd9Sstevel@tonic-gate 
1323bd670b35SErik Nordmark 	retval = conn_opt_set(&coas, level, name, inlen, (uchar_t *)invalp,
1324bd670b35SErik Nordmark 	    B_FALSE, connp->conn_cred);
1325bd670b35SErik Nordmark 	if (retval != 0)
1326bd670b35SErik Nordmark 		goto done;
1327bd670b35SErik Nordmark 
1328bd670b35SErik Nordmark 	if (coas.coa_changed & COA_ROUTE_CHANGED) {
1329bd670b35SErik Nordmark 		sctp_faddr_t *fp;
1330bd670b35SErik Nordmark 		/*
1331bd670b35SErik Nordmark 		 * We recache the information which might pick a different
1332bd670b35SErik Nordmark 		 * source and redo IPsec as a result.
1333bd670b35SErik Nordmark 		 */
1334*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next)
1335bd670b35SErik Nordmark 			sctp_get_dest(sctp, fp);
1336bd670b35SErik Nordmark 	}
1337bd670b35SErik Nordmark 	if (coas.coa_changed & COA_HEADER_CHANGED) {
1338bd670b35SErik Nordmark 		retval = sctp_build_hdrs(sctp, KM_NOSLEEP);
1339bd670b35SErik Nordmark 		if (retval != 0)
1340bd670b35SErik Nordmark 			goto done;
1341bd670b35SErik Nordmark 	}
1342bd670b35SErik Nordmark 	if (coas.coa_changed & COA_WROFF_CHANGED) {
1343bd670b35SErik Nordmark 		connp->conn_wroff = connp->conn_ht_iphc_allocated +
1344bd670b35SErik Nordmark 		    sctps->sctps_wroff_xtra;
1345bd670b35SErik Nordmark 		if (sctp->sctp_current != NULL) {
1346bd670b35SErik Nordmark 			/*
1347bd670b35SErik Nordmark 			 * Could be setting options before setting up
1348bd670b35SErik Nordmark 			 * connection.
1349bd670b35SErik Nordmark 			 */
1350bd670b35SErik Nordmark 			sctp_set_ulp_prop(sctp);
1351bd670b35SErik Nordmark 		}
1352bd670b35SErik Nordmark 	}
1353bd670b35SErik Nordmark done:
13547c478bd9Sstevel@tonic-gate 	WAKE_SCTP(sctp);
13557c478bd9Sstevel@tonic-gate 	return (retval);
13567c478bd9Sstevel@tonic-gate }
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate /*
13597c478bd9Sstevel@tonic-gate  * SCTP exported kernel interface for geting the first source address of
13607c478bd9Sstevel@tonic-gate  * a sctp_t.  The parameter addr is assumed to have enough space to hold
13617c478bd9Sstevel@tonic-gate  * one socket address.
13627c478bd9Sstevel@tonic-gate  */
13637c478bd9Sstevel@tonic-gate int
13647c478bd9Sstevel@tonic-gate sctp_getsockname(sctp_t *sctp, struct sockaddr *addr, socklen_t *addrlen)
13657c478bd9Sstevel@tonic-gate {
13667c478bd9Sstevel@tonic-gate 	int	err = 0;
13677c478bd9Sstevel@tonic-gate 	int	addrcnt = 1;
13687c478bd9Sstevel@tonic-gate 	sin_t	*sin4;
13697c478bd9Sstevel@tonic-gate 	sin6_t	*sin6;
1370bd670b35SErik Nordmark 	conn_t	*connp = sctp->sctp_connp;
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 	ASSERT(sctp != NULL);
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 	RUN_SCTP(sctp);
1375bd670b35SErik Nordmark 	addr->sa_family = connp->conn_family;
1376bd670b35SErik Nordmark 	switch (connp->conn_family) {
13777c478bd9Sstevel@tonic-gate 	case AF_INET:
13787c478bd9Sstevel@tonic-gate 		sin4 = (sin_t *)addr;
13797c478bd9Sstevel@tonic-gate 		if ((sctp->sctp_state <= SCTPS_LISTEN) &&
13807c478bd9Sstevel@tonic-gate 		    sctp->sctp_bound_to_all) {
13817c478bd9Sstevel@tonic-gate 			sin4->sin_addr.s_addr = INADDR_ANY;
1382bd670b35SErik Nordmark 			sin4->sin_port = connp->conn_lport;
13837c478bd9Sstevel@tonic-gate 		} else {
13847c478bd9Sstevel@tonic-gate 			err = sctp_getmyaddrs(sctp, sin4, &addrcnt);
13857c478bd9Sstevel@tonic-gate 			if (err != 0) {
13867c478bd9Sstevel@tonic-gate 				*addrlen = 0;
13877c478bd9Sstevel@tonic-gate 				break;
13887c478bd9Sstevel@tonic-gate 			}
13897c478bd9Sstevel@tonic-gate 		}
13907c478bd9Sstevel@tonic-gate 		*addrlen = sizeof (struct sockaddr_in);
13917c478bd9Sstevel@tonic-gate 		break;
13927c478bd9Sstevel@tonic-gate 	case AF_INET6:
13937c478bd9Sstevel@tonic-gate 		sin6 = (sin6_t *)addr;
13947c478bd9Sstevel@tonic-gate 		if ((sctp->sctp_state <= SCTPS_LISTEN) &&
13957c478bd9Sstevel@tonic-gate 		    sctp->sctp_bound_to_all) {
13967c478bd9Sstevel@tonic-gate 			bzero(&sin6->sin6_addr, sizeof (sin6->sin6_addr));
1397bd670b35SErik Nordmark 			sin6->sin6_port = connp->conn_lport;
13987c478bd9Sstevel@tonic-gate 		} else {
13997c478bd9Sstevel@tonic-gate 			err = sctp_getmyaddrs(sctp, sin6, &addrcnt);
14007c478bd9Sstevel@tonic-gate 			if (err != 0) {
14017c478bd9Sstevel@tonic-gate 				*addrlen = 0;
14027c478bd9Sstevel@tonic-gate 				break;
14037c478bd9Sstevel@tonic-gate 			}
14047c478bd9Sstevel@tonic-gate 		}
14057c478bd9Sstevel@tonic-gate 		*addrlen = sizeof (struct sockaddr_in6);
1406bd670b35SErik Nordmark 		/* Note that flowinfo is only returned for getpeername */
14077c478bd9Sstevel@tonic-gate 		break;
14087c478bd9Sstevel@tonic-gate 	}
14097c478bd9Sstevel@tonic-gate 	WAKE_SCTP(sctp);
14107c478bd9Sstevel@tonic-gate 	return (err);
14117c478bd9Sstevel@tonic-gate }
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate /*
14147c478bd9Sstevel@tonic-gate  * SCTP exported kernel interface for geting the primary peer address of
14157c478bd9Sstevel@tonic-gate  * a sctp_t.  The parameter addr is assumed to have enough space to hold
14167c478bd9Sstevel@tonic-gate  * one socket address.
14177c478bd9Sstevel@tonic-gate  */
14187c478bd9Sstevel@tonic-gate int
14197c478bd9Sstevel@tonic-gate sctp_getpeername(sctp_t *sctp, struct sockaddr *addr, socklen_t *addrlen)
14207c478bd9Sstevel@tonic-gate {
14217c478bd9Sstevel@tonic-gate 	int	err = 0;
14227c478bd9Sstevel@tonic-gate 	int	addrcnt = 1;
14237c478bd9Sstevel@tonic-gate 	sin6_t	*sin6;
1424bd670b35SErik Nordmark 	conn_t	*connp = sctp->sctp_connp;
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate 	ASSERT(sctp != NULL);
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 	RUN_SCTP(sctp);
1429bd670b35SErik Nordmark 	addr->sa_family = connp->conn_family;
1430bd670b35SErik Nordmark 	switch (connp->conn_family) {
14317c478bd9Sstevel@tonic-gate 	case AF_INET:
14327c478bd9Sstevel@tonic-gate 		err = sctp_getpeeraddrs(sctp, addr, &addrcnt);
14337c478bd9Sstevel@tonic-gate 		if (err != 0) {
14347c478bd9Sstevel@tonic-gate 			*addrlen = 0;
14357c478bd9Sstevel@tonic-gate 			break;
14367c478bd9Sstevel@tonic-gate 		}
14377c478bd9Sstevel@tonic-gate 		*addrlen = sizeof (struct sockaddr_in);
14387c478bd9Sstevel@tonic-gate 		break;
14397c478bd9Sstevel@tonic-gate 	case AF_INET6:
14407c478bd9Sstevel@tonic-gate 		sin6 = (sin6_t *)addr;
14417c478bd9Sstevel@tonic-gate 		err = sctp_getpeeraddrs(sctp, sin6, &addrcnt);
14427c478bd9Sstevel@tonic-gate 		if (err != 0) {
14437c478bd9Sstevel@tonic-gate 			*addrlen = 0;
14447c478bd9Sstevel@tonic-gate 			break;
14457c478bd9Sstevel@tonic-gate 		}
14467c478bd9Sstevel@tonic-gate 		*addrlen = sizeof (struct sockaddr_in6);
14477c478bd9Sstevel@tonic-gate 		break;
14487c478bd9Sstevel@tonic-gate 	}
14497c478bd9Sstevel@tonic-gate 	WAKE_SCTP(sctp);
14507c478bd9Sstevel@tonic-gate 	return (err);
14517c478bd9Sstevel@tonic-gate }
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate /*
14547c478bd9Sstevel@tonic-gate  * Return a list of IP addresses of the peer endpoint of this sctp_t.
14557c478bd9Sstevel@tonic-gate  * The parameter paddrs is supposed to be either (struct sockaddr_in *) or
14567c478bd9Sstevel@tonic-gate  * (struct sockaddr_in6 *) depending on the address family of the sctp_t.
14577c478bd9Sstevel@tonic-gate  */
14587c478bd9Sstevel@tonic-gate int
14597c478bd9Sstevel@tonic-gate sctp_getpeeraddrs(sctp_t *sctp, void *paddrs, int *addrcnt)
14607c478bd9Sstevel@tonic-gate {
14617c478bd9Sstevel@tonic-gate 	int			family;
14627c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
14637c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
14647c478bd9Sstevel@tonic-gate 	int			max;
14657c478bd9Sstevel@tonic-gate 	int			cnt;
14667c478bd9Sstevel@tonic-gate 	sctp_faddr_t		*fp = sctp->sctp_faddrs;
14677c478bd9Sstevel@tonic-gate 	in6_addr_t		addr;
1468bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	ASSERT(sctp != NULL);
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate 	if (sctp->sctp_faddrs == NULL)
14737c478bd9Sstevel@tonic-gate 		return (ENOTCONN);
14747c478bd9Sstevel@tonic-gate 
1475bd670b35SErik Nordmark 	family = connp->conn_family;
14767c478bd9Sstevel@tonic-gate 	max = *addrcnt;
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate 	/* If we want only one, give the primary */
14797c478bd9Sstevel@tonic-gate 	if (max == 1) {
1480*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		addr = sctp->sctp_primary->sf_faddr;
14817c478bd9Sstevel@tonic-gate 		switch (family) {
14827c478bd9Sstevel@tonic-gate 		case AF_INET:
14837c478bd9Sstevel@tonic-gate 			sin4 = paddrs;
14847c478bd9Sstevel@tonic-gate 			IN6_V4MAPPED_TO_INADDR(&addr, &sin4->sin_addr);
1485bd670b35SErik Nordmark 			sin4->sin_port = connp->conn_fport;
14867c478bd9Sstevel@tonic-gate 			sin4->sin_family = AF_INET;
14877c478bd9Sstevel@tonic-gate 			break;
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate 		case AF_INET6:
14907c478bd9Sstevel@tonic-gate 			sin6 = paddrs;
14917c478bd9Sstevel@tonic-gate 			sin6->sin6_addr = addr;
1492bd670b35SErik Nordmark 			sin6->sin6_port = connp->conn_fport;
14937c478bd9Sstevel@tonic-gate 			sin6->sin6_family = AF_INET6;
1494bd670b35SErik Nordmark 			sin6->sin6_flowinfo = connp->conn_flowinfo;
1495bd670b35SErik Nordmark 			if (IN6_IS_ADDR_LINKSCOPE(&addr) &&
1496bd670b35SErik Nordmark 			    sctp->sctp_primary != NULL &&
1497*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			    (sctp->sctp_primary->sf_ixa->ixa_flags &
1498bd670b35SErik Nordmark 			    IXAF_SCOPEID_SET)) {
1499bd670b35SErik Nordmark 				sin6->sin6_scope_id =
1500*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 				    sctp->sctp_primary->sf_ixa->ixa_scopeid;
1501bd670b35SErik Nordmark 			} else {
1502bd670b35SErik Nordmark 				sin6->sin6_scope_id = 0;
1503bd670b35SErik Nordmark 			}
1504bd670b35SErik Nordmark 			sin6->__sin6_src_id = 0;
15057c478bd9Sstevel@tonic-gate 			break;
15067c478bd9Sstevel@tonic-gate 		}
15077c478bd9Sstevel@tonic-gate 		return (0);
15087c478bd9Sstevel@tonic-gate 	}
15097c478bd9Sstevel@tonic-gate 
1510*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	for (cnt = 0; cnt < max && fp != NULL; cnt++, fp = fp->sf_next) {
1511*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		addr = fp->sf_faddr;
15127c478bd9Sstevel@tonic-gate 		switch (family) {
15137c478bd9Sstevel@tonic-gate 		case AF_INET:
15147c478bd9Sstevel@tonic-gate 			ASSERT(IN6_IS_ADDR_V4MAPPED(&addr));
15157c478bd9Sstevel@tonic-gate 			sin4 = (struct sockaddr_in *)paddrs + cnt;
15167c478bd9Sstevel@tonic-gate 			IN6_V4MAPPED_TO_INADDR(&addr, &sin4->sin_addr);
1517bd670b35SErik Nordmark 			sin4->sin_port = connp->conn_fport;
15187c478bd9Sstevel@tonic-gate 			sin4->sin_family = AF_INET;
15197c478bd9Sstevel@tonic-gate 			break;
15207c478bd9Sstevel@tonic-gate 		case AF_INET6:
15217c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)paddrs + cnt;
15227c478bd9Sstevel@tonic-gate 			sin6->sin6_addr = addr;
1523bd670b35SErik Nordmark 			sin6->sin6_port = connp->conn_fport;
15247c478bd9Sstevel@tonic-gate 			sin6->sin6_family = AF_INET6;
1525bd670b35SErik Nordmark 			sin6->sin6_flowinfo = connp->conn_flowinfo;
1526bd670b35SErik Nordmark 			if (IN6_IS_ADDR_LINKSCOPE(&addr) &&
1527*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			    (fp->sf_ixa->ixa_flags & IXAF_SCOPEID_SET))
1528*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 				sin6->sin6_scope_id = fp->sf_ixa->ixa_scopeid;
1529bd670b35SErik Nordmark 			else
1530bd670b35SErik Nordmark 				sin6->sin6_scope_id = 0;
1531bd670b35SErik Nordmark 			sin6->__sin6_src_id = 0;
15327c478bd9Sstevel@tonic-gate 			break;
15337c478bd9Sstevel@tonic-gate 		}
15347c478bd9Sstevel@tonic-gate 	}
15357c478bd9Sstevel@tonic-gate 	*addrcnt = cnt;
15367c478bd9Sstevel@tonic-gate 	return (0);
15377c478bd9Sstevel@tonic-gate }
1538