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