xref: /illumos-gate/usr/src/uts/common/inet/sctp/sctp_opt_data.c (revision 172c0d20caae15cd97be1f210ee724069f367c75)
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 				*i1 = MSS_ROUNDUP(*i1, (sctp->sctp_mss -
1302 					sizeof (sctp_data_hdr_t)));
1303 				sctp->sctp_rwnd = *i1;
1304 			}
1305 			/*
1306 			 * XXX should we return the rwnd here
1307 			 * and sctp_opt_get ?
1308 			 */
1309 			break;
1310 		default:
1311 			retval = EINVAL;
1312 			break;
1313 		}
1314 		break;
1315 
1316 	case IPPROTO_SCTP:
1317 		if (inlen < sizeof (int32_t)) {
1318 			retval = EINVAL;
1319 			break;
1320 		}
1321 		switch (name) {
1322 		case SCTP_RTOINFO:
1323 			retval = sctp_set_rtoinfo(sctp, invalp, inlen);
1324 			break;
1325 		case SCTP_ASSOCINFO:
1326 			retval = sctp_set_assocparams(sctp, invalp, inlen);
1327 			break;
1328 		case SCTP_INITMSG:
1329 			retval = sctp_set_initmsg(sctp, invalp, inlen);
1330 			break;
1331 		case SCTP_NODELAY:
1332 			sctp->sctp_ndelay = ONOFF(*i1);
1333 			break;
1334 		case SCTP_AUTOCLOSE:
1335 			if (SEC_TO_TICK(*i1) < 0) {
1336 				retval = EINVAL;
1337 				break;
1338 			}
1339 			/* Convert the number of seconds to ticks. */
1340 			sctp->sctp_autoclose = SEC_TO_TICK(*i1);
1341 			sctp_heartbeat_timer(sctp);
1342 			break;
1343 		case SCTP_SET_PEER_PRIMARY_ADDR:
1344 			retval = sctp_set_peerprim(sctp, invalp, inlen);
1345 			break;
1346 		case SCTP_PRIMARY_ADDR:
1347 			retval = sctp_set_prim(sctp, invalp, inlen);
1348 			break;
1349 		case SCTP_ADAPTION_LAYER: {
1350 			struct sctp_setadaption *ssb;
1351 
1352 			if (inlen < sizeof (struct sctp_setadaption)) {
1353 				retval = EINVAL;
1354 				break;
1355 			}
1356 			ssb = (struct sctp_setadaption *)invalp;
1357 			sctp->sctp_send_adaption = 1;
1358 			sctp->sctp_tx_adaption_code = ssb->ssb_adaption_ind;
1359 			break;
1360 		}
1361 		case SCTP_PEER_ADDR_PARAMS:
1362 			retval = sctp_set_peer_addr_params(sctp, invalp,
1363 			    inlen);
1364 			break;
1365 		case SCTP_DEFAULT_SEND_PARAM:
1366 			retval = sctp_set_def_send_params(sctp, invalp, inlen);
1367 			break;
1368 		case SCTP_EVENTS: {
1369 			struct sctp_event_subscribe *ev;
1370 
1371 			if (inlen < sizeof (struct sctp_event_subscribe)) {
1372 				retval = EINVAL;
1373 				break;
1374 			}
1375 			ev = (struct sctp_event_subscribe *)invalp;
1376 			sctp->sctp_recvsndrcvinfo =
1377 			    ONOFF(ev->sctp_data_io_event);
1378 			sctp->sctp_recvassocevnt =
1379 			    ONOFF(ev->sctp_association_event);
1380 			sctp->sctp_recvpathevnt =
1381 			    ONOFF(ev->sctp_address_event);
1382 			sctp->sctp_recvsendfailevnt =
1383 			    ONOFF(ev->sctp_send_failure_event);
1384 			sctp->sctp_recvpeererr =
1385 			    ONOFF(ev->sctp_peer_error_event);
1386 			sctp->sctp_recvshutdownevnt =
1387 			    ONOFF(ev->sctp_shutdown_event);
1388 			sctp->sctp_recvpdevnt =
1389 			    ONOFF(ev->sctp_partial_delivery_event);
1390 			sctp->sctp_recvalevnt =
1391 				ONOFF(ev->sctp_adaption_layer_event);
1392 			break;
1393 		}
1394 		case SCTP_ADD_ADDR:
1395 		case SCTP_REM_ADDR:
1396 			/*
1397 			 * The sctp_t has to be bound first before
1398 			 * the address list can be changed.
1399 			 */
1400 			if (sctp->sctp_state < SCTPS_BOUND) {
1401 				retval = EINVAL;
1402 				break;
1403 			}
1404 			if (sctp->sctp_family == AF_INET) {
1405 				addrcnt = inlen / sizeof (struct sockaddr_in);
1406 			} else {
1407 				ASSERT(sctp->sctp_family == AF_INET6);
1408 				addrcnt = inlen / sizeof (struct sockaddr_in6);
1409 			}
1410 			if (name == SCTP_ADD_ADDR) {
1411 				retval = sctp_bind_add(sctp, invalp, addrcnt,
1412 				    B_TRUE);
1413 			} else {
1414 				retval = sctp_bind_del(sctp, invalp, addrcnt,
1415 				    B_TRUE);
1416 			}
1417 			break;
1418 		case SCTP_UC_SWAP: {
1419 			struct sctp_uc_swap *us;
1420 
1421 			/*
1422 			 * Change handle & upcalls.
1423 			 */
1424 			if (inlen < sizeof (*us)) {
1425 				retval = EINVAL;
1426 				break;
1427 			}
1428 			us = (struct sctp_uc_swap *)invalp;
1429 			sctp->sctp_ulpd = us->sus_handle;
1430 			bcopy(us->sus_upcalls, &sctp->sctp_upcalls,
1431 			    sizeof (sctp_upcalls_t));
1432 			break;
1433 		}
1434 		case SCTP_PRSCTP:
1435 			sctp->sctp_prsctp_aware = onoff;
1436 			break;
1437 		case SCTP_I_WANT_MAPPED_V4_ADDR:
1438 		case SCTP_MAXSEG:
1439 		case SCTP_DISABLE_FRAGMENTS:
1440 			/* Not yet supported. */
1441 		default:
1442 			retval = EINVAL;
1443 			break;
1444 		}
1445 		break;
1446 
1447 	case IPPROTO_IP:
1448 		if (sctp->sctp_family != AF_INET) {
1449 			retval = ENOPROTOOPT;
1450 			break;
1451 		}
1452 		if ((name != IP_OPTIONS) && (inlen < sizeof (int32_t))) {
1453 			retval = EINVAL;
1454 			break;
1455 		}
1456 		switch (name) {
1457 		case IP_OPTIONS:
1458 		case T_IP_OPTIONS:
1459 			retval = sctp_opt_set_header(sctp, B_FALSE,
1460 			    invalp, inlen);
1461 			break;
1462 		case IP_TOS:
1463 		case T_IP_TOS:
1464 			sctp->sctp_ipha->ipha_type_of_service = (uchar_t)*i1;
1465 			break;
1466 		case IP_TTL:
1467 			sctp->sctp_ipha->ipha_ttl = (uchar_t)*i1;
1468 			break;
1469 		case IP_SEC_OPT:
1470 			/*
1471 			 * We should not allow policy setting after
1472 			 * we start listening for connections.
1473 			 */
1474 			if (sctp->sctp_state >= SCTPS_LISTEN) {
1475 				retval = EINVAL;
1476 			} else {
1477 				retval = ipsec_set_req(sctp->sctp_credp,
1478 				    sctp->sctp_connp, (ipsec_req_t *)invalp);
1479 			}
1480 			break;
1481 		/* IP level options */
1482 		case IP_RECVIF:
1483 			connp->conn_recvif = onoff;
1484 			break;
1485 		case IP_RECVSLLA:
1486 			connp->conn_recvslla = onoff;
1487 			break;
1488 		case IP_UNSPEC_SRC:
1489 			connp->conn_unspec_src = onoff;
1490 			break;
1491 		default:
1492 			retval = EINVAL;
1493 			break;
1494 		}
1495 		break;
1496 	case IPPROTO_IPV6: {
1497 		if (sctp->sctp_family != AF_INET6) {
1498 			retval = ENOPROTOOPT;
1499 			break;
1500 		}
1501 
1502 		switch (name) {
1503 		case IPV6_UNICAST_HOPS:
1504 			if (inlen < sizeof (int32_t)) {
1505 				retval = EINVAL;
1506 				break;
1507 			}
1508 			if (*i1 < -1 || *i1 > IPV6_MAX_HOPS) {
1509 				retval = EINVAL;
1510 				break;
1511 			}
1512 			if (*i1 == -1) {
1513 				ipp->ipp_unicast_hops = sctp_ipv6_hoplimit;
1514 				ipp->ipp_fields &= ~IPPF_UNICAST_HOPS;
1515 			} else {
1516 				ipp->ipp_unicast_hops = (uint8_t)*i1;
1517 				ipp->ipp_fields |= IPPF_UNICAST_HOPS;
1518 			}
1519 			retval = sctp_build_hdrs(sctp);
1520 			break;
1521 		case IPV6_UNSPEC_SRC:
1522 			if (inlen < sizeof (int32_t)) {
1523 				retval = EINVAL;
1524 				break;
1525 			}
1526 			connp->conn_unspec_src = onoff;
1527 			break;
1528 		case IPV6_RECVPKTINFO:
1529 			if (inlen < sizeof (int32_t)) {
1530 				retval = EINVAL;
1531 				break;
1532 			}
1533 			if (onoff)
1534 				sctp->sctp_ipv6_recvancillary |=
1535 				    SCTP_IPV6_RECVPKTINFO;
1536 			else
1537 				sctp->sctp_ipv6_recvancillary &=
1538 				    ~SCTP_IPV6_RECVPKTINFO;
1539 			/* Send it with the next msg */
1540 			sctp->sctp_recvifindex = 0;
1541 			connp->conn_ipv6_recvpktinfo = onoff;
1542 			break;
1543 		case IPV6_RECVHOPLIMIT:
1544 			if (inlen < sizeof (int32_t)) {
1545 				retval = EINVAL;
1546 				break;
1547 			}
1548 			if (onoff)
1549 				sctp->sctp_ipv6_recvancillary |=
1550 				    SCTP_IPV6_RECVHOPLIMIT;
1551 			else
1552 				sctp->sctp_ipv6_recvancillary &=
1553 				    ~SCTP_IPV6_RECVHOPLIMIT;
1554 			sctp->sctp_recvhops = 0xffffffffU;
1555 			connp->conn_ipv6_recvhoplimit = onoff;
1556 			break;
1557 		case IPV6_RECVHOPOPTS:
1558 			if (inlen < sizeof (int32_t)) {
1559 				retval = EINVAL;
1560 				break;
1561 			}
1562 			if (onoff)
1563 				sctp->sctp_ipv6_recvancillary |=
1564 				    SCTP_IPV6_RECVHOPOPTS;
1565 			else
1566 				sctp->sctp_ipv6_recvancillary &=
1567 				    ~SCTP_IPV6_RECVHOPOPTS;
1568 			connp->conn_ipv6_recvhopopts = onoff;
1569 			break;
1570 		case IPV6_RECVDSTOPTS:
1571 			if (inlen < sizeof (int32_t)) {
1572 				retval = EINVAL;
1573 				break;
1574 			}
1575 			if (onoff)
1576 				sctp->sctp_ipv6_recvancillary |=
1577 				    SCTP_IPV6_RECVDSTOPTS;
1578 			else
1579 				sctp->sctp_ipv6_recvancillary &=
1580 				    ~SCTP_IPV6_RECVDSTOPTS;
1581 			connp->conn_ipv6_recvdstopts = onoff;
1582 			break;
1583 		case IPV6_RECVRTHDR:
1584 			if (inlen < sizeof (int32_t)) {
1585 				retval = EINVAL;
1586 				break;
1587 			}
1588 			if (onoff)
1589 				sctp->sctp_ipv6_recvancillary |=
1590 				    SCTP_IPV6_RECVRTHDR;
1591 			else
1592 				sctp->sctp_ipv6_recvancillary &=
1593 				    ~SCTP_IPV6_RECVRTHDR;
1594 			connp->conn_ipv6_recvrthdr = onoff;
1595 			break;
1596 		case IPV6_RECVRTHDRDSTOPTS:
1597 			if (inlen < sizeof (int32_t)) {
1598 				retval = EINVAL;
1599 				break;
1600 			}
1601 			if (onoff)
1602 				sctp->sctp_ipv6_recvancillary |=
1603 				    SCTP_IPV6_RECVRTDSTOPTS;
1604 			else
1605 				sctp->sctp_ipv6_recvancillary &=
1606 				    ~SCTP_IPV6_RECVRTDSTOPTS;
1607 			connp->conn_ipv6_recvrtdstopts = onoff;
1608 			break;
1609 		case IPV6_PKTINFO:
1610 			if (inlen != 0 &&
1611 			    inlen != sizeof (struct in6_pktinfo)) {
1612 				retval = EINVAL;
1613 				break;
1614 			}
1615 
1616 			if (inlen == 0) {
1617 				ipp->ipp_fields &= ~(IPPF_IFINDEX |IPPF_ADDR);
1618 			} else  {
1619 				struct in6_pktinfo *pkti;
1620 
1621 				pkti = (struct in6_pktinfo *)invalp;
1622 				/* XXX Need to check if the index exists */
1623 				ipp->ipp_ifindex = pkti->ipi6_ifindex;
1624 				ipp->ipp_addr = pkti->ipi6_addr;
1625 				if (ipp->ipp_ifindex != 0)
1626 					ipp->ipp_fields |= IPPF_IFINDEX;
1627 				else
1628 					ipp->ipp_fields &= ~IPPF_IFINDEX;
1629 				if (!IN6_IS_ADDR_UNSPECIFIED(&ipp->ipp_addr))
1630 					ipp->ipp_fields |= IPPF_ADDR;
1631 				else
1632 					ipp->ipp_fields &= ~IPPF_ADDR;
1633 			}
1634 			retval = sctp_build_hdrs(sctp);
1635 			break;
1636 		case IPV6_NEXTHOP: {
1637 			struct sockaddr_in6 *sin6;
1638 
1639 			if (inlen != 0 && inlen != sizeof (sin6_t)) {
1640 				retval = EINVAL;
1641 				break;
1642 			}
1643 
1644 			if (inlen == 0) {
1645 				ipp->ipp_fields &= ~IPPF_NEXTHOP;
1646 			} else {
1647 				sin6 = (struct sockaddr_in6 *)invalp;
1648 				if (sin6->sin6_family != AF_INET6) {
1649 					retval = EAFNOSUPPORT;
1650 					break;
1651 				}
1652 				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1653 					retval = EADDRNOTAVAIL;
1654 					break;
1655 				}
1656 				ipp->ipp_nexthop = sin6->sin6_addr;
1657 				if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1658 					ipp->ipp_fields &= ~IPPF_NEXTHOP;
1659 				} else {
1660 					ire_t	*ire;
1661 
1662 					ire = ire_route_lookup_v6(
1663 					    &sin6->sin6_addr, 0, 0, 0, NULL,
1664 					    NULL, NULL, MATCH_IRE_DEFAULT);
1665 					if (ire == NULL) {
1666 						retval = EHOSTUNREACH;
1667 						break;
1668 					}
1669 					ire_refrele(ire);
1670 					ipp->ipp_fields |= IPPF_NEXTHOP;
1671 				}
1672 			}
1673 			retval = sctp_build_hdrs(sctp);
1674 			break;
1675 		}
1676 		case IPV6_HOPOPTS: {
1677 			ip6_hbh_t *hopts = (ip6_hbh_t *)invalp;
1678 
1679 			if (inlen != 0 &&
1680 			    inlen != (8 * (hopts->ip6h_len + 1))) {
1681 				retval = EINVAL;
1682 				break;
1683 			}
1684 
1685 			if (inlen == 0) {
1686 				ipp->ipp_fields &= ~IPPF_HOPOPTS;
1687 			} else {
1688 				retval = sctp_pkt_set((uchar_t *)invalp, inlen,
1689 				    (uchar_t **)&ipp->ipp_hopopts,
1690 				    &ipp->ipp_hopoptslen);
1691 				if (retval != 0)
1692 					break;
1693 				ipp->ipp_fields |= IPPF_HOPOPTS;
1694 			}
1695 			retval = sctp_build_hdrs(sctp);
1696 			break;
1697 		}
1698 		case IPV6_RTHDRDSTOPTS: {
1699 			ip6_dest_t *dopts = (ip6_dest_t *)invalp;
1700 
1701 			if (inlen != 0 &&
1702 			    inlen != (8 * (dopts->ip6d_len + 1))) {
1703 				retval = EINVAL;
1704 				break;
1705 			}
1706 
1707 			if (inlen == 0) {
1708 				ipp->ipp_fields &= ~IPPF_RTDSTOPTS;
1709 			} else {
1710 				retval = sctp_pkt_set((uchar_t *)invalp, inlen,
1711 				    (uchar_t **)&ipp->ipp_rtdstopts,
1712 				    &ipp->ipp_rtdstoptslen);
1713 				if (retval != 0)
1714 					break;
1715 				ipp->ipp_fields |= IPPF_RTDSTOPTS;
1716 			}
1717 			retval = sctp_build_hdrs(sctp);
1718 			break;
1719 		}
1720 		case IPV6_DSTOPTS: {
1721 			ip6_dest_t *dopts = (ip6_dest_t *)invalp;
1722 
1723 			if (inlen != 0 &&
1724 			    inlen != (8 * (dopts->ip6d_len + 1))) {
1725 				retval = EINVAL;
1726 				break;
1727 			}
1728 
1729 			if (inlen == 0) {
1730 				ipp->ipp_fields &= ~IPPF_DSTOPTS;
1731 			} else {
1732 				retval = sctp_pkt_set((uchar_t *)invalp, inlen,
1733 				    (uchar_t **)&ipp->ipp_dstopts,
1734 				    &ipp->ipp_dstoptslen);
1735 				if (retval != 0)
1736 					break;
1737 				ipp->ipp_fields |= IPPF_DSTOPTS;
1738 			}
1739 			retval = sctp_build_hdrs(sctp);
1740 			break;
1741 		}
1742 		case IPV6_RTHDR: {
1743 			ip6_rthdr_t *rt = (ip6_rthdr_t *)invalp;
1744 
1745 			if (inlen != 0 &&
1746 			    inlen != (8 * (rt->ip6r_len + 1))) {
1747 				retval = EINVAL;
1748 				break;
1749 			}
1750 
1751 			if (inlen == 0) {
1752 				ipp->ipp_fields &= ~IPPF_RTHDR;
1753 			} else {
1754 				retval = sctp_pkt_set((uchar_t *)invalp, inlen,
1755 				    (uchar_t **)&ipp->ipp_rthdr,
1756 				    &ipp->ipp_rthdrlen);
1757 				if (retval != 0)
1758 					break;
1759 				ipp->ipp_fields |= IPPF_RTHDR;
1760 			}
1761 			retval = sctp_build_hdrs(sctp);
1762 			break;
1763 		}
1764 		case IPV6_SEC_OPT:
1765 			/*
1766 			 * We should not allow policy setting after
1767 			 * we start listening for connections.
1768 			 */
1769 			if (sctp->sctp_state >= SCTPS_LISTEN) {
1770 				retval = EINVAL;
1771 			} else {
1772 				retval = ipsec_set_req(sctp->sctp_credp,
1773 				    sctp->sctp_connp, (ipsec_req_t *)invalp);
1774 			}
1775 			break;
1776 		case IPV6_V6ONLY:
1777 			/*
1778 			 * After the bound state, setting the v6only option
1779 			 * is too late.
1780 			 */
1781 			if (sctp->sctp_state >= SCTPS_BOUND) {
1782 				retval = EINVAL;
1783 			} else {
1784 				sctp->sctp_connp->conn_ipv6_v6only = onoff;
1785 			}
1786 			break;
1787 		default:
1788 			retval = EINVAL;
1789 			break;
1790 		}
1791 		break;
1792 	}
1793 	default:
1794 		retval = EINVAL;
1795 		break;
1796 	}
1797 
1798 	WAKE_SCTP(sctp);
1799 	return (retval);
1800 }
1801 
1802 /*
1803  * SCTP exported kernel interface for geting the first source address of
1804  * a sctp_t.  The parameter addr is assumed to have enough space to hold
1805  * one socket address.
1806  */
1807 int
1808 sctp_getsockname(sctp_t *sctp, struct sockaddr *addr, socklen_t *addrlen)
1809 {
1810 	int	err = 0;
1811 	int	addrcnt = 1;
1812 	sin_t	*sin4;
1813 	sin6_t	*sin6;
1814 
1815 	ASSERT(sctp != NULL);
1816 
1817 	RUN_SCTP(sctp);
1818 	addr->sa_family = sctp->sctp_family;
1819 	switch (sctp->sctp_family) {
1820 	case AF_INET:
1821 		sin4 = (sin_t *)addr;
1822 		if ((sctp->sctp_state <= SCTPS_LISTEN) &&
1823 		    sctp->sctp_bound_to_all) {
1824 			sin4->sin_addr.s_addr = INADDR_ANY;
1825 			sin4->sin_port = sctp->sctp_lport;
1826 		} else {
1827 			err = sctp_getmyaddrs(sctp, sin4, &addrcnt);
1828 			if (err != 0) {
1829 				*addrlen = 0;
1830 				break;
1831 			}
1832 		}
1833 		*addrlen = sizeof (struct sockaddr_in);
1834 		break;
1835 	case AF_INET6:
1836 		sin6 = (sin6_t *)addr;
1837 		if ((sctp->sctp_state <= SCTPS_LISTEN) &&
1838 		    sctp->sctp_bound_to_all) {
1839 			bzero(&sin6->sin6_addr, sizeof (sin6->sin6_addr));
1840 			sin6->sin6_port = sctp->sctp_lport;
1841 		} else {
1842 			err = sctp_getmyaddrs(sctp, sin6, &addrcnt);
1843 			if (err != 0) {
1844 				*addrlen = 0;
1845 				break;
1846 			}
1847 		}
1848 		*addrlen = sizeof (struct sockaddr_in6);
1849 		sin6->sin6_flowinfo = sctp->sctp_ip6h->ip6_vcf &
1850 		    ~IPV6_VERS_AND_FLOW_MASK;
1851 		sin6->sin6_scope_id = 0;
1852 		sin6->__sin6_src_id = 0;
1853 		break;
1854 	}
1855 	WAKE_SCTP(sctp);
1856 	return (err);
1857 }
1858 
1859 /*
1860  * SCTP exported kernel interface for geting the primary peer address of
1861  * a sctp_t.  The parameter addr is assumed to have enough space to hold
1862  * one socket address.
1863  */
1864 int
1865 sctp_getpeername(sctp_t *sctp, struct sockaddr *addr, socklen_t *addrlen)
1866 {
1867 	int	err = 0;
1868 	int	addrcnt = 1;
1869 	sin6_t	*sin6;
1870 
1871 	ASSERT(sctp != NULL);
1872 
1873 	RUN_SCTP(sctp);
1874 	addr->sa_family = sctp->sctp_family;
1875 	switch (sctp->sctp_family) {
1876 	case AF_INET:
1877 		err = sctp_getpeeraddrs(sctp, addr, &addrcnt);
1878 		if (err != 0) {
1879 			*addrlen = 0;
1880 			break;
1881 		}
1882 		*addrlen = sizeof (struct sockaddr_in);
1883 		break;
1884 	case AF_INET6:
1885 		sin6 = (sin6_t *)addr;
1886 		err = sctp_getpeeraddrs(sctp, sin6, &addrcnt);
1887 		if (err != 0) {
1888 			*addrlen = 0;
1889 			break;
1890 		}
1891 		*addrlen = sizeof (struct sockaddr_in6);
1892 		sin6->sin6_flowinfo = 0;
1893 		sin6->sin6_scope_id = 0;
1894 		sin6->__sin6_src_id = 0;
1895 		break;
1896 	}
1897 	WAKE_SCTP(sctp);
1898 	return (err);
1899 }
1900 
1901 /*
1902  * Return a list of IP addresses of the peer endpoint of this sctp_t.
1903  * The parameter paddrs is supposed to be either (struct sockaddr_in *) or
1904  * (struct sockaddr_in6 *) depending on the address family of the sctp_t.
1905  */
1906 int
1907 sctp_getpeeraddrs(sctp_t *sctp, void *paddrs, int *addrcnt)
1908 {
1909 	int			family;
1910 	struct sockaddr_in	*sin4;
1911 	struct sockaddr_in6	*sin6;
1912 	int			max;
1913 	int			cnt;
1914 	sctp_faddr_t		*fp = sctp->sctp_faddrs;
1915 	in6_addr_t		addr;
1916 
1917 	ASSERT(sctp != NULL);
1918 
1919 	if (sctp->sctp_faddrs == NULL)
1920 		return (ENOTCONN);
1921 
1922 	family = sctp->sctp_family;
1923 	max = *addrcnt;
1924 
1925 	/* If we want only one, give the primary */
1926 	if (max == 1) {
1927 		addr = sctp->sctp_primary->faddr;
1928 		switch (family) {
1929 		case AF_INET:
1930 			sin4 = paddrs;
1931 			IN6_V4MAPPED_TO_INADDR(&addr, &sin4->sin_addr);
1932 			sin4->sin_port = sctp->sctp_fport;
1933 			sin4->sin_family = AF_INET;
1934 			break;
1935 
1936 		case AF_INET6:
1937 			sin6 = paddrs;
1938 			sin6->sin6_addr = addr;
1939 			sin6->sin6_port = sctp->sctp_fport;
1940 			sin6->sin6_family = AF_INET6;
1941 			break;
1942 		}
1943 		return (0);
1944 	}
1945 
1946 	for (cnt = 0; cnt < max && fp != NULL; cnt++, fp = fp->next) {
1947 		addr = fp->faddr;
1948 		switch (family) {
1949 		case AF_INET:
1950 			ASSERT(IN6_IS_ADDR_V4MAPPED(&addr));
1951 			sin4 = (struct sockaddr_in *)paddrs + cnt;
1952 			IN6_V4MAPPED_TO_INADDR(&addr, &sin4->sin_addr);
1953 			sin4->sin_port = sctp->sctp_fport;
1954 			sin4->sin_family = AF_INET;
1955 			break;
1956 		case AF_INET6:
1957 			sin6 = (struct sockaddr_in6 *)paddrs + cnt;
1958 			sin6->sin6_addr = addr;
1959 			sin6->sin6_port = sctp->sctp_fport;
1960 			sin6->sin6_family = AF_INET6;
1961 			break;
1962 		}
1963 	}
1964 	*addrcnt = cnt;
1965 	return (0);
1966 }
1967