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