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