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