xref: /illumos-gate/usr/src/uts/common/inet/sctp/sctp_opt_data.c (revision c5c4113dfcabb1eed3d4bdf7609de5170027a794)
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 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/stream.h>
31 #define	_SUN_TPI_VERSION 2
32 #include <sys/tihdr.h>
33 #include <sys/socket.h>
34 #include <sys/xti_inet.h>
35 #include <sys/systm.h>
36 #include <sys/ddi.h>
37 #include <sys/sunddi.h>
38 #include <sys/kmem.h>
39 #include <sys/strsubr.h>
40 #include <sys/strsun.h>
41 #include <sys/policy.h>
42 
43 #include <inet/common.h>
44 #include <netinet/ip6.h>
45 #include <inet/ip.h>
46 #include <inet/ip_ire.h>
47 #include <inet/ip_if.h>
48 #include <inet/ipclassifier.h>
49 #include <inet/ipsec_impl.h>
50 
51 #include <netinet/in.h>
52 #include <netinet/ip.h>
53 #include <netinet/tcp.h>
54 
55 #include <inet/common.h>
56 #include <inet/ip.h>
57 #include <inet/ip6.h>
58 #include <inet/sctp_itf.h>
59 #include "sctp_impl.h"
60 #include "sctp_asconf.h"
61 #include "sctp_addr.h"
62 
63 static int	sctp_getpeeraddrs(sctp_t *, void *, int *);
64 
65 /*
66  * Copy the standard header into its new location,
67  * lay in the new options and then update the relevant
68  * fields in both sctp_t and the standard header.
69  * Returns 0 on success, errno otherwise.
70  */
71 static int
72 sctp_opt_set_header(sctp_t *sctp, const void *ptr, uint_t len)
73 {
74 	uint8_t *ip_optp;
75 	sctp_hdr_t *new_sctph;
76 
77 	if ((len > SCTP_MAX_IP_OPTIONS_LENGTH) || (len & 0x3))
78 		return (EINVAL);
79 
80 	if (len > IP_MAX_OPT_LENGTH - sctp->sctp_v4label_len)
81 		return (EINVAL);
82 
83 	ip_optp = (uint8_t *)sctp->sctp_ipha + IP_SIMPLE_HDR_LENGTH;
84 
85 	if (sctp->sctp_v4label_len > 0) {
86 		int padlen;
87 		uint8_t opt;
88 
89 		/* convert list termination to no-ops as needed */
90 		padlen = sctp->sctp_v4label_len - ip_optp[IPOPT_OLEN];
91 		ip_optp += ip_optp[IPOPT_OLEN];
92 		opt = len > 0 ? IPOPT_NOP : IPOPT_EOL;
93 		while (--padlen >= 0)
94 			*ip_optp++ = opt;
95 		ASSERT(ip_optp == (uint8_t *)sctp->sctp_ipha +
96 		    IP_SIMPLE_HDR_LENGTH + sctp->sctp_v4label_len);
97 	}
98 
99 	/*
100 	 * Move the existing SCTP header out where it belongs.
101 	 */
102 	new_sctph = (sctp_hdr_t *)(ip_optp + len);
103 	ovbcopy(sctp->sctp_sctph, new_sctph, sizeof (sctp_hdr_t));
104 	sctp->sctp_sctph = new_sctph;
105 
106 	/*
107 	 * Insert the new user-supplied IP options.
108 	 */
109 	if (len > 0)
110 		bcopy(ptr, ip_optp, len);
111 
112 	len += sctp->sctp_v4label_len;
113 	sctp->sctp_ip_hdr_len = len;
114 	sctp->sctp_ipha->ipha_version_and_hdr_length =
115 	    (IP_VERSION << 4) | (len >> 2);
116 	sctp->sctp_hdr_len = len + sizeof (sctp_hdr_t);
117 
118 	if (sctp->sctp_current) {
119 		/*
120 		 * Could be setting options before setting up connection.
121 		 */
122 		sctp_set_ulp_prop(sctp);
123 	}
124 	return (0);
125 }
126 
127 static int
128 sctp_get_status(sctp_t *sctp, void *ptr)
129 {
130 	struct sctp_status *sstat = ptr;
131 	sctp_faddr_t *fp;
132 	struct sockaddr_in *sin;
133 	struct sockaddr_in6 *sin6;
134 	struct sctp_paddrinfo *sp;
135 	mblk_t *meta, *mp;
136 	int i;
137 
138 	sstat->sstat_state = sctp->sctp_state;
139 	sstat->sstat_rwnd = sctp->sctp_frwnd;
140 
141 	sp = &sstat->sstat_primary;
142 	if (!sctp->sctp_primary) {
143 		bzero(sp, sizeof (*sp));
144 		goto noprim;
145 	}
146 	fp = sctp->sctp_primary;
147 
148 	if (fp->isv4) {
149 		sin = (struct sockaddr_in *)&sp->spinfo_address;
150 		sin->sin_family = AF_INET;
151 		sin->sin_port = sctp->sctp_fport;
152 		IN6_V4MAPPED_TO_INADDR(&fp->faddr, &sin->sin_addr);
153 		sp->spinfo_mtu = sctp->sctp_hdr_len;
154 	} else {
155 		sin6 = (struct sockaddr_in6 *)&sp->spinfo_address;
156 		sin6->sin6_family = AF_INET6;
157 		sin6->sin6_port = sctp->sctp_fport;
158 		sin6->sin6_addr = fp->faddr;
159 		sp->spinfo_mtu = sctp->sctp_hdr6_len;
160 	}
161 	sp->spinfo_state = fp->state == SCTP_FADDRS_ALIVE ? SCTP_ACTIVE :
162 	    SCTP_INACTIVE;
163 	sp->spinfo_cwnd = fp->cwnd;
164 	sp->spinfo_srtt = fp->srtt;
165 	sp->spinfo_rto = fp->rto;
166 	sp->spinfo_mtu += fp->sfa_pmss;
167 
168 noprim:
169 	sstat->sstat_unackdata = 0;
170 	sstat->sstat_penddata = 0;
171 	sstat->sstat_instrms = sctp->sctp_num_istr;
172 	sstat->sstat_outstrms = sctp->sctp_num_ostr;
173 	sstat->sstat_fragmentation_point = sctp->sctp_mss -
174 	    sizeof (sctp_data_hdr_t);
175 
176 	/* count unack'd */
177 	for (meta = sctp->sctp_xmit_head; meta; meta = meta->b_next) {
178 		for (mp = meta->b_cont; mp; mp = mp->b_next) {
179 			if (!SCTP_CHUNK_ISSENT(mp)) {
180 				break;
181 			}
182 			if (!SCTP_CHUNK_ISACKED(mp)) {
183 				sstat->sstat_unackdata++;
184 			}
185 		}
186 	}
187 
188 	/*
189 	 * Count penddata chunks. We can only count chunks in SCTP (not
190 	 * data already delivered to socket layer).
191 	 */
192 	if (sctp->sctp_instr != NULL) {
193 		for (i = 0; i < sctp->sctp_num_istr; i++) {
194 			for (meta = sctp->sctp_instr[i].istr_reass;
195 			    meta != NULL; meta = meta->b_next) {
196 				for (mp = meta->b_cont; mp; mp = mp->b_cont) {
197 					if (DB_TYPE(mp) != M_CTL) {
198 						sstat->sstat_penddata++;
199 					}
200 				}
201 			}
202 		}
203 	}
204 	/* Un-Ordered Frag list */
205 	for (meta = sctp->sctp_uo_frags; meta != NULL; meta = meta->b_next)
206 		sstat->sstat_penddata++;
207 
208 	return (sizeof (*sstat));
209 }
210 
211 /*
212  * SCTP_GET_PEER_ADDR_INFO
213  */
214 static int
215 sctp_get_paddrinfo(sctp_t *sctp, void *ptr, socklen_t *optlen)
216 {
217 	struct sctp_paddrinfo	*infop = ptr;
218 	struct sockaddr_in	*sin4;
219 	struct sockaddr_in6	*sin6;
220 	in6_addr_t		faddr;
221 	sctp_faddr_t		*fp;
222 
223 	switch (infop->spinfo_address.ss_family) {
224 	case AF_INET:
225 		sin4 = (struct sockaddr_in *)&infop->spinfo_address;
226 		IN6_INADDR_TO_V4MAPPED(&sin4->sin_addr, &faddr);
227 		break;
228 	case AF_INET6:
229 		sin6 = (struct sockaddr_in6 *)&infop->spinfo_address;
230 		faddr = sin6->sin6_addr;
231 		break;
232 	default:
233 		return (EAFNOSUPPORT);
234 	}
235 
236 	if ((fp = sctp_lookup_faddr(sctp, &faddr)) == NULL)
237 		return (EINVAL);
238 
239 	infop->spinfo_state = (fp->state == SCTP_FADDRS_ALIVE) ? SCTP_ACTIVE :
240 	    SCTP_INACTIVE;
241 	infop->spinfo_cwnd = fp->cwnd;
242 	infop->spinfo_srtt = TICK_TO_MSEC(fp->srtt);
243 	infop->spinfo_rto = TICK_TO_MSEC(fp->rto);
244 	infop->spinfo_mtu = fp->sfa_pmss;
245 
246 	*optlen = sizeof (struct sctp_paddrinfo);
247 	return (0);
248 }
249 
250 /*
251  * SCTP_RTOINFO
252  */
253 static int
254 sctp_get_rtoinfo(sctp_t *sctp, void *ptr)
255 {
256 	struct sctp_rtoinfo *srto = ptr;
257 
258 	srto->srto_initial = TICK_TO_MSEC(sctp->sctp_rto_initial);
259 	srto->srto_max = TICK_TO_MSEC(sctp->sctp_rto_max);
260 	srto->srto_min = TICK_TO_MSEC(sctp->sctp_rto_min);
261 
262 	return (sizeof (*srto));
263 }
264 
265 static int
266 sctp_set_rtoinfo(sctp_t *sctp, const void *invalp, uint_t inlen)
267 {
268 	const struct sctp_rtoinfo *srto;
269 	boolean_t ispriv;
270 	sctp_stack_t	*sctps = sctp->sctp_sctps;
271 
272 	if (inlen < sizeof (*srto)) {
273 		return (EINVAL);
274 	}
275 	srto = invalp;
276 
277 	ispriv = secpolicy_ip_config(sctp->sctp_credp, B_TRUE) == 0;
278 
279 	/*
280 	 * Bounds checking.  Priviledged user can set the RTO initial
281 	 * outside the ndd boundary.
282 	 */
283 	if (srto->srto_initial != 0 &&
284 	    (!ispriv && (srto->srto_initial < sctps->sctps_rto_initialg_low ||
285 	    srto->srto_initial > sctps->sctps_rto_initialg_high))) {
286 		return (EINVAL);
287 	}
288 	if (srto->srto_max != 0 &&
289 	    (!ispriv && (srto->srto_max < sctps->sctps_rto_maxg_low ||
290 	    srto->srto_max > sctps->sctps_rto_maxg_high))) {
291 		return (EINVAL);
292 	}
293 	if (srto->srto_min != 0 &&
294 	    (!ispriv && (srto->srto_min < sctps->sctps_rto_ming_low ||
295 	    srto->srto_min > sctps->sctps_rto_ming_high))) {
296 		return (EINVAL);
297 	}
298 
299 	if (srto->srto_initial != 0) {
300 		sctp->sctp_rto_initial = MSEC_TO_TICK(srto->srto_initial);
301 	}
302 	if (srto->srto_max != 0) {
303 		sctp->sctp_rto_max = MSEC_TO_TICK(srto->srto_max);
304 	}
305 	if (srto->srto_min != 0) {
306 		sctp->sctp_rto_min = MSEC_TO_TICK(srto->srto_min);
307 	}
308 
309 	return (0);
310 }
311 
312 /*
313  * SCTP_ASSOCINFO
314  */
315 static int
316 sctp_get_assocparams(sctp_t *sctp, void *ptr)
317 {
318 	struct sctp_assocparams *sap = ptr;
319 	sctp_faddr_t *fp;
320 	uint16_t i;
321 
322 	sap->sasoc_asocmaxrxt = sctp->sctp_pa_max_rxt;
323 
324 	/*
325 	 * Count the number of peer addresses
326 	 */
327 	for (i = 0, fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next) {
328 		i++;
329 	}
330 	sap->sasoc_number_peer_destinations = i;
331 	sap->sasoc_peer_rwnd = sctp->sctp_frwnd;
332 	sap->sasoc_local_rwnd = sctp->sctp_rwnd;
333 	sap->sasoc_cookie_life = TICK_TO_MSEC(sctp->sctp_cookie_lifetime);
334 
335 	return (sizeof (*sap));
336 }
337 
338 static int
339 sctp_set_assocparams(sctp_t *sctp, const void *invalp, uint_t inlen)
340 {
341 	const struct sctp_assocparams *sap = invalp;
342 	uint32_t sum = 0;
343 	sctp_faddr_t *fp;
344 	sctp_stack_t	*sctps = sctp->sctp_sctps;
345 
346 	if (inlen < sizeof (*sap)) {
347 		return (EINVAL);
348 	}
349 
350 	if (sap->sasoc_asocmaxrxt) {
351 		if (sctp->sctp_faddrs) {
352 			/*
353 			 * Bounds check: as per rfc2960, assoc max retr cannot
354 			 * exceed the sum of all individual path max retr's.
355 			 */
356 			for (fp = sctp->sctp_faddrs; fp; fp = fp->next) {
357 				sum += fp->max_retr;
358 			}
359 			if (sap->sasoc_asocmaxrxt > sum) {
360 				return (EINVAL);
361 			}
362 		}
363 		if (sap->sasoc_asocmaxrxt < sctps->sctps_pa_max_retr_low ||
364 		    sap->sasoc_asocmaxrxt > sctps->sctps_pa_max_retr_high) {
365 			/*
366 			 * Out of bounds.
367 			 */
368 			return (EINVAL);
369 		}
370 	}
371 	if (sap->sasoc_cookie_life != 0 &&
372 	    (sap->sasoc_cookie_life < sctps->sctps_cookie_life_low ||
373 	    sap->sasoc_cookie_life > sctps->sctps_cookie_life_high)) {
374 		return (EINVAL);
375 	}
376 
377 	if (sap->sasoc_asocmaxrxt > 0) {
378 		sctp->sctp_pa_max_rxt = sap->sasoc_asocmaxrxt;
379 	}
380 	if (sap->sasoc_cookie_life > 0) {
381 		sctp->sctp_cookie_lifetime = MSEC_TO_TICK(
382 		    sap->sasoc_cookie_life);
383 	}
384 	return (0);
385 }
386 
387 /*
388  * SCTP_INITMSG
389  */
390 static int
391 sctp_get_initmsg(sctp_t *sctp, void *ptr)
392 {
393 	struct sctp_initmsg *si = ptr;
394 
395 	si->sinit_num_ostreams = sctp->sctp_num_ostr;
396 	si->sinit_max_instreams = sctp->sctp_num_istr;
397 	si->sinit_max_attempts = sctp->sctp_max_init_rxt;
398 	si->sinit_max_init_timeo = TICK_TO_MSEC(sctp->sctp_init_rto_max);
399 
400 	return (sizeof (*si));
401 }
402 
403 static int
404 sctp_set_initmsg(sctp_t *sctp, const void *invalp, uint_t inlen)
405 {
406 	const struct sctp_initmsg *si = invalp;
407 	sctp_stack_t	*sctps = sctp->sctp_sctps;
408 
409 	if (sctp->sctp_state > SCTPS_LISTEN) {
410 		return (EINVAL);
411 	}
412 	if (inlen < sizeof (*si)) {
413 		return (EINVAL);
414 	}
415 	if (si->sinit_num_ostreams != 0 &&
416 	    (si->sinit_num_ostreams < sctps->sctps_initial_out_streams_low ||
417 	    si->sinit_num_ostreams >
418 	    sctps->sctps_initial_out_streams_high)) {
419 		/*
420 		 * Out of bounds.
421 		 */
422 		return (EINVAL);
423 	}
424 	if (si->sinit_max_instreams != 0 &&
425 	    (si->sinit_max_instreams < sctps->sctps_max_in_streams_low ||
426 	    si->sinit_max_instreams > sctps->sctps_max_in_streams_high)) {
427 		return (EINVAL);
428 	}
429 	if (si->sinit_max_attempts != 0 &&
430 	    (si->sinit_max_attempts < sctps->sctps_max_init_retr_low ||
431 	    si->sinit_max_attempts > sctps->sctps_max_init_retr_high)) {
432 		return (EINVAL);
433 	}
434 	if (si->sinit_max_init_timeo != 0 &&
435 	    (secpolicy_ip_config(sctp->sctp_credp, B_TRUE) != 0 &&
436 	    (si->sinit_max_init_timeo < sctps->sctps_rto_maxg_low ||
437 	    si->sinit_max_init_timeo > sctps->sctps_rto_maxg_high))) {
438 		return (EINVAL);
439 	}
440 	if (si->sinit_num_ostreams != 0)
441 		sctp->sctp_num_ostr = si->sinit_num_ostreams;
442 
443 	if (si->sinit_max_instreams != 0)
444 		sctp->sctp_num_istr = si->sinit_max_instreams;
445 
446 	if (si->sinit_max_attempts != 0)
447 		sctp->sctp_max_init_rxt = si->sinit_max_attempts;
448 
449 	if (si->sinit_max_init_timeo != 0) {
450 		sctp->sctp_init_rto_max =
451 		    MSEC_TO_TICK(si->sinit_max_init_timeo);
452 	}
453 	return (0);
454 }
455 
456 /*
457  * SCTP_PEER_ADDR_PARAMS
458  */
459 static int
460 sctp_find_peer_fp(sctp_t *sctp, const struct sockaddr_storage *ss,
461     sctp_faddr_t **fpp)
462 {
463 	struct sockaddr_in *sin;
464 	struct sockaddr_in6 *sin6;
465 	in6_addr_t addr;
466 
467 	if (ss->ss_family == AF_INET) {
468 		sin = (struct sockaddr_in *)ss;
469 		IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &addr);
470 	} else if (ss->ss_family == AF_INET6) {
471 		sin6 = (struct sockaddr_in6 *)ss;
472 		addr = sin6->sin6_addr;
473 	} else if (ss->ss_family) {
474 		return (EAFNOSUPPORT);
475 	}
476 
477 	if (!ss->ss_family ||
478 	    SCTP_IS_ADDR_UNSPEC(IN6_IS_ADDR_V4MAPPED(&addr), addr)) {
479 		*fpp = NULL;
480 	} else {
481 		*fpp = sctp_lookup_faddr(sctp, &addr);
482 		if (*fpp == NULL) {
483 			return (EINVAL);
484 		}
485 	}
486 	return (0);
487 }
488 
489 static int
490 sctp_get_peer_addr_params(sctp_t *sctp, void *ptr)
491 {
492 	struct sctp_paddrparams *spp = ptr;
493 	sctp_faddr_t *fp;
494 	int retval;
495 
496 	retval = sctp_find_peer_fp(sctp, &spp->spp_address, &fp);
497 	if (retval) {
498 		return (retval);
499 	}
500 	if (fp) {
501 		spp->spp_hbinterval = TICK_TO_MSEC(fp->hb_interval);
502 		spp->spp_pathmaxrxt = fp->max_retr;
503 	} else {
504 		spp->spp_hbinterval = TICK_TO_MSEC(sctp->sctp_hb_interval);
505 		spp->spp_pathmaxrxt = sctp->sctp_pp_max_rxt;
506 	}
507 	return (sizeof (*spp));
508 }
509 
510 static int
511 sctp_set_peer_addr_params(sctp_t *sctp, const void *invalp, uint_t inlen)
512 {
513 	const struct sctp_paddrparams *spp = invalp;
514 	sctp_faddr_t *fp, *fp2;
515 	int retval;
516 	uint32_t sum = 0;
517 	int64_t now;
518 	sctp_stack_t	*sctps = sctp->sctp_sctps;
519 
520 	if (inlen < sizeof (*spp)) {
521 		return (EINVAL);
522 	}
523 
524 	retval = sctp_find_peer_fp(sctp, &spp->spp_address, &fp);
525 	if (retval != 0) {
526 		return (retval);
527 	}
528 
529 	if (spp->spp_hbinterval && spp->spp_hbinterval != UINT32_MAX &&
530 	    (spp->spp_hbinterval < sctps->sctps_heartbeat_interval_low ||
531 	    spp->spp_hbinterval > sctps->sctps_heartbeat_interval_high)) {
532 		return (EINVAL);
533 	}
534 	if (spp->spp_pathmaxrxt &&
535 	    (spp->spp_pathmaxrxt < sctps->sctps_pp_max_retr_low ||
536 	    spp->spp_pathmaxrxt > sctps->sctps_pp_max_retr_high)) {
537 		return (EINVAL);
538 	}
539 	if (spp->spp_pathmaxrxt && sctp->sctp_faddrs) {
540 		for (fp2 = sctp->sctp_faddrs; fp2; fp2 = fp2->next) {
541 			if (!fp || fp2 == fp) {
542 				sum += spp->spp_pathmaxrxt;
543 			} else {
544 				sum += fp2->max_retr;
545 			}
546 		}
547 		if (sctp->sctp_pa_max_rxt > sum) {
548 			return (EINVAL);
549 		}
550 	}
551 
552 	now = lbolt64;
553 	if (fp != NULL) {
554 		if (spp->spp_hbinterval == UINT32_MAX) {
555 			/*
556 			 * Send heartbeat immediatelly, don't modify the
557 			 * current setting.
558 			 */
559 			sctp_send_heartbeat(sctp, fp);
560 		} else {
561 			fp->hb_interval = MSEC_TO_TICK(spp->spp_hbinterval);
562 			fp->hb_expiry = now + SET_HB_INTVL(fp);
563 			/*
564 			 * Restart the heartbeat timer using the new intrvl.
565 			 * We need to call sctp_heartbeat_timer() to set
566 			 * the earliest heartbeat expiry time.
567 			 */
568 			sctp_heartbeat_timer(sctp);
569 		}
570 		if (spp->spp_pathmaxrxt) {
571 			fp->max_retr = spp->spp_pathmaxrxt;
572 		}
573 	} else {
574 		for (fp2 = sctp->sctp_faddrs; fp2 != NULL; fp2 = fp2->next) {
575 			if (spp->spp_hbinterval == UINT32_MAX) {
576 				/*
577 				 * Send heartbeat immediatelly, don't modify
578 				 * the current setting.
579 				 */
580 				sctp_send_heartbeat(sctp, fp2);
581 			} else {
582 				fp2->hb_interval = MSEC_TO_TICK(
583 				    spp->spp_hbinterval);
584 				fp2->hb_expiry = now + SET_HB_INTVL(fp2);
585 			}
586 			if (spp->spp_pathmaxrxt) {
587 				fp2->max_retr = spp->spp_pathmaxrxt;
588 			}
589 		}
590 		if (spp->spp_hbinterval != UINT32_MAX) {
591 			sctp->sctp_hb_interval = MSEC_TO_TICK(
592 			    spp->spp_hbinterval);
593 			/* Restart the heartbeat timer using the new intrvl. */
594 			sctp_timer(sctp, sctp->sctp_heartbeat_mp,
595 			    sctp->sctp_hb_interval);
596 		}
597 		if (spp->spp_pathmaxrxt) {
598 			sctp->sctp_pp_max_rxt = spp->spp_pathmaxrxt;
599 		}
600 	}
601 	return (0);
602 }
603 
604 /*
605  * SCTP_DEFAULT_SEND_PARAM
606  */
607 static int
608 sctp_get_def_send_params(sctp_t *sctp, void *ptr)
609 {
610 	struct sctp_sndrcvinfo *sinfo = ptr;
611 
612 	sinfo->sinfo_stream = sctp->sctp_def_stream;
613 	sinfo->sinfo_ssn = 0;
614 	sinfo->sinfo_flags = sctp->sctp_def_flags;
615 	sinfo->sinfo_ppid = sctp->sctp_def_ppid;
616 	sinfo->sinfo_context = sctp->sctp_def_context;
617 	sinfo->sinfo_timetolive = sctp->sctp_def_timetolive;
618 	sinfo->sinfo_tsn = 0;
619 	sinfo->sinfo_cumtsn = 0;
620 
621 	return (sizeof (*sinfo));
622 }
623 
624 static int
625 sctp_set_def_send_params(sctp_t *sctp, const void *invalp, uint_t inlen)
626 {
627 	const struct sctp_sndrcvinfo *sinfo = invalp;
628 
629 	if (inlen < sizeof (*sinfo)) {
630 		return (EINVAL);
631 	}
632 	if (sinfo->sinfo_stream >= sctp->sctp_num_ostr) {
633 		return (EINVAL);
634 	}
635 
636 	sctp->sctp_def_stream = sinfo->sinfo_stream;
637 	sctp->sctp_def_flags = sinfo->sinfo_flags;
638 	sctp->sctp_def_ppid = sinfo->sinfo_ppid;
639 	sctp->sctp_def_context = sinfo->sinfo_context;
640 	sctp->sctp_def_timetolive = sinfo->sinfo_timetolive;
641 
642 	return (0);
643 }
644 
645 static int
646 sctp_set_prim(sctp_t *sctp, const void *invalp, uint_t inlen)
647 {
648 	const struct	sctp_setpeerprim *pp = invalp;
649 	int		retval;
650 	sctp_faddr_t	*fp;
651 
652 	if (inlen < sizeof (*pp)) {
653 		return (EINVAL);
654 	}
655 
656 	retval = sctp_find_peer_fp(sctp, &pp->sspp_addr, &fp);
657 	if (retval)
658 		return (retval);
659 
660 	if (fp == NULL)
661 		return (EINVAL);
662 	if (fp == sctp->sctp_primary)
663 		return (0);
664 	sctp->sctp_primary = fp;
665 
666 	/* Only switch current if fp is alive */
667 	if (fp->state != SCTP_FADDRS_ALIVE || fp == sctp->sctp_current) {
668 		return (0);
669 	}
670 	sctp_set_faddr_current(sctp, fp);
671 
672 	return (0);
673 }
674 
675 /* Handy on off switch for socket option processing. */
676 #define	ONOFF(x)	((x) == 0 ? 0 : 1)
677 
678 /*
679  * SCTP routine to get the values of options.
680  */
681 int
682 sctp_get_opt(sctp_t *sctp, int level, int name, void *ptr, socklen_t *optlen)
683 {
684 	int	*i1 = (int *)ptr;
685 	int	retval = 0;
686 	int	buflen = *optlen;
687 	conn_t		*connp = sctp->sctp_connp;
688 	ip6_pkt_t	*ipp = &sctp->sctp_sticky_ipp;
689 
690 	/* In most cases, the return buffer is just an int */
691 	*optlen = sizeof (int32_t);
692 
693 	RUN_SCTP(sctp);
694 
695 	if (connp->conn_state_flags & CONN_CLOSING) {
696 		WAKE_SCTP(sctp);
697 		return (EINVAL);
698 	}
699 
700 	switch (level) {
701 	case SOL_SOCKET:
702 		switch (name) {
703 		case SO_LINGER:	{
704 			struct linger *lgr = (struct linger *)ptr;
705 
706 			lgr->l_onoff = sctp->sctp_linger ? SO_LINGER : 0;
707 			lgr->l_linger = TICK_TO_MSEC(sctp->sctp_lingertime);
708 			*optlen = sizeof (struct linger);
709 			break;
710 		}
711 		case SO_DEBUG:
712 			*i1 = sctp->sctp_debug ? SO_DEBUG : 0;
713 			break;
714 		case SO_DONTROUTE:
715 			*i1 = connp->conn_dontroute ? SO_DONTROUTE : 0;
716 			break;
717 		case SO_USELOOPBACK:
718 			*i1 = connp->conn_loopback ? SO_USELOOPBACK : 0;
719 			break;
720 		case SO_BROADCAST:
721 			*i1 = connp->conn_broadcast ? SO_BROADCAST : 0;
722 			break;
723 		case SO_REUSEADDR:
724 			*i1 = connp->conn_reuseaddr ? SO_REUSEADDR : 0;
725 			break;
726 		case SO_DGRAM_ERRIND:
727 			*i1 = sctp->sctp_dgram_errind ? SO_DGRAM_ERRIND : 0;
728 			break;
729 		case SO_SNDBUF:
730 			*i1 = sctp->sctp_xmit_hiwater;
731 			break;
732 		case SO_RCVBUF:
733 			*i1 = sctp->sctp_rwnd;
734 			break;
735 		case SO_ALLZONES:
736 			*i1 = connp->conn_allzones;
737 			break;
738 		case SO_MAC_EXEMPT:
739 			*i1 = connp->conn_mac_exempt;
740 			break;
741 		case SO_PROTOTYPE:
742 			*i1 = IPPROTO_SCTP;
743 			break;
744 		case SO_DOMAIN:
745 			*i1 = sctp->sctp_family;
746 			break;
747 		default:
748 			retval = ENOPROTOOPT;
749 			break;
750 		}
751 		break;
752 
753 	case IPPROTO_SCTP:
754 		switch (name) {
755 		case SCTP_RTOINFO:
756 			if (buflen < sizeof (struct sctp_rtoinfo)) {
757 				retval = EINVAL;
758 				break;
759 			}
760 			*optlen = sctp_get_rtoinfo(sctp, ptr);
761 			break;
762 		case SCTP_ASSOCINFO:
763 			if (buflen < sizeof (struct sctp_assocparams)) {
764 				retval = EINVAL;
765 				break;
766 			}
767 			*optlen = sctp_get_assocparams(sctp, ptr);
768 			break;
769 		case SCTP_INITMSG:
770 			if (buflen < sizeof (struct sctp_initmsg)) {
771 				retval = EINVAL;
772 				break;
773 			}
774 			*optlen = sctp_get_initmsg(sctp, ptr);
775 			break;
776 		case SCTP_NODELAY:
777 			*i1 = sctp->sctp_ndelay;
778 			break;
779 		case SCTP_AUTOCLOSE:
780 			*i1 = TICK_TO_SEC(sctp->sctp_autoclose);
781 			break;
782 		case SCTP_ADAPTION_LAYER:
783 			if (buflen < sizeof (struct sctp_setadaption)) {
784 				retval = EINVAL;
785 				break;
786 			}
787 			((struct sctp_setadaption *)ptr)->ssb_adaption_ind =
788 			    sctp->sctp_tx_adaption_code;
789 			break;
790 		case SCTP_PEER_ADDR_PARAMS:
791 			if (buflen < sizeof (struct sctp_paddrparams)) {
792 				retval = EINVAL;
793 				break;
794 			}
795 			*optlen = sctp_get_peer_addr_params(sctp, ptr);
796 			break;
797 		case SCTP_DEFAULT_SEND_PARAM:
798 			if (buflen < sizeof (struct sctp_sndrcvinfo)) {
799 				retval = EINVAL;
800 				break;
801 			}
802 			*optlen = sctp_get_def_send_params(sctp, ptr);
803 			break;
804 		case SCTP_EVENTS: {
805 			struct sctp_event_subscribe *ev;
806 
807 			if (buflen < sizeof (struct sctp_event_subscribe)) {
808 				retval = EINVAL;
809 				break;
810 			}
811 			ev = (struct sctp_event_subscribe *)ptr;
812 			ev->sctp_data_io_event =
813 			    ONOFF(sctp->sctp_recvsndrcvinfo);
814 			ev->sctp_association_event =
815 			    ONOFF(sctp->sctp_recvassocevnt);
816 			ev->sctp_address_event =
817 			    ONOFF(sctp->sctp_recvpathevnt);
818 			ev->sctp_send_failure_event =
819 			    ONOFF(sctp->sctp_recvsendfailevnt);
820 			ev->sctp_peer_error_event =
821 			    ONOFF(sctp->sctp_recvpeererr);
822 			ev->sctp_shutdown_event =
823 			    ONOFF(sctp->sctp_recvshutdownevnt);
824 			ev->sctp_partial_delivery_event =
825 			    ONOFF(sctp->sctp_recvpdevnt);
826 			ev->sctp_adaption_layer_event =
827 			    ONOFF(sctp->sctp_recvalevnt);
828 			*optlen = sizeof (struct sctp_event_subscribe);
829 			break;
830 		}
831 		case SCTP_STATUS:
832 			if (buflen < sizeof (struct sctp_status)) {
833 				retval = EINVAL;
834 				break;
835 			}
836 			*optlen = sctp_get_status(sctp, ptr);
837 			break;
838 		case SCTP_GET_PEER_ADDR_INFO:
839 			if (buflen < sizeof (struct sctp_paddrinfo)) {
840 				retval = EINVAL;
841 				break;
842 			}
843 			retval = sctp_get_paddrinfo(sctp, ptr, optlen);
844 			break;
845 		case SCTP_GET_NLADDRS:
846 			*(int32_t *)ptr = sctp->sctp_nsaddrs;
847 			break;
848 		case SCTP_GET_LADDRS: {
849 			int addr_cnt;
850 			int addr_size;
851 
852 			if (sctp->sctp_family == AF_INET)
853 				addr_size = sizeof (struct sockaddr_in);
854 			else
855 				addr_size = sizeof (struct sockaddr_in6);
856 			addr_cnt = buflen / addr_size;
857 			retval = sctp_getmyaddrs(sctp, ptr, &addr_cnt);
858 			if (retval == 0)
859 				*optlen = addr_cnt * addr_size;
860 			break;
861 		}
862 		case SCTP_GET_NPADDRS: {
863 			int i;
864 			sctp_faddr_t *fp;
865 
866 			for (i = 0, fp = sctp->sctp_faddrs; fp != NULL;
867 			    i++, fp = fp->next)
868 				;
869 			*(int32_t *)ptr = i;
870 			break;
871 		}
872 		case SCTP_GET_PADDRS: {
873 			int addr_cnt;
874 			int addr_size;
875 
876 			if (sctp->sctp_family == AF_INET)
877 				addr_size = sizeof (struct sockaddr_in);
878 			else
879 				addr_size = sizeof (struct sockaddr_in6);
880 			addr_cnt = buflen / addr_size;
881 			retval = sctp_getpeeraddrs(sctp, ptr, &addr_cnt);
882 			if (retval == 0)
883 				*optlen = addr_cnt * addr_size;
884 			break;
885 		}
886 		case SCTP_PRSCTP:
887 			*i1 = sctp->sctp_prsctp_aware ? 1 : 0;
888 			break;
889 		case SCTP_I_WANT_MAPPED_V4_ADDR:
890 		case SCTP_MAXSEG:
891 		case SCTP_DISABLE_FRAGMENTS:
892 			/* Not yet supported. */
893 		default:
894 			retval = ENOPROTOOPT;
895 			break;
896 		}
897 		break;
898 
899 	case IPPROTO_IP:
900 		if (sctp->sctp_family != AF_INET) {
901 			retval = EINVAL;
902 			break;
903 		}
904 		switch (name) {
905 		case IP_OPTIONS:
906 		case T_IP_OPTIONS: {
907 			/*
908 			 * This is compatible with BSD in that in only return
909 			 * the reverse source route with the final destination
910 			 * as the last entry. The first 4 bytes of the option
911 			 * will contain the final destination. Allocate a
912 			 * buffer large enough to hold all the options, we
913 			 * add IP_ADDR_LEN to SCTP_MAX_IP_OPTIONS_LENGTH since
914 			 * ip_opt_get_user() adds the final destination
915 			 * at the start.
916 			 */
917 			char	*opt_ptr;
918 			int	opt_len;
919 			uchar_t	obuf[SCTP_MAX_IP_OPTIONS_LENGTH + IP_ADDR_LEN];
920 
921 			opt_ptr = (char *)sctp->sctp_ipha +
922 			    IP_SIMPLE_HDR_LENGTH;
923 			opt_len = (char *)sctp->sctp_sctph - opt_ptr;
924 			/* Caller ensures enough space */
925 			if (opt_len > 0) {
926 				/*
927 				 * TODO: Do we have to handle getsockopt on an
928 				 * initiator as well?
929 				 */
930 				opt_len = ip_opt_get_user(sctp->sctp_ipha,
931 				    obuf);
932 				ASSERT(opt_len <= sizeof (obuf));
933 			} else {
934 				opt_len = 0;
935 			}
936 			if (buflen < opt_len) {
937 				/* Silently truncate */
938 				opt_len = buflen;
939 			}
940 			*optlen = opt_len;
941 			bcopy(obuf, ptr, opt_len);
942 			break;
943 		}
944 		case IP_TOS:
945 		case T_IP_TOS:
946 			*i1 = (int)sctp->sctp_ipha->ipha_type_of_service;
947 			break;
948 		case IP_TTL:
949 			*i1 = (int)sctp->sctp_ipha->ipha_ttl;
950 			break;
951 		case IP_NEXTHOP:
952 			if (connp->conn_nexthop_set) {
953 				*(ipaddr_t *)ptr = connp->conn_nexthop_v4;
954 				*optlen = sizeof (ipaddr_t);
955 			} else {
956 				*optlen = 0;
957 			}
958 			break;
959 		default:
960 			retval = ENOPROTOOPT;
961 			break;
962 		}
963 		break;
964 	case IPPROTO_IPV6:
965 		if (sctp->sctp_family != AF_INET6) {
966 			retval = EINVAL;
967 			break;
968 		}
969 		switch (name) {
970 		case IPV6_UNICAST_HOPS:
971 			*i1 = (unsigned int) sctp->sctp_ip6h->ip6_hops;
972 			break;	/* goto sizeof (int) option return */
973 		case IPV6_RECVPKTINFO:
974 			if (sctp->sctp_ipv6_recvancillary &
975 			    SCTP_IPV6_RECVPKTINFO) {
976 				*i1 = 1;
977 			} else {
978 				*i1 = 0;
979 			}
980 			break;	/* goto sizeof (int) option return */
981 		case IPV6_RECVHOPLIMIT:
982 			if (sctp->sctp_ipv6_recvancillary &
983 			    SCTP_IPV6_RECVHOPLIMIT) {
984 				*i1 = 1;
985 			} else {
986 				*i1 = 0;
987 			}
988 			break;	/* goto sizeof (int) option return */
989 		case IPV6_RECVHOPOPTS:
990 			if (sctp->sctp_ipv6_recvancillary &
991 			    SCTP_IPV6_RECVHOPOPTS) {
992 				*i1 = 1;
993 			} else {
994 				*i1 = 0;
995 			}
996 			break;	/* goto sizeof (int) option return */
997 		case IPV6_RECVDSTOPTS:
998 			if (sctp->sctp_ipv6_recvancillary &
999 			    SCTP_IPV6_RECVDSTOPTS) {
1000 				*i1 = 1;
1001 			} else {
1002 				*i1 = 0;
1003 			}
1004 			break;	/* goto sizeof (int) option return */
1005 		case IPV6_RECVRTHDR:
1006 			if (sctp->sctp_ipv6_recvancillary &
1007 			    SCTP_IPV6_RECVRTHDR) {
1008 				*i1 = 1;
1009 			} else {
1010 				*i1 = 0;
1011 			}
1012 			break;	/* goto sizeof (int) option return */
1013 		case IPV6_RECVRTHDRDSTOPTS:
1014 			if (sctp->sctp_ipv6_recvancillary &
1015 			    SCTP_IPV6_RECVRTDSTOPTS) {
1016 				*i1 = 1;
1017 			} else {
1018 				*i1 = 0;
1019 			}
1020 			break;	/* goto sizeof (int) option return */
1021 		case IPV6_PKTINFO: {
1022 			struct in6_pktinfo *pkti;
1023 
1024 			if (buflen < sizeof (struct in6_pktinfo)) {
1025 				retval = EINVAL;
1026 				break;
1027 			}
1028 			pkti = (struct in6_pktinfo *)ptr;
1029 			if (ipp->ipp_fields & IPPF_IFINDEX)
1030 				pkti->ipi6_ifindex = ipp->ipp_ifindex;
1031 			else
1032 				pkti->ipi6_ifindex = 0;
1033 			if (ipp->ipp_fields & IPPF_ADDR)
1034 				pkti->ipi6_addr = ipp->ipp_addr;
1035 			else
1036 				pkti->ipi6_addr = ipv6_all_zeros;
1037 			*optlen = sizeof (struct in6_pktinfo);
1038 			break;
1039 		}
1040 		case IPV6_NEXTHOP: {
1041 			sin6_t *sin6;
1042 
1043 			if (buflen < sizeof (sin6_t)) {
1044 				retval = EINVAL;
1045 				break;
1046 			}
1047 			sin6 = (sin6_t *)ptr;
1048 			if (!(ipp->ipp_fields & IPPF_NEXTHOP))
1049 				break;
1050 			*sin6 = sctp_sin6_null;
1051 			sin6->sin6_family = AF_INET6;
1052 			sin6->sin6_addr = ipp->ipp_nexthop;
1053 			*optlen = sizeof (sin6_t);
1054 			break;
1055 		}
1056 		case IPV6_HOPOPTS: {
1057 			int len;
1058 
1059 			if (!(ipp->ipp_fields & IPPF_HOPOPTS))
1060 				break;
1061 			len = ipp->ipp_hopoptslen - sctp->sctp_v6label_len;
1062 			if (len <= 0)
1063 				break;
1064 			if (buflen < len) {
1065 				retval = EINVAL;
1066 				break;
1067 			}
1068 			bcopy((char *)ipp->ipp_hopopts +
1069 			    sctp->sctp_v6label_len, ptr, len);
1070 			if (sctp->sctp_v6label_len > 0) {
1071 				char *cptr = ptr;
1072 
1073 				/*
1074 				 * If the label length is greater than zero,
1075 				 * then we need to hide the label from user.
1076 				 * Make it look as though a normal Hop-By-Hop
1077 				 * Options Header is present here.
1078 				 */
1079 				cptr[0] = ((char *)ipp->ipp_hopopts)[0];
1080 				cptr[1] = (len + 7) / 8 - 1;
1081 			}
1082 			*optlen = len;
1083 			break;
1084 		}
1085 		case IPV6_RTHDRDSTOPTS:
1086 			if (!(ipp->ipp_fields & IPPF_RTDSTOPTS))
1087 				break;
1088 			if (buflen < ipp->ipp_rtdstoptslen) {
1089 				retval = EINVAL;
1090 				break;
1091 			}
1092 			bcopy(ipp->ipp_rtdstopts, ptr, ipp->ipp_rtdstoptslen);
1093 			*optlen  = ipp->ipp_rtdstoptslen;
1094 			break;
1095 		case IPV6_RTHDR:
1096 			if (!(ipp->ipp_fields & IPPF_RTHDR))
1097 				break;
1098 			if (buflen < ipp->ipp_rthdrlen) {
1099 				retval = EINVAL;
1100 				break;
1101 			}
1102 			bcopy(ipp->ipp_rthdr, ptr, ipp->ipp_rthdrlen);
1103 			*optlen = ipp->ipp_rthdrlen;
1104 			break;
1105 		case IPV6_DSTOPTS:
1106 			if (!(ipp->ipp_fields & IPPF_DSTOPTS))
1107 				break;
1108 			if (buflen < ipp->ipp_dstoptslen) {
1109 				retval = EINVAL;
1110 				break;
1111 			}
1112 			bcopy(ipp->ipp_dstopts, ptr, ipp->ipp_dstoptslen);
1113 			*optlen  = ipp->ipp_dstoptslen;
1114 			break;
1115 		case IPV6_V6ONLY:
1116 			*i1 = sctp->sctp_connp->conn_ipv6_v6only;
1117 			break;
1118 		default:
1119 			retval = ENOPROTOOPT;
1120 			break;
1121 		}
1122 		break;
1123 
1124 	default:
1125 		retval = ENOPROTOOPT;
1126 		break;
1127 	}
1128 	WAKE_SCTP(sctp);
1129 	return (retval);
1130 }
1131 
1132 int
1133 sctp_set_opt(sctp_t *sctp, int level, int name, const void *invalp,
1134     socklen_t inlen)
1135 {
1136 	ip6_pkt_t	*ipp = &sctp->sctp_sticky_ipp;
1137 	int		*i1 = (int *)invalp;
1138 	boolean_t	onoff;
1139 	int		retval = 0, addrcnt;
1140 	conn_t		*connp = sctp->sctp_connp;
1141 	sctp_stack_t	*sctps = sctp->sctp_sctps;
1142 
1143 	/* In all cases, the size of the option must be bigger than int */
1144 	if (inlen >= sizeof (int32_t)) {
1145 		onoff = ONOFF(*i1);
1146 	}
1147 	retval = 0;
1148 
1149 	RUN_SCTP(sctp);
1150 
1151 	if (connp->conn_state_flags & CONN_CLOSING) {
1152 		WAKE_SCTP(sctp);
1153 		return (EINVAL);
1154 	}
1155 
1156 	switch (level) {
1157 	case SOL_SOCKET:
1158 		if (inlen < sizeof (int32_t)) {
1159 			retval = EINVAL;
1160 			break;
1161 		}
1162 		switch (name) {
1163 		case SO_LINGER: {
1164 			struct linger *lgr;
1165 
1166 			if (inlen != sizeof (struct linger)) {
1167 				retval = EINVAL;
1168 				break;
1169 			}
1170 			lgr = (struct linger *)invalp;
1171 			if (lgr->l_onoff != 0) {
1172 				sctp->sctp_linger = 1;
1173 				sctp->sctp_lingertime = MSEC_TO_TICK(
1174 				    lgr->l_linger);
1175 			} else {
1176 				sctp->sctp_linger = 0;
1177 				sctp->sctp_lingertime = 0;
1178 			}
1179 			break;
1180 		}
1181 		case SO_DEBUG:
1182 			sctp->sctp_debug = onoff;
1183 			break;
1184 		case SO_KEEPALIVE:
1185 			break;
1186 		case SO_DONTROUTE:
1187 			/*
1188 			 * SO_DONTROUTE, SO_USELOOPBACK and SO_BROADCAST are
1189 			 * only of interest to IP.
1190 			 */
1191 			connp->conn_dontroute = onoff;
1192 			break;
1193 		case SO_USELOOPBACK:
1194 			connp->conn_loopback = onoff;
1195 			break;
1196 		case SO_BROADCAST:
1197 			connp->conn_broadcast = onoff;
1198 			break;
1199 		case SO_REUSEADDR:
1200 			connp->conn_reuseaddr = onoff;
1201 			break;
1202 		case SO_DGRAM_ERRIND:
1203 			sctp->sctp_dgram_errind = onoff;
1204 			break;
1205 		case SO_SNDBUF:
1206 			if (*i1 > sctps->sctps_max_buf) {
1207 				retval = ENOBUFS;
1208 				break;
1209 			}
1210 			if (*i1 < 0) {
1211 				retval = EINVAL;
1212 				break;
1213 			}
1214 			sctp->sctp_xmit_hiwater = *i1;
1215 			if (sctps->sctps_snd_lowat_fraction != 0)
1216 				sctp->sctp_xmit_lowater =
1217 				    sctp->sctp_xmit_hiwater /
1218 				    sctps->sctps_snd_lowat_fraction;
1219 			break;
1220 		case SO_RCVBUF:
1221 			if (*i1 > sctps->sctps_max_buf) {
1222 				retval = ENOBUFS;
1223 				break;
1224 			}
1225 			/* Silently ignore zero */
1226 			if (*i1 != 0) {
1227 				/*
1228 				 * Insist on a receive window that is at least
1229 				 * sctp_recv_hiwat_minmss * MSS (default 4*MSS)
1230 				 * to avoid funny interactions of Nagle
1231 				 * algorithm, SWS avoidance and delayed
1232 				 * acknowledgement.
1233 				 */
1234 				*i1 = MAX(*i1,
1235 				    sctps->sctps_recv_hiwat_minmss *
1236 				    sctp->sctp_mss);
1237 				sctp->sctp_rwnd = *i1;
1238 				sctp->sctp_irwnd = sctp->sctp_rwnd;
1239 				sctp->sctp_pd_point = sctp->sctp_rwnd;
1240 			}
1241 			/*
1242 			 * XXX should we return the rwnd here
1243 			 * and sctp_opt_get ?
1244 			 */
1245 			break;
1246 		case SO_ALLZONES:
1247 			if (secpolicy_ip(sctp->sctp_credp, OP_CONFIG,
1248 			    B_TRUE)) {
1249 				retval = EACCES;
1250 				break;
1251 			}
1252 			if (sctp->sctp_state >= SCTPS_BOUND) {
1253 				retval = EINVAL;
1254 				break;
1255 			}
1256 			sctp->sctp_allzones = onoff;
1257 			break;
1258 		case SO_MAC_EXEMPT:
1259 			if (secpolicy_net_mac_aware(sctp->sctp_credp) != 0) {
1260 				retval = EACCES;
1261 				break;
1262 			}
1263 			if (sctp->sctp_state >= SCTPS_BOUND) {
1264 				retval = EINVAL;
1265 				break;
1266 			}
1267 			connp->conn_mac_exempt = onoff;
1268 			break;
1269 		default:
1270 			retval = ENOPROTOOPT;
1271 			break;
1272 		}
1273 		break;
1274 
1275 	case IPPROTO_SCTP:
1276 		if (inlen < sizeof (int32_t)) {
1277 			retval = EINVAL;
1278 			break;
1279 		}
1280 		switch (name) {
1281 		case SCTP_RTOINFO:
1282 			retval = sctp_set_rtoinfo(sctp, invalp, inlen);
1283 			break;
1284 		case SCTP_ASSOCINFO:
1285 			retval = sctp_set_assocparams(sctp, invalp, inlen);
1286 			break;
1287 		case SCTP_INITMSG:
1288 			retval = sctp_set_initmsg(sctp, invalp, inlen);
1289 			break;
1290 		case SCTP_NODELAY:
1291 			sctp->sctp_ndelay = ONOFF(*i1);
1292 			break;
1293 		case SCTP_AUTOCLOSE:
1294 			if (SEC_TO_TICK(*i1) < 0) {
1295 				retval = EINVAL;
1296 				break;
1297 			}
1298 			/* Convert the number of seconds to ticks. */
1299 			sctp->sctp_autoclose = SEC_TO_TICK(*i1);
1300 			sctp_heartbeat_timer(sctp);
1301 			break;
1302 		case SCTP_SET_PEER_PRIMARY_ADDR:
1303 			retval = sctp_set_peerprim(sctp, invalp, inlen);
1304 			break;
1305 		case SCTP_PRIMARY_ADDR:
1306 			retval = sctp_set_prim(sctp, invalp, inlen);
1307 			break;
1308 		case SCTP_ADAPTION_LAYER: {
1309 			struct sctp_setadaption *ssb;
1310 
1311 			if (inlen < sizeof (struct sctp_setadaption)) {
1312 				retval = EINVAL;
1313 				break;
1314 			}
1315 			ssb = (struct sctp_setadaption *)invalp;
1316 			sctp->sctp_send_adaption = 1;
1317 			sctp->sctp_tx_adaption_code = ssb->ssb_adaption_ind;
1318 			break;
1319 		}
1320 		case SCTP_PEER_ADDR_PARAMS:
1321 			retval = sctp_set_peer_addr_params(sctp, invalp,
1322 			    inlen);
1323 			break;
1324 		case SCTP_DEFAULT_SEND_PARAM:
1325 			retval = sctp_set_def_send_params(sctp, invalp, inlen);
1326 			break;
1327 		case SCTP_EVENTS: {
1328 			struct sctp_event_subscribe *ev;
1329 
1330 			if (inlen < sizeof (struct sctp_event_subscribe)) {
1331 				retval = EINVAL;
1332 				break;
1333 			}
1334 			ev = (struct sctp_event_subscribe *)invalp;
1335 			sctp->sctp_recvsndrcvinfo =
1336 			    ONOFF(ev->sctp_data_io_event);
1337 			sctp->sctp_recvassocevnt =
1338 			    ONOFF(ev->sctp_association_event);
1339 			sctp->sctp_recvpathevnt =
1340 			    ONOFF(ev->sctp_address_event);
1341 			sctp->sctp_recvsendfailevnt =
1342 			    ONOFF(ev->sctp_send_failure_event);
1343 			sctp->sctp_recvpeererr =
1344 			    ONOFF(ev->sctp_peer_error_event);
1345 			sctp->sctp_recvshutdownevnt =
1346 			    ONOFF(ev->sctp_shutdown_event);
1347 			sctp->sctp_recvpdevnt =
1348 			    ONOFF(ev->sctp_partial_delivery_event);
1349 			sctp->sctp_recvalevnt =
1350 			    ONOFF(ev->sctp_adaption_layer_event);
1351 			break;
1352 		}
1353 		case SCTP_ADD_ADDR:
1354 		case SCTP_REM_ADDR:
1355 			/*
1356 			 * The sctp_t has to be bound first before
1357 			 * the address list can be changed.
1358 			 */
1359 			if (sctp->sctp_state < SCTPS_BOUND) {
1360 				retval = EINVAL;
1361 				break;
1362 			}
1363 			if (sctp->sctp_family == AF_INET) {
1364 				addrcnt = inlen / sizeof (struct sockaddr_in);
1365 			} else {
1366 				ASSERT(sctp->sctp_family == AF_INET6);
1367 				addrcnt = inlen / sizeof (struct sockaddr_in6);
1368 			}
1369 			if (name == SCTP_ADD_ADDR) {
1370 				retval = sctp_bind_add(sctp, invalp, addrcnt,
1371 				    B_TRUE, sctp->sctp_lport);
1372 			} else {
1373 				retval = sctp_bind_del(sctp, invalp, addrcnt,
1374 				    B_TRUE);
1375 			}
1376 			break;
1377 		case SCTP_UC_SWAP: {
1378 			struct sctp_uc_swap *us;
1379 
1380 			/*
1381 			 * Change handle & upcalls.
1382 			 */
1383 			if (inlen < sizeof (*us)) {
1384 				retval = EINVAL;
1385 				break;
1386 			}
1387 			us = (struct sctp_uc_swap *)invalp;
1388 			sctp->sctp_ulpd = us->sus_handle;
1389 			bcopy(us->sus_upcalls, &sctp->sctp_upcalls,
1390 			    sizeof (sctp_upcalls_t));
1391 			break;
1392 		}
1393 		case SCTP_PRSCTP:
1394 			sctp->sctp_prsctp_aware = onoff;
1395 			break;
1396 		case SCTP_I_WANT_MAPPED_V4_ADDR:
1397 		case SCTP_MAXSEG:
1398 		case SCTP_DISABLE_FRAGMENTS:
1399 			/* Not yet supported. */
1400 		default:
1401 			retval = ENOPROTOOPT;
1402 			break;
1403 		}
1404 		break;
1405 
1406 	case IPPROTO_IP:
1407 		if (sctp->sctp_family != AF_INET) {
1408 			retval = ENOPROTOOPT;
1409 			break;
1410 		}
1411 		if ((name != IP_OPTIONS) && (inlen < sizeof (int32_t))) {
1412 			retval = EINVAL;
1413 			break;
1414 		}
1415 		switch (name) {
1416 		case IP_OPTIONS:
1417 		case T_IP_OPTIONS:
1418 			retval = sctp_opt_set_header(sctp, invalp, inlen);
1419 			break;
1420 		case IP_TOS:
1421 		case T_IP_TOS:
1422 			sctp->sctp_ipha->ipha_type_of_service = (uchar_t)*i1;
1423 			break;
1424 		case IP_TTL:
1425 			sctp->sctp_ipha->ipha_ttl = (uchar_t)*i1;
1426 			break;
1427 		case IP_SEC_OPT:
1428 			/*
1429 			 * We should not allow policy setting after
1430 			 * we start listening for connections.
1431 			 */
1432 			if (sctp->sctp_state >= SCTPS_LISTEN) {
1433 				retval = EINVAL;
1434 			} else {
1435 				retval = ipsec_set_req(sctp->sctp_credp,
1436 				    sctp->sctp_connp, (ipsec_req_t *)invalp);
1437 			}
1438 			break;
1439 		/* IP level options */
1440 		case IP_RECVIF:
1441 			connp->conn_recvif = onoff;
1442 			break;
1443 		case IP_RECVSLLA:
1444 			connp->conn_recvslla = onoff;
1445 			break;
1446 		case IP_UNSPEC_SRC:
1447 			connp->conn_unspec_src = onoff;
1448 			break;
1449 		case IP_NEXTHOP: {
1450 			ipaddr_t addr = *i1;
1451 			ipif_t *ipif = NULL;
1452 			ill_t *ill;
1453 			ip_stack_t *ipst = sctps->sctps_netstack->netstack_ip;
1454 
1455 			if (secpolicy_ip(sctp->sctp_credp, OP_CONFIG,
1456 			    B_TRUE) == 0) {
1457 				ipif = ipif_lookup_onlink_addr(addr,
1458 				    connp->conn_zoneid, ipst);
1459 				if (ipif == NULL) {
1460 					retval = EHOSTUNREACH;
1461 					break;
1462 				}
1463 				ill = ipif->ipif_ill;
1464 				mutex_enter(&ill->ill_lock);
1465 				if ((ill->ill_state_flags & ILL_CONDEMNED) ||
1466 				    (ipif->ipif_state_flags & IPIF_CONDEMNED)) {
1467 					mutex_exit(&ill->ill_lock);
1468 					ipif_refrele(ipif);
1469 					retval =  EHOSTUNREACH;
1470 					break;
1471 				}
1472 				mutex_exit(&ill->ill_lock);
1473 				ipif_refrele(ipif);
1474 				mutex_enter(&connp->conn_lock);
1475 				connp->conn_nexthop_v4 = addr;
1476 				connp->conn_nexthop_set = B_TRUE;
1477 				mutex_exit(&connp->conn_lock);
1478 			}
1479 			break;
1480 		}
1481 		default:
1482 			retval = ENOPROTOOPT;
1483 			break;
1484 		}
1485 		break;
1486 	case IPPROTO_IPV6: {
1487 		if (sctp->sctp_family != AF_INET6) {
1488 			retval = ENOPROTOOPT;
1489 			break;
1490 		}
1491 
1492 		switch (name) {
1493 		case IPV6_UNICAST_HOPS:
1494 			if (inlen < sizeof (int32_t)) {
1495 				retval = EINVAL;
1496 				break;
1497 			}
1498 			if (*i1 < -1 || *i1 > IPV6_MAX_HOPS) {
1499 				retval = EINVAL;
1500 				break;
1501 			}
1502 			if (*i1 == -1) {
1503 				ipp->ipp_unicast_hops =
1504 				    sctps->sctps_ipv6_hoplimit;
1505 				ipp->ipp_fields &= ~IPPF_UNICAST_HOPS;
1506 			} else {
1507 				ipp->ipp_unicast_hops = (uint8_t)*i1;
1508 				ipp->ipp_fields |= IPPF_UNICAST_HOPS;
1509 			}
1510 			retval = sctp_build_hdrs(sctp);
1511 			break;
1512 		case IPV6_UNSPEC_SRC:
1513 			if (inlen < sizeof (int32_t)) {
1514 				retval = EINVAL;
1515 				break;
1516 			}
1517 			connp->conn_unspec_src = onoff;
1518 			break;
1519 		case IPV6_RECVPKTINFO:
1520 			if (inlen < sizeof (int32_t)) {
1521 				retval = EINVAL;
1522 				break;
1523 			}
1524 			if (onoff)
1525 				sctp->sctp_ipv6_recvancillary |=
1526 				    SCTP_IPV6_RECVPKTINFO;
1527 			else
1528 				sctp->sctp_ipv6_recvancillary &=
1529 				    ~SCTP_IPV6_RECVPKTINFO;
1530 			/* Send it with the next msg */
1531 			sctp->sctp_recvifindex = 0;
1532 			connp->conn_ip_recvpktinfo = onoff;
1533 			break;
1534 		case IPV6_RECVHOPLIMIT:
1535 			if (inlen < sizeof (int32_t)) {
1536 				retval = EINVAL;
1537 				break;
1538 			}
1539 			if (onoff)
1540 				sctp->sctp_ipv6_recvancillary |=
1541 				    SCTP_IPV6_RECVHOPLIMIT;
1542 			else
1543 				sctp->sctp_ipv6_recvancillary &=
1544 				    ~SCTP_IPV6_RECVHOPLIMIT;
1545 			sctp->sctp_recvhops = 0xffffffffU;
1546 			connp->conn_ipv6_recvhoplimit = onoff;
1547 			break;
1548 		case IPV6_RECVHOPOPTS:
1549 			if (inlen < sizeof (int32_t)) {
1550 				retval = EINVAL;
1551 				break;
1552 			}
1553 			if (onoff)
1554 				sctp->sctp_ipv6_recvancillary |=
1555 				    SCTP_IPV6_RECVHOPOPTS;
1556 			else
1557 				sctp->sctp_ipv6_recvancillary &=
1558 				    ~SCTP_IPV6_RECVHOPOPTS;
1559 			connp->conn_ipv6_recvhopopts = onoff;
1560 			break;
1561 		case IPV6_RECVDSTOPTS:
1562 			if (inlen < sizeof (int32_t)) {
1563 				retval = EINVAL;
1564 				break;
1565 			}
1566 			if (onoff)
1567 				sctp->sctp_ipv6_recvancillary |=
1568 				    SCTP_IPV6_RECVDSTOPTS;
1569 			else
1570 				sctp->sctp_ipv6_recvancillary &=
1571 				    ~SCTP_IPV6_RECVDSTOPTS;
1572 			connp->conn_ipv6_recvdstopts = onoff;
1573 			break;
1574 		case IPV6_RECVRTHDR:
1575 			if (inlen < sizeof (int32_t)) {
1576 				retval = EINVAL;
1577 				break;
1578 			}
1579 			if (onoff)
1580 				sctp->sctp_ipv6_recvancillary |=
1581 				    SCTP_IPV6_RECVRTHDR;
1582 			else
1583 				sctp->sctp_ipv6_recvancillary &=
1584 				    ~SCTP_IPV6_RECVRTHDR;
1585 			connp->conn_ipv6_recvrthdr = onoff;
1586 			break;
1587 		case IPV6_RECVRTHDRDSTOPTS:
1588 			if (inlen < sizeof (int32_t)) {
1589 				retval = EINVAL;
1590 				break;
1591 			}
1592 			if (onoff)
1593 				sctp->sctp_ipv6_recvancillary |=
1594 				    SCTP_IPV6_RECVRTDSTOPTS;
1595 			else
1596 				sctp->sctp_ipv6_recvancillary &=
1597 				    ~SCTP_IPV6_RECVRTDSTOPTS;
1598 			connp->conn_ipv6_recvrtdstopts = onoff;
1599 			break;
1600 		case IPV6_PKTINFO:
1601 			if (inlen != 0 &&
1602 			    inlen != sizeof (struct in6_pktinfo)) {
1603 				retval = EINVAL;
1604 				break;
1605 			}
1606 
1607 			if (inlen == 0) {
1608 				ipp->ipp_fields &= ~(IPPF_IFINDEX |IPPF_ADDR);
1609 			} else  {
1610 				struct in6_pktinfo *pkti;
1611 
1612 				pkti = (struct in6_pktinfo *)invalp;
1613 				/* XXX Need to check if the index exists */
1614 				ipp->ipp_ifindex = pkti->ipi6_ifindex;
1615 				ipp->ipp_addr = pkti->ipi6_addr;
1616 				if (ipp->ipp_ifindex != 0)
1617 					ipp->ipp_fields |= IPPF_IFINDEX;
1618 				else
1619 					ipp->ipp_fields &= ~IPPF_IFINDEX;
1620 				if (!IN6_IS_ADDR_UNSPECIFIED(&ipp->ipp_addr))
1621 					ipp->ipp_fields |= IPPF_ADDR;
1622 				else
1623 					ipp->ipp_fields &= ~IPPF_ADDR;
1624 			}
1625 			retval = sctp_build_hdrs(sctp);
1626 			break;
1627 		case IPV6_NEXTHOP: {
1628 			struct sockaddr_in6 *sin6;
1629 			ip_stack_t *ipst = sctps->sctps_netstack->netstack_ip;
1630 
1631 			if (inlen != 0 && inlen != sizeof (sin6_t)) {
1632 				retval = EINVAL;
1633 				break;
1634 			}
1635 
1636 			if (inlen == 0) {
1637 				ipp->ipp_fields &= ~IPPF_NEXTHOP;
1638 			} else {
1639 				sin6 = (struct sockaddr_in6 *)invalp;
1640 				if (sin6->sin6_family != AF_INET6) {
1641 					retval = EAFNOSUPPORT;
1642 					break;
1643 				}
1644 				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1645 					retval = EADDRNOTAVAIL;
1646 					break;
1647 				}
1648 				ipp->ipp_nexthop = sin6->sin6_addr;
1649 				if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1650 					ipp->ipp_fields &= ~IPPF_NEXTHOP;
1651 				} else {
1652 					ire_t	*ire;
1653 
1654 					ire = ire_route_lookup_v6(
1655 					    &sin6->sin6_addr, NULL, NULL, 0,
1656 					    NULL, NULL, ALL_ZONES, NULL,
1657 					    MATCH_IRE_DEFAULT, ipst);
1658 					if (ire == NULL) {
1659 						retval = EHOSTUNREACH;
1660 						break;
1661 					}
1662 					ire_refrele(ire);
1663 					ipp->ipp_fields |= IPPF_NEXTHOP;
1664 				}
1665 			}
1666 			retval = sctp_build_hdrs(sctp);
1667 			break;
1668 		}
1669 		case IPV6_HOPOPTS: {
1670 			ip6_hbh_t *hopts = (ip6_hbh_t *)invalp;
1671 
1672 			if (inlen != 0 &&
1673 			    inlen != (8 * (hopts->ip6h_len + 1))) {
1674 				retval = EINVAL;
1675 				break;
1676 			}
1677 
1678 			retval = optcom_pkt_set((uchar_t *)invalp, inlen,
1679 			    B_TRUE, (uchar_t **)&ipp->ipp_hopopts,
1680 			    &ipp->ipp_hopoptslen, sctp->sctp_v6label_len);
1681 			if (retval != 0)
1682 				break;
1683 			if (ipp->ipp_hopoptslen == 0)
1684 				ipp->ipp_fields &= ~IPPF_HOPOPTS;
1685 			else
1686 				ipp->ipp_fields |= IPPF_HOPOPTS;
1687 			retval = sctp_build_hdrs(sctp);
1688 			break;
1689 		}
1690 		case IPV6_RTHDRDSTOPTS: {
1691 			ip6_dest_t *dopts = (ip6_dest_t *)invalp;
1692 
1693 			if (inlen != 0 &&
1694 			    inlen != (8 * (dopts->ip6d_len + 1))) {
1695 				retval = EINVAL;
1696 				break;
1697 			}
1698 
1699 			retval = optcom_pkt_set((uchar_t *)invalp, inlen,
1700 			    B_TRUE, (uchar_t **)&ipp->ipp_rtdstopts,
1701 			    &ipp->ipp_rtdstoptslen, 0);
1702 			if (retval != 0)
1703 				break;
1704 			if (ipp->ipp_rtdstoptslen == 0)
1705 				ipp->ipp_fields &= ~IPPF_RTDSTOPTS;
1706 			else
1707 				ipp->ipp_fields |= IPPF_RTDSTOPTS;
1708 			retval = sctp_build_hdrs(sctp);
1709 			break;
1710 		}
1711 		case IPV6_DSTOPTS: {
1712 			ip6_dest_t *dopts = (ip6_dest_t *)invalp;
1713 
1714 			if (inlen != 0 &&
1715 			    inlen != (8 * (dopts->ip6d_len + 1))) {
1716 				retval = EINVAL;
1717 				break;
1718 			}
1719 
1720 			retval = optcom_pkt_set((uchar_t *)invalp, inlen,
1721 			    B_TRUE, (uchar_t **)&ipp->ipp_dstopts,
1722 			    &ipp->ipp_dstoptslen, 0);
1723 			if (retval != 0)
1724 				break;
1725 			if (ipp->ipp_dstoptslen == 0)
1726 				ipp->ipp_fields &= ~IPPF_DSTOPTS;
1727 			else
1728 				ipp->ipp_fields |= IPPF_DSTOPTS;
1729 			retval = sctp_build_hdrs(sctp);
1730 			break;
1731 		}
1732 		case IPV6_RTHDR: {
1733 			ip6_rthdr_t *rt = (ip6_rthdr_t *)invalp;
1734 
1735 			if (inlen != 0 &&
1736 			    inlen != (8 * (rt->ip6r_len + 1))) {
1737 				retval = EINVAL;
1738 				break;
1739 			}
1740 
1741 			retval = optcom_pkt_set((uchar_t *)invalp, inlen,
1742 			    B_TRUE, (uchar_t **)&ipp->ipp_rthdr,
1743 			    &ipp->ipp_rthdrlen, 0);
1744 			if (retval != 0)
1745 				break;
1746 			if (ipp->ipp_rthdrlen == 0)
1747 				ipp->ipp_fields &= ~IPPF_RTHDR;
1748 			else
1749 				ipp->ipp_fields |= IPPF_RTHDR;
1750 			retval = sctp_build_hdrs(sctp);
1751 			break;
1752 		}
1753 		case IPV6_SEC_OPT:
1754 			/*
1755 			 * We should not allow policy setting after
1756 			 * we start listening for connections.
1757 			 */
1758 			if (sctp->sctp_state >= SCTPS_LISTEN) {
1759 				retval = EINVAL;
1760 			} else {
1761 				retval = ipsec_set_req(sctp->sctp_credp,
1762 				    sctp->sctp_connp, (ipsec_req_t *)invalp);
1763 			}
1764 			break;
1765 		case IPV6_V6ONLY:
1766 			/*
1767 			 * After the bound state, setting the v6only option
1768 			 * is too late.
1769 			 */
1770 			if (sctp->sctp_state >= SCTPS_BOUND) {
1771 				retval = EINVAL;
1772 			} else {
1773 				sctp->sctp_connp->conn_ipv6_v6only = onoff;
1774 			}
1775 			break;
1776 		default:
1777 			retval = ENOPROTOOPT;
1778 			break;
1779 		}
1780 		break;
1781 	}
1782 	default:
1783 		retval = ENOPROTOOPT;
1784 		break;
1785 	}
1786 
1787 	WAKE_SCTP(sctp);
1788 	return (retval);
1789 }
1790 
1791 /*
1792  * SCTP exported kernel interface for geting the first source address of
1793  * a sctp_t.  The parameter addr is assumed to have enough space to hold
1794  * one socket address.
1795  */
1796 int
1797 sctp_getsockname(sctp_t *sctp, struct sockaddr *addr, socklen_t *addrlen)
1798 {
1799 	int	err = 0;
1800 	int	addrcnt = 1;
1801 	sin_t	*sin4;
1802 	sin6_t	*sin6;
1803 
1804 	ASSERT(sctp != NULL);
1805 
1806 	RUN_SCTP(sctp);
1807 	addr->sa_family = sctp->sctp_family;
1808 	switch (sctp->sctp_family) {
1809 	case AF_INET:
1810 		sin4 = (sin_t *)addr;
1811 		if ((sctp->sctp_state <= SCTPS_LISTEN) &&
1812 		    sctp->sctp_bound_to_all) {
1813 			sin4->sin_addr.s_addr = INADDR_ANY;
1814 			sin4->sin_port = sctp->sctp_lport;
1815 		} else {
1816 			err = sctp_getmyaddrs(sctp, sin4, &addrcnt);
1817 			if (err != 0) {
1818 				*addrlen = 0;
1819 				break;
1820 			}
1821 		}
1822 		*addrlen = sizeof (struct sockaddr_in);
1823 		break;
1824 	case AF_INET6:
1825 		sin6 = (sin6_t *)addr;
1826 		if ((sctp->sctp_state <= SCTPS_LISTEN) &&
1827 		    sctp->sctp_bound_to_all) {
1828 			bzero(&sin6->sin6_addr, sizeof (sin6->sin6_addr));
1829 			sin6->sin6_port = sctp->sctp_lport;
1830 		} else {
1831 			err = sctp_getmyaddrs(sctp, sin6, &addrcnt);
1832 			if (err != 0) {
1833 				*addrlen = 0;
1834 				break;
1835 			}
1836 		}
1837 		*addrlen = sizeof (struct sockaddr_in6);
1838 		sin6->sin6_flowinfo = sctp->sctp_ip6h->ip6_vcf &
1839 		    ~IPV6_VERS_AND_FLOW_MASK;
1840 		sin6->sin6_scope_id = 0;
1841 		sin6->__sin6_src_id = 0;
1842 		break;
1843 	}
1844 	WAKE_SCTP(sctp);
1845 	return (err);
1846 }
1847 
1848 /*
1849  * SCTP exported kernel interface for geting the primary peer address of
1850  * a sctp_t.  The parameter addr is assumed to have enough space to hold
1851  * one socket address.
1852  */
1853 int
1854 sctp_getpeername(sctp_t *sctp, struct sockaddr *addr, socklen_t *addrlen)
1855 {
1856 	int	err = 0;
1857 	int	addrcnt = 1;
1858 	sin6_t	*sin6;
1859 
1860 	ASSERT(sctp != NULL);
1861 
1862 	RUN_SCTP(sctp);
1863 	addr->sa_family = sctp->sctp_family;
1864 	switch (sctp->sctp_family) {
1865 	case AF_INET:
1866 		err = sctp_getpeeraddrs(sctp, addr, &addrcnt);
1867 		if (err != 0) {
1868 			*addrlen = 0;
1869 			break;
1870 		}
1871 		*addrlen = sizeof (struct sockaddr_in);
1872 		break;
1873 	case AF_INET6:
1874 		sin6 = (sin6_t *)addr;
1875 		err = sctp_getpeeraddrs(sctp, sin6, &addrcnt);
1876 		if (err != 0) {
1877 			*addrlen = 0;
1878 			break;
1879 		}
1880 		*addrlen = sizeof (struct sockaddr_in6);
1881 		sin6->sin6_flowinfo = 0;
1882 		sin6->sin6_scope_id = 0;
1883 		sin6->__sin6_src_id = 0;
1884 		break;
1885 	}
1886 	WAKE_SCTP(sctp);
1887 	return (err);
1888 }
1889 
1890 /*
1891  * Return a list of IP addresses of the peer endpoint of this sctp_t.
1892  * The parameter paddrs is supposed to be either (struct sockaddr_in *) or
1893  * (struct sockaddr_in6 *) depending on the address family of the sctp_t.
1894  */
1895 int
1896 sctp_getpeeraddrs(sctp_t *sctp, void *paddrs, int *addrcnt)
1897 {
1898 	int			family;
1899 	struct sockaddr_in	*sin4;
1900 	struct sockaddr_in6	*sin6;
1901 	int			max;
1902 	int			cnt;
1903 	sctp_faddr_t		*fp = sctp->sctp_faddrs;
1904 	in6_addr_t		addr;
1905 
1906 	ASSERT(sctp != NULL);
1907 
1908 	if (sctp->sctp_faddrs == NULL)
1909 		return (ENOTCONN);
1910 
1911 	family = sctp->sctp_family;
1912 	max = *addrcnt;
1913 
1914 	/* If we want only one, give the primary */
1915 	if (max == 1) {
1916 		addr = sctp->sctp_primary->faddr;
1917 		switch (family) {
1918 		case AF_INET:
1919 			sin4 = paddrs;
1920 			IN6_V4MAPPED_TO_INADDR(&addr, &sin4->sin_addr);
1921 			sin4->sin_port = sctp->sctp_fport;
1922 			sin4->sin_family = AF_INET;
1923 			break;
1924 
1925 		case AF_INET6:
1926 			sin6 = paddrs;
1927 			sin6->sin6_addr = addr;
1928 			sin6->sin6_port = sctp->sctp_fport;
1929 			sin6->sin6_family = AF_INET6;
1930 			break;
1931 		}
1932 		return (0);
1933 	}
1934 
1935 	for (cnt = 0; cnt < max && fp != NULL; cnt++, fp = fp->next) {
1936 		addr = fp->faddr;
1937 		switch (family) {
1938 		case AF_INET:
1939 			ASSERT(IN6_IS_ADDR_V4MAPPED(&addr));
1940 			sin4 = (struct sockaddr_in *)paddrs + cnt;
1941 			IN6_V4MAPPED_TO_INADDR(&addr, &sin4->sin_addr);
1942 			sin4->sin_port = sctp->sctp_fport;
1943 			sin4->sin_family = AF_INET;
1944 			break;
1945 		case AF_INET6:
1946 			sin6 = (struct sockaddr_in6 *)paddrs + cnt;
1947 			sin6->sin6_addr = addr;
1948 			sin6->sin6_port = sctp->sctp_fport;
1949 			sin6->sin6_family = AF_INET6;
1950 			break;
1951 		}
1952 	}
1953 	*addrcnt = cnt;
1954 	return (0);
1955 }
1956