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