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