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