sctp_sys_calls.c revision 270357
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: stable/10/lib/libc/net/sctp_sys_calls.c 270357 2014-08-22 20:01:35Z tuexen $"); 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 61static void 62in6_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 71int 72sctp_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 99int 100sctp_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 168int 169sctp_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 280int 281sctp_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_MAX_BURST: 360 ((struct sctp_assoc_value *)arg)->assoc_id = id; 361 break; 362 case SCTP_ENABLE_STREAM_RESET: 363 ((struct sctp_assoc_value *)arg)->assoc_id = id; 364 break; 365 default: 366 break; 367 } 368 return (getsockopt(sd, IPPROTO_SCTP, opt, arg, size)); 369} 370 371int 372sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs) 373{ 374 struct sctp_getaddresses *addrs; 375 struct sockaddr *sa; 376 sctp_assoc_t asoc; 377 caddr_t lim; 378 socklen_t opt_len; 379 int cnt; 380 381 if (raddrs == NULL) { 382 errno = EFAULT; 383 return (-1); 384 } 385 asoc = id; 386 opt_len = (socklen_t) sizeof(sctp_assoc_t); 387 if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE, 388 &asoc, &opt_len) != 0) { 389 return (-1); 390 } 391 /* size required is returned in 'asoc' */ 392 opt_len = (socklen_t) ((size_t)asoc + sizeof(struct sctp_getaddresses)); 393 addrs = calloc(1, (size_t)opt_len); 394 if (addrs == NULL) { 395 errno = ENOMEM; 396 return (-1); 397 } 398 addrs->sget_assoc_id = id; 399 /* Now lets get the array of addresses */ 400 if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES, 401 addrs, &opt_len) != 0) { 402 free(addrs); 403 return (-1); 404 } 405 *raddrs = (struct sockaddr *)&addrs->addr[0]; 406 cnt = 0; 407 sa = (struct sockaddr *)&addrs->addr[0]; 408 lim = (caddr_t)addrs + opt_len; 409 while (((caddr_t)sa < lim) && (sa->sa_len > 0)) { 410 sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 411 cnt++; 412 } 413 return (cnt); 414} 415 416void 417sctp_freepaddrs(struct sockaddr *addrs) 418{ 419 void *fr_addr; 420 421 /* Take away the hidden association id */ 422 fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t)); 423 /* Now free it */ 424 free(fr_addr); 425} 426 427int 428sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs) 429{ 430 struct sctp_getaddresses *addrs; 431 caddr_t lim; 432 struct sockaddr *sa; 433 size_t size_of_addresses; 434 socklen_t opt_len; 435 int cnt; 436 437 if (raddrs == NULL) { 438 errno = EFAULT; 439 return (-1); 440 } 441 size_of_addresses = 0; 442 opt_len = (socklen_t) sizeof(int); 443 if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE, 444 &size_of_addresses, &opt_len) != 0) { 445 errno = ENOMEM; 446 return (-1); 447 } 448 if (size_of_addresses == 0) { 449 errno = ENOTCONN; 450 return (-1); 451 } 452 opt_len = (socklen_t) (size_of_addresses + 453 sizeof(struct sockaddr_storage) + 454 sizeof(struct sctp_getaddresses)); 455 addrs = calloc(1, (size_t)opt_len); 456 if (addrs == NULL) { 457 errno = ENOMEM; 458 return (-1); 459 } 460 addrs->sget_assoc_id = id; 461 /* Now lets get the array of addresses */ 462 if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs, 463 &opt_len) != 0) { 464 free(addrs); 465 errno = ENOMEM; 466 return (-1); 467 } 468 *raddrs = (struct sockaddr *)&addrs->addr[0]; 469 cnt = 0; 470 sa = (struct sockaddr *)&addrs->addr[0]; 471 lim = (caddr_t)addrs + opt_len; 472 while (((caddr_t)sa < lim) && (sa->sa_len > 0)) { 473 sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 474 cnt++; 475 } 476 return (cnt); 477} 478 479void 480sctp_freeladdrs(struct sockaddr *addrs) 481{ 482 void *fr_addr; 483 484 /* Take away the hidden association id */ 485 fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t)); 486 /* Now free it */ 487 free(fr_addr); 488} 489 490ssize_t 491sctp_sendmsg(int s, 492 const void *data, 493 size_t len, 494 const struct sockaddr *to, 495 socklen_t tolen, 496 uint32_t ppid, 497 uint32_t flags, 498 uint16_t stream_no, 499 uint32_t timetolive, 500 uint32_t context) 501{ 502#ifdef SYS_sctp_generic_sendmsg 503 struct sctp_sndrcvinfo sinfo; 504 505 memset(&sinfo, 0, sizeof(struct sctp_sndrcvinfo)); 506 sinfo.sinfo_ppid = ppid; 507 sinfo.sinfo_flags = flags; 508 sinfo.sinfo_stream = stream_no; 509 sinfo.sinfo_timetolive = timetolive; 510 sinfo.sinfo_context = context; 511 sinfo.sinfo_assoc_id = 0; 512 return (syscall(SYS_sctp_generic_sendmsg, s, 513 data, len, to, tolen, &sinfo, 0)); 514#else 515 struct msghdr msg; 516 struct sctp_sndrcvinfo *sinfo; 517 struct iovec iov; 518 char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; 519 struct cmsghdr *cmsg; 520 struct sockaddr *who = NULL; 521 union { 522 struct sockaddr_in in; 523 struct sockaddr_in6 in6; 524 } addr; 525 526 if ((tolen > 0) && 527 ((to == NULL) || (tolen < sizeof(struct sockaddr)))) { 528 errno = EINVAL; 529 return (-1); 530 } 531 if ((to != NULL) && (tolen > 0)) { 532 switch (to->sa_family) { 533 case AF_INET: 534 if (tolen != sizeof(struct sockaddr_in)) { 535 errno = EINVAL; 536 return (-1); 537 } 538 if ((to->sa_len > 0) && 539 (to->sa_len != sizeof(struct sockaddr_in))) { 540 errno = EINVAL; 541 return (-1); 542 } 543 memcpy(&addr, to, sizeof(struct sockaddr_in)); 544 addr.in.sin_len = sizeof(struct sockaddr_in); 545 break; 546 case AF_INET6: 547 if (tolen != sizeof(struct sockaddr_in6)) { 548 errno = EINVAL; 549 return (-1); 550 } 551 if ((to->sa_len > 0) && 552 (to->sa_len != sizeof(struct sockaddr_in6))) { 553 errno = EINVAL; 554 return (-1); 555 } 556 memcpy(&addr, to, sizeof(struct sockaddr_in6)); 557 addr.in6.sin6_len = sizeof(struct sockaddr_in6); 558 break; 559 default: 560 errno = EAFNOSUPPORT; 561 return (-1); 562 } 563 who = (struct sockaddr *)&addr; 564 } 565 iov.iov_base = (char *)data; 566 iov.iov_len = len; 567 568 if (who) { 569 msg.msg_name = (caddr_t)who; 570 msg.msg_namelen = who->sa_len; 571 } else { 572 msg.msg_name = (caddr_t)NULL; 573 msg.msg_namelen = 0; 574 } 575 msg.msg_iov = &iov; 576 msg.msg_iovlen = 1; 577 msg.msg_control = cmsgbuf; 578 msg.msg_controllen = CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); 579 cmsg = (struct cmsghdr *)cmsgbuf; 580 cmsg->cmsg_level = IPPROTO_SCTP; 581 cmsg->cmsg_type = SCTP_SNDRCV; 582 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 583 sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); 584 sinfo->sinfo_stream = stream_no; 585 sinfo->sinfo_ssn = 0; 586 sinfo->sinfo_flags = flags; 587 sinfo->sinfo_ppid = ppid; 588 sinfo->sinfo_context = context; 589 sinfo->sinfo_assoc_id = 0; 590 sinfo->sinfo_timetolive = timetolive; 591 return (sendmsg(s, &msg, 0)); 592#endif 593} 594 595 596sctp_assoc_t 597sctp_getassocid(int sd, struct sockaddr *sa) 598{ 599 struct sctp_paddrinfo sp; 600 socklen_t siz; 601 602 /* First get the assoc id */ 603 siz = sizeof(sp); 604 memset(&sp, 0, sizeof(sp)); 605 memcpy((caddr_t)&sp.spinfo_address, sa, sa->sa_len); 606 if (getsockopt(sd, IPPROTO_SCTP, 607 SCTP_GET_PEER_ADDR_INFO, &sp, &siz) != 0) { 608 /* We depend on the fact that 0 can never be returned */ 609 return ((sctp_assoc_t) 0); 610 } 611 return (sp.spinfo_assoc_id); 612} 613 614ssize_t 615sctp_send(int sd, const void *data, size_t len, 616 const struct sctp_sndrcvinfo *sinfo, 617 int flags) 618{ 619 620#ifdef SYS_sctp_generic_sendmsg 621 struct sockaddr *to = NULL; 622 623 return (syscall(SYS_sctp_generic_sendmsg, sd, 624 data, len, to, 0, sinfo, flags)); 625#else 626 struct msghdr msg; 627 struct iovec iov; 628 char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; 629 struct cmsghdr *cmsg; 630 631 if (sinfo == NULL) { 632 errno = EINVAL; 633 return (-1); 634 } 635 iov.iov_base = (char *)data; 636 iov.iov_len = len; 637 638 msg.msg_name = NULL; 639 msg.msg_namelen = 0; 640 msg.msg_iov = &iov; 641 msg.msg_iovlen = 1; 642 msg.msg_control = cmsgbuf; 643 msg.msg_controllen = CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); 644 cmsg = (struct cmsghdr *)cmsgbuf; 645 cmsg->cmsg_level = IPPROTO_SCTP; 646 cmsg->cmsg_type = SCTP_SNDRCV; 647 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 648 memcpy(CMSG_DATA(cmsg), sinfo, sizeof(struct sctp_sndrcvinfo)); 649 return (sendmsg(sd, &msg, flags)); 650#endif 651} 652 653 654 655ssize_t 656sctp_sendx(int sd, const void *msg, size_t msg_len, 657 struct sockaddr *addrs, int addrcnt, 658 struct sctp_sndrcvinfo *sinfo, 659 int flags) 660{ 661 struct sctp_sndrcvinfo __sinfo; 662 ssize_t ret; 663 int i, cnt, *aa, saved_errno; 664 char *buf; 665 int no_end_cx = 0; 666 size_t len, add_len; 667 struct sockaddr *at; 668 669 if (addrs == NULL) { 670 errno = EINVAL; 671 return (-1); 672 } 673#ifdef SYS_sctp_generic_sendmsg 674 if (addrcnt == 1) { 675 socklen_t l; 676 677 /* 678 * Quick way, we don't need to do a connectx so lets use the 679 * syscall directly. 680 */ 681 l = addrs->sa_len; 682 return (syscall(SYS_sctp_generic_sendmsg, sd, 683 msg, msg_len, addrs, l, sinfo, flags)); 684 } 685#endif 686 687 len = sizeof(int); 688 at = addrs; 689 cnt = 0; 690 /* validate all the addresses and get the size */ 691 for (i = 0; i < addrcnt; i++) { 692 if (at->sa_family == AF_INET) { 693 add_len = sizeof(struct sockaddr_in); 694 } else if (at->sa_family == AF_INET6) { 695 add_len = sizeof(struct sockaddr_in6); 696 } else { 697 errno = EINVAL; 698 return (-1); 699 } 700 len += add_len; 701 at = (struct sockaddr *)((caddr_t)at + add_len); 702 cnt++; 703 } 704 /* do we have any? */ 705 if (cnt == 0) { 706 errno = EINVAL; 707 return (-1); 708 } 709 buf = malloc(len); 710 if (buf == NULL) { 711 errno = ENOMEM; 712 return (-1); 713 } 714 aa = (int *)buf; 715 *aa = cnt; 716 aa++; 717 memcpy((caddr_t)aa, addrs, (size_t)(len - sizeof(int))); 718 ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_DELAYED, (void *)buf, 719 (socklen_t) len); 720 721 free(buf); 722 if (ret != 0) { 723 if (errno == EALREADY) { 724 no_end_cx = 1; 725 goto continue_send; 726 } 727 return (ret); 728 } 729continue_send: 730 if (sinfo == NULL) { 731 sinfo = &__sinfo; 732 memset(&__sinfo, 0, sizeof(__sinfo)); 733 } 734 sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs); 735 if (sinfo->sinfo_assoc_id == 0) { 736 (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs, 737 (socklen_t) addrs->sa_len); 738 errno = ENOENT; 739 return (-1); 740 } 741 ret = sctp_send(sd, msg, msg_len, sinfo, flags); 742 saved_errno = errno; 743 if (no_end_cx == 0) 744 (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs, 745 (socklen_t) addrs->sa_len); 746 747 errno = saved_errno; 748 return (ret); 749} 750 751ssize_t 752sctp_sendmsgx(int sd, 753 const void *msg, 754 size_t len, 755 struct sockaddr *addrs, 756 int addrcnt, 757 uint32_t ppid, 758 uint32_t flags, 759 uint16_t stream_no, 760 uint32_t timetolive, 761 uint32_t context) 762{ 763 struct sctp_sndrcvinfo sinfo; 764 765 memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo)); 766 sinfo.sinfo_ppid = ppid; 767 sinfo.sinfo_flags = flags; 768 sinfo.sinfo_ssn = stream_no; 769 sinfo.sinfo_timetolive = timetolive; 770 sinfo.sinfo_context = context; 771 return (sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0)); 772} 773 774ssize_t 775sctp_recvmsg(int s, 776 void *dbuf, 777 size_t len, 778 struct sockaddr *from, 779 socklen_t * fromlen, 780 struct sctp_sndrcvinfo *sinfo, 781 int *msg_flags) 782{ 783#ifdef SYS_sctp_generic_recvmsg 784 struct iovec iov; 785 786 iov.iov_base = dbuf; 787 iov.iov_len = len; 788 return (syscall(SYS_sctp_generic_recvmsg, s, 789 &iov, 1, from, fromlen, sinfo, msg_flags)); 790#else 791 ssize_t sz; 792 struct msghdr msg; 793 struct iovec iov; 794 char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV]; 795 struct cmsghdr *cmsg; 796 797 if (msg_flags == NULL) { 798 errno = EINVAL; 799 return (-1); 800 } 801 msg.msg_flags = 0; 802 iov.iov_base = dbuf; 803 iov.iov_len = len; 804 msg.msg_name = (caddr_t)from; 805 if (fromlen == NULL) 806 msg.msg_namelen = 0; 807 else 808 msg.msg_namelen = *fromlen; 809 msg.msg_iov = &iov; 810 msg.msg_iovlen = 1; 811 msg.msg_control = cmsgbuf; 812 msg.msg_controllen = sizeof(cmsgbuf); 813 sz = recvmsg(s, &msg, *msg_flags); 814 *msg_flags = msg.msg_flags; 815 if (sz <= 0) { 816 return (sz); 817 } 818 if (sinfo) { 819 sinfo->sinfo_assoc_id = 0; 820 } 821 if ((msg.msg_controllen > 0) && (sinfo != NULL)) { 822 /* 823 * parse through and see if we find the sctp_sndrcvinfo (if 824 * the user wants it). 825 */ 826 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 827 if (cmsg->cmsg_level != IPPROTO_SCTP) { 828 continue; 829 } 830 if (cmsg->cmsg_type == SCTP_SNDRCV) { 831 memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_sndrcvinfo)); 832 break; 833 } 834 if (cmsg->cmsg_type == SCTP_EXTRCV) { 835 /* 836 * Let's hope that the user provided enough 837 * enough memory. At least he asked for more 838 * information. 839 */ 840 memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_extrcvinfo)); 841 break; 842 } 843 } 844 } 845 return (sz); 846#endif 847} 848 849ssize_t 850sctp_recvv(int sd, 851 const struct iovec *iov, 852 int iovlen, 853 struct sockaddr *from, 854 socklen_t * fromlen, 855 void *info, 856 socklen_t * infolen, 857 unsigned int *infotype, 858 int *flags) 859{ 860 char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV]; 861 struct msghdr msg; 862 struct cmsghdr *cmsg; 863 ssize_t ret; 864 struct sctp_rcvinfo *rcvinfo; 865 struct sctp_nxtinfo *nxtinfo; 866 867 if (((info != NULL) && (infolen == NULL)) | 868 ((info == NULL) && (infolen != NULL) && (*infolen != 0)) || 869 ((info != NULL) && (infotype == NULL))) { 870 errno = EINVAL; 871 return (-1); 872 } 873 if (infotype) { 874 *infotype = SCTP_RECVV_NOINFO; 875 } 876 msg.msg_name = from; 877 if (fromlen == NULL) { 878 msg.msg_namelen = 0; 879 } else { 880 msg.msg_namelen = *fromlen; 881 } 882 msg.msg_iov = (struct iovec *)iov; 883 msg.msg_iovlen = iovlen; 884 msg.msg_control = cmsgbuf; 885 msg.msg_controllen = sizeof(cmsgbuf); 886 ret = recvmsg(sd, &msg, *flags); 887 *flags = msg.msg_flags; 888 if ((ret > 0) && 889 (msg.msg_controllen > 0) && 890 (infotype != NULL) && 891 (infolen != NULL) && 892 (*infolen > 0)) { 893 rcvinfo = NULL; 894 nxtinfo = NULL; 895 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 896 if (cmsg->cmsg_level != IPPROTO_SCTP) { 897 continue; 898 } 899 if (cmsg->cmsg_type == SCTP_RCVINFO) { 900 rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg); 901 if (nxtinfo != NULL) { 902 break; 903 } else { 904 continue; 905 } 906 } 907 if (cmsg->cmsg_type == SCTP_NXTINFO) { 908 nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg); 909 if (rcvinfo != NULL) { 910 break; 911 } else { 912 continue; 913 } 914 } 915 } 916 if (rcvinfo != NULL) { 917 if ((nxtinfo != NULL) && (*infolen >= sizeof(struct sctp_recvv_rn))) { 918 struct sctp_recvv_rn *rn_info; 919 920 rn_info = (struct sctp_recvv_rn *)info; 921 rn_info->recvv_rcvinfo = *rcvinfo; 922 rn_info->recvv_nxtinfo = *nxtinfo; 923 *infolen = (socklen_t) sizeof(struct sctp_recvv_rn); 924 *infotype = SCTP_RECVV_RN; 925 } else if (*infolen >= sizeof(struct sctp_rcvinfo)) { 926 memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo)); 927 *infolen = (socklen_t) sizeof(struct sctp_rcvinfo); 928 *infotype = SCTP_RECVV_RCVINFO; 929 } 930 } else if (nxtinfo != NULL) { 931 if (*infolen >= sizeof(struct sctp_nxtinfo)) { 932 memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo)); 933 *infolen = (socklen_t) sizeof(struct sctp_nxtinfo); 934 *infotype = SCTP_RECVV_NXTINFO; 935 } 936 } 937 } 938 return (ret); 939} 940 941ssize_t 942sctp_sendv(int sd, 943 const struct iovec *iov, int iovcnt, 944 struct sockaddr *addrs, int addrcnt, 945 void *info, socklen_t infolen, unsigned int infotype, 946 int flags) 947{ 948 ssize_t ret; 949 int i; 950 socklen_t addr_len; 951 struct msghdr msg; 952 in_port_t port; 953 struct sctp_sendv_spa *spa_info; 954 struct cmsghdr *cmsg; 955 char *cmsgbuf; 956 struct sockaddr *addr; 957 struct sockaddr_in *addr_in; 958 struct sockaddr_in6 *addr_in6; 959 960 if ((addrcnt < 0) || 961 (iovcnt < 0) || 962 ((addrs == NULL) && (addrcnt > 0)) || 963 ((addrs != NULL) && (addrcnt == 0)) || 964 ((iov == NULL) && (iovcnt > 0)) || 965 ((iov != NULL) && (iovcnt == 0))) { 966 errno = EINVAL; 967 return (-1); 968 } 969 cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) + 970 CMSG_SPACE(sizeof(struct sctp_prinfo)) + 971 CMSG_SPACE(sizeof(struct sctp_authinfo)) + 972 (size_t)addrcnt * CMSG_SPACE(sizeof(struct in6_addr))); 973 if (cmsgbuf == NULL) { 974 errno = ENOMEM; 975 return (-1); 976 } 977 msg.msg_control = cmsgbuf; 978 msg.msg_controllen = 0; 979 cmsg = (struct cmsghdr *)cmsgbuf; 980 switch (infotype) { 981 case SCTP_SENDV_NOINFO: 982 if ((infolen != 0) || (info != NULL)) { 983 free(cmsgbuf); 984 errno = EINVAL; 985 return (-1); 986 } 987 break; 988 case SCTP_SENDV_SNDINFO: 989 if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) { 990 free(cmsgbuf); 991 errno = EINVAL; 992 return (-1); 993 } 994 cmsg->cmsg_level = IPPROTO_SCTP; 995 cmsg->cmsg_type = SCTP_SNDINFO; 996 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); 997 memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo)); 998 msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); 999 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); 1000 break; 1001 case SCTP_SENDV_PRINFO: 1002 if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) { 1003 free(cmsgbuf); 1004 errno = EINVAL; 1005 return (-1); 1006 } 1007 cmsg->cmsg_level = IPPROTO_SCTP; 1008 cmsg->cmsg_type = SCTP_PRINFO; 1009 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); 1010 memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo)); 1011 msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); 1012 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo))); 1013 break; 1014 case SCTP_SENDV_AUTHINFO: 1015 if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) { 1016 free(cmsgbuf); 1017 errno = EINVAL; 1018 return (-1); 1019 } 1020 cmsg->cmsg_level = IPPROTO_SCTP; 1021 cmsg->cmsg_type = SCTP_AUTHINFO; 1022 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo)); 1023 memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo)); 1024 msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo)); 1025 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo))); 1026 break; 1027 case SCTP_SENDV_SPA: 1028 if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) { 1029 free(cmsgbuf); 1030 errno = EINVAL; 1031 return (-1); 1032 } 1033 spa_info = (struct sctp_sendv_spa *)info; 1034 if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) { 1035 cmsg->cmsg_level = IPPROTO_SCTP; 1036 cmsg->cmsg_type = SCTP_SNDINFO; 1037 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); 1038 memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo)); 1039 msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); 1040 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); 1041 } 1042 if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) { 1043 cmsg->cmsg_level = IPPROTO_SCTP; 1044 cmsg->cmsg_type = SCTP_PRINFO; 1045 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); 1046 memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo)); 1047 msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); 1048 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo))); 1049 } 1050 if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) { 1051 cmsg->cmsg_level = IPPROTO_SCTP; 1052 cmsg->cmsg_type = SCTP_AUTHINFO; 1053 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo)); 1054 memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo)); 1055 msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo)); 1056 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo))); 1057 } 1058 break; 1059 default: 1060 free(cmsgbuf); 1061 errno = EINVAL; 1062 return (-1); 1063 } 1064 addr = addrs; 1065 msg.msg_name = NULL; 1066 msg.msg_namelen = 0; 1067 1068 for (i = 0; i < addrcnt; i++) { 1069 switch (addr->sa_family) { 1070 case AF_INET: 1071 addr_len = (socklen_t) sizeof(struct sockaddr_in); 1072 addr_in = (struct sockaddr_in *)addr; 1073 if (addr_in->sin_len != addr_len) { 1074 free(cmsgbuf); 1075 errno = EINVAL; 1076 return (-1); 1077 } 1078 if (i == 0) { 1079 port = addr_in->sin_port; 1080 } else { 1081 if (port == addr_in->sin_port) { 1082 cmsg->cmsg_level = IPPROTO_SCTP; 1083 cmsg->cmsg_type = SCTP_DSTADDRV4; 1084 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); 1085 memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr)); 1086 msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr)); 1087 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr))); 1088 } else { 1089 free(cmsgbuf); 1090 errno = EINVAL; 1091 return (-1); 1092 } 1093 } 1094 break; 1095 case AF_INET6: 1096 addr_len = (socklen_t) sizeof(struct sockaddr_in6); 1097 addr_in6 = (struct sockaddr_in6 *)addr; 1098 if (addr_in6->sin6_len != addr_len) { 1099 free(cmsgbuf); 1100 errno = EINVAL; 1101 return (-1); 1102 } 1103 if (i == 0) { 1104 port = addr_in6->sin6_port; 1105 } else { 1106 if (port == addr_in6->sin6_port) { 1107 cmsg->cmsg_level = IPPROTO_SCTP; 1108 cmsg->cmsg_type = SCTP_DSTADDRV6; 1109 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr)); 1110 memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr)); 1111 msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr)); 1112 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr))); 1113 } else { 1114 free(cmsgbuf); 1115 errno = EINVAL; 1116 return (-1); 1117 } 1118 } 1119 break; 1120 default: 1121 free(cmsgbuf); 1122 errno = EINVAL; 1123 return (-1); 1124 } 1125 if (i == 0) { 1126 msg.msg_name = addr; 1127 msg.msg_namelen = addr_len; 1128 } 1129 addr = (struct sockaddr *)((caddr_t)addr + addr_len); 1130 } 1131 if (msg.msg_controllen == 0) { 1132 msg.msg_control = NULL; 1133 } 1134 msg.msg_iov = (struct iovec *)iov; 1135 msg.msg_iovlen = iovcnt; 1136 msg.msg_flags = 0; 1137 ret = sendmsg(sd, &msg, flags); 1138 free(cmsgbuf); 1139 return (ret); 1140} 1141 1142 1143#if !defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT) 1144 1145int 1146sctp_peeloff(int sd, sctp_assoc_t assoc_id) 1147{ 1148 /* NOT supported, return invalid sd */ 1149 errno = ENOTSUP; 1150 return (-1); 1151} 1152 1153#endif 1154#if defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT) 1155int 1156sctp_peeloff(int sd, sctp_assoc_t assoc_id) 1157{ 1158 return (syscall(SYS_sctp_peeloff, sd, assoc_id)); 1159} 1160 1161#endif 1162 1163#undef SCTP_CONTROL_VEC_SIZE_RCV 1164