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