xref: /illumos-gate/usr/src/uts/common/inet/sctp/sctp_opt_data.c (revision d8a7fe16f62711cdc5c4267da8b34ff24a6b668c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/types.h>
28 #include <sys/stream.h>
29 #define	_SUN_TPI_VERSION 2
30 #include <sys/tihdr.h>
31 #include <sys/socket.h>
32 #include <sys/xti_inet.h>
33 #include <sys/systm.h>
34 #include <sys/ddi.h>
35 #include <sys/sunddi.h>
36 #include <sys/kmem.h>
37 #include <sys/strsubr.h>
38 #include <sys/strsun.h>
39 #include <sys/policy.h>
40 
41 #include <inet/common.h>
42 #include <netinet/ip6.h>
43 #include <inet/ip.h>
44 #include <inet/ip_ire.h>
45 #include <inet/ip_if.h>
46 #include <inet/proto_set.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 static int
65 sctp_get_status(sctp_t *sctp, void *ptr)
66 {
67 	struct sctp_status *sstat = ptr;
68 	sctp_faddr_t *fp;
69 	struct sockaddr_in *sin;
70 	struct sockaddr_in6 *sin6;
71 	struct sctp_paddrinfo *sp;
72 	mblk_t *meta, *mp;
73 	int i;
74 	conn_t	*connp = sctp->sctp_connp;
75 
76 	sstat->sstat_state = sctp->sctp_state;
77 	sstat->sstat_rwnd = sctp->sctp_frwnd;
78 
79 	sp = &sstat->sstat_primary;
80 	if (!sctp->sctp_primary) {
81 		bzero(sp, sizeof (*sp));
82 		goto noprim;
83 	}
84 	fp = sctp->sctp_primary;
85 
86 	if (fp->isv4) {
87 		sin = (struct sockaddr_in *)&sp->spinfo_address;
88 		sin->sin_family = AF_INET;
89 		sin->sin_port = connp->conn_fport;
90 		IN6_V4MAPPED_TO_INADDR(&fp->faddr, &sin->sin_addr);
91 		sp->spinfo_mtu = sctp->sctp_hdr_len;
92 	} else {
93 		sin6 = (struct sockaddr_in6 *)&sp->spinfo_address;
94 		sin6->sin6_family = AF_INET6;
95 		sin6->sin6_port = connp->conn_fport;
96 		sin6->sin6_addr = fp->faddr;
97 		sp->spinfo_mtu = sctp->sctp_hdr6_len;
98 	}
99 	sp->spinfo_state = fp->state == SCTP_FADDRS_ALIVE ? SCTP_ACTIVE :
100 	    SCTP_INACTIVE;
101 	sp->spinfo_cwnd = fp->cwnd;
102 	sp->spinfo_srtt = fp->srtt;
103 	sp->spinfo_rto = fp->rto;
104 	sp->spinfo_mtu += fp->sfa_pmss;
105 
106 noprim:
107 	sstat->sstat_unackdata = 0;
108 	sstat->sstat_penddata = 0;
109 	sstat->sstat_instrms = sctp->sctp_num_istr;
110 	sstat->sstat_outstrms = sctp->sctp_num_ostr;
111 	sstat->sstat_fragmentation_point = sctp->sctp_mss -
112 	    sizeof (sctp_data_hdr_t);
113 
114 	/* count unack'd */
115 	for (meta = sctp->sctp_xmit_head; meta; meta = meta->b_next) {
116 		for (mp = meta->b_cont; mp; mp = mp->b_next) {
117 			if (!SCTP_CHUNK_ISSENT(mp)) {
118 				break;
119 			}
120 			if (!SCTP_CHUNK_ISACKED(mp)) {
121 				sstat->sstat_unackdata++;
122 			}
123 		}
124 	}
125 
126 	/*
127 	 * Count penddata chunks. We can only count chunks in SCTP (not
128 	 * data already delivered to socket layer).
129 	 */
130 	if (sctp->sctp_instr != NULL) {
131 		for (i = 0; i < sctp->sctp_num_istr; i++) {
132 			for (meta = sctp->sctp_instr[i].istr_reass;
133 			    meta != NULL; meta = meta->b_next) {
134 				for (mp = meta->b_cont; mp; mp = mp->b_cont) {
135 					if (DB_TYPE(mp) != M_CTL) {
136 						sstat->sstat_penddata++;
137 					}
138 				}
139 			}
140 		}
141 	}
142 	/* Un-Ordered Frag list */
143 	for (meta = sctp->sctp_uo_frags; meta != NULL; meta = meta->b_next)
144 		sstat->sstat_penddata++;
145 
146 	return (sizeof (*sstat));
147 }
148 
149 /*
150  * SCTP_GET_PEER_ADDR_INFO
151  */
152 static int
153 sctp_get_paddrinfo(sctp_t *sctp, void *ptr, socklen_t *optlen)
154 {
155 	struct sctp_paddrinfo	*infop = ptr;
156 	struct sockaddr_in	*sin4;
157 	struct sockaddr_in6	*sin6;
158 	in6_addr_t		faddr;
159 	sctp_faddr_t		*fp;
160 
161 	switch (infop->spinfo_address.ss_family) {
162 	case AF_INET:
163 		sin4 = (struct sockaddr_in *)&infop->spinfo_address;
164 		IN6_INADDR_TO_V4MAPPED(&sin4->sin_addr, &faddr);
165 		break;
166 	case AF_INET6:
167 		sin6 = (struct sockaddr_in6 *)&infop->spinfo_address;
168 		faddr = sin6->sin6_addr;
169 		break;
170 	default:
171 		return (EAFNOSUPPORT);
172 	}
173 
174 	if ((fp = sctp_lookup_faddr(sctp, &faddr)) == NULL)
175 		return (EINVAL);
176 
177 	infop->spinfo_state = (fp->state == SCTP_FADDRS_ALIVE) ? SCTP_ACTIVE :
178 	    SCTP_INACTIVE;
179 	infop->spinfo_cwnd = fp->cwnd;
180 	infop->spinfo_srtt = TICK_TO_MSEC(fp->srtt);
181 	infop->spinfo_rto = TICK_TO_MSEC(fp->rto);
182 	infop->spinfo_mtu = fp->sfa_pmss;
183 
184 	*optlen = sizeof (struct sctp_paddrinfo);
185 	return (0);
186 }
187 
188 /*
189  * SCTP_RTOINFO
190  */
191 static int
192 sctp_get_rtoinfo(sctp_t *sctp, void *ptr)
193 {
194 	struct sctp_rtoinfo *srto = ptr;
195 
196 	srto->srto_initial = TICK_TO_MSEC(sctp->sctp_rto_initial);
197 	srto->srto_max = TICK_TO_MSEC(sctp->sctp_rto_max);
198 	srto->srto_min = TICK_TO_MSEC(sctp->sctp_rto_min);
199 
200 	return (sizeof (*srto));
201 }
202 
203 static int
204 sctp_set_rtoinfo(sctp_t *sctp, const void *invalp)
205 {
206 	const struct sctp_rtoinfo *srto;
207 	boolean_t ispriv;
208 	sctp_stack_t	*sctps = sctp->sctp_sctps;
209 	conn_t		*connp = sctp->sctp_connp;
210 	uint32_t	new_min, new_max;
211 
212 	srto = invalp;
213 
214 	ispriv = secpolicy_ip_config(connp->conn_cred, B_TRUE) == 0;
215 
216 	/*
217 	 * Bounds checking.  Priviledged user can set the RTO initial
218 	 * outside the ndd boundary.
219 	 */
220 	if (srto->srto_initial != 0 &&
221 	    (!ispriv && (srto->srto_initial < sctps->sctps_rto_initialg_low ||
222 	    srto->srto_initial > sctps->sctps_rto_initialg_high))) {
223 		return (EINVAL);
224 	}
225 	if (srto->srto_max != 0 &&
226 	    (!ispriv && (srto->srto_max < sctps->sctps_rto_maxg_low ||
227 	    srto->srto_max > sctps->sctps_rto_maxg_high))) {
228 		return (EINVAL);
229 	}
230 	if (srto->srto_min != 0 &&
231 	    (!ispriv && (srto->srto_min < sctps->sctps_rto_ming_low ||
232 	    srto->srto_min > sctps->sctps_rto_ming_high))) {
233 		return (EINVAL);
234 	}
235 
236 	new_min = (srto->srto_min != 0) ? srto->srto_min : sctp->sctp_rto_min;
237 	new_max = (srto->srto_max != 0) ? srto->srto_max : sctp->sctp_rto_max;
238 	if (new_max < new_min) {
239 		return (EINVAL);
240 	}
241 
242 	if (srto->srto_initial != 0) {
243 		sctp->sctp_rto_initial = MSEC_TO_TICK(srto->srto_initial);
244 	}
245 
246 	/* Ensure that sctp_rto_max will never be zero. */
247 	if (srto->srto_max != 0) {
248 		sctp->sctp_rto_max = MAX(MSEC_TO_TICK(srto->srto_max), 1);
249 	}
250 	if (srto->srto_min != 0) {
251 		sctp->sctp_rto_min = MSEC_TO_TICK(srto->srto_min);
252 	}
253 
254 	return (0);
255 }
256 
257 /*
258  * SCTP_ASSOCINFO
259  */
260 static int
261 sctp_get_assocparams(sctp_t *sctp, void *ptr)
262 {
263 	struct sctp_assocparams *sap = ptr;
264 	sctp_faddr_t *fp;
265 	uint16_t i;
266 
267 	sap->sasoc_asocmaxrxt = sctp->sctp_pa_max_rxt;
268 
269 	/*
270 	 * Count the number of peer addresses
271 	 */
272 	for (i = 0, fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next) {
273 		i++;
274 	}
275 	sap->sasoc_number_peer_destinations = i;
276 	sap->sasoc_peer_rwnd = sctp->sctp_frwnd;
277 	sap->sasoc_local_rwnd = sctp->sctp_rwnd;
278 	sap->sasoc_cookie_life = TICK_TO_MSEC(sctp->sctp_cookie_lifetime);
279 
280 	return (sizeof (*sap));
281 }
282 
283 static int
284 sctp_set_assocparams(sctp_t *sctp, const void *invalp)
285 {
286 	const struct sctp_assocparams *sap = invalp;
287 	uint32_t sum = 0;
288 	sctp_faddr_t *fp;
289 	sctp_stack_t	*sctps = sctp->sctp_sctps;
290 
291 	if (sap->sasoc_asocmaxrxt) {
292 		if (sctp->sctp_faddrs) {
293 			/*
294 			 * Bounds check: as per rfc2960, assoc max retr cannot
295 			 * exceed the sum of all individual path max retr's.
296 			 */
297 			for (fp = sctp->sctp_faddrs; fp; fp = fp->next) {
298 				sum += fp->max_retr;
299 			}
300 			if (sap->sasoc_asocmaxrxt > sum) {
301 				return (EINVAL);
302 			}
303 		}
304 		if (sap->sasoc_asocmaxrxt < sctps->sctps_pa_max_retr_low ||
305 		    sap->sasoc_asocmaxrxt > sctps->sctps_pa_max_retr_high) {
306 			/*
307 			 * Out of bounds.
308 			 */
309 			return (EINVAL);
310 		}
311 	}
312 	if (sap->sasoc_cookie_life != 0 &&
313 	    (sap->sasoc_cookie_life < sctps->sctps_cookie_life_low ||
314 	    sap->sasoc_cookie_life > sctps->sctps_cookie_life_high)) {
315 		return (EINVAL);
316 	}
317 
318 	if (sap->sasoc_asocmaxrxt > 0) {
319 		sctp->sctp_pa_max_rxt = sap->sasoc_asocmaxrxt;
320 	}
321 	if (sap->sasoc_cookie_life > 0) {
322 		sctp->sctp_cookie_lifetime = MSEC_TO_TICK(
323 		    sap->sasoc_cookie_life);
324 	}
325 	return (0);
326 }
327 
328 /*
329  * SCTP_INITMSG
330  */
331 static int
332 sctp_get_initmsg(sctp_t *sctp, void *ptr)
333 {
334 	struct sctp_initmsg *si = ptr;
335 
336 	si->sinit_num_ostreams = sctp->sctp_num_ostr;
337 	si->sinit_max_instreams = sctp->sctp_num_istr;
338 	si->sinit_max_attempts = sctp->sctp_max_init_rxt;
339 	si->sinit_max_init_timeo = TICK_TO_MSEC(sctp->sctp_init_rto_max);
340 
341 	return (sizeof (*si));
342 }
343 
344 static int
345 sctp_set_initmsg(sctp_t *sctp, const void *invalp, uint_t inlen)
346 {
347 	const struct sctp_initmsg *si = invalp;
348 	sctp_stack_t	*sctps = sctp->sctp_sctps;
349 	conn_t		*connp = sctp->sctp_connp;
350 
351 	if (sctp->sctp_state > SCTPS_LISTEN) {
352 		return (EINVAL);
353 	}
354 	if (inlen < sizeof (*si)) {
355 		return (EINVAL);
356 	}
357 	if (si->sinit_num_ostreams != 0 &&
358 	    (si->sinit_num_ostreams < sctps->sctps_initial_out_streams_low ||
359 	    si->sinit_num_ostreams >
360 	    sctps->sctps_initial_out_streams_high)) {
361 		/*
362 		 * Out of bounds.
363 		 */
364 		return (EINVAL);
365 	}
366 	if (si->sinit_max_instreams != 0 &&
367 	    (si->sinit_max_instreams < sctps->sctps_max_in_streams_low ||
368 	    si->sinit_max_instreams > sctps->sctps_max_in_streams_high)) {
369 		return (EINVAL);
370 	}
371 	if (si->sinit_max_attempts != 0 &&
372 	    (si->sinit_max_attempts < sctps->sctps_max_init_retr_low ||
373 	    si->sinit_max_attempts > sctps->sctps_max_init_retr_high)) {
374 		return (EINVAL);
375 	}
376 	if (si->sinit_max_init_timeo != 0 &&
377 	    (secpolicy_ip_config(connp->conn_cred, B_TRUE) != 0 &&
378 	    (si->sinit_max_init_timeo < sctps->sctps_rto_maxg_low ||
379 	    si->sinit_max_init_timeo > sctps->sctps_rto_maxg_high))) {
380 		return (EINVAL);
381 	}
382 	if (si->sinit_num_ostreams != 0)
383 		sctp->sctp_num_ostr = si->sinit_num_ostreams;
384 
385 	if (si->sinit_max_instreams != 0)
386 		sctp->sctp_num_istr = si->sinit_max_instreams;
387 
388 	if (si->sinit_max_attempts != 0)
389 		sctp->sctp_max_init_rxt = si->sinit_max_attempts;
390 
391 	if (si->sinit_max_init_timeo != 0) {
392 		sctp->sctp_init_rto_max =
393 		    MSEC_TO_TICK(si->sinit_max_init_timeo);
394 	}
395 	return (0);
396 }
397 
398 /*
399  * SCTP_PEER_ADDR_PARAMS
400  */
401 static int
402 sctp_find_peer_fp(sctp_t *sctp, const struct sockaddr_storage *ss,
403     sctp_faddr_t **fpp)
404 {
405 	struct sockaddr_in *sin;
406 	struct sockaddr_in6 *sin6;
407 	in6_addr_t addr;
408 
409 	if (ss->ss_family == AF_INET) {
410 		sin = (struct sockaddr_in *)ss;
411 		IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &addr);
412 	} else if (ss->ss_family == AF_INET6) {
413 		sin6 = (struct sockaddr_in6 *)ss;
414 		addr = sin6->sin6_addr;
415 	} else if (ss->ss_family) {
416 		return (EAFNOSUPPORT);
417 	}
418 
419 	if (!ss->ss_family ||
420 	    SCTP_IS_ADDR_UNSPEC(IN6_IS_ADDR_V4MAPPED(&addr), addr)) {
421 		*fpp = NULL;
422 	} else {
423 		*fpp = sctp_lookup_faddr(sctp, &addr);
424 		if (*fpp == NULL) {
425 			return (EINVAL);
426 		}
427 	}
428 	return (0);
429 }
430 
431 static int
432 sctp_get_peer_addr_params(sctp_t *sctp, void *ptr)
433 {
434 	struct sctp_paddrparams *spp = ptr;
435 	sctp_faddr_t *fp;
436 	int retval;
437 
438 	retval = sctp_find_peer_fp(sctp, &spp->spp_address, &fp);
439 	if (retval) {
440 		return (retval);
441 	}
442 	if (fp) {
443 		spp->spp_hbinterval = TICK_TO_MSEC(fp->hb_interval);
444 		spp->spp_pathmaxrxt = fp->max_retr;
445 	} else {
446 		spp->spp_hbinterval = TICK_TO_MSEC(sctp->sctp_hb_interval);
447 		spp->spp_pathmaxrxt = sctp->sctp_pp_max_rxt;
448 	}
449 	return (sizeof (*spp));
450 }
451 
452 static int
453 sctp_set_peer_addr_params(sctp_t *sctp, const void *invalp)
454 {
455 	const struct sctp_paddrparams *spp = invalp;
456 	sctp_faddr_t *fp, *fp2;
457 	int retval;
458 	uint32_t sum = 0;
459 	int64_t now;
460 	sctp_stack_t	*sctps = sctp->sctp_sctps;
461 
462 	retval = sctp_find_peer_fp(sctp, &spp->spp_address, &fp);
463 	if (retval != 0) {
464 		return (retval);
465 	}
466 
467 	if (spp->spp_hbinterval && spp->spp_hbinterval != UINT32_MAX &&
468 	    (spp->spp_hbinterval < sctps->sctps_heartbeat_interval_low ||
469 	    spp->spp_hbinterval > sctps->sctps_heartbeat_interval_high)) {
470 		return (EINVAL);
471 	}
472 	if (spp->spp_pathmaxrxt &&
473 	    (spp->spp_pathmaxrxt < sctps->sctps_pp_max_retr_low ||
474 	    spp->spp_pathmaxrxt > sctps->sctps_pp_max_retr_high)) {
475 		return (EINVAL);
476 	}
477 	if (spp->spp_pathmaxrxt && sctp->sctp_faddrs) {
478 		for (fp2 = sctp->sctp_faddrs; fp2; fp2 = fp2->next) {
479 			if (!fp || fp2 == fp) {
480 				sum += spp->spp_pathmaxrxt;
481 			} else {
482 				sum += fp2->max_retr;
483 			}
484 		}
485 		if (sctp->sctp_pa_max_rxt > sum) {
486 			return (EINVAL);
487 		}
488 	}
489 
490 	now = ddi_get_lbolt64();
491 	if (fp != NULL) {
492 		if (spp->spp_hbinterval == UINT32_MAX) {
493 			/*
494 			 * Send heartbeat immediatelly, don't modify the
495 			 * current setting.
496 			 */
497 			sctp_send_heartbeat(sctp, fp);
498 		} else {
499 			fp->hb_interval = MSEC_TO_TICK(spp->spp_hbinterval);
500 			fp->hb_expiry = now + SET_HB_INTVL(fp);
501 			/*
502 			 * Restart the heartbeat timer using the new intrvl.
503 			 * We need to call sctp_heartbeat_timer() to set
504 			 * the earliest heartbeat expiry time.
505 			 */
506 			sctp_heartbeat_timer(sctp);
507 		}
508 		if (spp->spp_pathmaxrxt) {
509 			fp->max_retr = spp->spp_pathmaxrxt;
510 		}
511 	} else {
512 		for (fp2 = sctp->sctp_faddrs; fp2 != NULL; fp2 = fp2->next) {
513 			if (spp->spp_hbinterval == UINT32_MAX) {
514 				/*
515 				 * Send heartbeat immediatelly, don't modify
516 				 * the current setting.
517 				 */
518 				sctp_send_heartbeat(sctp, fp2);
519 			} else {
520 				fp2->hb_interval = MSEC_TO_TICK(
521 				    spp->spp_hbinterval);
522 				fp2->hb_expiry = now + SET_HB_INTVL(fp2);
523 			}
524 			if (spp->spp_pathmaxrxt) {
525 				fp2->max_retr = spp->spp_pathmaxrxt;
526 			}
527 		}
528 		if (spp->spp_hbinterval != UINT32_MAX) {
529 			sctp->sctp_hb_interval = MSEC_TO_TICK(
530 			    spp->spp_hbinterval);
531 			/* Restart the heartbeat timer using the new intrvl. */
532 			sctp_timer(sctp, sctp->sctp_heartbeat_mp,
533 			    sctp->sctp_hb_interval);
534 		}
535 		if (spp->spp_pathmaxrxt) {
536 			sctp->sctp_pp_max_rxt = spp->spp_pathmaxrxt;
537 		}
538 	}
539 	return (0);
540 }
541 
542 /*
543  * SCTP_DEFAULT_SEND_PARAM
544  */
545 static int
546 sctp_get_def_send_params(sctp_t *sctp, void *ptr)
547 {
548 	struct sctp_sndrcvinfo *sinfo = ptr;
549 
550 	sinfo->sinfo_stream = sctp->sctp_def_stream;
551 	sinfo->sinfo_ssn = 0;
552 	sinfo->sinfo_flags = sctp->sctp_def_flags;
553 	sinfo->sinfo_ppid = sctp->sctp_def_ppid;
554 	sinfo->sinfo_context = sctp->sctp_def_context;
555 	sinfo->sinfo_timetolive = sctp->sctp_def_timetolive;
556 	sinfo->sinfo_tsn = 0;
557 	sinfo->sinfo_cumtsn = 0;
558 
559 	return (sizeof (*sinfo));
560 }
561 
562 static int
563 sctp_set_def_send_params(sctp_t *sctp, const void *invalp)
564 {
565 	const struct sctp_sndrcvinfo *sinfo = invalp;
566 
567 	if (sinfo->sinfo_stream >= sctp->sctp_num_ostr) {
568 		return (EINVAL);
569 	}
570 
571 	sctp->sctp_def_stream = sinfo->sinfo_stream;
572 	sctp->sctp_def_flags = sinfo->sinfo_flags;
573 	sctp->sctp_def_ppid = sinfo->sinfo_ppid;
574 	sctp->sctp_def_context = sinfo->sinfo_context;
575 	sctp->sctp_def_timetolive = sinfo->sinfo_timetolive;
576 
577 	return (0);
578 }
579 
580 static int
581 sctp_set_prim(sctp_t *sctp, const void *invalp)
582 {
583 	const struct	sctp_setpeerprim *pp = invalp;
584 	int		retval;
585 	sctp_faddr_t	*fp;
586 
587 	retval = sctp_find_peer_fp(sctp, &pp->sspp_addr, &fp);
588 	if (retval)
589 		return (retval);
590 
591 	if (fp == NULL)
592 		return (EINVAL);
593 	if (fp == sctp->sctp_primary)
594 		return (0);
595 	sctp->sctp_primary = fp;
596 
597 	/* Only switch current if fp is alive */
598 	if (fp->state != SCTP_FADDRS_ALIVE || fp == sctp->sctp_current) {
599 		return (0);
600 	}
601 	sctp_set_faddr_current(sctp, fp);
602 
603 	return (0);
604 }
605 
606 /*
607  * Table of all known options handled on a SCTP protocol stack.
608  *
609  * Note: This table contains options processed by both SCTP and IP levels
610  *       and is the superset of options that can be performed on a SCTP and IP
611  *       stack.
612  */
613 opdes_t	sctp_opt_arr[] = {
614 
615 { SO_LINGER,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0,
616 	sizeof (struct linger), 0 },
617 
618 { SO_DEBUG,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
619 { SO_KEEPALIVE,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
620 { SO_DONTROUTE,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
621 { SO_USELOOPBACK, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0
622 	},
623 { SO_BROADCAST,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
624 { SO_REUSEADDR, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
625 { SO_OOBINLINE, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
626 { SO_TYPE,	SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
627 { SO_SNDBUF,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
628 { SO_RCVBUF,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
629 { SO_DGRAM_ERRIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0
630 	},
631 { SO_SND_COPYAVOID, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
632 { SO_ANON_MLP, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int),
633 	0 },
634 { SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int),
635 	0 },
636 { SO_ALLZONES, SOL_SOCKET, OA_R, OA_RW, OP_CONFIG, 0, sizeof (int),
637 	0 },
638 { SO_EXCLBIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
639 
640 { SO_DOMAIN,	SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
641 
642 { SO_PROTOTYPE,	SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
643 
644 { SCTP_ADAPTATION_LAYER, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
645 	sizeof (struct sctp_setadaptation), 0 },
646 { SCTP_ADD_ADDR, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, OP_VARLEN,
647 	sizeof (int), 0 },
648 { SCTP_ASSOCINFO, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
649 	sizeof (struct sctp_assocparams), 0 },
650 { SCTP_AUTOCLOSE, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
651 { SCTP_DEFAULT_SEND_PARAM, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
652 	sizeof (struct sctp_sndrcvinfo), 0 },
653 { SCTP_DISABLE_FRAGMENTS, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
654 	sizeof (int), 0 },
655 { SCTP_EVENTS, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
656 	sizeof (struct sctp_event_subscribe), 0 },
657 { SCTP_GET_LADDRS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, OP_VARLEN,
658 	sizeof (int), 0 },
659 { SCTP_GET_NLADDRS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
660 { SCTP_GET_NPADDRS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
661 { SCTP_GET_PADDRS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, OP_VARLEN,
662 	sizeof (int), 0 },
663 { SCTP_GET_PEER_ADDR_INFO, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0,
664 	sizeof (struct sctp_paddrinfo), 0 },
665 { SCTP_INITMSG, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
666 	sizeof (struct sctp_initmsg), 0 },
667 { SCTP_I_WANT_MAPPED_V4_ADDR, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
668 	sizeof (int), 0 },
669 { SCTP_MAXSEG, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
670 { SCTP_NODELAY, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
671 { SCTP_PEER_ADDR_PARAMS, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
672 	sizeof (struct sctp_paddrparams), 0 },
673 { SCTP_PRIMARY_ADDR, IPPROTO_SCTP, OA_W, OA_W, OP_NP, 0,
674 	sizeof (struct sctp_setpeerprim), 0 },
675 { SCTP_PRSCTP, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
676 { SCTP_GET_ASSOC_STATS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0,
677 	sizeof (sctp_assoc_stats_t), 0 },
678 { SCTP_REM_ADDR, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, OP_VARLEN,
679 	sizeof (int), 0 },
680 { SCTP_RTOINFO, IPPROTO_SCTP, OA_RW, OA_RW, OP_NP, 0,
681 	sizeof (struct sctp_rtoinfo), 0 },
682 { SCTP_SET_PEER_PRIMARY_ADDR, IPPROTO_SCTP, OA_W, OA_W, OP_NP, 0,
683 	sizeof (struct sctp_setprim), 0 },
684 { SCTP_STATUS, IPPROTO_SCTP, OA_R, OA_R, OP_NP, 0,
685 	sizeof (struct sctp_status), 0 },
686 { SCTP_UC_SWAP, IPPROTO_SCTP, OA_W, OA_W, OP_NP, 0,
687 	sizeof (struct sctp_uc_swap), 0 },
688 
689 { IP_OPTIONS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP,
690 	(OP_VARLEN|OP_NODEFAULT),
691 	40, -1 /* not initialized */ },
692 { T_IP_OPTIONS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP,
693 	(OP_VARLEN|OP_NODEFAULT),
694 	40, -1 /* not initialized */ },
695 
696 { IP_TOS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
697 { T_IP_TOS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
698 { IP_TTL,	IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_DEF_FN,
699 	sizeof (int), -1 /* not initialized */ },
700 
701 { IP_SEC_OPT, IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_NODEFAULT,
702 	sizeof (ipsec_req_t), -1 /* not initialized */ },
703 
704 { IP_BOUND_IF, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0,
705 	sizeof (int),	0 /* no ifindex */ },
706 
707 { IP_UNSPEC_SRC, IPPROTO_IP, OA_R, OA_RW, OP_RAW, 0,
708 	sizeof (int), 0 },
709 
710 { IPV6_UNICAST_HOPS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, OP_DEF_FN,
711 	sizeof (int), -1 /* not initialized */ },
712 
713 { IPV6_BOUND_IF, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
714 	sizeof (int),	0 /* no ifindex */ },
715 
716 { IP_DONTFRAG, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
717 
718 { IP_NEXTHOP, IPPROTO_IP, OA_R, OA_RW, OP_CONFIG, 0,
719 	sizeof (in_addr_t),	-1 /* not initialized  */ },
720 
721 { IPV6_UNSPEC_SRC, IPPROTO_IPV6, OA_R, OA_RW, OP_RAW, 0,
722 	sizeof (int), 0 },
723 
724 { IPV6_PKTINFO, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
725 	(OP_NODEFAULT|OP_VARLEN),
726 	sizeof (struct in6_pktinfo), -1 /* not initialized */ },
727 { IPV6_NEXTHOP, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
728 	OP_NODEFAULT,
729 	sizeof (sin6_t), -1 /* not initialized */ },
730 { IPV6_HOPOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
731 	(OP_VARLEN|OP_NODEFAULT), 255*8,
732 	-1 /* not initialized */ },
733 { IPV6_DSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
734 	(OP_VARLEN|OP_NODEFAULT), 255*8,
735 	-1 /* not initialized */ },
736 { IPV6_RTHDRDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
737 	(OP_VARLEN|OP_NODEFAULT), 255*8,
738 	-1 /* not initialized */ },
739 { IPV6_RTHDR, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
740 	(OP_VARLEN|OP_NODEFAULT), 255*8,
741 	-1 /* not initialized */ },
742 { IPV6_TCLASS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
743 	OP_NODEFAULT,
744 	sizeof (int), -1 /* not initialized */ },
745 { IPV6_PATHMTU, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
746 	OP_NODEFAULT,
747 	sizeof (struct ip6_mtuinfo), -1 /* not initialized */ },
748 { IPV6_DONTFRAG, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
749 	sizeof (int), 0 },
750 { IPV6_USE_MIN_MTU, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
751 	sizeof (int), 0 },
752 { IPV6_V6ONLY, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
753 	sizeof (int), 0 },
754 
755 /* Enable receipt of ancillary data */
756 { IPV6_RECVPKTINFO, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
757 	sizeof (int), 0 },
758 { IPV6_RECVHOPLIMIT, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
759 	sizeof (int), 0 },
760 { IPV6_RECVTCLASS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
761 	sizeof (int), 0 },
762 { IPV6_RECVHOPOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
763 	sizeof (int), 0 },
764 { _OLD_IPV6_RECVDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
765 	sizeof (int), 0 },
766 { IPV6_RECVDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
767 	sizeof (int), 0 },
768 { IPV6_RECVRTHDR, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
769 	sizeof (int), 0 },
770 { IPV6_RECVRTHDRDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
771 	sizeof (int), 0 },
772 { IPV6_RECVTCLASS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
773 	sizeof (int), 0 },
774 
775 { IPV6_SEC_OPT, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, OP_NODEFAULT,
776 	sizeof (ipsec_req_t), -1 /* not initialized */ },
777 { IPV6_SRC_PREFERENCES, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
778 	sizeof (uint32_t), IPV6_PREFER_SRC_DEFAULT },
779 };
780 
781 uint_t sctp_opt_arr_size = A_CNT(sctp_opt_arr);
782 
783 /* Handy on off switch for socket option processing. */
784 #define	ONOFF(x)	((x) == 0 ? 0 : 1)
785 
786 /*
787  * SCTP routine to get the values of options.
788  */
789 int
790 sctp_get_opt(sctp_t *sctp, int level, int name, void *ptr, socklen_t *optlen)
791 {
792 	int	*i1 = (int *)ptr;
793 	int	retval = 0;
794 	int	buflen = *optlen;
795 	conn_t	*connp = sctp->sctp_connp;
796 	conn_opt_arg_t	coas;
797 
798 	coas.coa_connp = connp;
799 	coas.coa_ixa = connp->conn_ixa;
800 	coas.coa_ipp = &connp->conn_xmit_ipp;
801 
802 	/* In most cases, the return buffer is just an int */
803 	*optlen = sizeof (int32_t);
804 
805 	RUN_SCTP(sctp);
806 
807 	if (connp->conn_state_flags & CONN_CLOSING) {
808 		WAKE_SCTP(sctp);
809 		return (EINVAL);
810 	}
811 
812 	/*
813 	 * Check that the level and name are supported by SCTP, and that
814 	 * the length and credentials are ok.
815 	 */
816 	retval = proto_opt_check(level, name, buflen, NULL, sctp_opt_arr,
817 	    sctp_opt_arr_size, B_FALSE, B_TRUE, connp->conn_cred);
818 	if (retval != 0) {
819 		WAKE_SCTP(sctp);
820 		if (retval < 0) {
821 			retval = proto_tlitosyserr(-retval);
822 		}
823 		return (retval);
824 	}
825 
826 	switch (level) {
827 	case IPPROTO_SCTP:
828 		switch (name) {
829 		case SCTP_RTOINFO:
830 			*optlen = sctp_get_rtoinfo(sctp, ptr);
831 			break;
832 		case SCTP_ASSOCINFO:
833 			*optlen = sctp_get_assocparams(sctp, ptr);
834 			break;
835 		case SCTP_INITMSG:
836 			*optlen = sctp_get_initmsg(sctp, ptr);
837 			break;
838 		case SCTP_NODELAY:
839 			*i1 = sctp->sctp_ndelay;
840 			break;
841 		case SCTP_AUTOCLOSE:
842 			*i1 = TICK_TO_SEC(sctp->sctp_autoclose);
843 			break;
844 		case SCTP_ADAPTATION_LAYER:
845 			((struct sctp_setadaptation *)ptr)->ssb_adaptation_ind =
846 			    sctp->sctp_tx_adaptation_code;
847 			break;
848 		case SCTP_PEER_ADDR_PARAMS:
849 			*optlen = sctp_get_peer_addr_params(sctp, ptr);
850 			break;
851 		case SCTP_DEFAULT_SEND_PARAM:
852 			*optlen = sctp_get_def_send_params(sctp, ptr);
853 			break;
854 		case SCTP_EVENTS: {
855 			struct sctp_event_subscribe *ev;
856 
857 			ev = (struct sctp_event_subscribe *)ptr;
858 			ev->sctp_data_io_event =
859 			    ONOFF(sctp->sctp_recvsndrcvinfo);
860 			ev->sctp_association_event =
861 			    ONOFF(sctp->sctp_recvassocevnt);
862 			ev->sctp_address_event =
863 			    ONOFF(sctp->sctp_recvpathevnt);
864 			ev->sctp_send_failure_event =
865 			    ONOFF(sctp->sctp_recvsendfailevnt);
866 			ev->sctp_peer_error_event =
867 			    ONOFF(sctp->sctp_recvpeererr);
868 			ev->sctp_shutdown_event =
869 			    ONOFF(sctp->sctp_recvshutdownevnt);
870 			ev->sctp_partial_delivery_event =
871 			    ONOFF(sctp->sctp_recvpdevnt);
872 			ev->sctp_adaptation_layer_event =
873 			    ONOFF(sctp->sctp_recvalevnt);
874 			*optlen = sizeof (struct sctp_event_subscribe);
875 			break;
876 		}
877 		case SCTP_STATUS:
878 			*optlen = sctp_get_status(sctp, ptr);
879 			break;
880 		case SCTP_GET_PEER_ADDR_INFO:
881 			retval = sctp_get_paddrinfo(sctp, ptr, optlen);
882 			break;
883 		case SCTP_GET_NLADDRS:
884 			*(int32_t *)ptr = sctp->sctp_nsaddrs;
885 			break;
886 		case SCTP_GET_LADDRS: {
887 			int addr_cnt;
888 			int addr_size;
889 
890 			if (connp->conn_family == AF_INET)
891 				addr_size = sizeof (struct sockaddr_in);
892 			else
893 				addr_size = sizeof (struct sockaddr_in6);
894 			addr_cnt = buflen / addr_size;
895 			retval = sctp_getmyaddrs(sctp, ptr, &addr_cnt);
896 			if (retval == 0)
897 				*optlen = addr_cnt * addr_size;
898 			break;
899 		}
900 		case SCTP_GET_NPADDRS: {
901 			int i;
902 			sctp_faddr_t *fp;
903 
904 			for (i = 0, fp = sctp->sctp_faddrs; fp != NULL;
905 			    i++, fp = fp->next)
906 				;
907 			*(int32_t *)ptr = i;
908 			break;
909 		}
910 		case SCTP_GET_PADDRS: {
911 			int addr_cnt;
912 			int addr_size;
913 
914 			if (connp->conn_family == AF_INET)
915 				addr_size = sizeof (struct sockaddr_in);
916 			else
917 				addr_size = sizeof (struct sockaddr_in6);
918 			addr_cnt = buflen / addr_size;
919 			retval = sctp_getpeeraddrs(sctp, ptr, &addr_cnt);
920 			if (retval == 0)
921 				*optlen = addr_cnt * addr_size;
922 			break;
923 		}
924 		case SCTP_PRSCTP:
925 			*i1 = sctp->sctp_prsctp_aware ? 1 : 0;
926 			break;
927 
928 		case SCTP_GET_ASSOC_STATS: {
929 			sctp_assoc_stats_t *sas;
930 
931 			sas = (sctp_assoc_stats_t *)ptr;
932 
933 			/*
934 			 * Copy the current stats to the stats struct.
935 			 * For stats which can be reset by snmp users
936 			 * add the cumulative and current stats for
937 			 * the raw totals to output to the user.
938 			 */
939 			sas->sas_gapcnt = sctp->sctp_gapcnt;
940 			sas->sas_outseqtsns = sctp->sctp_outseqtsns;
941 			sas->sas_osacks = sctp->sctp_osacks;
942 			sas->sas_isacks = sctp->sctp_isacks;
943 			sas->sas_idupchunks = sctp->sctp_idupchunks;
944 			sas->sas_rtxchunks =  sctp->sctp_rxtchunks +
945 			    sctp->sctp_cum_rxtchunks;
946 			sas->sas_octrlchunks = sctp->sctp_obchunks +
947 			    sctp->sctp_cum_obchunks;
948 			sas->sas_ictrlchunks = sctp->sctp_ibchunks +
949 			    sctp->sctp_cum_ibchunks;
950 			sas->sas_oodchunks = sctp->sctp_odchunks +
951 			    sctp->sctp_cum_odchunks;
952 			sas->sas_iodchunks = sctp->sctp_idchunks +
953 			    sctp->sctp_cum_idchunks;
954 			sas->sas_ouodchunks = sctp->sctp_oudchunks +
955 			    sctp->sctp_cum_oudchunks;
956 			sas->sas_iuodchunks = sctp->sctp_iudchunks +
957 			    sctp->sctp_cum_iudchunks;
958 
959 			/*
960 			 * Copy out the maximum observed RTO since the
961 			 * time this data was last requested
962 			 */
963 			if (sctp->sctp_maxrto == 0) {
964 				/* unchanged during obervation period */
965 				sas->sas_maxrto = sctp->sctp_prev_maxrto;
966 			} else {
967 				/* record new period maximum */
968 				sas->sas_maxrto = sctp->sctp_maxrto;
969 			}
970 			/* Record the value sent to the user this period */
971 			sctp->sctp_prev_maxrto = sas->sas_maxrto;
972 
973 			/* Mark beginning of a new observation period */
974 			sctp->sctp_maxrto = 0;
975 
976 			*optlen = sizeof (sctp_assoc_stats_t);
977 			break;
978 		}
979 		case SCTP_I_WANT_MAPPED_V4_ADDR:
980 		case SCTP_MAXSEG:
981 		case SCTP_DISABLE_FRAGMENTS:
982 		default:
983 			/* Not yet supported. */
984 			retval = ENOPROTOOPT;
985 			break;
986 		}
987 		WAKE_SCTP(sctp);
988 		return (retval);
989 	case IPPROTO_IP:
990 		if (connp->conn_family != AF_INET) {
991 			retval = EINVAL;
992 			break;
993 		}
994 		switch (name) {
995 		case IP_OPTIONS:
996 		case T_IP_OPTIONS: {
997 			/*
998 			 * This is compatible with BSD in that in only return
999 			 * the reverse source route with the final destination
1000 			 * as the last entry. The first 4 bytes of the option
1001 			 * will contain the final destination. Allocate a
1002 			 * buffer large enough to hold all the options, we
1003 			 * add IP_ADDR_LEN to SCTP_MAX_IP_OPTIONS_LENGTH since
1004 			 * ip_opt_get_user() adds the final destination
1005 			 * at the start.
1006 			 */
1007 			int	opt_len;
1008 			uchar_t	obuf[SCTP_MAX_IP_OPTIONS_LENGTH + IP_ADDR_LEN];
1009 
1010 			opt_len = ip_opt_get_user(connp, obuf);
1011 			ASSERT(opt_len <= sizeof (obuf));
1012 
1013 			if (buflen < opt_len) {
1014 				/* Silently truncate */
1015 				opt_len = buflen;
1016 			}
1017 			*optlen = opt_len;
1018 			bcopy(obuf, ptr, opt_len);
1019 			WAKE_SCTP(sctp);
1020 			return (0);
1021 		}
1022 		default:
1023 			break;
1024 		}
1025 		break;
1026 	}
1027 	mutex_enter(&connp->conn_lock);
1028 	retval = conn_opt_get(&coas, level, name, ptr);
1029 	mutex_exit(&connp->conn_lock);
1030 	WAKE_SCTP(sctp);
1031 	if (retval == -1)
1032 		return (EINVAL);
1033 	*optlen = retval;
1034 	return (0);
1035 }
1036 
1037 int
1038 sctp_set_opt(sctp_t *sctp, int level, int name, const void *invalp,
1039     socklen_t inlen)
1040 {
1041 	int		*i1 = (int *)invalp;
1042 	boolean_t	onoff;
1043 	int		retval = 0, addrcnt;
1044 	conn_t		*connp = sctp->sctp_connp;
1045 	sctp_stack_t	*sctps = sctp->sctp_sctps;
1046 	conn_opt_arg_t	coas;
1047 
1048 	coas.coa_connp = connp;
1049 	coas.coa_ixa = connp->conn_ixa;
1050 	coas.coa_ipp = &connp->conn_xmit_ipp;
1051 	coas.coa_ancillary = B_FALSE;
1052 	coas.coa_changed = 0;
1053 
1054 	/* In all cases, the size of the option must be bigger than int */
1055 	if (inlen >= sizeof (int32_t)) {
1056 		onoff = ONOFF(*i1);
1057 	}
1058 	retval = 0;
1059 
1060 	RUN_SCTP(sctp);
1061 
1062 	if (connp->conn_state_flags & CONN_CLOSING) {
1063 		WAKE_SCTP(sctp);
1064 		return (EINVAL);
1065 	}
1066 
1067 	/*
1068 	 * Check that the level and name are supported by SCTP, and that
1069 	 * the length an credentials are ok.
1070 	 */
1071 	retval = proto_opt_check(level, name, inlen, NULL, sctp_opt_arr,
1072 	    sctp_opt_arr_size, B_TRUE, B_FALSE, connp->conn_cred);
1073 	if (retval != 0) {
1074 		if (retval < 0) {
1075 			retval = proto_tlitosyserr(-retval);
1076 		}
1077 		goto done;
1078 	}
1079 
1080 	/* Note: both SCTP and TCP interpret l_linger as being in seconds */
1081 	switch (level) {
1082 	case SOL_SOCKET:
1083 		switch (name) {
1084 		case SO_SNDBUF:
1085 			if (*i1 > sctps->sctps_max_buf) {
1086 				retval = ENOBUFS;
1087 				goto done;
1088 			}
1089 			if (*i1 < 0) {
1090 				retval = EINVAL;
1091 				goto done;
1092 			}
1093 			connp->conn_sndbuf = *i1;
1094 			if (sctps->sctps_snd_lowat_fraction != 0) {
1095 				connp->conn_sndlowat = connp->conn_sndbuf /
1096 				    sctps->sctps_snd_lowat_fraction;
1097 			}
1098 			goto done;
1099 		case SO_RCVBUF:
1100 			if (*i1 > sctps->sctps_max_buf) {
1101 				retval = ENOBUFS;
1102 				goto done;
1103 			}
1104 			/* Silently ignore zero */
1105 			if (*i1 != 0) {
1106 				struct sock_proto_props sopp;
1107 
1108 				/*
1109 				 * Insist on a receive window that is at least
1110 				 * sctp_recv_hiwat_minmss * MSS (default 4*MSS)
1111 				 * to avoid funny interactions of Nagle
1112 				 * algorithm, SWS avoidance and delayed
1113 				 * acknowledgement.
1114 				 */
1115 				*i1 = MAX(*i1,
1116 				    sctps->sctps_recv_hiwat_minmss *
1117 				    sctp->sctp_mss);
1118 				/*
1119 				 * Note that sctp_rwnd is modified by the
1120 				 * protocol and here we just whack it.
1121 				 */
1122 				connp->conn_rcvbuf = sctp->sctp_rwnd = *i1;
1123 				sctp->sctp_irwnd = sctp->sctp_rwnd;
1124 				sctp->sctp_pd_point = sctp->sctp_rwnd;
1125 
1126 				sopp.sopp_flags = SOCKOPT_RCVHIWAT;
1127 				sopp.sopp_rxhiwat = connp->conn_rcvbuf;
1128 				sctp->sctp_ulp_prop(sctp->sctp_ulpd, &sopp);
1129 
1130 			}
1131 			/*
1132 			 * XXX should we return the rwnd here
1133 			 * and sctp_opt_get ?
1134 			 */
1135 			goto done;
1136 		case SO_ALLZONES:
1137 			if (sctp->sctp_state >= SCTPS_BOUND) {
1138 				retval = EINVAL;
1139 				goto done;
1140 			}
1141 			break;
1142 		case SO_MAC_EXEMPT:
1143 			if (sctp->sctp_state >= SCTPS_BOUND) {
1144 				retval = EINVAL;
1145 				goto done;
1146 			}
1147 			break;
1148 		}
1149 		break;
1150 
1151 	case IPPROTO_SCTP:
1152 		switch (name) {
1153 		case SCTP_RTOINFO:
1154 			retval = sctp_set_rtoinfo(sctp, invalp);
1155 			break;
1156 		case SCTP_ASSOCINFO:
1157 			retval = sctp_set_assocparams(sctp, invalp);
1158 			break;
1159 		case SCTP_INITMSG:
1160 			retval = sctp_set_initmsg(sctp, invalp, inlen);
1161 			break;
1162 		case SCTP_NODELAY:
1163 			sctp->sctp_ndelay = ONOFF(*i1);
1164 			break;
1165 		case SCTP_AUTOCLOSE:
1166 			if (SEC_TO_TICK(*i1) < 0) {
1167 				retval = EINVAL;
1168 				break;
1169 			}
1170 			/* Convert the number of seconds to ticks. */
1171 			sctp->sctp_autoclose = SEC_TO_TICK(*i1);
1172 			sctp_heartbeat_timer(sctp);
1173 			break;
1174 		case SCTP_SET_PEER_PRIMARY_ADDR:
1175 			retval = sctp_set_peerprim(sctp, invalp);
1176 			break;
1177 		case SCTP_PRIMARY_ADDR:
1178 			retval = sctp_set_prim(sctp, invalp);
1179 			break;
1180 		case SCTP_ADAPTATION_LAYER: {
1181 			struct sctp_setadaptation *ssb;
1182 
1183 			ssb = (struct sctp_setadaptation *)invalp;
1184 			sctp->sctp_send_adaptation = 1;
1185 			sctp->sctp_tx_adaptation_code = ssb->ssb_adaptation_ind;
1186 			break;
1187 		}
1188 		case SCTP_PEER_ADDR_PARAMS:
1189 			retval = sctp_set_peer_addr_params(sctp, invalp);
1190 			break;
1191 		case SCTP_DEFAULT_SEND_PARAM:
1192 			retval = sctp_set_def_send_params(sctp, invalp);
1193 			break;
1194 		case SCTP_EVENTS: {
1195 			struct sctp_event_subscribe *ev;
1196 
1197 			ev = (struct sctp_event_subscribe *)invalp;
1198 			sctp->sctp_recvsndrcvinfo =
1199 			    ONOFF(ev->sctp_data_io_event);
1200 			sctp->sctp_recvassocevnt =
1201 			    ONOFF(ev->sctp_association_event);
1202 			sctp->sctp_recvpathevnt =
1203 			    ONOFF(ev->sctp_address_event);
1204 			sctp->sctp_recvsendfailevnt =
1205 			    ONOFF(ev->sctp_send_failure_event);
1206 			sctp->sctp_recvpeererr =
1207 			    ONOFF(ev->sctp_peer_error_event);
1208 			sctp->sctp_recvshutdownevnt =
1209 			    ONOFF(ev->sctp_shutdown_event);
1210 			sctp->sctp_recvpdevnt =
1211 			    ONOFF(ev->sctp_partial_delivery_event);
1212 			sctp->sctp_recvalevnt =
1213 			    ONOFF(ev->sctp_adaptation_layer_event);
1214 			break;
1215 		}
1216 		case SCTP_ADD_ADDR:
1217 		case SCTP_REM_ADDR:
1218 			/*
1219 			 * The sctp_t has to be bound first before
1220 			 * the address list can be changed.
1221 			 */
1222 			if (sctp->sctp_state < SCTPS_BOUND) {
1223 				retval = EINVAL;
1224 				break;
1225 			}
1226 			if (connp->conn_family == AF_INET) {
1227 				addrcnt = inlen / sizeof (struct sockaddr_in);
1228 			} else {
1229 				ASSERT(connp->conn_family == AF_INET6);
1230 				addrcnt = inlen / sizeof (struct sockaddr_in6);
1231 			}
1232 			if (name == SCTP_ADD_ADDR) {
1233 				retval = sctp_bind_add(sctp, invalp, addrcnt,
1234 				    B_TRUE, connp->conn_lport);
1235 			} else {
1236 				retval = sctp_bind_del(sctp, invalp, addrcnt,
1237 				    B_TRUE);
1238 			}
1239 			break;
1240 		case SCTP_UC_SWAP: {
1241 			struct sctp_uc_swap *us;
1242 
1243 			/*
1244 			 * Change handle & upcalls.
1245 			 */
1246 			us = (struct sctp_uc_swap *)invalp;
1247 			sctp->sctp_ulpd = us->sus_handle;
1248 			sctp->sctp_upcalls = us->sus_upcalls;
1249 			break;
1250 		}
1251 		case SCTP_PRSCTP:
1252 			sctp->sctp_prsctp_aware = onoff;
1253 			break;
1254 		case SCTP_I_WANT_MAPPED_V4_ADDR:
1255 		case SCTP_MAXSEG:
1256 		case SCTP_DISABLE_FRAGMENTS:
1257 			/* Not yet supported. */
1258 			retval = ENOPROTOOPT;
1259 			break;
1260 		}
1261 		goto done;
1262 
1263 	case IPPROTO_IP:
1264 		if (connp->conn_family != AF_INET) {
1265 			retval = ENOPROTOOPT;
1266 			goto done;
1267 		}
1268 		switch (name) {
1269 		case IP_SEC_OPT:
1270 			/*
1271 			 * We should not allow policy setting after
1272 			 * we start listening for connections.
1273 			 */
1274 			if (sctp->sctp_state >= SCTPS_LISTEN) {
1275 				retval = EINVAL;
1276 				goto done;
1277 			}
1278 			break;
1279 		}
1280 		break;
1281 	case IPPROTO_IPV6:
1282 		if (connp->conn_family != AF_INET6) {
1283 			retval = EINVAL;
1284 			goto done;
1285 		}
1286 
1287 		switch (name) {
1288 		case IPV6_RECVPKTINFO:
1289 			/* Send it with the next msg */
1290 			sctp->sctp_recvifindex = 0;
1291 			break;
1292 		case IPV6_RECVTCLASS:
1293 			/* Force it to be sent up with the next msg */
1294 			sctp->sctp_recvtclass = 0xffffffffU;
1295 			break;
1296 		case IPV6_RECVHOPLIMIT:
1297 			/* Force it to be sent up with the next msg */
1298 			sctp->sctp_recvhops = 0xffffffffU;
1299 			break;
1300 		case IPV6_SEC_OPT:
1301 			/*
1302 			 * We should not allow policy setting after
1303 			 * we start listening for connections.
1304 			 */
1305 			if (sctp->sctp_state >= SCTPS_LISTEN) {
1306 				retval = EINVAL;
1307 				goto done;
1308 			}
1309 			break;
1310 		case IPV6_V6ONLY:
1311 			/*
1312 			 * After the bound state, setting the v6only option
1313 			 * is too late.
1314 			 */
1315 			if (sctp->sctp_state >= SCTPS_BOUND) {
1316 				retval = EINVAL;
1317 				goto done;
1318 			}
1319 			break;
1320 		}
1321 		break;
1322 	}
1323 
1324 	retval = conn_opt_set(&coas, level, name, inlen, (uchar_t *)invalp,
1325 	    B_FALSE, connp->conn_cred);
1326 	if (retval != 0)
1327 		goto done;
1328 
1329 	if (coas.coa_changed & COA_ROUTE_CHANGED) {
1330 		sctp_faddr_t *fp;
1331 		/*
1332 		 * We recache the information which might pick a different
1333 		 * source and redo IPsec as a result.
1334 		 */
1335 		for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next)
1336 			sctp_get_dest(sctp, fp);
1337 	}
1338 	if (coas.coa_changed & COA_HEADER_CHANGED) {
1339 		retval = sctp_build_hdrs(sctp, KM_NOSLEEP);
1340 		if (retval != 0)
1341 			goto done;
1342 	}
1343 	if (coas.coa_changed & COA_WROFF_CHANGED) {
1344 		connp->conn_wroff = connp->conn_ht_iphc_allocated +
1345 		    sctps->sctps_wroff_xtra;
1346 		if (sctp->sctp_current != NULL) {
1347 			/*
1348 			 * Could be setting options before setting up
1349 			 * connection.
1350 			 */
1351 			sctp_set_ulp_prop(sctp);
1352 		}
1353 	}
1354 done:
1355 	WAKE_SCTP(sctp);
1356 	return (retval);
1357 }
1358 
1359 /*
1360  * SCTP exported kernel interface for geting the first source address of
1361  * a sctp_t.  The parameter addr is assumed to have enough space to hold
1362  * one socket address.
1363  */
1364 int
1365 sctp_getsockname(sctp_t *sctp, struct sockaddr *addr, socklen_t *addrlen)
1366 {
1367 	int	err = 0;
1368 	int	addrcnt = 1;
1369 	sin_t	*sin4;
1370 	sin6_t	*sin6;
1371 	conn_t	*connp = sctp->sctp_connp;
1372 
1373 	ASSERT(sctp != NULL);
1374 
1375 	RUN_SCTP(sctp);
1376 	addr->sa_family = connp->conn_family;
1377 	switch (connp->conn_family) {
1378 	case AF_INET:
1379 		sin4 = (sin_t *)addr;
1380 		if ((sctp->sctp_state <= SCTPS_LISTEN) &&
1381 		    sctp->sctp_bound_to_all) {
1382 			sin4->sin_addr.s_addr = INADDR_ANY;
1383 			sin4->sin_port = connp->conn_lport;
1384 		} else {
1385 			err = sctp_getmyaddrs(sctp, sin4, &addrcnt);
1386 			if (err != 0) {
1387 				*addrlen = 0;
1388 				break;
1389 			}
1390 		}
1391 		*addrlen = sizeof (struct sockaddr_in);
1392 		break;
1393 	case AF_INET6:
1394 		sin6 = (sin6_t *)addr;
1395 		if ((sctp->sctp_state <= SCTPS_LISTEN) &&
1396 		    sctp->sctp_bound_to_all) {
1397 			bzero(&sin6->sin6_addr, sizeof (sin6->sin6_addr));
1398 			sin6->sin6_port = connp->conn_lport;
1399 		} else {
1400 			err = sctp_getmyaddrs(sctp, sin6, &addrcnt);
1401 			if (err != 0) {
1402 				*addrlen = 0;
1403 				break;
1404 			}
1405 		}
1406 		*addrlen = sizeof (struct sockaddr_in6);
1407 		/* Note that flowinfo is only returned for getpeername */
1408 		break;
1409 	}
1410 	WAKE_SCTP(sctp);
1411 	return (err);
1412 }
1413 
1414 /*
1415  * SCTP exported kernel interface for geting the primary peer address of
1416  * a sctp_t.  The parameter addr is assumed to have enough space to hold
1417  * one socket address.
1418  */
1419 int
1420 sctp_getpeername(sctp_t *sctp, struct sockaddr *addr, socklen_t *addrlen)
1421 {
1422 	int	err = 0;
1423 	int	addrcnt = 1;
1424 	sin6_t	*sin6;
1425 	conn_t	*connp = sctp->sctp_connp;
1426 
1427 	ASSERT(sctp != NULL);
1428 
1429 	RUN_SCTP(sctp);
1430 	addr->sa_family = connp->conn_family;
1431 	switch (connp->conn_family) {
1432 	case AF_INET:
1433 		err = sctp_getpeeraddrs(sctp, addr, &addrcnt);
1434 		if (err != 0) {
1435 			*addrlen = 0;
1436 			break;
1437 		}
1438 		*addrlen = sizeof (struct sockaddr_in);
1439 		break;
1440 	case AF_INET6:
1441 		sin6 = (sin6_t *)addr;
1442 		err = sctp_getpeeraddrs(sctp, sin6, &addrcnt);
1443 		if (err != 0) {
1444 			*addrlen = 0;
1445 			break;
1446 		}
1447 		*addrlen = sizeof (struct sockaddr_in6);
1448 		break;
1449 	}
1450 	WAKE_SCTP(sctp);
1451 	return (err);
1452 }
1453 
1454 /*
1455  * Return a list of IP addresses of the peer endpoint of this sctp_t.
1456  * The parameter paddrs is supposed to be either (struct sockaddr_in *) or
1457  * (struct sockaddr_in6 *) depending on the address family of the sctp_t.
1458  */
1459 int
1460 sctp_getpeeraddrs(sctp_t *sctp, void *paddrs, int *addrcnt)
1461 {
1462 	int			family;
1463 	struct sockaddr_in	*sin4;
1464 	struct sockaddr_in6	*sin6;
1465 	int			max;
1466 	int			cnt;
1467 	sctp_faddr_t		*fp = sctp->sctp_faddrs;
1468 	in6_addr_t		addr;
1469 	conn_t			*connp = sctp->sctp_connp;
1470 
1471 	ASSERT(sctp != NULL);
1472 
1473 	if (sctp->sctp_faddrs == NULL)
1474 		return (ENOTCONN);
1475 
1476 	family = connp->conn_family;
1477 	max = *addrcnt;
1478 
1479 	/* If we want only one, give the primary */
1480 	if (max == 1) {
1481 		addr = sctp->sctp_primary->faddr;
1482 		switch (family) {
1483 		case AF_INET:
1484 			sin4 = paddrs;
1485 			IN6_V4MAPPED_TO_INADDR(&addr, &sin4->sin_addr);
1486 			sin4->sin_port = connp->conn_fport;
1487 			sin4->sin_family = AF_INET;
1488 			break;
1489 
1490 		case AF_INET6:
1491 			sin6 = paddrs;
1492 			sin6->sin6_addr = addr;
1493 			sin6->sin6_port = connp->conn_fport;
1494 			sin6->sin6_family = AF_INET6;
1495 			sin6->sin6_flowinfo = connp->conn_flowinfo;
1496 			if (IN6_IS_ADDR_LINKSCOPE(&addr) &&
1497 			    sctp->sctp_primary != NULL &&
1498 			    (sctp->sctp_primary->ixa->ixa_flags &
1499 			    IXAF_SCOPEID_SET)) {
1500 				sin6->sin6_scope_id =
1501 				    sctp->sctp_primary->ixa->ixa_scopeid;
1502 			} else {
1503 				sin6->sin6_scope_id = 0;
1504 			}
1505 			sin6->__sin6_src_id = 0;
1506 			break;
1507 		}
1508 		return (0);
1509 	}
1510 
1511 	for (cnt = 0; cnt < max && fp != NULL; cnt++, fp = fp->next) {
1512 		addr = fp->faddr;
1513 		switch (family) {
1514 		case AF_INET:
1515 			ASSERT(IN6_IS_ADDR_V4MAPPED(&addr));
1516 			sin4 = (struct sockaddr_in *)paddrs + cnt;
1517 			IN6_V4MAPPED_TO_INADDR(&addr, &sin4->sin_addr);
1518 			sin4->sin_port = connp->conn_fport;
1519 			sin4->sin_family = AF_INET;
1520 			break;
1521 		case AF_INET6:
1522 			sin6 = (struct sockaddr_in6 *)paddrs + cnt;
1523 			sin6->sin6_addr = addr;
1524 			sin6->sin6_port = connp->conn_fport;
1525 			sin6->sin6_family = AF_INET6;
1526 			sin6->sin6_flowinfo = connp->conn_flowinfo;
1527 			if (IN6_IS_ADDR_LINKSCOPE(&addr) &&
1528 			    (fp->ixa->ixa_flags & IXAF_SCOPEID_SET))
1529 				sin6->sin6_scope_id = fp->ixa->ixa_scopeid;
1530 			else
1531 				sin6->sin6_scope_id = 0;
1532 			sin6->__sin6_src_id = 0;
1533 			break;
1534 		}
1535 	}
1536 	*addrcnt = cnt;
1537 	return (0);
1538 }
1539