Home | History | Annotate | Download | only in sctp
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <sys/types.h>
     28 #include <sys/stream.h>
     29 #define	_SUN_TPI_VERSION 2
     30 #include <sys/tihdr.h>
     31 #include <sys/socket.h>
     32 #include <sys/xti_inet.h>
     33 #include <sys/systm.h>
     34 #include <sys/ddi.h>
     35 #include <sys/sunddi.h>
     36 #include <sys/kmem.h>
     37 #include <sys/strsubr.h>
     38 #include <sys/strsun.h>
     39 #include <sys/policy.h>
     40 
     41 #include <inet/common.h>
     42 #include <netinet/ip6.h>
     43 #include <inet/ip.h>
     44 #include <inet/ip_ire.h>
     45 #include <inet/ip_if.h>
     46 #include <inet/proto_set.h>
     47 #include <inet/ipclassifier.h>
     48 #include <inet/ipsec_impl.h>
     49 
     50 #include <netinet/in.h>
     51 #include <netinet/ip.h>
     52 #include <netinet/tcp.h>
     53 
     54 #include <inet/common.h>
     55 #include <inet/ip.h>
     56 #include <inet/ip6.h>
     57 #include <inet/sctp_itf.h>
     58 #include "sctp_impl.h"
     59 #include "sctp_asconf.h"
     60 #include "sctp_addr.h"
     61 
     62 static int	sctp_getpeeraddrs(sctp_t *, void *, int *);
     63 
     64 static int
     65 sctp_get_status(sctp_t *sctp, void *ptr)
     66 {
     67 	struct sctp_status *sstat = ptr;
     68 	sctp_faddr_t *fp;
     69 	struct sockaddr_in *sin;
     70 	struct sockaddr_in6 *sin6;
     71 	struct sctp_paddrinfo *sp;
     72 	mblk_t *meta, *mp;
     73 	int i;
     74 	conn_t	*connp = sctp->sctp_connp;
     75 
     76 	sstat->sstat_state = sctp->sctp_state;
     77 	sstat->sstat_rwnd = sctp->sctp_frwnd;
     78 
     79 	sp = &sstat->sstat_primary;
     80 	if (!sctp->sctp_primary) {
     81 		bzero(sp, sizeof (*sp));
     82 		goto noprim;
     83 	}
     84 	fp = sctp->sctp_primary;
     85 
     86 	if (fp->isv4) {
     87 		sin = (struct sockaddr_in *)&sp->spinfo_address;
     88 		sin->sin_family = AF_INET;
     89 		sin->sin_port = connp->conn_fport;
     90 		IN6_V4MAPPED_TO_INADDR(&fp->faddr, &sin->sin_addr);
     91 		sp->spinfo_mtu = sctp->sctp_hdr_len;
     92 	} else {
     93 		sin6 = (struct sockaddr_in6 *)&sp->spinfo_address;
     94 		sin6->sin6_family = AF_INET6;
     95 		sin6->sin6_port = connp->conn_fport;
     96 		sin6->sin6_addr = fp->faddr;
     97 		sp->spinfo_mtu = sctp->sctp_hdr6_len;
     98 	}
     99 	sp->spinfo_state = fp->state == SCTP_FADDRS_ALIVE ? SCTP_ACTIVE :
    100 	    SCTP_INACTIVE;
    101 	sp->spinfo_cwnd = fp->cwnd;
    102 	sp->spinfo_srtt = fp->srtt;
    103 	sp->spinfo_rto = fp->rto;
    104 	sp->spinfo_mtu += fp->sfa_pmss;
    105 
    106 noprim:
    107 	sstat->sstat_unackdata = 0;
    108 	sstat->sstat_penddata = 0;
    109 	sstat->sstat_instrms = sctp->sctp_num_istr;
    110 	sstat->sstat_outstrms = sctp->sctp_num_ostr;
    111 	sstat->sstat_fragmentation_point = sctp->sctp_mss -
    112 	    sizeof (sctp_data_hdr_t);
    113 
    114 	/* count unack'd */
    115 	for (meta = sctp->sctp_xmit_head; meta; meta = meta->b_next) {
    116 		for (mp = meta->b_cont; mp; mp = mp->b_next) {
    117 			if (!SCTP_CHUNK_ISSENT(mp)) {
    118 				break;
    119 			}
    120 			if (!SCTP_CHUNK_ISACKED(mp)) {
    121 				sstat->sstat_unackdata++;
    122 			}
    123 		}
    124 	}
    125 
    126 	/*
    127 	 * Count penddata chunks. We can only count chunks in SCTP (not
    128 	 * data already delivered to socket layer).
    129 	 */
    130 	if (sctp->sctp_instr != NULL) {
    131 		for (i = 0; i < sctp->sctp_num_istr; i++) {
    132 			for (meta = sctp->sctp_instr[i].istr_reass;
    133 			    meta != NULL; meta = meta->b_next) {
    134 				for (mp = meta->b_cont; mp; mp = mp->b_cont) {
    135 					if (DB_TYPE(mp) != M_CTL) {
    136 						sstat->sstat_penddata++;
    137 					}
    138 				}
    139 			}
    140 		}
    141 	}
    142 	/* Un-Ordered Frag list */
    143 	for (meta = sctp->sctp_uo_frags; meta != NULL; meta = meta->b_next)
    144 		sstat->sstat_penddata++;
    145 
    146 	return (sizeof (*sstat));
    147 }
    148 
    149 /*
    150  * SCTP_GET_PEER_ADDR_INFO
    151  */
    152 static int
    153 sctp_get_paddrinfo(sctp_t *sctp, void *ptr, socklen_t *optlen)
    154 {
    155 	struct sctp_paddrinfo	*infop = ptr;
    156 	struct sockaddr_in	*sin4;
    157 	struct sockaddr_in6	*sin6;
    158 	in6_addr_t		faddr;
    159 	sctp_faddr_t		*fp;
    160 
    161 	switch (infop->spinfo_address.ss_family) {
    162 	case AF_INET:
    163 		sin4 = (struct sockaddr_in *)&infop->spinfo_address;
    164 		IN6_INADDR_TO_V4MAPPED(&sin4->sin_addr, &faddr);
    165 		break;
    166 	case AF_INET6:
    167 		sin6 = (struct sockaddr_in6 *)&infop->spinfo_address;
    168 		faddr = sin6->sin6_addr;
    169 		break;
    170 	default:
    171 		return (EAFNOSUPPORT);
    172 	}
    173 
    174 	if ((fp = sctp_lookup_faddr(sctp, &faddr)) == NULL)
    175 		return (EINVAL);
    176 
    177 	infop->spinfo_state = (fp->state == SCTP_FADDRS_ALIVE) ? SCTP_ACTIVE :
    178 	    SCTP_INACTIVE;
    179 	infop->spinfo_cwnd = fp->cwnd;
    180 	infop->spinfo_srtt = TICK_TO_MSEC(fp->srtt);
    181 	infop->spinfo_rto = TICK_TO_MSEC(fp->rto);
    182 	infop->spinfo_mtu = fp->sfa_pmss;
    183 
    184 	*optlen = sizeof (struct sctp_paddrinfo);
    185 	return (0);
    186 }
    187 
    188 /*
    189  * SCTP_RTOINFO
    190  */
    191 static int
    192 sctp_get_rtoinfo(sctp_t *sctp, void *ptr)
    193 {
    194 	struct sctp_rtoinfo *srto = ptr;
    195 
    196 	srto->srto_initial = TICK_TO_MSEC(sctp->sctp_rto_initial);
    197 	srto->srto_max = TICK_TO_MSEC(sctp->sctp_rto_max);
    198 	srto->srto_min = TICK_TO_MSEC(sctp->sctp_rto_min);
    199 
    200 	return (sizeof (*srto));
    201 }
    202 
    203 static int
    204 sctp_set_rtoinfo(sctp_t *sctp, const void *invalp)
    205 {
    206 	const struct sctp_rtoinfo *srto;
    207 	boolean_t ispriv;
    208 	sctp_stack_t	*sctps = sctp->sctp_sctps;
    209 	conn_t		*connp = sctp->sctp_connp;
    210 	uint32_t	new_min, new_max;
    211 
    212 	srto = invalp;
    213 
    214 	ispriv = secpolicy_ip_config(connp->conn_cred, B_TRUE) == 0;
    215 
    216 	/*
    217 	 * Bounds checking.  Priviledged user can set the RTO initial
    218 	 * outside the ndd boundary.
    219 	 */
    220 	if (srto->srto_initial != 0 &&
    221 	    (!ispriv && (srto->srto_initial < sctps->sctps_rto_initialg_low ||
    222 	    srto->srto_initial > sctps->sctps_rto_initialg_high))) {
    223 		return (EINVAL);
    224 	}
    225 	if (srto->srto_max != 0 &&
    226 	    (!ispriv && (srto->srto_max < sctps->sctps_rto_maxg_low ||
    227 	    srto->srto_max > sctps->sctps_rto_maxg_high))) {
    228 		return (EINVAL);
    229 	}
    230 	if (srto->srto_min != 0 &&
    231 	    (!ispriv && (srto->srto_min < sctps->sctps_rto_ming_low ||
    232 	    srto->srto_min > sctps->sctps_rto_ming_high))) {
    233 		return (EINVAL);
    234 	}
    235 
    236 	new_min = (srto->srto_min != 0) ? srto->srto_min : sctp->sctp_rto_min;
    237 	new_max = (srto->srto_max != 0) ? srto->srto_max : sctp->sctp_rto_max;
    238 	if (new_max < new_min) {
    239 		return (EINVAL);
    240 	}
    241 
    242 	if (srto->srto_initial != 0) {
    243 		sctp->sctp_rto_initial = MSEC_TO_TICK(srto->srto_initial);
    244 	}
    245 
    246 	/* Ensure that sctp_rto_max will never be zero. */
    247 	if (srto->srto_max != 0) {
    248 		sctp->sctp_rto_max = MAX(MSEC_TO_TICK(srto->srto_max), 1);
    249 	}
    250 	if (srto->srto_min != 0) {
    251 		sctp->sctp_rto_min = MSEC_TO_TICK(srto->srto_min);
    252 	}
    253 
    254 	return (0);
    255 }
    256 
    257 /*
    258  * SCTP_ASSOCINFO
    259  */
    260 static int
    261 sctp_get_assocparams(sctp_t *sctp, void *ptr)
    262 {
    263 	struct sctp_assocparams *sap = ptr;
    264 	sctp_faddr_t *fp;
    265 	uint16_t i;
    266 
    267 	sap->sasoc_asocmaxrxt = sctp->sctp_pa_max_rxt;
    268 
    269 	/*
    270 	 * Count the number of peer addresses
    271 	 */
    272 	for (i = 0, fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next) {
    273 		i++;
    274 	}
    275 	sap->sasoc_number_peer_destinations = i;
    276 	sap->sasoc_peer_rwnd = sctp->sctp_frwnd;
    277 	sap->sasoc_local_rwnd = sctp->sctp_rwnd;
    278 	sap->sasoc_cookie_life = TICK_TO_MSEC(sctp->sctp_cookie_lifetime);
    279 
    280 	return (sizeof (*sap));
    281 }
    282 
    283 static int
    284 sctp_set_assocparams(sctp_t *sctp, const void *invalp)
    285 {
    286 	const struct sctp_assocparams *sap = invalp;
    287 	uint32_t sum = 0;
    288 	sctp_faddr_t *fp;
    289 	sctp_stack_t	*sctps = sctp->sctp_sctps;
    290 
    291 	if (sap->sasoc_asocmaxrxt) {
    292 		if (sctp->sctp_faddrs) {
    293 			/*
    294 			 * Bounds check: as per rfc2960, assoc max retr cannot
    295 			 * exceed the sum of all individual path max retr's.
    296 			 */
    297 			for (fp = sctp->sctp_faddrs; fp; fp = fp->next) {
    298 				sum += fp->max_retr;
    299 			}
    300 			if (sap->sasoc_asocmaxrxt > sum) {
    301 				return (EINVAL);
    302 			}
    303 		}
    304 		if (sap->sasoc_asocmaxrxt < sctps->sctps_pa_max_retr_low ||
    305 		    sap->sasoc_asocmaxrxt > sctps->sctps_pa_max_retr_high) {
    306 			/*
    307 			 * Out of bounds.
    308 			 */
    309 			return (EINVAL);
    310 		}
    311 	}
    312 	if (sap->sasoc_cookie_life != 0 &&
    313 	    (sap->sasoc_cookie_life < sctps->sctps_cookie_life_low ||
    314 	    sap->sasoc_cookie_life > sctps->sctps_cookie_life_high)) {
    315 		return (EINVAL);
    316 	}
    317 
    318 	if (sap->sasoc_asocmaxrxt > 0) {
    319 		sctp->sctp_pa_max_rxt = sap->sasoc_asocmaxrxt;
    320 	}
    321 	if (sap->sasoc_cookie_life > 0) {
    322 		sctp->sctp_cookie_lifetime = MSEC_TO_TICK(
    323 		    sap->sasoc_cookie_life);
    324 	}
    325 	return (0);
    326 }
    327 
    328 /*
    329  * SCTP_INITMSG
    330  */
    331 static int
    332 sctp_get_initmsg(sctp_t *sctp, void *ptr)
    333 {
    334 	struct sctp_initmsg *si = ptr;
    335 
    336 	si->sinit_num_ostreams = sctp->sctp_num_ostr;
    337 	si->sinit_max_instreams = sctp->sctp_num_istr;
    338 	si->sinit_max_attempts = sctp->sctp_max_init_rxt;
    339 	si->sinit_max_init_timeo = TICK_TO_MSEC(sctp->sctp_init_rto_max);
    340 
    341 	return (sizeof (*si));
    342 }
    343 
    344 static int
    345 sctp_set_initmsg(sctp_t *sctp, const void *invalp, uint_t inlen)
    346 {
    347 	const struct sctp_initmsg *si = invalp;
    348 	sctp_stack_t	*sctps = sctp->sctp_sctps;
    349 	conn_t		*connp = sctp->sctp_connp;
    350 
    351 	if (sctp->sctp_state > SCTPS_LISTEN) {
    352 		return (EINVAL);
    353 	}
    354 	if (inlen < sizeof (*si)) {
    355 		return (EINVAL);
    356 	}
    357 	if (si->sinit_num_ostreams != 0 &&
    358 	    (si->sinit_num_ostreams < sctps->sctps_initial_out_streams_low ||
    359 	    si->sinit_num_ostreams >
    360 	    sctps->sctps_initial_out_streams_high)) {
    361 		/*
    362 		 * Out of bounds.
    363 		 */
    364 		return (EINVAL);
    365 	}
    366 	if (si->sinit_max_instreams != 0 &&
    367 	    (si->sinit_max_instreams < sctps->sctps_max_in_streams_low ||
    368 	    si->sinit_max_instreams > sctps->sctps_max_in_streams_high)) {
    369 		return (EINVAL);
    370 	}
    371 	if (si->sinit_max_attempts != 0 &&
    372 	    (si->sinit_max_attempts < sctps->sctps_max_init_retr_low ||
    373 	    si->sinit_max_attempts > sctps->sctps_max_init_retr_high)) {
    374 		return (EINVAL);
    375 	}
    376 	if (si->sinit_max_init_timeo != 0 &&
    377 	    (secpolicy_ip_config(connp->conn_cred, B_TRUE) != 0 &&
    378 	    (si->sinit_max_init_timeo < sctps->sctps_rto_maxg_low ||
    379 	    si->sinit_max_init_timeo > sctps->sctps_rto_maxg_high))) {
    380 		return (EINVAL);
    381 	}
    382 	if (si->sinit_num_ostreams != 0)
    383 		sctp->sctp_num_ostr = si->sinit_num_ostreams;
    384 
    385 	if (si->sinit_max_instreams != 0)
    386 		sctp->sctp_num_istr = si->sinit_max_instreams;
    387 
    388 	if (si->sinit_max_attempts != 0)
    389 		sctp->sctp_max_init_rxt = si->sinit_max_attempts;
    390 
    391 	if (si->sinit_max_init_timeo != 0) {
    392 		sctp->sctp_init_rto_max =
    393 		    MSEC_TO_TICK(si->sinit_max_init_timeo);
    394 	}
    395 	return (0);
    396 }
    397 
    398 /*
    399  * SCTP_PEER_ADDR_PARAMS
    400  */
    401 static int
    402 sctp_find_peer_fp(sctp_t *sctp, const struct sockaddr_storage *ss,
    403     sctp_faddr_t **fpp)
    404 {
    405 	struct sockaddr_in *sin;
    406 	struct sockaddr_in6 *sin6;
    407 	in6_addr_t addr;
    408 
    409 	if (ss->ss_family == AF_INET) {
    410 		sin = (struct sockaddr_in *)ss;
    411 		IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &addr);
    412 	} else if (ss->ss_family == AF_INET6) {
    413 		sin6 = (struct sockaddr_in6 *)ss;
    414 		addr = sin6->sin6_addr;
    415 	} else if (ss->ss_family) {
    416 		return (EAFNOSUPPORT);
    417 	}
    418 
    419 	if (!ss->ss_family ||
    420 	    SCTP_IS_ADDR_UNSPEC(IN6_IS_ADDR_V4MAPPED(&addr), addr)) {
    421 		*fpp = NULL;
    422 	} else {
    423 		*fpp = sctp_lookup_faddr(sctp, &addr);
    424 		if (*fpp == NULL) {
    425 			return (EINVAL);
    426 		}
    427 	}
    428 	return (0);
    429 }
    430 
    431 static int
    432 sctp_get_peer_addr_params(sctp_t *sctp, void *ptr)
    433 {
    434 	struct sctp_paddrparams *spp = ptr;
    435 	sctp_faddr_t *fp;
    436 	int retval;
    437 
    438 	retval = sctp_find_peer_fp(sctp, &spp->spp_address, &fp);
    439 	if (retval) {
    440 		return (retval);
    441 	}
    442 	if (fp) {
    443 		spp->spp_hbinterval = TICK_TO_MSEC(fp->hb_interval);
    444 		spp->spp_pathmaxrxt = fp->max_retr;
    445 	} else {
    446 		spp->spp_hbinterval = TICK_TO_MSEC(sctp->sctp_hb_interval);
    447 		spp->spp_pathmaxrxt = sctp->sctp_pp_max_rxt;
    448 	}
    449 	return (sizeof (*spp));
    450 }
    451 
    452 static int
    453 sctp_set_peer_addr_params(sctp_t *sctp, const void *invalp)
    454 {
    455 	const struct sctp_paddrparams *spp = invalp;
    456 	sctp_faddr_t *fp, *fp2;
    457 	int retval;
    458 	uint32_t sum = 0;
    459 	int64_t now;
    460 	sctp_stack_t	*sctps = sctp->sctp_sctps;
    461 
    462 	retval = sctp_find_peer_fp(sctp, &spp->spp_address, &fp);
    463 	if (retval != 0) {
    464 		return (retval);
    465 	}
    466 
    467 	if (spp->spp_hbinterval && spp->spp_hbinterval != UINT32_MAX &&
    468 	    (spp->spp_hbinterval < sctps->sctps_heartbeat_interval_low ||
    469 	    spp->spp_hbinterval > sctps->sctps_heartbeat_interval_high)) {
    470 		return (EINVAL);
    471 	}
    472 	if (spp->spp_pathmaxrxt &&
    473 	    (spp->spp_pathmaxrxt < sctps->sctps_pp_max_retr_low ||
    474 	    spp->spp_pathmaxrxt > sctps->sctps_pp_max_retr_high)) {
    475 		return (EINVAL);
    476 	}
    477 	if (spp->spp_pathmaxrxt && sctp->sctp_faddrs) {
    478 		for (fp2 = sctp->sctp_faddrs; fp2; fp2 = fp2->next) {
    479 			if (!fp || fp2 == fp) {
    480 				sum += spp->spp_pathmaxrxt;
    481 			} else {
    482 				sum += fp2->max_retr;
    483 			}
    484 		}
    485 		if (sctp->sctp_pa_max_rxt > sum) {
    486 			return (EINVAL);
    487 		}
    488 	}
    489 
    490 	now = ddi_get_lbolt64();
    491 	if (fp != NULL) {
    492 		if (spp->spp_hbinterval == UINT32_MAX) {
    493 			/*
    494 			 * Send heartbeat immediatelly, don't modify the
    495 			 * current setting.
    496 			 */
    497 			sctp_send_heartbeat(sctp, fp);
    498 		} else {
    499 			fp->hb_interval = MSEC_TO_TICK(spp->spp_hbinterval);
    500 			fp->hb_expiry = now + SET_HB_INTVL(fp);
    501 			/*
    502 			 * Restart the heartbeat timer using the new intrvl.
    503 			 * We need to call sctp_heartbeat_timer() to set
    504 			 * the earliest heartbeat expiry time.
    505 			 */
    506 			sctp_heartbeat_timer(sctp);
    507 		}
    508 		if (spp->spp_pathmaxrxt) {
    509 			fp->max_retr = spp->spp_pathmaxrxt;
    510 		}
    511 	} else {
    512 		for (fp2 = sctp->sctp_faddrs; fp2 != NULL; fp2 = fp2->next) {
    513 			if (spp->spp_hbinterval == UINT32_MAX) {
    514 				/*
    515 				 * Send heartbeat immediatelly, don't modify
    516 				 * the current setting.
    517 				 */
    518 				sctp_send_heartbeat(sctp, fp2);
    519 			} else {
    520 				fp2->hb_interval = MSEC_TO_TICK(
    521 				    spp->spp_hbinterval);
    522 				fp2->hb_expiry = now + SET_HB_INTVL(fp2);
    523 			}
    524 			if (spp->spp_pathmaxrxt) {
    525 				fp2->max_retr = spp->spp_pathmaxrxt;
    526 			}
    527 		}
    528 		if (spp->spp_hbinterval != UINT32_MAX) {
    529 			sctp->sctp_hb_interval = MSEC_TO_TICK(
    530 			    spp->spp_hbinterval);
    531 			/* Restart the heartbeat timer using the new intrvl. */
    532 			sctp_timer(sctp, sctp->sctp_heartbeat_mp,
    533 			    sctp->sctp_hb_interval);
    534 		}
    535 		if (spp->spp_pathmaxrxt) {
    536 			sctp->sctp_pp_max_rxt = spp->spp_pathmaxrxt;
    537 		}
    538 	}
    539 	return (0);
    540 }
    541 
    542 /*
    543  * SCTP_DEFAULT_SEND_PARAM
    544  */
    545 static int
    546 sctp_get_def_send_params(sctp_t *sctp, void *ptr)
    547 {
    548 	struct sctp_sndrcvinfo *sinfo = ptr;
    549 
    550 	sinfo->sinfo_stream = sctp->sctp_def_stream;
    551 	sinfo->sinfo_ssn = 0;
    552 	sinfo->sinfo_flags = sctp->sctp_def_flags;
    553 	sinfo->sinfo_ppid = sctp->sctp_def_ppid;
    554 	sinfo->sinfo_context = sctp->sctp_def_context;
    555 	sinfo->sinfo_timetolive = sctp->sctp_def_timetolive;
    556 	sinfo->sinfo_tsn = 0;
    557 	sinfo->sinfo_cumtsn = 0;
    558 
    559 	return (sizeof (*sinfo));
    560 }
    561 
    562 static int
    563 sctp_set_def_send_params(sctp_t *sctp, const void *invalp)
    564 {
    565 	const struct sctp_sndrcvinfo *sinfo = invalp;
    566 
    567 	if (sinfo->sinfo_stream >= sctp->sctp_num_ostr) {
    568 		return (EINVAL);
    569 	}
    570 
    571 	sctp->sctp_def_stream = sinfo->sinfo_stream;
    572 	sctp->sctp_def_flags = sinfo->sinfo_flags;
    573 	sctp->sctp_def_ppid = sinfo->sinfo_ppid;
    574 	sctp->sctp_def_context = sinfo->sinfo_context;
    575 	sctp->sctp_def_timetolive = sinfo->sinfo_timetolive;
    576 
    577 	return (0);
    578 }
    579 
    580 static int
    581 sctp_set_prim(sctp_t *sctp, const void *invalp)
    582 {
    583 	const struct	sctp_setpeerprim *pp = invalp;
    584 	int		retval;
    585 	sctp_faddr_t	*fp;
    586 
    587 	retval = sctp_find_peer_fp(sctp, &pp->sspp_addr, &fp);
    588 	if (retval)
    589 		return (retval);
    590 
    591 	if (fp == NULL)
    592 		return (EINVAL);
    593 	if (fp == sctp->sctp_primary)
    594 		return (0);
    595 	sctp->sctp_primary = fp;
    596 
    597 	/* Only switch current if fp is alive */
    598 	if (fp->state != SCTP_FADDRS_ALIVE || fp == sctp->sctp_current) {
    599 		return (0);
    600 	}
    601 	sctp_set_faddr_current(sctp, fp);
    602 
    603 	return (0);
    604 }
    605 
    606 /*
    607  * Table of all known options handled on a SCTP protocol stack.
    608  *
    609  * Note: This table contains options processed by both SCTP and IP levels
    610  *       and is the superset of options that can be performed on a SCTP and IP
    611  *       stack.
    612  */
    613 opdes_t	sctp_opt_arr[] = {
    614 
    615 { SO_LINGER,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0,
    616 	sizeof (struct linger), 0 },
    617 
    618 { SO_DEBUG,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
    619 { SO_KEEPALIVE,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
    620 { SO_DONTROUTE,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
    621 { SO_USELOOPBACK, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0
    622 	},
    623 { SO_BROADCAST,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
    624 { SO_REUSEADDR, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
    625 { SO_OOBINLINE, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
    626 { SO_TYPE,	SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
    627 { SO_SNDBUF,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
    628 { SO_RCVBUF,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
    629 { SO_DGRAM_ERRIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0
    630 	},
    631 { SO_SND_COPYAVOID, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
    632 { SO_ANON_MLP, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int),
    633 	0 },
    634 { SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int),
    635 	0 },
    636 { SO_ALLZONES, SOL_SOCKET, OA_R, OA_RW, OP_CONFIG, 0, sizeof (int),
    637 	0 },
    638 { SO_EXCLBIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
    639 
    640 { SO_DOMAIN,	SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
    641 
    642 { SO_PROTOTYPE,	SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
    643 
    644 { SCTP_ADAPTATION_LAYER, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
    645 	sizeof (struct sctp_setadaptation), 0 },
    646 { SCTP_ADD_ADDR, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, OP_VARLEN,
    647 	sizeof (int), 0 },
    648 { SCTP_ASSOCINFO, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
    649 	sizeof (struct sctp_assocparams), 0 },
    650 { SCTP_AUTOCLOSE, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
    651 { SCTP_DEFAULT_SEND_PARAM, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
    652 	sizeof (struct sctp_sndrcvinfo), 0 },
    653 { SCTP_DISABLE_FRAGMENTS, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
    654 	sizeof (int), 0 },
    655 { SCTP_EVENTS, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
    656 	sizeof (struct sctp_event_subscribe), 0 },
    657 { SCTP_GET_LADDRS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, OP_VARLEN,
    658 	sizeof (int), 0 },
    659 { SCTP_GET_NLADDRS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
    660 { SCTP_GET_NPADDRS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
    661 { SCTP_GET_PADDRS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, OP_VARLEN,
    662 	sizeof (int), 0 },
    663 { SCTP_GET_PEER_ADDR_INFO, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0,
    664 	sizeof (struct sctp_paddrinfo), 0 },
    665 { SCTP_INITMSG, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
    666 	sizeof (struct sctp_initmsg), 0 },
    667 { SCTP_I_WANT_MAPPED_V4_ADDR, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
    668 	sizeof (int), 0 },
    669 { SCTP_MAXSEG, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
    670 { SCTP_NODELAY, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
    671 { SCTP_PEER_ADDR_PARAMS, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
    672 	sizeof (struct sctp_paddrparams), 0 },
    673 { SCTP_PRIMARY_ADDR, IPPROTO_SCTP, OA_W, OA_W, OP_NP, 0,
    674 	sizeof (struct sctp_setpeerprim), 0 },
    675 { SCTP_PRSCTP, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
    676 { SCTP_GET_ASSOC_STATS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0,
    677 	sizeof (sctp_assoc_stats_t), 0 },
    678 { SCTP_REM_ADDR, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, OP_VARLEN,
    679 	sizeof (int), 0 },
    680 { SCTP_RTOINFO, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
    681 	sizeof (struct sctp_rtoinfo), 0 },
    682 { SCTP_SET_PEER_PRIMARY_ADDR, IPPROTO_SCTP, OA_W, OA_W, OP_NP, 0,
    683 	sizeof (struct sctp_setprim), 0 },
    684 { SCTP_STATUS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0,
    685 	sizeof (struct sctp_status), 0 },
    686 { SCTP_UC_SWAP, IPPROTO_SCTP, OA_W, OA_W, OP_NP, 0,
    687 	sizeof (struct sctp_uc_swap), 0 },
    688 
    689 { IP_OPTIONS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP,
    690 	(OP_VARLEN|OP_NODEFAULT),
    691 	40, -1 /* not initialized */ },
    692 { T_IP_OPTIONS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP,
    693 	(OP_VARLEN|OP_NODEFAULT),
    694 	40, -1 /* not initialized */ },
    695 
    696 { IP_TOS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
    697 { T_IP_TOS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
    698 { IP_TTL,	IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_DEF_FN,
    699 	sizeof (int), -1 /* not initialized */ },
    700 
    701 { IP_SEC_OPT, IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_NODEFAULT,
    702 	sizeof (ipsec_req_t), -1 /* not initialized */ },
    703 
    704 { IP_BOUND_IF, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0,
    705 	sizeof (int),	0 /* no ifindex */ },
    706 
    707 { IP_UNSPEC_SRC, IPPROTO_IP, OA_R, OA_RW, OP_RAW, 0,
    708 	sizeof (int), 0 },
    709 
    710 { IPV6_UNICAST_HOPS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, OP_DEF_FN,
    711 	sizeof (int), -1 /* not initialized */ },
    712 
    713 { IPV6_BOUND_IF, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
    714 	sizeof (int),	0 /* no ifindex */ },
    715 
    716 { IP_DONTFRAG, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
    717 
    718 { IP_NEXTHOP, IPPROTO_IP, OA_R, OA_RW, OP_CONFIG, 0,
    719 	sizeof (in_addr_t),	-1 /* not initialized  */ },
    720 
    721 { IPV6_UNSPEC_SRC, IPPROTO_IPV6, OA_R, OA_RW, OP_RAW, 0,
    722 	sizeof (int), 0 },
    723 
    724 { IPV6_PKTINFO, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
    725 	(OP_NODEFAULT|OP_VARLEN),
    726 	sizeof (struct in6_pktinfo), -1 /* not initialized */ },
    727 { IPV6_NEXTHOP, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
    728 	OP_NODEFAULT,
    729 	sizeof (sin6_t), -1 /* not initialized */ },
    730 { IPV6_HOPOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
    731 	(OP_VARLEN|OP_NODEFAULT), 255*8,
    732 	-1 /* not initialized */ },
    733 { IPV6_DSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
    734 	(OP_VARLEN|OP_NODEFAULT), 255*8,
    735 	-1 /* not initialized */ },
    736 { IPV6_RTHDRDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
    737 	(OP_VARLEN|OP_NODEFAULT), 255*8,
    738 	-1 /* not initialized */ },
    739 { IPV6_RTHDR, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
    740 	(OP_VARLEN|OP_NODEFAULT), 255*8,
    741 	-1 /* not initialized */ },
    742 { IPV6_TCLASS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
    743 	OP_NODEFAULT,
    744 	sizeof (int), -1 /* not initialized */ },
    745 { IPV6_PATHMTU, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
    746 	OP_NODEFAULT,
    747 	sizeof (struct ip6_mtuinfo), -1 /* not initialized */ },
    748 { IPV6_DONTFRAG, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
    749 	sizeof (int), 0 },
    750 { IPV6_USE_MIN_MTU, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
    751 	sizeof (int), 0 },
    752 { IPV6_V6ONLY, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
    753 	sizeof (int), 0 },
    754 
    755 /* Enable receipt of ancillary data */
    756 { IPV6_RECVPKTINFO, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
    757 	sizeof (int), 0 },
    758 { IPV6_RECVHOPLIMIT, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
    759 	sizeof (int), 0 },
    760 { IPV6_RECVTCLASS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
    761 	sizeof (int), 0 },
    762 { IPV6_RECVHOPOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
    763 	sizeof (int), 0 },
    764 { _OLD_IPV6_RECVDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
    765 	sizeof (int), 0 },
    766 { IPV6_RECVDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
    767 	sizeof (int), 0 },
    768 { IPV6_RECVRTHDR, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
    769 	sizeof (int), 0 },
    770 { IPV6_RECVRTHDRDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
    771 	sizeof (int), 0 },
    772 { IPV6_RECVTCLASS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
    773 	sizeof (int), 0 },
    774 
    775 { IPV6_SEC_OPT, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, OP_NODEFAULT,
    776 	sizeof (ipsec_req_t), -1 /* not initialized */ },
    777 { IPV6_SRC_PREFERENCES, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
    778 	sizeof (uint32_t), IPV6_PREFER_SRC_DEFAULT },
    779 };
    780 
    781 uint_t sctp_opt_arr_size = A_CNT(sctp_opt_arr);
    782 
    783 /* Handy on off switch for socket option processing. */
    784 #define	ONOFF(x)	((x) == 0 ? 0 : 1)
    785 
    786 /*
    787  * SCTP routine to get the values of options.
    788  */
    789 int
    790 sctp_get_opt(sctp_t *sctp, int level, int name, void *ptr, socklen_t *optlen)
    791 {
    792 	int	*i1 = (int *)ptr;
    793 	int	retval = 0;
    794 	int	buflen = *optlen;
    795 	conn_t	*connp = sctp->sctp_connp;
    796 	conn_opt_arg_t	coas;
    797 
    798 	coas.coa_connp = connp;
    799 	coas.coa_ixa = connp->conn_ixa;
    800 	coas.coa_ipp = &connp->conn_xmit_ipp;
    801 
    802 	/* In most cases, the return buffer is just an int */
    803 	*optlen = sizeof (int32_t);
    804 
    805 	RUN_SCTP(sctp);
    806 
    807 	if (connp->conn_state_flags & CONN_CLOSING) {
    808 		WAKE_SCTP(sctp);
    809 		return (EINVAL);
    810 	}
    811 
    812 	/*
    813 	 * Check that the level and name are supported by SCTP, and that
    814 	 * the length and credentials are ok.
    815 	 */
    816 	retval = proto_opt_check(level, name, buflen, NULL, sctp_opt_arr,
    817 	    sctp_opt_arr_size, B_FALSE, B_TRUE, connp->conn_cred);
    818 	if (retval != 0) {
    819 		WAKE_SCTP(sctp);
    820 		if (retval < 0) {
    821 			retval = proto_tlitosyserr(-retval);
    822 		}
    823 		return (retval);
    824 	}
    825 
    826 	switch (level) {
    827 	case IPPROTO_SCTP:
    828 		switch (name) {
    829 		case SCTP_RTOINFO:
    830 			*optlen = sctp_get_rtoinfo(sctp, ptr);
    831 			break;
    832 		case SCTP_ASSOCINFO:
    833 			*optlen = sctp_get_assocparams(sctp, ptr);
    834 			break;
    835 		case SCTP_INITMSG:
    836 			*optlen = sctp_get_initmsg(sctp, ptr);
    837 			break;
    838 		case SCTP_NODELAY:
    839 			*i1 = sctp->sctp_ndelay;
    840 			break;
    841 		case SCTP_AUTOCLOSE:
    842 			*i1 = TICK_TO_SEC(sctp->sctp_autoclose);
    843 			break;
    844 		case SCTP_ADAPTATION_LAYER:
    845 			((struct sctp_setadaptation *)ptr)->ssb_adaptation_ind =
    846 			    sctp->sctp_tx_adaptation_code;
    847 			break;
    848 		case SCTP_PEER_ADDR_PARAMS:
    849 			*optlen = sctp_get_peer_addr_params(sctp, ptr);
    850 			break;
    851 		case SCTP_DEFAULT_SEND_PARAM:
    852 			*optlen = sctp_get_def_send_params(sctp, ptr);
    853 			break;
    854 		case SCTP_EVENTS: {
    855 			struct sctp_event_subscribe *ev;
    856 
    857 			ev = (struct sctp_event_subscribe *)ptr;
    858 			ev->sctp_data_io_event =
    859 			    ONOFF(sctp->sctp_recvsndrcvinfo);
    860 			ev->sctp_association_event =
    861 			    ONOFF(sctp->sctp_recvassocevnt);
    862 			ev->sctp_address_event =
    863 			    ONOFF(sctp->sctp_recvpathevnt);
    864 			ev->sctp_send_failure_event =
    865 			    ONOFF(sctp->sctp_recvsendfailevnt);
    866 			ev->sctp_peer_error_event =
    867 			    ONOFF(sctp->sctp_recvpeererr);
    868 			ev->sctp_shutdown_event =
    869 			    ONOFF(sctp->sctp_recvshutdownevnt);
    870 			ev->sctp_partial_delivery_event =
    871 			    ONOFF(sctp->sctp_recvpdevnt);
    872 			ev->sctp_adaptation_layer_event =
    873 			    ONOFF(sctp->sctp_recvalevnt);
    874 			*optlen = sizeof (struct sctp_event_subscribe);
    875 			break;
    876 		}
    877 		case SCTP_STATUS:
    878 			*optlen = sctp_get_status(sctp, ptr);
    879 			break;
    880 		case SCTP_GET_PEER_ADDR_INFO:
    881 			retval = sctp_get_paddrinfo(sctp, ptr, optlen);
    882 			break;
    883 		case SCTP_GET_NLADDRS:
    884 			*(int32_t *)ptr = sctp->sctp_nsaddrs;
    885 			break;
    886 		case SCTP_GET_LADDRS: {
    887 			int addr_cnt;
    888 			int addr_size;
    889 
    890 			if (connp->conn_family == AF_INET)
    891 				addr_size = sizeof (struct sockaddr_in);
    892 			else
    893 				addr_size = sizeof (struct sockaddr_in6);
    894 			addr_cnt = buflen / addr_size;
    895 			retval = sctp_getmyaddrs(sctp, ptr, &addr_cnt);
    896 			if (retval == 0)
    897 				*optlen = addr_cnt * addr_size;
    898 			break;
    899 		}
    900 		case SCTP_GET_NPADDRS: {
    901 			int i;
    902 			sctp_faddr_t *fp;
    903 
    904 			for (i = 0, fp = sctp->sctp_faddrs; fp != NULL;
    905 			    i++, fp = fp->next)
    906 				;
    907 			*(int32_t *)ptr = i;
    908 			break;
    909 		}
    910 		case SCTP_GET_PADDRS: {
    911 			int addr_cnt;
    912 			int addr_size;
    913 
    914 			if (connp->conn_family == AF_INET)
    915 				addr_size = sizeof (struct sockaddr_in);
    916 			else
    917 				addr_size = sizeof (struct sockaddr_in6);
    918 			addr_cnt = buflen / addr_size;
    919 			retval = sctp_getpeeraddrs(sctp, ptr, &addr_cnt);
    920 			if (retval == 0)
    921 				*optlen = addr_cnt * addr_size;
    922 			break;
    923 		}
    924 		case SCTP_PRSCTP:
    925 			*i1 = sctp->sctp_prsctp_aware ? 1 : 0;
    926 			break;
    927 
    928 		case SCTP_GET_ASSOC_STATS: {
    929 			sctp_assoc_stats_t *sas;
    930 
    931 			sas = (sctp_assoc_stats_t *)ptr;
    932 
    933 			/*
    934 			 * Copy the current stats to the stats struct.
    935 			 * For stats which can be reset by snmp users
    936 			 * add the cumulative and current stats for
    937 			 * the raw totals to output to the user.
    938 			 */
    939 			sas->sas_gapcnt = sctp->sctp_gapcnt;
    940 			sas->sas_outseqtsns = sctp->sctp_outseqtsns;
    941 			sas->sas_osacks = sctp->sctp_osacks;
    942 			sas->sas_isacks = sctp->sctp_isacks;
    943 			sas->sas_idupchunks = sctp->sctp_idupchunks;
    944 			sas->sas_rtxchunks =  sctp->sctp_rxtchunks +
    945 			    sctp->sctp_cum_rxtchunks;
    946 			sas->sas_octrlchunks = sctp->sctp_obchunks +
    947 			    sctp->sctp_cum_obchunks;
    948 			sas->sas_ictrlchunks = sctp->sctp_ibchunks +
    949 			    sctp->sctp_cum_ibchunks;
    950 			sas->sas_oodchunks = sctp->sctp_odchunks +
    951 			    sctp->sctp_cum_odchunks;
    952 			sas->sas_iodchunks = sctp->sctp_idchunks +
    953 			    sctp->sctp_cum_idchunks;
    954 			sas->sas_ouodchunks = sctp->sctp_oudchunks +
    955 			    sctp->sctp_cum_oudchunks;
    956 			sas->sas_iuodchunks = sctp->sctp_iudchunks +
    957 			    sctp->sctp_cum_iudchunks;
    958 
    959 			/*
    960 			 * Copy out the maximum observed RTO since the
    961 			 * time this data was last requested
    962 			 */
    963 			if (sctp->sctp_maxrto == 0) {
    964 				/* unchanged during obervation period */
    965 				sas->sas_maxrto = sctp->sctp_prev_maxrto;
    966 			} else {
    967 				/* record new period maximum */
    968 				sas->sas_maxrto = sctp->sctp_maxrto;
    969 			}
    970 			/* Record the value sent to the user this period */
    971 			sctp->sctp_prev_maxrto = sas->sas_maxrto;
    972 
    973 			/* Mark beginning of a new observation period */
    974 			sctp->sctp_maxrto = 0;
    975 
    976 			*optlen = sizeof (sctp_assoc_stats_t);
    977 			break;
    978 		}
    979 		case SCTP_I_WANT_MAPPED_V4_ADDR:
    980 		case SCTP_MAXSEG:
    981 		case SCTP_DISABLE_FRAGMENTS:
    982 		default:
    983 			/* Not yet supported. */
    984 			retval = ENOPROTOOPT;
    985 			break;
    986 		}
    987 		WAKE_SCTP(sctp);
    988 		return (retval);
    989 	case IPPROTO_IP:
    990 		if (connp->conn_family != AF_INET) {
    991 			retval = EINVAL;
    992 			break;
    993 		}
    994 		switch (name) {
    995 		case IP_OPTIONS:
    996 		case T_IP_OPTIONS: {
    997 			/*
    998 			 * This is compatible with BSD in that in only return
    999 			 * the reverse source route with the final destination
   1000 			 * as the last entry. The first 4 bytes of the option
   1001 			 * will contain the final destination. Allocate a
   1002 			 * buffer large enough to hold all the options, we
   1003 			 * add IP_ADDR_LEN to SCTP_MAX_IP_OPTIONS_LENGTH since
   1004 			 * ip_opt_get_user() adds the final destination
   1005 			 * at the start.
   1006 			 */
   1007 			int	opt_len;
   1008 			uchar_t	obuf[SCTP_MAX_IP_OPTIONS_LENGTH + IP_ADDR_LEN];
   1009 
   1010 			opt_len = ip_opt_get_user(connp, obuf);
   1011 			ASSERT(opt_len <= sizeof (obuf));
   1012 
   1013 			if (buflen < opt_len) {
   1014 				/* Silently truncate */
   1015 				opt_len = buflen;
   1016 			}
   1017 			*optlen = opt_len;
   1018 			bcopy(obuf, ptr, opt_len);
   1019 			WAKE_SCTP(sctp);
   1020 			return (0);
   1021 		}
   1022 		default:
   1023 			break;
   1024 		}
   1025 		break;
   1026 	}
   1027 	mutex_enter(&connp->conn_lock);
   1028 	retval = conn_opt_get(&coas, level, name, ptr);
   1029 	mutex_exit(&connp->conn_lock);
   1030 	WAKE_SCTP(sctp);
   1031 	if (retval == -1)
   1032 		return (EINVAL);
   1033 	*optlen = retval;
   1034 	return (0);
   1035 }
   1036 
   1037 int
   1038 sctp_set_opt(sctp_t *sctp, int level, int name, const void *invalp,
   1039     socklen_t inlen)
   1040 {
   1041 	int		*i1 = (int *)invalp;
   1042 	boolean_t	onoff;
   1043 	int		retval = 0, addrcnt;
   1044 	conn_t		*connp = sctp->sctp_connp;
   1045 	sctp_stack_t	*sctps = sctp->sctp_sctps;
   1046 	conn_opt_arg_t	coas;
   1047 
   1048 	coas.coa_connp = connp;
   1049 	coas.coa_ixa = connp->conn_ixa;
   1050 	coas.coa_ipp = &connp->conn_xmit_ipp;
   1051 	coas.coa_ancillary = B_FALSE;
   1052 	coas.coa_changed = 0;
   1053 
   1054 	/* In all cases, the size of the option must be bigger than int */
   1055 	if (inlen >= sizeof (int32_t)) {
   1056 		onoff = ONOFF(*i1);
   1057 	}
   1058 	retval = 0;
   1059 
   1060 	RUN_SCTP(sctp);
   1061 
   1062 	if (connp->conn_state_flags & CONN_CLOSING) {
   1063 		WAKE_SCTP(sctp);
   1064 		return (EINVAL);
   1065 	}
   1066 
   1067 	/*
   1068 	 * Check that the level and name are supported by SCTP, and that
   1069 	 * the length an credentials are ok.
   1070 	 */
   1071 	retval = proto_opt_check(level, name, inlen, NULL, sctp_opt_arr,
   1072 	    sctp_opt_arr_size, B_TRUE, B_FALSE, connp->conn_cred);
   1073 	if (retval != 0) {
   1074 		if (retval < 0) {
   1075 			retval = proto_tlitosyserr(-retval);
   1076 		}
   1077 		goto done;
   1078 	}
   1079 
   1080 	/* Note: both SCTP and TCP interpret l_linger as being in seconds */
   1081 	switch (level) {
   1082 	case SOL_SOCKET:
   1083 		switch (name) {
   1084 		case SO_SNDBUF:
   1085 			if (*i1 > sctps->sctps_max_buf) {
   1086 				retval = ENOBUFS;
   1087 				goto done;
   1088 			}
   1089 			if (*i1 < 0) {
   1090 				retval = EINVAL;
   1091 				goto done;
   1092 			}
   1093 			connp->conn_sndbuf = *i1;
   1094 			if (sctps->sctps_snd_lowat_fraction != 0) {
   1095 				connp->conn_sndlowat = connp->conn_sndbuf /
   1096 				    sctps->sctps_snd_lowat_fraction;
   1097 			}
   1098 			goto done;
   1099 		case SO_RCVBUF:
   1100 			if (*i1 > sctps->sctps_max_buf) {
   1101 				retval = ENOBUFS;
   1102 				goto done;
   1103 			}
   1104 			/* Silently ignore zero */
   1105 			if (*i1 != 0) {
   1106 				struct sock_proto_props sopp;
   1107 
   1108 				/*
   1109 				 * Insist on a receive window that is at least
   1110 				 * sctp_recv_hiwat_minmss * MSS (default 4*MSS)
   1111 				 * to avoid funny interactions of Nagle
   1112 				 * algorithm, SWS avoidance and delayed
   1113 				 * acknowledgement.
   1114 				 */
   1115 				*i1 = MAX(*i1,
   1116 				    sctps->sctps_recv_hiwat_minmss *
   1117 				    sctp->sctp_mss);
   1118 				/*
   1119 				 * Note that sctp_rwnd is modified by the
   1120 				 * protocol and here we just whack it.
   1121 				 */
   1122 				connp->conn_rcvbuf = sctp->sctp_rwnd = *i1;
   1123 				sctp->sctp_irwnd = sctp->sctp_rwnd;
   1124 				sctp->sctp_pd_point = sctp->sctp_rwnd;
   1125 
   1126 				sopp.sopp_flags = SOCKOPT_RCVHIWAT;
   1127 				sopp.sopp_rxhiwat = connp->conn_rcvbuf;
   1128 				sctp->sctp_ulp_prop(sctp->sctp_ulpd, &sopp);
   1129 
   1130 			}
   1131 			/*
   1132 			 * XXX should we return the rwnd here
   1133 			 * and sctp_opt_get ?
   1134 			 */
   1135 			goto done;
   1136 		case SO_ALLZONES:
   1137 			if (sctp->sctp_state >= SCTPS_BOUND) {
   1138 				retval = EINVAL;
   1139 				goto done;
   1140 			}
   1141 			break;
   1142 		case SO_MAC_EXEMPT:
   1143 			if (sctp->sctp_state >= SCTPS_BOUND) {
   1144 				retval = EINVAL;
   1145 				goto done;
   1146 			}
   1147 			break;
   1148 		}
   1149 		break;
   1150 
   1151 	case IPPROTO_SCTP:
   1152 		switch (name) {
   1153 		case SCTP_RTOINFO:
   1154 			retval = sctp_set_rtoinfo(sctp, invalp);
   1155 			break;
   1156 		case SCTP_ASSOCINFO:
   1157 			retval = sctp_set_assocparams(sctp, invalp);
   1158 			break;
   1159 		case SCTP_INITMSG:
   1160 			retval = sctp_set_initmsg(sctp, invalp, inlen);
   1161 			break;
   1162 		case SCTP_NODELAY:
   1163 			sctp->sctp_ndelay = ONOFF(*i1);
   1164 			break;
   1165 		case SCTP_AUTOCLOSE:
   1166 			if (SEC_TO_TICK(*i1) < 0) {
   1167 				retval = EINVAL;
   1168 				break;
   1169 			}
   1170 			/* Convert the number of seconds to ticks. */
   1171 			sctp->sctp_autoclose = SEC_TO_TICK(*i1);
   1172 			sctp_heartbeat_timer(sctp);
   1173 			break;
   1174 		case SCTP_SET_PEER_PRIMARY_ADDR:
   1175 			retval = sctp_set_peerprim(sctp, invalp);
   1176 			break;
   1177 		case SCTP_PRIMARY_ADDR:
   1178 			retval = sctp_set_prim(sctp, invalp);
   1179 			break;
   1180 		case SCTP_ADAPTATION_LAYER: {
   1181 			struct sctp_setadaptation *ssb;
   1182 
   1183 			ssb = (struct sctp_setadaptation *)invalp;
   1184 			sctp->sctp_send_adaptation = 1;
   1185 			sctp->sctp_tx_adaptation_code = ssb->ssb_adaptation_ind;
   1186 			break;
   1187 		}
   1188 		case SCTP_PEER_ADDR_PARAMS:
   1189 			retval = sctp_set_peer_addr_params(sctp, invalp);
   1190 			break;
   1191 		case SCTP_DEFAULT_SEND_PARAM:
   1192 			retval = sctp_set_def_send_params(sctp, invalp);
   1193 			break;
   1194 		case SCTP_EVENTS: {
   1195 			struct sctp_event_subscribe *ev;
   1196 
   1197 			ev = (struct sctp_event_subscribe *)invalp;
   1198 			sctp->sctp_recvsndrcvinfo =
   1199 			    ONOFF(ev->sctp_data_io_event);
   1200 			sctp->sctp_recvassocevnt =
   1201 			    ONOFF(ev->sctp_association_event);
   1202 			sctp->sctp_recvpathevnt =
   1203 			    ONOFF(ev->sctp_address_event);
   1204 			sctp->sctp_recvsendfailevnt =
   1205 			    ONOFF(ev->sctp_send_failure_event);
   1206 			sctp->sctp_recvpeererr =
   1207 			    ONOFF(ev->sctp_peer_error_event);
   1208 			sctp->sctp_recvshutdownevnt =
   1209 			    ONOFF(ev->sctp_shutdown_event);
   1210 			sctp->sctp_recvpdevnt =
   1211 			    ONOFF(ev->sctp_partial_delivery_event);
   1212 			sctp->sctp_recvalevnt =
   1213 			    ONOFF(ev->sctp_adaptation_layer_event);
   1214 			break;
   1215 		}
   1216 		case SCTP_ADD_ADDR:
   1217 		case SCTP_REM_ADDR:
   1218 			/*
   1219 			 * The sctp_t has to be bound first before
   1220 			 * the address list can be changed.
   1221 			 */
   1222 			if (sctp->sctp_state < SCTPS_BOUND) {
   1223 				retval = EINVAL;
   1224 				break;
   1225 			}
   1226 			if (connp->conn_family == AF_INET) {
   1227 				addrcnt = inlen / sizeof (struct sockaddr_in);
   1228 			} else {
   1229 				ASSERT(connp->conn_family == AF_INET6);
   1230 				addrcnt = inlen / sizeof (struct sockaddr_in6);
   1231 			}
   1232 			if (name == SCTP_ADD_ADDR) {
   1233 				retval = sctp_bind_add(sctp, invalp, addrcnt,
   1234 				    B_TRUE, connp->conn_lport);
   1235 			} else {
   1236 				retval = sctp_bind_del(sctp, invalp, addrcnt,
   1237 				    B_TRUE);
   1238 			}
   1239 			break;
   1240 		case SCTP_UC_SWAP: {
   1241 			struct sctp_uc_swap *us;
   1242 
   1243 			/*
   1244 			 * Change handle & upcalls.
   1245 			 */
   1246 			us = (struct sctp_uc_swap *)invalp;
   1247 			sctp->sctp_ulpd = us->sus_handle;
   1248 			sctp->sctp_upcalls = us->sus_upcalls;
   1249 			break;
   1250 		}
   1251 		case SCTP_PRSCTP:
   1252 			sctp->sctp_prsctp_aware = onoff;
   1253 			break;
   1254 		case SCTP_I_WANT_MAPPED_V4_ADDR:
   1255 		case SCTP_MAXSEG:
   1256 		case SCTP_DISABLE_FRAGMENTS:
   1257 			/* Not yet supported. */
   1258 			retval = ENOPROTOOPT;
   1259 			break;
   1260 		}
   1261 		goto done;
   1262 
   1263 	case IPPROTO_IP:
   1264 		if (connp->conn_family != AF_INET) {
   1265 			retval = ENOPROTOOPT;
   1266 			goto done;
   1267 		}
   1268 		switch (name) {
   1269 		case IP_SEC_OPT:
   1270 			/*
   1271 			 * We should not allow policy setting after
   1272 			 * we start listening for connections.
   1273 			 */
   1274 			if (sctp->sctp_state >= SCTPS_LISTEN) {
   1275 				retval = EINVAL;
   1276 				goto done;
   1277 			}
   1278 			break;
   1279 		}
   1280 		break;
   1281 	case IPPROTO_IPV6:
   1282 		if (connp->conn_family != AF_INET6) {
   1283 			retval = EINVAL;
   1284 			goto done;
   1285 		}
   1286 
   1287 		switch (name) {
   1288 		case IPV6_RECVPKTINFO:
   1289 			/* Send it with the next msg */
   1290 			sctp->sctp_recvifindex = 0;
   1291 			break;
   1292 		case IPV6_RECVTCLASS:
   1293 			/* Force it to be sent up with the next msg */
   1294 			sctp->sctp_recvtclass = 0xffffffffU;
   1295 			break;
   1296 		case IPV6_RECVHOPLIMIT:
   1297 			/* Force it to be sent up with the next msg */
   1298 			sctp->sctp_recvhops = 0xffffffffU;
   1299 			break;
   1300 		case IPV6_SEC_OPT:
   1301 			/*
   1302 			 * We should not allow policy setting after
   1303 			 * we start listening for connections.
   1304 			 */
   1305 			if (sctp->sctp_state >= SCTPS_LISTEN) {
   1306 				retval = EINVAL;
   1307 				goto done;
   1308 			}
   1309 			break;
   1310 		case IPV6_V6ONLY:
   1311 			/*
   1312 			 * After the bound state, setting the v6only option
   1313 			 * is too late.
   1314 			 */
   1315 			if (sctp->sctp_state >= SCTPS_BOUND) {
   1316 				retval = EINVAL;
   1317 				goto done;
   1318 			}
   1319 			break;
   1320 		}
   1321 		break;
   1322 	}
   1323 
   1324 	retval = conn_opt_set(&coas, level, name, inlen, (uchar_t *)invalp,
   1325 	    B_FALSE, connp->conn_cred);
   1326 	if (retval != 0)
   1327 		goto done;
   1328 
   1329 	if (coas.coa_changed & COA_ROUTE_CHANGED) {
   1330 		sctp_faddr_t *fp;
   1331 		/*
   1332 		 * We recache the information which might pick a different
   1333 		 * source and redo IPsec as a result.
   1334 		 */
   1335 		for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next)
   1336 			sctp_get_dest(sctp, fp);
   1337 	}
   1338 	if (coas.coa_changed & COA_HEADER_CHANGED) {
   1339 		retval = sctp_build_hdrs(sctp, KM_NOSLEEP);
   1340 		if (retval != 0)
   1341 			goto done;
   1342 	}
   1343 	if (coas.coa_changed & COA_WROFF_CHANGED) {
   1344 		connp->conn_wroff = connp->conn_ht_iphc_allocated +
   1345 		    sctps->sctps_wroff_xtra;
   1346 		if (sctp->sctp_current != NULL) {
   1347 			/*
   1348 			 * Could be setting options before setting up
   1349 			 * connection.
   1350 			 */
   1351 			sctp_set_ulp_prop(sctp);
   1352 		}
   1353 	}
   1354 done:
   1355 	WAKE_SCTP(sctp);
   1356 	return (retval);
   1357 }
   1358 
   1359 /*
   1360  * SCTP exported kernel interface for geting the first source address of
   1361  * a sctp_t.  The parameter addr is assumed to have enough space to hold
   1362  * one socket address.
   1363  */
   1364 int
   1365 sctp_getsockname(sctp_t *sctp, struct sockaddr *addr, socklen_t *addrlen)
   1366 {
   1367 	int	err = 0;
   1368 	int	addrcnt = 1;
   1369 	sin_t	*sin4;
   1370 	sin6_t	*sin6;
   1371 	conn_t	*connp = sctp->sctp_connp;
   1372 
   1373 	ASSERT(sctp != NULL);
   1374 
   1375 	RUN_SCTP(sctp);
   1376 	addr->sa_family = connp->conn_family;
   1377 	switch (connp->conn_family) {
   1378 	case AF_INET:
   1379 		sin4 = (sin_t *)addr;
   1380 		if ((sctp->sctp_state <= SCTPS_LISTEN) &&
   1381 		    sctp->sctp_bound_to_all) {
   1382 			sin4->sin_addr.s_addr = INADDR_ANY;
   1383 			sin4->sin_port = connp->conn_lport;
   1384 		} else {
   1385 			err = sctp_getmyaddrs(sctp, sin4, &addrcnt);
   1386 			if (err != 0) {
   1387 				*addrlen = 0;
   1388 				break;
   1389 			}
   1390 		}
   1391 		*addrlen = sizeof (struct sockaddr_in);
   1392 		break;
   1393 	case AF_INET6:
   1394 		sin6 = (sin6_t *)addr;
   1395 		if ((sctp->sctp_state <= SCTPS_LISTEN) &&
   1396 		    sctp->sctp_bound_to_all) {
   1397 			bzero(&sin6->sin6_addr, sizeof (sin6->sin6_addr));
   1398 			sin6->sin6_port = connp->conn_lport;
   1399 		} else {
   1400 			err = sctp_getmyaddrs(sctp, sin6, &addrcnt);
   1401 			if (err != 0) {
   1402 				*addrlen = 0;
   1403 				break;
   1404 			}
   1405 		}
   1406 		*addrlen = sizeof (struct sockaddr_in6);
   1407 		/* Note that flowinfo is only returned for getpeername */
   1408 		break;
   1409 	}
   1410 	WAKE_SCTP(sctp);
   1411 	return (err);
   1412 }
   1413 
   1414 /*
   1415  * SCTP exported kernel interface for geting the primary peer address of
   1416  * a sctp_t.  The parameter addr is assumed to have enough space to hold
   1417  * one socket address.
   1418  */
   1419 int
   1420 sctp_getpeername(sctp_t *sctp, struct sockaddr *addr, socklen_t *addrlen)
   1421 {
   1422 	int	err = 0;
   1423 	int	addrcnt = 1;
   1424 	sin6_t	*sin6;
   1425 	conn_t	*connp = sctp->sctp_connp;
   1426 
   1427 	ASSERT(sctp != NULL);
   1428 
   1429 	RUN_SCTP(sctp);
   1430 	addr->sa_family = connp->conn_family;
   1431 	switch (connp->conn_family) {
   1432 	case AF_INET:
   1433 		err = sctp_getpeeraddrs(sctp, addr, &addrcnt);
   1434 		if (err != 0) {
   1435 			*addrlen = 0;
   1436 			break;
   1437 		}
   1438 		*addrlen = sizeof (struct sockaddr_in);
   1439 		break;
   1440 	case AF_INET6:
   1441 		sin6 = (sin6_t *)addr;
   1442 		err = sctp_getpeeraddrs(sctp, sin6, &addrcnt);
   1443 		if (err != 0) {
   1444 			*addrlen = 0;
   1445 			break;
   1446 		}
   1447 		*addrlen = sizeof (struct sockaddr_in6);
   1448 		break;
   1449 	}
   1450 	WAKE_SCTP(sctp);
   1451 	return (err);
   1452 }
   1453 
   1454 /*
   1455  * Return a list of IP addresses of the peer endpoint of this sctp_t.
   1456  * The parameter paddrs is supposed to be either (struct sockaddr_in *) or
   1457  * (struct sockaddr_in6 *) depending on the address family of the sctp_t.
   1458  */
   1459 int
   1460 sctp_getpeeraddrs(sctp_t *sctp, void *paddrs, int *addrcnt)
   1461 {
   1462 	int			family;
   1463 	struct sockaddr_in	*sin4;
   1464 	struct sockaddr_in6	*sin6;
   1465 	int			max;
   1466 	int			cnt;
   1467 	sctp_faddr_t		*fp = sctp->sctp_faddrs;
   1468 	in6_addr_t		addr;
   1469 	conn_t			*connp = sctp->sctp_connp;
   1470 
   1471 	ASSERT(sctp != NULL);
   1472 
   1473 	if (sctp->sctp_faddrs == NULL)
   1474 		return (ENOTCONN);
   1475 
   1476 	family = connp->conn_family;
   1477 	max = *addrcnt;
   1478 
   1479 	/* If we want only one, give the primary */
   1480 	if (max == 1) {
   1481 		addr = sctp->sctp_primary->faddr;
   1482 		switch (family) {
   1483 		case AF_INET:
   1484 			sin4 = paddrs;
   1485 			IN6_V4MAPPED_TO_INADDR(&addr, &sin4->sin_addr);
   1486 			sin4->sin_port = connp->conn_fport;
   1487 			sin4->sin_family = AF_INET;
   1488 			break;
   1489 
   1490 		case AF_INET6:
   1491 			sin6 = paddrs;
   1492 			sin6->sin6_addr = addr;
   1493 			sin6->sin6_port = connp->conn_fport;
   1494 			sin6->sin6_family = AF_INET6;
   1495 			sin6->sin6_flowinfo = connp->conn_flowinfo;
   1496 			if (IN6_IS_ADDR_LINKSCOPE(&addr) &&
   1497 			    sctp->sctp_primary != NULL &&
   1498 			    (sctp->sctp_primary->ixa->ixa_flags &
   1499 			    IXAF_SCOPEID_SET)) {
   1500 				sin6->sin6_scope_id =
   1501 				    sctp->sctp_primary->ixa->ixa_scopeid;
   1502 			} else {
   1503 				sin6->sin6_scope_id = 0;
   1504 			}
   1505 			sin6->__sin6_src_id = 0;
   1506 			break;
   1507 		}
   1508 		return (0);
   1509 	}
   1510 
   1511 	for (cnt = 0; cnt < max && fp != NULL; cnt++, fp = fp->next) {
   1512 		addr = fp->faddr;
   1513 		switch (family) {
   1514 		case AF_INET:
   1515 			ASSERT(IN6_IS_ADDR_V4MAPPED(&addr));
   1516 			sin4 = (struct sockaddr_in *)paddrs + cnt;
   1517 			IN6_V4MAPPED_TO_INADDR(&addr, &sin4->sin_addr);
   1518 			sin4->sin_port = connp->conn_fport;
   1519 			sin4->sin_family = AF_INET;
   1520 			break;
   1521 		case AF_INET6:
   1522 			sin6 = (struct sockaddr_in6 *)paddrs + cnt;
   1523 			sin6->sin6_addr = addr;
   1524 			sin6->sin6_port = connp->conn_fport;
   1525 			sin6->sin6_family = AF_INET6;
   1526 			sin6->sin6_flowinfo = connp->conn_flowinfo;
   1527 			if (IN6_IS_ADDR_LINKSCOPE(&addr) &&
   1528 			    (fp->ixa->ixa_flags & IXAF_SCOPEID_SET))
   1529 				sin6->sin6_scope_id = fp->ixa->ixa_scopeid;
   1530 			else
   1531 				sin6->sin6_scope_id = 0;
   1532 			sin6->__sin6_src_id = 0;
   1533 			break;
   1534 		}
   1535 	}
   1536 	*addrcnt = cnt;
   1537 	return (0);
   1538 }
   1539