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