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