1 /*- 2 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 3 * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. 4 * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * a) Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * b) Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the distribution. 15 * 16 * c) Neither the name of Cisco Systems, Inc. nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 * THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include <stdio.h> 37 #include <string.h> 38 #include <errno.h> 39 #include <stdlib.h> 40 #include <unistd.h> 41 #include <sys/types.h> 42 #include <sys/socket.h> 43 #include <sys/errno.h> 44 #include <sys/syscall.h> 45 #include <sys/uio.h> 46 #include <netinet/in.h> 47 #include <arpa/inet.h> 48 #include <netinet/sctp_uio.h> 49 #include <netinet/sctp.h> 50 51 #ifndef IN6_IS_ADDR_V4MAPPED 52 #define IN6_IS_ADDR_V4MAPPED(a) \ 53 ((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \ 54 (*(const uint32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \ 55 (*(const uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) 56 #endif 57 58 #define SCTP_CONTROL_VEC_SIZE_RCV 16384 59 60 61 static void 62 in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 63 { 64 bzero(sin, sizeof(*sin)); 65 sin->sin_len = sizeof(struct sockaddr_in); 66 sin->sin_family = AF_INET; 67 sin->sin_port = sin6->sin6_port; 68 sin->sin_addr.s_addr = sin6->sin6_addr.__u6_addr.__u6_addr32[3]; 69 } 70 71 int 72 sctp_getaddrlen(sa_family_t family) 73 { 74 int ret, sd; 75 socklen_t siz; 76 struct sctp_assoc_value av; 77 78 av.assoc_value = family; 79 siz = sizeof(av); 80 #if defined(AF_INET) 81 sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 82 #elif defined(AF_INET6) 83 sd = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP); 84 #else 85 sd = -1; 86 #endif 87 if (sd == -1) { 88 return (-1); 89 } 90 ret = getsockopt(sd, IPPROTO_SCTP, SCTP_GET_ADDR_LEN, &av, &siz); 91 close(sd); 92 if (ret == 0) { 93 return ((int)av.assoc_value); 94 } else { 95 return (-1); 96 } 97 } 98 99 int 100 sctp_connectx(int sd, const struct sockaddr *addrs, int addrcnt, 101 sctp_assoc_t * id) 102 { 103 char *buf; 104 int i, ret, *aa; 105 char *cpto; 106 const struct sockaddr *at; 107 size_t len; 108 109 /* validate the address count and list */ 110 if ((addrs == NULL) || (addrcnt <= 0)) { 111 errno = EINVAL; 112 return (-1); 113 } 114 if ((buf = malloc(sizeof(int) + (size_t)addrcnt * sizeof(struct sockaddr_in6))) == NULL) { 115 errno = E2BIG; 116 return (-1); 117 } 118 len = sizeof(int); 119 at = addrs; 120 cpto = buf + sizeof(int); 121 /* validate all the addresses and get the size */ 122 for (i = 0; i < addrcnt; i++) { 123 switch (at->sa_family) { 124 case AF_INET: 125 if (at->sa_len != sizeof(struct sockaddr_in)) { 126 free(buf); 127 errno = EINVAL; 128 return (-1); 129 } 130 memcpy(cpto, at, sizeof(struct sockaddr_in)); 131 cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in)); 132 len += sizeof(struct sockaddr_in); 133 break; 134 case AF_INET6: 135 if (at->sa_len != sizeof(struct sockaddr_in6)) { 136 free(buf); 137 errno = EINVAL; 138 return (-1); 139 } 140 if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)at)->sin6_addr)) { 141 in6_sin6_2_sin((struct sockaddr_in *)cpto, (struct sockaddr_in6 *)at); 142 cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in)); 143 len += sizeof(struct sockaddr_in); 144 } else { 145 memcpy(cpto, at, sizeof(struct sockaddr_in6)); 146 cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in6)); 147 len += sizeof(struct sockaddr_in6); 148 } 149 break; 150 default: 151 free(buf); 152 errno = EINVAL; 153 return (-1); 154 } 155 at = (struct sockaddr *)((caddr_t)at + at->sa_len); 156 } 157 aa = (int *)buf; 158 *aa = addrcnt; 159 ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X, (void *)buf, 160 (socklen_t) len); 161 if ((ret == 0) && (id != NULL)) { 162 *id = *(sctp_assoc_t *) buf; 163 } 164 free(buf); 165 return (ret); 166 } 167 168 int 169 sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags) 170 { 171 struct sctp_getaddresses *gaddrs; 172 struct sockaddr *sa; 173 struct sockaddr_in *sin; 174 struct sockaddr_in6 *sin6; 175 int i; 176 size_t argsz; 177 uint16_t sport = 0; 178 179 /* validate the flags */ 180 if ((flags != SCTP_BINDX_ADD_ADDR) && 181 (flags != SCTP_BINDX_REM_ADDR)) { 182 errno = EFAULT; 183 return (-1); 184 } 185 /* validate the address count and list */ 186 if ((addrcnt <= 0) || (addrs == NULL)) { 187 errno = EINVAL; 188 return (-1); 189 } 190 /* First pre-screen the addresses */ 191 sa = addrs; 192 for (i = 0; i < addrcnt; i++) { 193 switch (sa->sa_family) { 194 case AF_INET: 195 if (sa->sa_len != sizeof(struct sockaddr_in)) { 196 errno = EINVAL; 197 return (-1); 198 } 199 sin = (struct sockaddr_in *)sa; 200 if (sin->sin_port) { 201 /* non-zero port, check or save */ 202 if (sport) { 203 /* Check against our port */ 204 if (sport != sin->sin_port) { 205 errno = EINVAL; 206 return (-1); 207 } 208 } else { 209 /* save off the port */ 210 sport = sin->sin_port; 211 } 212 } 213 break; 214 case AF_INET6: 215 if (sa->sa_len != sizeof(struct sockaddr_in6)) { 216 errno = EINVAL; 217 return (-1); 218 } 219 sin6 = (struct sockaddr_in6 *)sa; 220 if (sin6->sin6_port) { 221 /* non-zero port, check or save */ 222 if (sport) { 223 /* Check against our port */ 224 if (sport != sin6->sin6_port) { 225 errno = EINVAL; 226 return (-1); 227 } 228 } else { 229 /* save off the port */ 230 sport = sin6->sin6_port; 231 } 232 } 233 break; 234 default: 235 /* Invalid address family specified. */ 236 errno = EAFNOSUPPORT; 237 return (-1); 238 } 239 sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 240 } 241 argsz = sizeof(struct sctp_getaddresses) + 242 sizeof(struct sockaddr_storage); 243 if ((gaddrs = (struct sctp_getaddresses *)malloc(argsz)) == NULL) { 244 errno = ENOMEM; 245 return (-1); 246 } 247 sa = addrs; 248 for (i = 0; i < addrcnt; i++) { 249 memset(gaddrs, 0, argsz); 250 gaddrs->sget_assoc_id = 0; 251 memcpy(gaddrs->addr, sa, sa->sa_len); 252 /* 253 * Now, if there was a port mentioned, assure that the first 254 * address has that port to make sure it fails or succeeds 255 * correctly. 256 */ 257 if ((i == 0) && (sport != 0)) { 258 switch (gaddrs->addr->sa_family) { 259 case AF_INET: 260 sin = (struct sockaddr_in *)gaddrs->addr; 261 sin->sin_port = sport; 262 break; 263 case AF_INET6: 264 sin6 = (struct sockaddr_in6 *)gaddrs->addr; 265 sin6->sin6_port = sport; 266 break; 267 } 268 } 269 if (setsockopt(sd, IPPROTO_SCTP, flags, gaddrs, 270 (socklen_t) argsz) != 0) { 271 free(gaddrs); 272 return (-1); 273 } 274 sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 275 } 276 free(gaddrs); 277 return (0); 278 } 279 280 int 281 sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t * size) 282 { 283 if (arg == NULL) { 284 errno = EINVAL; 285 return (-1); 286 } 287 if ((id == SCTP_CURRENT_ASSOC) || 288 (id == SCTP_ALL_ASSOC)) { 289 errno = EINVAL; 290 return (-1); 291 } 292 switch (opt) { 293 case SCTP_RTOINFO: 294 ((struct sctp_rtoinfo *)arg)->srto_assoc_id = id; 295 break; 296 case SCTP_ASSOCINFO: 297 ((struct sctp_assocparams *)arg)->sasoc_assoc_id = id; 298 break; 299 case SCTP_DEFAULT_SEND_PARAM: 300 ((struct sctp_assocparams *)arg)->sasoc_assoc_id = id; 301 break; 302 case SCTP_PRIMARY_ADDR: 303 ((struct sctp_setprim *)arg)->ssp_assoc_id = id; 304 break; 305 case SCTP_PEER_ADDR_PARAMS: 306 ((struct sctp_paddrparams *)arg)->spp_assoc_id = id; 307 break; 308 case SCTP_MAXSEG: 309 ((struct sctp_assoc_value *)arg)->assoc_id = id; 310 break; 311 case SCTP_AUTH_KEY: 312 ((struct sctp_authkey *)arg)->sca_assoc_id = id; 313 break; 314 case SCTP_AUTH_ACTIVE_KEY: 315 ((struct sctp_authkeyid *)arg)->scact_assoc_id = id; 316 break; 317 case SCTP_DELAYED_SACK: 318 ((struct sctp_sack_info *)arg)->sack_assoc_id = id; 319 break; 320 case SCTP_CONTEXT: 321 ((struct sctp_assoc_value *)arg)->assoc_id = id; 322 break; 323 case SCTP_STATUS: 324 ((struct sctp_status *)arg)->sstat_assoc_id = id; 325 break; 326 case SCTP_GET_PEER_ADDR_INFO: 327 ((struct sctp_paddrinfo *)arg)->spinfo_assoc_id = id; 328 break; 329 case SCTP_PEER_AUTH_CHUNKS: 330 ((struct sctp_authchunks *)arg)->gauth_assoc_id = id; 331 break; 332 case SCTP_LOCAL_AUTH_CHUNKS: 333 ((struct sctp_authchunks *)arg)->gauth_assoc_id = id; 334 break; 335 case SCTP_TIMEOUTS: 336 ((struct sctp_timeouts *)arg)->stimo_assoc_id = id; 337 break; 338 case SCTP_EVENT: 339 ((struct sctp_event *)arg)->se_assoc_id = id; 340 break; 341 case SCTP_DEFAULT_SNDINFO: 342 ((struct sctp_sndinfo *)arg)->snd_assoc_id = id; 343 break; 344 case SCTP_DEFAULT_PRINFO: 345 ((struct sctp_default_prinfo *)arg)->pr_assoc_id = id; 346 break; 347 case SCTP_PEER_ADDR_THLDS: 348 ((struct sctp_paddrthlds *)arg)->spt_assoc_id = id; 349 break; 350 case SCTP_REMOTE_UDP_ENCAPS_PORT: 351 ((struct sctp_udpencaps *)arg)->sue_assoc_id = id; 352 break; 353 case SCTP_ECN_SUPPORTED: 354 ((struct sctp_assoc_value *)arg)->assoc_id = id; 355 break; 356 case SCTP_PR_SUPPORTED: 357 ((struct sctp_assoc_value *)arg)->assoc_id = id; 358 break; 359 case SCTP_AUTH_SUPPORTED: 360 ((struct sctp_assoc_value *)arg)->assoc_id = id; 361 break; 362 case SCTP_ASCONF_SUPPORTED: 363 ((struct sctp_assoc_value *)arg)->assoc_id = id; 364 break; 365 case SCTP_RECONFIG_SUPPORTED: 366 ((struct sctp_assoc_value *)arg)->assoc_id = id; 367 break; 368 case SCTP_NRSACK_SUPPORTED: 369 ((struct sctp_assoc_value *)arg)->assoc_id = id; 370 break; 371 case SCTP_PKTDROP_SUPPORTED: 372 ((struct sctp_assoc_value *)arg)->assoc_id = id; 373 break; 374 case SCTP_MAX_BURST: 375 ((struct sctp_assoc_value *)arg)->assoc_id = id; 376 break; 377 case SCTP_ENABLE_STREAM_RESET: 378 ((struct sctp_assoc_value *)arg)->assoc_id = id; 379 break; 380 case SCTP_PR_STREAM_STATUS: 381 ((struct sctp_prstatus *)arg)->sprstat_assoc_id = id; 382 break; 383 case SCTP_PR_ASSOC_STATUS: 384 ((struct sctp_prstatus *)arg)->sprstat_assoc_id = id; 385 break; 386 default: 387 break; 388 } 389 return (getsockopt(sd, IPPROTO_SCTP, opt, arg, size)); 390 } 391 392 int 393 sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs) 394 { 395 struct sctp_getaddresses *addrs; 396 struct sockaddr *sa; 397 sctp_assoc_t asoc; 398 caddr_t lim; 399 socklen_t opt_len; 400 int cnt; 401 402 if (raddrs == NULL) { 403 errno = EFAULT; 404 return (-1); 405 } 406 asoc = id; 407 opt_len = (socklen_t) sizeof(sctp_assoc_t); 408 if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE, 409 &asoc, &opt_len) != 0) { 410 return (-1); 411 } 412 /* size required is returned in 'asoc' */ 413 opt_len = (socklen_t) ((size_t)asoc + sizeof(struct sctp_getaddresses)); 414 addrs = calloc(1, (size_t)opt_len); 415 if (addrs == NULL) { 416 errno = ENOMEM; 417 return (-1); 418 } 419 addrs->sget_assoc_id = id; 420 /* Now lets get the array of addresses */ 421 if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES, 422 addrs, &opt_len) != 0) { 423 free(addrs); 424 return (-1); 425 } 426 *raddrs = (struct sockaddr *)&addrs->addr[0]; 427 cnt = 0; 428 sa = (struct sockaddr *)&addrs->addr[0]; 429 lim = (caddr_t)addrs + opt_len; 430 while (((caddr_t)sa < lim) && (sa->sa_len > 0)) { 431 sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 432 cnt++; 433 } 434 return (cnt); 435 } 436 437 void 438 sctp_freepaddrs(struct sockaddr *addrs) 439 { 440 void *fr_addr; 441 442 /* Take away the hidden association id */ 443 fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t)); 444 /* Now free it */ 445 free(fr_addr); 446 } 447 448 int 449 sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs) 450 { 451 struct sctp_getaddresses *addrs; 452 caddr_t lim; 453 struct sockaddr *sa; 454 size_t size_of_addresses; 455 socklen_t opt_len; 456 int cnt; 457 458 if (raddrs == NULL) { 459 errno = EFAULT; 460 return (-1); 461 } 462 size_of_addresses = 0; 463 opt_len = (socklen_t) sizeof(int); 464 if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE, 465 &size_of_addresses, &opt_len) != 0) { 466 errno = ENOMEM; 467 return (-1); 468 } 469 if (size_of_addresses == 0) { 470 errno = ENOTCONN; 471 return (-1); 472 } 473 opt_len = (socklen_t) (size_of_addresses + 474 sizeof(struct sockaddr_storage) + 475 sizeof(struct sctp_getaddresses)); 476 addrs = calloc(1, (size_t)opt_len); 477 if (addrs == NULL) { 478 errno = ENOMEM; 479 return (-1); 480 } 481 addrs->sget_assoc_id = id; 482 /* Now lets get the array of addresses */ 483 if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs, 484 &opt_len) != 0) { 485 free(addrs); 486 errno = ENOMEM; 487 return (-1); 488 } 489 *raddrs = (struct sockaddr *)&addrs->addr[0]; 490 cnt = 0; 491 sa = (struct sockaddr *)&addrs->addr[0]; 492 lim = (caddr_t)addrs + opt_len; 493 while (((caddr_t)sa < lim) && (sa->sa_len > 0)) { 494 sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 495 cnt++; 496 } 497 return (cnt); 498 } 499 500 void 501 sctp_freeladdrs(struct sockaddr *addrs) 502 { 503 void *fr_addr; 504 505 /* Take away the hidden association id */ 506 fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t)); 507 /* Now free it */ 508 free(fr_addr); 509 } 510 511 ssize_t 512 sctp_sendmsg(int s, 513 const void *data, 514 size_t len, 515 const struct sockaddr *to, 516 socklen_t tolen, 517 uint32_t ppid, 518 uint32_t flags, 519 uint16_t stream_no, 520 uint32_t timetolive, 521 uint32_t context) 522 { 523 #ifdef SYS_sctp_generic_sendmsg 524 struct sctp_sndrcvinfo sinfo; 525 526 memset(&sinfo, 0, sizeof(struct sctp_sndrcvinfo)); 527 sinfo.sinfo_ppid = ppid; 528 sinfo.sinfo_flags = flags; 529 sinfo.sinfo_stream = stream_no; 530 sinfo.sinfo_timetolive = timetolive; 531 sinfo.sinfo_context = context; 532 sinfo.sinfo_assoc_id = 0; 533 return (syscall(SYS_sctp_generic_sendmsg, s, 534 data, len, to, tolen, &sinfo, 0)); 535 #else 536 struct msghdr msg; 537 struct sctp_sndrcvinfo *sinfo; 538 struct iovec iov; 539 char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; 540 struct cmsghdr *cmsg; 541 struct sockaddr *who = NULL; 542 union { 543 struct sockaddr_in in; 544 struct sockaddr_in6 in6; 545 } addr; 546 547 if ((tolen > 0) && 548 ((to == NULL) || (tolen < sizeof(struct sockaddr)))) { 549 errno = EINVAL; 550 return (-1); 551 } 552 if ((to != NULL) && (tolen > 0)) { 553 switch (to->sa_family) { 554 case AF_INET: 555 if (tolen != sizeof(struct sockaddr_in)) { 556 errno = EINVAL; 557 return (-1); 558 } 559 if ((to->sa_len > 0) && 560 (to->sa_len != sizeof(struct sockaddr_in))) { 561 errno = EINVAL; 562 return (-1); 563 } 564 memcpy(&addr, to, sizeof(struct sockaddr_in)); 565 addr.in.sin_len = sizeof(struct sockaddr_in); 566 break; 567 case AF_INET6: 568 if (tolen != sizeof(struct sockaddr_in6)) { 569 errno = EINVAL; 570 return (-1); 571 } 572 if ((to->sa_len > 0) && 573 (to->sa_len != sizeof(struct sockaddr_in6))) { 574 errno = EINVAL; 575 return (-1); 576 } 577 memcpy(&addr, to, sizeof(struct sockaddr_in6)); 578 addr.in6.sin6_len = sizeof(struct sockaddr_in6); 579 break; 580 default: 581 errno = EAFNOSUPPORT; 582 return (-1); 583 } 584 who = (struct sockaddr *)&addr; 585 } 586 iov.iov_base = (char *)data; 587 iov.iov_len = len; 588 589 if (who) { 590 msg.msg_name = (caddr_t)who; 591 msg.msg_namelen = who->sa_len; 592 } else { 593 msg.msg_name = (caddr_t)NULL; 594 msg.msg_namelen = 0; 595 } 596 msg.msg_iov = &iov; 597 msg.msg_iovlen = 1; 598 msg.msg_control = cmsgbuf; 599 msg.msg_controllen = CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); 600 cmsg = (struct cmsghdr *)cmsgbuf; 601 cmsg->cmsg_level = IPPROTO_SCTP; 602 cmsg->cmsg_type = SCTP_SNDRCV; 603 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 604 sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); 605 memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo)); 606 sinfo->sinfo_stream = stream_no; 607 sinfo->sinfo_ssn = 0; 608 sinfo->sinfo_flags = flags; 609 sinfo->sinfo_ppid = ppid; 610 sinfo->sinfo_context = context; 611 sinfo->sinfo_assoc_id = 0; 612 sinfo->sinfo_timetolive = timetolive; 613 return (sendmsg(s, &msg, 0)); 614 #endif 615 } 616 617 618 sctp_assoc_t 619 sctp_getassocid(int sd, struct sockaddr *sa) 620 { 621 struct sctp_paddrinfo sp; 622 socklen_t siz; 623 624 /* First get the assoc id */ 625 siz = sizeof(sp); 626 memset(&sp, 0, sizeof(sp)); 627 memcpy((caddr_t)&sp.spinfo_address, sa, sa->sa_len); 628 if (getsockopt(sd, IPPROTO_SCTP, 629 SCTP_GET_PEER_ADDR_INFO, &sp, &siz) != 0) { 630 /* We depend on the fact that 0 can never be returned */ 631 return ((sctp_assoc_t) 0); 632 } 633 return (sp.spinfo_assoc_id); 634 } 635 636 ssize_t 637 sctp_send(int sd, const void *data, size_t len, 638 const struct sctp_sndrcvinfo *sinfo, 639 int flags) 640 { 641 642 #ifdef SYS_sctp_generic_sendmsg 643 struct sockaddr *to = NULL; 644 645 return (syscall(SYS_sctp_generic_sendmsg, sd, 646 data, len, to, 0, sinfo, flags)); 647 #else 648 struct msghdr msg; 649 struct iovec iov; 650 char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; 651 struct cmsghdr *cmsg; 652 653 if (sinfo == NULL) { 654 errno = EINVAL; 655 return (-1); 656 } 657 iov.iov_base = (char *)data; 658 iov.iov_len = len; 659 660 msg.msg_name = NULL; 661 msg.msg_namelen = 0; 662 msg.msg_iov = &iov; 663 msg.msg_iovlen = 1; 664 msg.msg_control = cmsgbuf; 665 msg.msg_controllen = CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); 666 cmsg = (struct cmsghdr *)cmsgbuf; 667 cmsg->cmsg_level = IPPROTO_SCTP; 668 cmsg->cmsg_type = SCTP_SNDRCV; 669 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 670 memcpy(CMSG_DATA(cmsg), sinfo, sizeof(struct sctp_sndrcvinfo)); 671 return (sendmsg(sd, &msg, flags)); 672 #endif 673 } 674 675 676 677 ssize_t 678 sctp_sendx(int sd, const void *msg, size_t msg_len, 679 struct sockaddr *addrs, int addrcnt, 680 struct sctp_sndrcvinfo *sinfo, 681 int flags) 682 { 683 struct sctp_sndrcvinfo __sinfo; 684 ssize_t ret; 685 int i, cnt, *aa, saved_errno; 686 char *buf; 687 int no_end_cx = 0; 688 size_t len, add_len; 689 struct sockaddr *at; 690 691 if (addrs == NULL) { 692 errno = EINVAL; 693 return (-1); 694 } 695 #ifdef SYS_sctp_generic_sendmsg 696 if (addrcnt == 1) { 697 socklen_t l; 698 699 /* 700 * Quick way, we don't need to do a connectx so lets use the 701 * syscall directly. 702 */ 703 l = addrs->sa_len; 704 return (syscall(SYS_sctp_generic_sendmsg, sd, 705 msg, msg_len, addrs, l, sinfo, flags)); 706 } 707 #endif 708 709 len = sizeof(int); 710 at = addrs; 711 cnt = 0; 712 /* validate all the addresses and get the size */ 713 for (i = 0; i < addrcnt; i++) { 714 if (at->sa_family == AF_INET) { 715 add_len = sizeof(struct sockaddr_in); 716 } else if (at->sa_family == AF_INET6) { 717 add_len = sizeof(struct sockaddr_in6); 718 } else { 719 errno = EINVAL; 720 return (-1); 721 } 722 len += add_len; 723 at = (struct sockaddr *)((caddr_t)at + add_len); 724 cnt++; 725 } 726 /* do we have any? */ 727 if (cnt == 0) { 728 errno = EINVAL; 729 return (-1); 730 } 731 buf = malloc(len); 732 if (buf == NULL) { 733 errno = ENOMEM; 734 return (-1); 735 } 736 aa = (int *)buf; 737 *aa = cnt; 738 aa++; 739 memcpy((caddr_t)aa, addrs, (size_t)(len - sizeof(int))); 740 ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_DELAYED, (void *)buf, 741 (socklen_t) len); 742 743 free(buf); 744 if (ret != 0) { 745 if (errno == EALREADY) { 746 no_end_cx = 1; 747 goto continue_send; 748 } 749 return (ret); 750 } 751 continue_send: 752 if (sinfo == NULL) { 753 sinfo = &__sinfo; 754 memset(&__sinfo, 0, sizeof(__sinfo)); 755 } 756 sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs); 757 if (sinfo->sinfo_assoc_id == 0) { 758 (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs, 759 (socklen_t) addrs->sa_len); 760 errno = ENOENT; 761 return (-1); 762 } 763 ret = sctp_send(sd, msg, msg_len, sinfo, flags); 764 saved_errno = errno; 765 if (no_end_cx == 0) 766 (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs, 767 (socklen_t) addrs->sa_len); 768 769 errno = saved_errno; 770 return (ret); 771 } 772 773 ssize_t 774 sctp_sendmsgx(int sd, 775 const void *msg, 776 size_t len, 777 struct sockaddr *addrs, 778 int addrcnt, 779 uint32_t ppid, 780 uint32_t flags, 781 uint16_t stream_no, 782 uint32_t timetolive, 783 uint32_t context) 784 { 785 struct sctp_sndrcvinfo sinfo; 786 787 memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo)); 788 sinfo.sinfo_ppid = ppid; 789 sinfo.sinfo_flags = flags; 790 sinfo.sinfo_ssn = stream_no; 791 sinfo.sinfo_timetolive = timetolive; 792 sinfo.sinfo_context = context; 793 return (sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0)); 794 } 795 796 ssize_t 797 sctp_recvmsg(int s, 798 void *dbuf, 799 size_t len, 800 struct sockaddr *from, 801 socklen_t * fromlen, 802 struct sctp_sndrcvinfo *sinfo, 803 int *msg_flags) 804 { 805 #ifdef SYS_sctp_generic_recvmsg 806 struct iovec iov; 807 808 iov.iov_base = dbuf; 809 iov.iov_len = len; 810 return (syscall(SYS_sctp_generic_recvmsg, s, 811 &iov, 1, from, fromlen, sinfo, msg_flags)); 812 #else 813 ssize_t sz; 814 struct msghdr msg; 815 struct iovec iov; 816 char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV]; 817 struct cmsghdr *cmsg; 818 819 if (msg_flags == NULL) { 820 errno = EINVAL; 821 return (-1); 822 } 823 msg.msg_flags = 0; 824 iov.iov_base = dbuf; 825 iov.iov_len = len; 826 msg.msg_name = (caddr_t)from; 827 if (fromlen == NULL) 828 msg.msg_namelen = 0; 829 else 830 msg.msg_namelen = *fromlen; 831 msg.msg_iov = &iov; 832 msg.msg_iovlen = 1; 833 msg.msg_control = cmsgbuf; 834 msg.msg_controllen = sizeof(cmsgbuf); 835 sz = recvmsg(s, &msg, *msg_flags); 836 *msg_flags = msg.msg_flags; 837 if (sz <= 0) { 838 return (sz); 839 } 840 if (sinfo) { 841 sinfo->sinfo_assoc_id = 0; 842 } 843 if ((msg.msg_controllen > 0) && (sinfo != NULL)) { 844 /* 845 * parse through and see if we find the sctp_sndrcvinfo (if 846 * the user wants it). 847 */ 848 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 849 if (cmsg->cmsg_level != IPPROTO_SCTP) { 850 continue; 851 } 852 if (cmsg->cmsg_type == SCTP_SNDRCV) { 853 memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_sndrcvinfo)); 854 break; 855 } 856 if (cmsg->cmsg_type == SCTP_EXTRCV) { 857 /* 858 * Let's hope that the user provided enough 859 * enough memory. At least he asked for more 860 * information. 861 */ 862 memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_extrcvinfo)); 863 break; 864 } 865 } 866 } 867 return (sz); 868 #endif 869 } 870 871 ssize_t 872 sctp_recvv(int sd, 873 const struct iovec *iov, 874 int iovlen, 875 struct sockaddr *from, 876 socklen_t * fromlen, 877 void *info, 878 socklen_t * infolen, 879 unsigned int *infotype, 880 int *flags) 881 { 882 char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV]; 883 struct msghdr msg; 884 struct cmsghdr *cmsg; 885 ssize_t ret; 886 struct sctp_rcvinfo *rcvinfo; 887 struct sctp_nxtinfo *nxtinfo; 888 889 if (((info != NULL) && (infolen == NULL)) | 890 ((info == NULL) && (infolen != NULL) && (*infolen != 0)) || 891 ((info != NULL) && (infotype == NULL))) { 892 errno = EINVAL; 893 return (-1); 894 } 895 if (infotype) { 896 *infotype = SCTP_RECVV_NOINFO; 897 } 898 msg.msg_name = from; 899 if (fromlen == NULL) { 900 msg.msg_namelen = 0; 901 } else { 902 msg.msg_namelen = *fromlen; 903 } 904 msg.msg_iov = (struct iovec *)iov; 905 msg.msg_iovlen = iovlen; 906 msg.msg_control = cmsgbuf; 907 msg.msg_controllen = sizeof(cmsgbuf); 908 ret = recvmsg(sd, &msg, *flags); 909 *flags = msg.msg_flags; 910 if ((ret > 0) && 911 (msg.msg_controllen > 0) && 912 (infotype != NULL) && 913 (infolen != NULL) && 914 (*infolen > 0)) { 915 rcvinfo = NULL; 916 nxtinfo = NULL; 917 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 918 if (cmsg->cmsg_level != IPPROTO_SCTP) { 919 continue; 920 } 921 if (cmsg->cmsg_type == SCTP_RCVINFO) { 922 rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg); 923 if (nxtinfo != NULL) { 924 break; 925 } else { 926 continue; 927 } 928 } 929 if (cmsg->cmsg_type == SCTP_NXTINFO) { 930 nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg); 931 if (rcvinfo != NULL) { 932 break; 933 } else { 934 continue; 935 } 936 } 937 } 938 if (rcvinfo != NULL) { 939 if ((nxtinfo != NULL) && (*infolen >= sizeof(struct sctp_recvv_rn))) { 940 struct sctp_recvv_rn *rn_info; 941 942 rn_info = (struct sctp_recvv_rn *)info; 943 rn_info->recvv_rcvinfo = *rcvinfo; 944 rn_info->recvv_nxtinfo = *nxtinfo; 945 *infolen = (socklen_t) sizeof(struct sctp_recvv_rn); 946 *infotype = SCTP_RECVV_RN; 947 } else if (*infolen >= sizeof(struct sctp_rcvinfo)) { 948 memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo)); 949 *infolen = (socklen_t) sizeof(struct sctp_rcvinfo); 950 *infotype = SCTP_RECVV_RCVINFO; 951 } 952 } else if (nxtinfo != NULL) { 953 if (*infolen >= sizeof(struct sctp_nxtinfo)) { 954 memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo)); 955 *infolen = (socklen_t) sizeof(struct sctp_nxtinfo); 956 *infotype = SCTP_RECVV_NXTINFO; 957 } 958 } 959 } 960 return (ret); 961 } 962 963 ssize_t 964 sctp_sendv(int sd, 965 const struct iovec *iov, int iovcnt, 966 struct sockaddr *addrs, int addrcnt, 967 void *info, socklen_t infolen, unsigned int infotype, 968 int flags) 969 { 970 ssize_t ret; 971 int i; 972 socklen_t addr_len; 973 struct msghdr msg; 974 in_port_t port; 975 struct sctp_sendv_spa *spa_info; 976 struct cmsghdr *cmsg; 977 char *cmsgbuf; 978 struct sockaddr *addr; 979 struct sockaddr_in *addr_in; 980 struct sockaddr_in6 *addr_in6; 981 982 if ((addrcnt < 0) || 983 (iovcnt < 0) || 984 ((addrs == NULL) && (addrcnt > 0)) || 985 ((addrs != NULL) && (addrcnt == 0)) || 986 ((iov == NULL) && (iovcnt > 0)) || 987 ((iov != NULL) && (iovcnt == 0))) { 988 errno = EINVAL; 989 return (-1); 990 } 991 cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) + 992 CMSG_SPACE(sizeof(struct sctp_prinfo)) + 993 CMSG_SPACE(sizeof(struct sctp_authinfo)) + 994 (size_t)addrcnt * CMSG_SPACE(sizeof(struct in6_addr))); 995 if (cmsgbuf == NULL) { 996 errno = ENOMEM; 997 return (-1); 998 } 999 msg.msg_control = cmsgbuf; 1000 msg.msg_controllen = 0; 1001 cmsg = (struct cmsghdr *)cmsgbuf; 1002 switch (infotype) { 1003 case SCTP_SENDV_NOINFO: 1004 if ((infolen != 0) || (info != NULL)) { 1005 free(cmsgbuf); 1006 errno = EINVAL; 1007 return (-1); 1008 } 1009 break; 1010 case SCTP_SENDV_SNDINFO: 1011 if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) { 1012 free(cmsgbuf); 1013 errno = EINVAL; 1014 return (-1); 1015 } 1016 cmsg->cmsg_level = IPPROTO_SCTP; 1017 cmsg->cmsg_type = SCTP_SNDINFO; 1018 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); 1019 memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo)); 1020 msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); 1021 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); 1022 break; 1023 case SCTP_SENDV_PRINFO: 1024 if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) { 1025 free(cmsgbuf); 1026 errno = EINVAL; 1027 return (-1); 1028 } 1029 cmsg->cmsg_level = IPPROTO_SCTP; 1030 cmsg->cmsg_type = SCTP_PRINFO; 1031 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); 1032 memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo)); 1033 msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); 1034 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo))); 1035 break; 1036 case SCTP_SENDV_AUTHINFO: 1037 if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) { 1038 free(cmsgbuf); 1039 errno = EINVAL; 1040 return (-1); 1041 } 1042 cmsg->cmsg_level = IPPROTO_SCTP; 1043 cmsg->cmsg_type = SCTP_AUTHINFO; 1044 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo)); 1045 memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo)); 1046 msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo)); 1047 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo))); 1048 break; 1049 case SCTP_SENDV_SPA: 1050 if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) { 1051 free(cmsgbuf); 1052 errno = EINVAL; 1053 return (-1); 1054 } 1055 spa_info = (struct sctp_sendv_spa *)info; 1056 if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) { 1057 cmsg->cmsg_level = IPPROTO_SCTP; 1058 cmsg->cmsg_type = SCTP_SNDINFO; 1059 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); 1060 memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo)); 1061 msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); 1062 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); 1063 } 1064 if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) { 1065 cmsg->cmsg_level = IPPROTO_SCTP; 1066 cmsg->cmsg_type = SCTP_PRINFO; 1067 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); 1068 memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo)); 1069 msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); 1070 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo))); 1071 } 1072 if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) { 1073 cmsg->cmsg_level = IPPROTO_SCTP; 1074 cmsg->cmsg_type = SCTP_AUTHINFO; 1075 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo)); 1076 memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo)); 1077 msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo)); 1078 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo))); 1079 } 1080 break; 1081 default: 1082 free(cmsgbuf); 1083 errno = EINVAL; 1084 return (-1); 1085 } 1086 addr = addrs; 1087 msg.msg_name = NULL; 1088 msg.msg_namelen = 0; 1089 1090 for (i = 0; i < addrcnt; i++) { 1091 switch (addr->sa_family) { 1092 case AF_INET: 1093 addr_len = (socklen_t) sizeof(struct sockaddr_in); 1094 addr_in = (struct sockaddr_in *)addr; 1095 if (addr_in->sin_len != addr_len) { 1096 free(cmsgbuf); 1097 errno = EINVAL; 1098 return (-1); 1099 } 1100 if (i == 0) { 1101 port = addr_in->sin_port; 1102 } else { 1103 if (port == addr_in->sin_port) { 1104 cmsg->cmsg_level = IPPROTO_SCTP; 1105 cmsg->cmsg_type = SCTP_DSTADDRV4; 1106 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); 1107 memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr)); 1108 msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr)); 1109 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr))); 1110 } else { 1111 free(cmsgbuf); 1112 errno = EINVAL; 1113 return (-1); 1114 } 1115 } 1116 break; 1117 case AF_INET6: 1118 addr_len = (socklen_t) sizeof(struct sockaddr_in6); 1119 addr_in6 = (struct sockaddr_in6 *)addr; 1120 if (addr_in6->sin6_len != addr_len) { 1121 free(cmsgbuf); 1122 errno = EINVAL; 1123 return (-1); 1124 } 1125 if (i == 0) { 1126 port = addr_in6->sin6_port; 1127 } else { 1128 if (port == addr_in6->sin6_port) { 1129 cmsg->cmsg_level = IPPROTO_SCTP; 1130 cmsg->cmsg_type = SCTP_DSTADDRV6; 1131 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr)); 1132 memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr)); 1133 msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr)); 1134 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr))); 1135 } else { 1136 free(cmsgbuf); 1137 errno = EINVAL; 1138 return (-1); 1139 } 1140 } 1141 break; 1142 default: 1143 free(cmsgbuf); 1144 errno = EINVAL; 1145 return (-1); 1146 } 1147 if (i == 0) { 1148 msg.msg_name = addr; 1149 msg.msg_namelen = addr_len; 1150 } 1151 addr = (struct sockaddr *)((caddr_t)addr + addr_len); 1152 } 1153 if (msg.msg_controllen == 0) { 1154 msg.msg_control = NULL; 1155 } 1156 msg.msg_iov = (struct iovec *)iov; 1157 msg.msg_iovlen = iovcnt; 1158 msg.msg_flags = 0; 1159 ret = sendmsg(sd, &msg, flags); 1160 free(cmsgbuf); 1161 return (ret); 1162 } 1163 1164 1165 #if !defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT) 1166 1167 int 1168 sctp_peeloff(int sd, sctp_assoc_t assoc_id) 1169 { 1170 /* NOT supported, return invalid sd */ 1171 errno = ENOTSUP; 1172 return (-1); 1173 } 1174 1175 #endif 1176 #if defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT) 1177 int 1178 sctp_peeloff(int sd, sctp_assoc_t assoc_id) 1179 { 1180 return (syscall(SYS_sctp_peeloff, sd, assoc_id)); 1181 } 1182 1183 #endif 1184 1185 #undef SCTP_CONTROL_VEC_SIZE_RCV 1186