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