1221512Stuexen/*- 2221512Stuexen * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 3235827Stuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. 4235827Stuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. 5165242Srrs * 6165242Srrs * Redistribution and use in source and binary forms, with or without 7221512Stuexen * modification, are permitted provided that the following conditions are met: 8165242Srrs * 9221512Stuexen * a) Redistributions of source code must retain the above copyright notice, 10221512Stuexen * this list of conditions and the following disclaimer. 11221512Stuexen * 12221512Stuexen * b) Redistributions in binary form must reproduce the above copyright 13221512Stuexen * notice, this list of conditions and the following disclaimer in 14221512Stuexen * the documentation and/or other materials provided with the distribution. 15221512Stuexen * 16221512Stuexen * c) Neither the name of Cisco Systems, Inc. nor the names of its 17221512Stuexen * contributors may be used to endorse or promote products derived 18221512Stuexen * from this software without specific prior written permission. 19221512Stuexen * 20221512Stuexen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21221512Stuexen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22221512Stuexen * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23221512Stuexen * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24221512Stuexen * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25221512Stuexen * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26221512Stuexen * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27221512Stuexen * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28221512Stuexen * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29221512Stuexen * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30221512Stuexen * THE POSSIBILITY OF SUCH DAMAGE. 31165242Srrs */ 32221512Stuexen 33165242Srrs#include <sys/cdefs.h> 34165242Srrs__FBSDID("$FreeBSD: releng/10.3/lib/libc/net/sctp_sys_calls.c 294911 2016-01-27 14:01:21Z tuexen $"); 35235827Stuexen 36165242Srrs#include <stdio.h> 37165242Srrs#include <string.h> 38165242Srrs#include <errno.h> 39165242Srrs#include <stdlib.h> 40165242Srrs#include <unistd.h> 41165242Srrs#include <sys/types.h> 42165242Srrs#include <sys/socket.h> 43165242Srrs#include <sys/errno.h> 44165242Srrs#include <sys/syscall.h> 45165242Srrs#include <sys/uio.h> 46165242Srrs#include <netinet/in.h> 47165242Srrs#include <arpa/inet.h> 48165242Srrs#include <netinet/sctp_uio.h> 49165242Srrs#include <netinet/sctp.h> 50165242Srrs 51165242Srrs#ifndef IN6_IS_ADDR_V4MAPPED 52165242Srrs#define IN6_IS_ADDR_V4MAPPED(a) \ 53209684Sbrucec ((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \ 54209684Sbrucec (*(const uint32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \ 55209684Sbrucec (*(const uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) 56165242Srrs#endif 57165242Srrs 58165242Srrs#define SCTP_CONTROL_VEC_SIZE_RCV 16384 59165242Srrs 60166884Srrs 61165242Srrsstatic void 62165242Srrsin6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 63165242Srrs{ 64165242Srrs bzero(sin, sizeof(*sin)); 65165242Srrs sin->sin_len = sizeof(struct sockaddr_in); 66165242Srrs sin->sin_family = AF_INET; 67165242Srrs sin->sin_port = sin6->sin6_port; 68165242Srrs sin->sin_addr.s_addr = sin6->sin6_addr.__u6_addr.__u6_addr32[3]; 69165242Srrs} 70165242Srrs 71165242Srrsint 72165242Srrssctp_getaddrlen(sa_family_t family) 73165242Srrs{ 74223132Stuexen int ret, sd; 75165242Srrs socklen_t siz; 76165242Srrs struct sctp_assoc_value av; 77165242Srrs 78165242Srrs av.assoc_value = family; 79165242Srrs siz = sizeof(av); 80165242Srrs#if defined(AF_INET) 81165242Srrs sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 82165242Srrs#elif defined(AF_INET6) 83165242Srrs sd = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP); 84223132Stuexen#else 85223132Stuexen sd = -1; 86165242Srrs#endif 87165242Srrs if (sd == -1) { 88170993Srrs return (-1); 89165242Srrs } 90223132Stuexen ret = getsockopt(sd, IPPROTO_SCTP, SCTP_GET_ADDR_LEN, &av, &siz); 91165242Srrs close(sd); 92223132Stuexen if (ret == 0) { 93165242Srrs return ((int)av.assoc_value); 94165242Srrs } else { 95170993Srrs return (-1); 96165242Srrs } 97165242Srrs} 98165242Srrs 99165242Srrsint 100170580Srrssctp_connectx(int sd, const struct sockaddr *addrs, int addrcnt, 101170580Srrs sctp_assoc_t * id) 102165242Srrs{ 103249333Stuexen char *buf; 104255695Stuexen int i, ret, *aa; 105165242Srrs char *cpto; 106165242Srrs const struct sockaddr *at; 107255695Stuexen size_t len; 108165242Srrs 109170580Srrs /* validate the address count and list */ 110170580Srrs if ((addrs == NULL) || (addrcnt <= 0)) { 111170580Srrs errno = EINVAL; 112170580Srrs return (-1); 113170580Srrs } 114249333Stuexen if ((buf = malloc(sizeof(int) + (size_t)addrcnt * sizeof(struct sockaddr_in6))) == NULL) { 115249333Stuexen errno = E2BIG; 116249333Stuexen return (-1); 117249333Stuexen } 118255695Stuexen len = sizeof(int); 119165242Srrs at = addrs; 120249333Stuexen cpto = buf + sizeof(int); 121165242Srrs /* validate all the addresses and get the size */ 122165242Srrs for (i = 0; i < addrcnt; i++) { 123243302Stuexen switch (at->sa_family) { 124243302Stuexen case AF_INET: 125171031Srrs if (at->sa_len != sizeof(struct sockaddr_in)) { 126249333Stuexen free(buf); 127171031Srrs errno = EINVAL; 128171031Srrs return (-1); 129171031Srrs } 130243302Stuexen memcpy(cpto, at, sizeof(struct sockaddr_in)); 131243302Stuexen cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in)); 132243302Stuexen len += sizeof(struct sockaddr_in); 133243302Stuexen break; 134243302Stuexen case AF_INET6: 135171031Srrs if (at->sa_len != sizeof(struct sockaddr_in6)) { 136249333Stuexen free(buf); 137171031Srrs errno = EINVAL; 138171031Srrs return (-1); 139171031Srrs } 140165242Srrs if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)at)->sin6_addr)) { 141165242Srrs in6_sin6_2_sin((struct sockaddr_in *)cpto, (struct sockaddr_in6 *)at); 142165242Srrs cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in)); 143165242Srrs len += sizeof(struct sockaddr_in); 144165242Srrs } else { 145243302Stuexen memcpy(cpto, at, sizeof(struct sockaddr_in6)); 146243302Stuexen cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in6)); 147243302Stuexen len += sizeof(struct sockaddr_in6); 148165242Srrs } 149243302Stuexen break; 150243302Stuexen default: 151249333Stuexen free(buf); 152165242Srrs errno = EINVAL; 153165242Srrs return (-1); 154165242Srrs } 155249333Stuexen at = (struct sockaddr *)((caddr_t)at + at->sa_len); 156165242Srrs } 157165242Srrs aa = (int *)buf; 158249333Stuexen *aa = addrcnt; 159165242Srrs ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X, (void *)buf, 160169623Srrs (socklen_t) len); 161249333Stuexen if ((ret == 0) && (id != NULL)) { 162249333Stuexen *id = *(sctp_assoc_t *) buf; 163167598Srrs } 164255695Stuexen free(buf); 165165242Srrs return (ret); 166165242Srrs} 167165242Srrs 168165242Srrsint 169165242Srrssctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags) 170165242Srrs{ 171165242Srrs struct sctp_getaddresses *gaddrs; 172165242Srrs struct sockaddr *sa; 173171572Srrs struct sockaddr_in *sin; 174171572Srrs struct sockaddr_in6 *sin6; 175228630Stuexen int i; 176228630Stuexen size_t argsz; 177171572Srrs uint16_t sport = 0; 178165242Srrs 179170580Srrs /* validate the flags */ 180165242Srrs if ((flags != SCTP_BINDX_ADD_ADDR) && 181165242Srrs (flags != SCTP_BINDX_REM_ADDR)) { 182165242Srrs errno = EFAULT; 183165242Srrs return (-1); 184165242Srrs } 185170580Srrs /* validate the address count and list */ 186170580Srrs if ((addrcnt <= 0) || (addrs == NULL)) { 187170580Srrs errno = EINVAL; 188170580Srrs return (-1); 189170580Srrs } 190171572Srrs /* First pre-screen the addresses */ 191165242Srrs sa = addrs; 192165242Srrs for (i = 0; i < addrcnt; i++) { 193243302Stuexen switch (sa->sa_family) { 194243302Stuexen case AF_INET: 195243302Stuexen if (sa->sa_len != sizeof(struct sockaddr_in)) { 196243302Stuexen errno = EINVAL; 197243302Stuexen return (-1); 198243302Stuexen } 199171572Srrs sin = (struct sockaddr_in *)sa; 200171572Srrs if (sin->sin_port) { 201171572Srrs /* non-zero port, check or save */ 202171572Srrs if (sport) { 203171572Srrs /* Check against our port */ 204171572Srrs if (sport != sin->sin_port) { 205243302Stuexen errno = EINVAL; 206243302Stuexen return (-1); 207171572Srrs } 208171572Srrs } else { 209171572Srrs /* save off the port */ 210171572Srrs sport = sin->sin_port; 211171572Srrs } 212171572Srrs } 213243302Stuexen break; 214243302Stuexen case AF_INET6: 215243302Stuexen if (sa->sa_len != sizeof(struct sockaddr_in6)) { 216243302Stuexen errno = EINVAL; 217243302Stuexen return (-1); 218243302Stuexen } 219171572Srrs sin6 = (struct sockaddr_in6 *)sa; 220171572Srrs if (sin6->sin6_port) { 221171572Srrs /* non-zero port, check or save */ 222171572Srrs if (sport) { 223171572Srrs /* Check against our port */ 224171572Srrs if (sport != sin6->sin6_port) { 225243302Stuexen errno = EINVAL; 226243302Stuexen return (-1); 227171572Srrs } 228171572Srrs } else { 229171572Srrs /* save off the port */ 230171572Srrs sport = sin6->sin6_port; 231171572Srrs } 232171572Srrs } 233243302Stuexen break; 234243302Stuexen default: 235243302Stuexen /* Invalid address family specified. */ 236260428Stuexen errno = EAFNOSUPPORT; 237243302Stuexen return (-1); 238171572Srrs } 239228630Stuexen sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 240171572Srrs } 241243302Stuexen argsz = sizeof(struct sctp_getaddresses) + 242243302Stuexen sizeof(struct sockaddr_storage); 243243302Stuexen if ((gaddrs = (struct sctp_getaddresses *)malloc(argsz)) == NULL) { 244243302Stuexen errno = ENOMEM; 245243302Stuexen return (-1); 246243302Stuexen } 247243302Stuexen sa = addrs; 248171572Srrs for (i = 0; i < addrcnt; i++) { 249171031Srrs memset(gaddrs, 0, argsz); 250171031Srrs gaddrs->sget_assoc_id = 0; 251228630Stuexen memcpy(gaddrs->addr, sa, sa->sa_len); 252260428Stuexen /* 253260428Stuexen * Now, if there was a port mentioned, assure that the first 254260428Stuexen * address has that port to make sure it fails or succeeds 255260428Stuexen * correctly. 256260428Stuexen */ 257260428Stuexen if ((i == 0) && (sport != 0)) { 258260428Stuexen switch (gaddrs->addr->sa_family) { 259260428Stuexen case AF_INET: 260260428Stuexen sin = (struct sockaddr_in *)gaddrs->addr; 261260428Stuexen sin->sin_port = sport; 262260428Stuexen break; 263260428Stuexen case AF_INET6: 264260428Stuexen sin6 = (struct sockaddr_in6 *)gaddrs->addr; 265260428Stuexen sin6->sin6_port = sport; 266260428Stuexen break; 267260428Stuexen } 268260428Stuexen } 269171031Srrs if (setsockopt(sd, IPPROTO_SCTP, flags, gaddrs, 270171031Srrs (socklen_t) argsz) != 0) { 271165242Srrs free(gaddrs); 272165242Srrs return (-1); 273165242Srrs } 274228630Stuexen sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 275165242Srrs } 276165242Srrs free(gaddrs); 277165242Srrs return (0); 278165242Srrs} 279165242Srrs 280165242Srrsint 281165242Srrssctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t * size) 282165242Srrs{ 283165242Srrs if (arg == NULL) { 284171152Srrs errno = EINVAL; 285171152Srrs return (-1); 286165242Srrs } 287253105Stuexen if ((id == SCTP_CURRENT_ASSOC) || 288253105Stuexen (id == SCTP_ALL_ASSOC)) { 289253105Stuexen errno = EINVAL; 290253105Stuexen return (-1); 291253105Stuexen } 292171572Srrs switch (opt) { 293171572Srrs case SCTP_RTOINFO: 294171572Srrs ((struct sctp_rtoinfo *)arg)->srto_assoc_id = id; 295171572Srrs break; 296171572Srrs case SCTP_ASSOCINFO: 297171572Srrs ((struct sctp_assocparams *)arg)->sasoc_assoc_id = id; 298171572Srrs break; 299171572Srrs case SCTP_DEFAULT_SEND_PARAM: 300171572Srrs ((struct sctp_assocparams *)arg)->sasoc_assoc_id = id; 301171572Srrs break; 302171572Srrs case SCTP_PRIMARY_ADDR: 303171572Srrs ((struct sctp_setprim *)arg)->ssp_assoc_id = id; 304171572Srrs break; 305171572Srrs case SCTP_PEER_ADDR_PARAMS: 306171572Srrs ((struct sctp_paddrparams *)arg)->spp_assoc_id = id; 307171572Srrs break; 308171572Srrs case SCTP_MAXSEG: 309171572Srrs ((struct sctp_assoc_value *)arg)->assoc_id = id; 310171572Srrs break; 311171572Srrs case SCTP_AUTH_KEY: 312171572Srrs ((struct sctp_authkey *)arg)->sca_assoc_id = id; 313171572Srrs break; 314171572Srrs case SCTP_AUTH_ACTIVE_KEY: 315171572Srrs ((struct sctp_authkeyid *)arg)->scact_assoc_id = id; 316171572Srrs break; 317171572Srrs case SCTP_DELAYED_SACK: 318171572Srrs ((struct sctp_sack_info *)arg)->sack_assoc_id = id; 319171572Srrs break; 320171572Srrs case SCTP_CONTEXT: 321171572Srrs ((struct sctp_assoc_value *)arg)->assoc_id = id; 322171572Srrs break; 323171572Srrs case SCTP_STATUS: 324171572Srrs ((struct sctp_status *)arg)->sstat_assoc_id = id; 325171572Srrs break; 326171572Srrs case SCTP_GET_PEER_ADDR_INFO: 327171572Srrs ((struct sctp_paddrinfo *)arg)->spinfo_assoc_id = id; 328171572Srrs break; 329171572Srrs case SCTP_PEER_AUTH_CHUNKS: 330171572Srrs ((struct sctp_authchunks *)arg)->gauth_assoc_id = id; 331171572Srrs break; 332171572Srrs case SCTP_LOCAL_AUTH_CHUNKS: 333171572Srrs ((struct sctp_authchunks *)arg)->gauth_assoc_id = id; 334171572Srrs break; 335221512Stuexen case SCTP_TIMEOUTS: 336221512Stuexen ((struct sctp_timeouts *)arg)->stimo_assoc_id = id; 337221512Stuexen break; 338223132Stuexen case SCTP_EVENT: 339223132Stuexen ((struct sctp_event *)arg)->se_assoc_id = id; 340223132Stuexen break; 341223178Stuexen case SCTP_DEFAULT_SNDINFO: 342223178Stuexen ((struct sctp_sndinfo *)arg)->snd_assoc_id = id; 343223178Stuexen break; 344223178Stuexen case SCTP_DEFAULT_PRINFO: 345223178Stuexen ((struct sctp_default_prinfo *)arg)->pr_assoc_id = id; 346223178Stuexen break; 347224641Stuexen case SCTP_PEER_ADDR_THLDS: 348224641Stuexen ((struct sctp_paddrthlds *)arg)->spt_assoc_id = id; 349224641Stuexen break; 350227755Stuexen case SCTP_REMOTE_UDP_ENCAPS_PORT: 351227755Stuexen ((struct sctp_udpencaps *)arg)->sue_assoc_id = id; 352227755Stuexen break; 353270356Stuexen case SCTP_ECN_SUPPORTED: 354270356Stuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 355270356Stuexen break; 356270357Stuexen case SCTP_PR_SUPPORTED: 357270357Stuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 358270357Stuexen break; 359270362Stuexen case SCTP_AUTH_SUPPORTED: 360270362Stuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 361270362Stuexen break; 362270362Stuexen case SCTP_ASCONF_SUPPORTED: 363270362Stuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 364270362Stuexen break; 365270361Stuexen case SCTP_RECONFIG_SUPPORTED: 366270361Stuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 367270361Stuexen break; 368270359Stuexen case SCTP_NRSACK_SUPPORTED: 369270359Stuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 370270359Stuexen break; 371270360Stuexen case SCTP_PKTDROP_SUPPORTED: 372270360Stuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 373270360Stuexen break; 374223180Stuexen case SCTP_MAX_BURST: 375223180Stuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 376223180Stuexen break; 377253104Stuexen case SCTP_ENABLE_STREAM_RESET: 378253104Stuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 379253104Stuexen break; 380270363Stuexen case SCTP_PR_STREAM_STATUS: 381270363Stuexen ((struct sctp_prstatus *)arg)->sprstat_assoc_id = id; 382270363Stuexen break; 383270363Stuexen case SCTP_PR_ASSOC_STATUS: 384270363Stuexen ((struct sctp_prstatus *)arg)->sprstat_assoc_id = id; 385270363Stuexen break; 386283724Stuexen case SCTP_MAX_CWND: 387283724Stuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 388283724Stuexen break; 389171572Srrs default: 390171572Srrs break; 391171572Srrs } 392169623Srrs return (getsockopt(sd, IPPROTO_SCTP, opt, arg, size)); 393165242Srrs} 394165242Srrs 395165242Srrsint 396165242Srrssctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs) 397165242Srrs{ 398165242Srrs struct sctp_getaddresses *addrs; 399165242Srrs struct sockaddr *sa; 400165242Srrs sctp_assoc_t asoc; 401165242Srrs caddr_t lim; 402228630Stuexen socklen_t opt_len; 403165242Srrs int cnt; 404165242Srrs 405165242Srrs if (raddrs == NULL) { 406165242Srrs errno = EFAULT; 407165242Srrs return (-1); 408165242Srrs } 409165242Srrs asoc = id; 410228630Stuexen opt_len = (socklen_t) sizeof(sctp_assoc_t); 411165242Srrs if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE, 412228630Stuexen &asoc, &opt_len) != 0) { 413165242Srrs return (-1); 414165242Srrs } 415165242Srrs /* size required is returned in 'asoc' */ 416228630Stuexen opt_len = (socklen_t) ((size_t)asoc + sizeof(struct sctp_getaddresses)); 417228630Stuexen addrs = calloc(1, (size_t)opt_len); 418165242Srrs if (addrs == NULL) { 419242512Stuexen errno = ENOMEM; 420165242Srrs return (-1); 421165242Srrs } 422165242Srrs addrs->sget_assoc_id = id; 423165242Srrs /* Now lets get the array of addresses */ 424165242Srrs if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES, 425228630Stuexen addrs, &opt_len) != 0) { 426165242Srrs free(addrs); 427165242Srrs return (-1); 428165242Srrs } 429228630Stuexen *raddrs = (struct sockaddr *)&addrs->addr[0]; 430165242Srrs cnt = 0; 431165242Srrs sa = (struct sockaddr *)&addrs->addr[0]; 432228630Stuexen lim = (caddr_t)addrs + opt_len; 433165242Srrs while (((caddr_t)sa < lim) && (sa->sa_len > 0)) { 434165242Srrs sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 435165242Srrs cnt++; 436165242Srrs } 437165242Srrs return (cnt); 438165242Srrs} 439165242Srrs 440167598Srrsvoid 441165242Srrssctp_freepaddrs(struct sockaddr *addrs) 442165242Srrs{ 443165242Srrs void *fr_addr; 444165242Srrs 445249333Stuexen /* Take away the hidden association id */ 446165242Srrs fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t)); 447165242Srrs /* Now free it */ 448165242Srrs free(fr_addr); 449165242Srrs} 450165242Srrs 451165242Srrsint 452165242Srrssctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs) 453165242Srrs{ 454165242Srrs struct sctp_getaddresses *addrs; 455165242Srrs caddr_t lim; 456165242Srrs struct sockaddr *sa; 457228630Stuexen size_t size_of_addresses; 458228630Stuexen socklen_t opt_len; 459165242Srrs int cnt; 460165242Srrs 461165242Srrs if (raddrs == NULL) { 462165242Srrs errno = EFAULT; 463165242Srrs return (-1); 464165242Srrs } 465165242Srrs size_of_addresses = 0; 466228630Stuexen opt_len = (socklen_t) sizeof(int); 467165242Srrs if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE, 468228630Stuexen &size_of_addresses, &opt_len) != 0) { 469165242Srrs errno = ENOMEM; 470165242Srrs return (-1); 471165242Srrs } 472165242Srrs if (size_of_addresses == 0) { 473165242Srrs errno = ENOTCONN; 474165242Srrs return (-1); 475165242Srrs } 476228630Stuexen opt_len = (socklen_t) (size_of_addresses + 477228630Stuexen sizeof(struct sockaddr_storage) + 478228630Stuexen sizeof(struct sctp_getaddresses)); 479228630Stuexen addrs = calloc(1, (size_t)opt_len); 480165242Srrs if (addrs == NULL) { 481165242Srrs errno = ENOMEM; 482165242Srrs return (-1); 483165242Srrs } 484165242Srrs addrs->sget_assoc_id = id; 485165242Srrs /* Now lets get the array of addresses */ 486165242Srrs if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs, 487228630Stuexen &opt_len) != 0) { 488165242Srrs free(addrs); 489165242Srrs errno = ENOMEM; 490165242Srrs return (-1); 491165242Srrs } 492228630Stuexen *raddrs = (struct sockaddr *)&addrs->addr[0]; 493165242Srrs cnt = 0; 494165242Srrs sa = (struct sockaddr *)&addrs->addr[0]; 495228630Stuexen lim = (caddr_t)addrs + opt_len; 496165242Srrs while (((caddr_t)sa < lim) && (sa->sa_len > 0)) { 497165242Srrs sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 498165242Srrs cnt++; 499165242Srrs } 500165242Srrs return (cnt); 501165242Srrs} 502165242Srrs 503167598Srrsvoid 504165242Srrssctp_freeladdrs(struct sockaddr *addrs) 505165242Srrs{ 506165242Srrs void *fr_addr; 507165242Srrs 508249333Stuexen /* Take away the hidden association id */ 509165242Srrs fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t)); 510165242Srrs /* Now free it */ 511165242Srrs free(fr_addr); 512165242Srrs} 513165242Srrs 514165242Srrsssize_t 515165242Srrssctp_sendmsg(int s, 516165242Srrs const void *data, 517165242Srrs size_t len, 518165242Srrs const struct sockaddr *to, 519169623Srrs socklen_t tolen, 520209684Sbrucec uint32_t ppid, 521209684Sbrucec uint32_t flags, 522209684Sbrucec uint16_t stream_no, 523209684Sbrucec uint32_t timetolive, 524209684Sbrucec uint32_t context) 525165242Srrs{ 526165242Srrs#ifdef SYS_sctp_generic_sendmsg 527165242Srrs struct sctp_sndrcvinfo sinfo; 528165242Srrs 529228531Stuexen memset(&sinfo, 0, sizeof(struct sctp_sndrcvinfo)); 530165242Srrs sinfo.sinfo_ppid = ppid; 531165242Srrs sinfo.sinfo_flags = flags; 532165242Srrs sinfo.sinfo_stream = stream_no; 533165242Srrs sinfo.sinfo_timetolive = timetolive; 534165242Srrs sinfo.sinfo_context = context; 535165242Srrs sinfo.sinfo_assoc_id = 0; 536165242Srrs return (syscall(SYS_sctp_generic_sendmsg, s, 537165242Srrs data, len, to, tolen, &sinfo, 0)); 538165242Srrs#else 539165242Srrs struct msghdr msg; 540249333Stuexen struct sctp_sndrcvinfo *sinfo; 541221512Stuexen struct iovec iov; 542249333Stuexen char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; 543165242Srrs struct cmsghdr *cmsg; 544165242Srrs struct sockaddr *who = NULL; 545165242Srrs union { 546165242Srrs struct sockaddr_in in; 547165242Srrs struct sockaddr_in6 in6; 548165242Srrs } addr; 549165242Srrs 550221512Stuexen if ((tolen > 0) && 551221512Stuexen ((to == NULL) || (tolen < sizeof(struct sockaddr)))) { 552169623Srrs errno = EINVAL; 553246629Stuexen return (-1); 554169623Srrs } 555249333Stuexen if ((to != NULL) && (tolen > 0)) { 556249333Stuexen switch (to->sa_family) { 557249333Stuexen case AF_INET: 558169623Srrs if (tolen != sizeof(struct sockaddr_in)) { 559169623Srrs errno = EINVAL; 560246629Stuexen return (-1); 561165242Srrs } 562221512Stuexen if ((to->sa_len > 0) && 563221512Stuexen (to->sa_len != sizeof(struct sockaddr_in))) { 564169623Srrs errno = EINVAL; 565246629Stuexen return (-1); 566169623Srrs } 567169623Srrs memcpy(&addr, to, sizeof(struct sockaddr_in)); 568169623Srrs addr.in.sin_len = sizeof(struct sockaddr_in); 569249333Stuexen break; 570249333Stuexen case AF_INET6: 571169623Srrs if (tolen != sizeof(struct sockaddr_in6)) { 572169623Srrs errno = EINVAL; 573246629Stuexen return (-1); 574169623Srrs } 575221512Stuexen if ((to->sa_len > 0) && 576221512Stuexen (to->sa_len != sizeof(struct sockaddr_in6))) { 577169623Srrs errno = EINVAL; 578246629Stuexen return (-1); 579169623Srrs } 580169623Srrs memcpy(&addr, to, sizeof(struct sockaddr_in6)); 581169623Srrs addr.in6.sin6_len = sizeof(struct sockaddr_in6); 582249333Stuexen break; 583249333Stuexen default: 584169623Srrs errno = EAFNOSUPPORT; 585246629Stuexen return (-1); 586165242Srrs } 587165242Srrs who = (struct sockaddr *)&addr; 588165242Srrs } 589221512Stuexen iov.iov_base = (char *)data; 590221512Stuexen iov.iov_len = len; 591165242Srrs 592169623Srrs if (who) { 593165242Srrs msg.msg_name = (caddr_t)who; 594165242Srrs msg.msg_namelen = who->sa_len; 595165242Srrs } else { 596165242Srrs msg.msg_name = (caddr_t)NULL; 597165242Srrs msg.msg_namelen = 0; 598165242Srrs } 599221512Stuexen msg.msg_iov = &iov; 600165242Srrs msg.msg_iovlen = 1; 601249333Stuexen msg.msg_control = cmsgbuf; 602249333Stuexen msg.msg_controllen = CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); 603283702Stuexen msg.msg_flags = 0; 604249333Stuexen cmsg = (struct cmsghdr *)cmsgbuf; 605165242Srrs cmsg->cmsg_level = IPPROTO_SCTP; 606165242Srrs cmsg->cmsg_type = SCTP_SNDRCV; 607165242Srrs cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 608249333Stuexen sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); 609270362Stuexen memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo)); 610249333Stuexen sinfo->sinfo_stream = stream_no; 611249333Stuexen sinfo->sinfo_ssn = 0; 612249333Stuexen sinfo->sinfo_flags = flags; 613249333Stuexen sinfo->sinfo_ppid = ppid; 614249333Stuexen sinfo->sinfo_context = context; 615249333Stuexen sinfo->sinfo_assoc_id = 0; 616249333Stuexen sinfo->sinfo_timetolive = timetolive; 617249333Stuexen return (sendmsg(s, &msg, 0)); 618165242Srrs#endif 619165242Srrs} 620165242Srrs 621165242Srrs 622165242Srrssctp_assoc_t 623165242Srrssctp_getassocid(int sd, struct sockaddr *sa) 624165242Srrs{ 625171440Srrs struct sctp_paddrinfo sp; 626165270Srodrigc socklen_t siz; 627165242Srrs 628165242Srrs /* First get the assoc id */ 629171440Srrs siz = sizeof(sp); 630165242Srrs memset(&sp, 0, sizeof(sp)); 631171440Srrs memcpy((caddr_t)&sp.spinfo_address, sa, sa->sa_len); 632165242Srrs if (getsockopt(sd, IPPROTO_SCTP, 633171440Srrs SCTP_GET_PEER_ADDR_INFO, &sp, &siz) != 0) { 634249333Stuexen /* We depend on the fact that 0 can never be returned */ 635165242Srrs return ((sctp_assoc_t) 0); 636165242Srrs } 637171440Srrs return (sp.spinfo_assoc_id); 638165242Srrs} 639165242Srrs 640165242Srrsssize_t 641165242Srrssctp_send(int sd, const void *data, size_t len, 642165242Srrs const struct sctp_sndrcvinfo *sinfo, 643165242Srrs int flags) 644165242Srrs{ 645165242Srrs 646165242Srrs#ifdef SYS_sctp_generic_sendmsg 647165242Srrs struct sockaddr *to = NULL; 648165242Srrs 649165242Srrs return (syscall(SYS_sctp_generic_sendmsg, sd, 650165242Srrs data, len, to, 0, sinfo, flags)); 651165242Srrs#else 652165242Srrs struct msghdr msg; 653221512Stuexen struct iovec iov; 654249333Stuexen char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; 655165242Srrs struct cmsghdr *cmsg; 656165242Srrs 657165242Srrs if (sinfo == NULL) { 658171440Srrs errno = EINVAL; 659171440Srrs return (-1); 660165242Srrs } 661221512Stuexen iov.iov_base = (char *)data; 662221512Stuexen iov.iov_len = len; 663165242Srrs 664249333Stuexen msg.msg_name = NULL; 665165242Srrs msg.msg_namelen = 0; 666221512Stuexen msg.msg_iov = &iov; 667165242Srrs msg.msg_iovlen = 1; 668249333Stuexen msg.msg_control = cmsgbuf; 669249333Stuexen msg.msg_controllen = CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); 670283702Stuexen msg.msg_flags = 0; 671249333Stuexen cmsg = (struct cmsghdr *)cmsgbuf; 672165242Srrs cmsg->cmsg_level = IPPROTO_SCTP; 673165242Srrs cmsg->cmsg_type = SCTP_SNDRCV; 674165242Srrs cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 675249333Stuexen memcpy(CMSG_DATA(cmsg), sinfo, sizeof(struct sctp_sndrcvinfo)); 676249333Stuexen return (sendmsg(sd, &msg, flags)); 677165242Srrs#endif 678165242Srrs} 679165242Srrs 680165242Srrs 681165242Srrs 682165242Srrsssize_t 683165242Srrssctp_sendx(int sd, const void *msg, size_t msg_len, 684165242Srrs struct sockaddr *addrs, int addrcnt, 685165242Srrs struct sctp_sndrcvinfo *sinfo, 686165242Srrs int flags) 687165242Srrs{ 688209760Srrs struct sctp_sndrcvinfo __sinfo; 689165242Srrs ssize_t ret; 690165242Srrs int i, cnt, *aa, saved_errno; 691165242Srrs char *buf; 692228630Stuexen int no_end_cx = 0; 693228630Stuexen size_t len, add_len; 694165242Srrs struct sockaddr *at; 695165242Srrs 696171572Srrs if (addrs == NULL) { 697171572Srrs errno = EINVAL; 698171572Srrs return (-1); 699171572Srrs } 700166884Srrs#ifdef SYS_sctp_generic_sendmsg 701221512Stuexen if (addrcnt == 1) { 702166884Srrs socklen_t l; 703294911Stuexen ssize_t ret; 704166884Srrs 705166884Srrs /* 706166884Srrs * Quick way, we don't need to do a connectx so lets use the 707166884Srrs * syscall directly. 708166884Srrs */ 709166884Srrs l = addrs->sa_len; 710294911Stuexen ret = syscall(SYS_sctp_generic_sendmsg, sd, 711294911Stuexen msg, msg_len, addrs, l, sinfo, flags); 712294911Stuexen if ((ret >= 0) && (sinfo != NULL)) { 713294911Stuexen sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs); 714294911Stuexen } 715294911Stuexen return (ret); 716166884Srrs } 717166884Srrs#endif 718171440Srrs 719165242Srrs len = sizeof(int); 720165242Srrs at = addrs; 721165242Srrs cnt = 0; 722165242Srrs /* validate all the addresses and get the size */ 723165242Srrs for (i = 0; i < addrcnt; i++) { 724165242Srrs if (at->sa_family == AF_INET) { 725165242Srrs add_len = sizeof(struct sockaddr_in); 726165242Srrs } else if (at->sa_family == AF_INET6) { 727165242Srrs add_len = sizeof(struct sockaddr_in6); 728165242Srrs } else { 729165242Srrs errno = EINVAL; 730165242Srrs return (-1); 731165242Srrs } 732165242Srrs len += add_len; 733165242Srrs at = (struct sockaddr *)((caddr_t)at + add_len); 734165242Srrs cnt++; 735165242Srrs } 736165242Srrs /* do we have any? */ 737165242Srrs if (cnt == 0) { 738165242Srrs errno = EINVAL; 739165242Srrs return (-1); 740165242Srrs } 741165242Srrs buf = malloc(len); 742165242Srrs if (buf == NULL) { 743242512Stuexen errno = ENOMEM; 744171440Srrs return (-1); 745165242Srrs } 746165242Srrs aa = (int *)buf; 747165242Srrs *aa = cnt; 748165242Srrs aa++; 749228630Stuexen memcpy((caddr_t)aa, addrs, (size_t)(len - sizeof(int))); 750165242Srrs ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_DELAYED, (void *)buf, 751165242Srrs (socklen_t) len); 752165242Srrs 753165242Srrs free(buf); 754165242Srrs if (ret != 0) { 755165242Srrs if (errno == EALREADY) { 756203323Sbrucec no_end_cx = 1; 757165242Srrs goto continue_send; 758165242Srrs } 759165242Srrs return (ret); 760165242Srrs } 761165242Srrscontinue_send: 762209760Srrs if (sinfo == NULL) { 763209760Srrs sinfo = &__sinfo; 764209760Srrs memset(&__sinfo, 0, sizeof(__sinfo)); 765209760Srrs } 766165242Srrs sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs); 767165242Srrs if (sinfo->sinfo_assoc_id == 0) { 768165242Srrs (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs, 769165242Srrs (socklen_t) addrs->sa_len); 770165242Srrs errno = ENOENT; 771165242Srrs return (-1); 772165242Srrs } 773165242Srrs ret = sctp_send(sd, msg, msg_len, sinfo, flags); 774165242Srrs saved_errno = errno; 775165242Srrs if (no_end_cx == 0) 776165242Srrs (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs, 777165242Srrs (socklen_t) addrs->sa_len); 778165242Srrs 779165242Srrs errno = saved_errno; 780165242Srrs return (ret); 781165242Srrs} 782165242Srrs 783165242Srrsssize_t 784165242Srrssctp_sendmsgx(int sd, 785165242Srrs const void *msg, 786165242Srrs size_t len, 787165242Srrs struct sockaddr *addrs, 788165242Srrs int addrcnt, 789209684Sbrucec uint32_t ppid, 790209684Sbrucec uint32_t flags, 791209684Sbrucec uint16_t stream_no, 792209684Sbrucec uint32_t timetolive, 793209684Sbrucec uint32_t context) 794165242Srrs{ 795165242Srrs struct sctp_sndrcvinfo sinfo; 796165242Srrs 797165242Srrs memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo)); 798165242Srrs sinfo.sinfo_ppid = ppid; 799165242Srrs sinfo.sinfo_flags = flags; 800165242Srrs sinfo.sinfo_ssn = stream_no; 801165242Srrs sinfo.sinfo_timetolive = timetolive; 802165242Srrs sinfo.sinfo_context = context; 803246629Stuexen return (sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0)); 804165242Srrs} 805165242Srrs 806165242Srrsssize_t 807165242Srrssctp_recvmsg(int s, 808165242Srrs void *dbuf, 809165242Srrs size_t len, 810165242Srrs struct sockaddr *from, 811165242Srrs socklen_t * fromlen, 812165242Srrs struct sctp_sndrcvinfo *sinfo, 813165242Srrs int *msg_flags) 814165242Srrs{ 815165242Srrs#ifdef SYS_sctp_generic_recvmsg 816221512Stuexen struct iovec iov; 817165242Srrs 818221512Stuexen iov.iov_base = dbuf; 819221512Stuexen iov.iov_len = len; 820165242Srrs return (syscall(SYS_sctp_generic_recvmsg, s, 821221512Stuexen &iov, 1, from, fromlen, sinfo, msg_flags)); 822165242Srrs#else 823165242Srrs ssize_t sz; 824165242Srrs struct msghdr msg; 825221512Stuexen struct iovec iov; 826249333Stuexen char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV]; 827165242Srrs struct cmsghdr *cmsg; 828165242Srrs 829165242Srrs if (msg_flags == NULL) { 830165242Srrs errno = EINVAL; 831165242Srrs return (-1); 832165242Srrs } 833221512Stuexen iov.iov_base = dbuf; 834221512Stuexen iov.iov_len = len; 835165242Srrs msg.msg_name = (caddr_t)from; 836165242Srrs if (fromlen == NULL) 837165242Srrs msg.msg_namelen = 0; 838165242Srrs else 839165242Srrs msg.msg_namelen = *fromlen; 840221512Stuexen msg.msg_iov = &iov; 841165242Srrs msg.msg_iovlen = 1; 842249333Stuexen msg.msg_control = cmsgbuf; 843249333Stuexen msg.msg_controllen = sizeof(cmsgbuf); 844283702Stuexen msg.msg_flags = 0; 845170580Srrs sz = recvmsg(s, &msg, *msg_flags); 846221512Stuexen *msg_flags = msg.msg_flags; 847221512Stuexen if (sz <= 0) { 848165242Srrs return (sz); 849221512Stuexen } 850221512Stuexen if (sinfo) { 851165242Srrs sinfo->sinfo_assoc_id = 0; 852221512Stuexen } 853249333Stuexen if ((msg.msg_controllen > 0) && (sinfo != NULL)) { 854165242Srrs /* 855165242Srrs * parse through and see if we find the sctp_sndrcvinfo (if 856165242Srrs * the user wants it). 857165242Srrs */ 858249333Stuexen for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 859249333Stuexen if (cmsg->cmsg_level != IPPROTO_SCTP) { 860249333Stuexen continue; 861249333Stuexen } 862249333Stuexen if (cmsg->cmsg_type == SCTP_SNDRCV) { 863249333Stuexen memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_sndrcvinfo)); 864165242Srrs break; 865165242Srrs } 866249333Stuexen if (cmsg->cmsg_type == SCTP_EXTRCV) { 867249333Stuexen /* 868249333Stuexen * Let's hope that the user provided enough 869249333Stuexen * enough memory. At least he asked for more 870249333Stuexen * information. 871249333Stuexen */ 872249333Stuexen memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_extrcvinfo)); 873249333Stuexen break; 874165242Srrs } 875165242Srrs } 876165242Srrs } 877165242Srrs return (sz); 878165242Srrs#endif 879165242Srrs} 880165242Srrs 881223132Stuexenssize_t 882223132Stuexensctp_recvv(int sd, 883223132Stuexen const struct iovec *iov, 884223132Stuexen int iovlen, 885223132Stuexen struct sockaddr *from, 886223132Stuexen socklen_t * fromlen, 887223132Stuexen void *info, 888223132Stuexen socklen_t * infolen, 889223132Stuexen unsigned int *infotype, 890223132Stuexen int *flags) 891223132Stuexen{ 892249333Stuexen char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV]; 893223132Stuexen struct msghdr msg; 894223132Stuexen struct cmsghdr *cmsg; 895249333Stuexen ssize_t ret; 896223132Stuexen struct sctp_rcvinfo *rcvinfo; 897223132Stuexen struct sctp_nxtinfo *nxtinfo; 898165242Srrs 899283701Stuexen if (((info != NULL) && (infolen == NULL)) || 900223152Stuexen ((info == NULL) && (infolen != NULL) && (*infolen != 0)) || 901223152Stuexen ((info != NULL) && (infotype == NULL))) { 902223152Stuexen errno = EINVAL; 903223152Stuexen return (-1); 904223152Stuexen } 905223132Stuexen if (infotype) { 906223132Stuexen *infotype = SCTP_RECVV_NOINFO; 907223132Stuexen } 908223132Stuexen msg.msg_name = from; 909223132Stuexen if (fromlen == NULL) { 910223132Stuexen msg.msg_namelen = 0; 911223132Stuexen } else { 912223132Stuexen msg.msg_namelen = *fromlen; 913223132Stuexen } 914223132Stuexen msg.msg_iov = (struct iovec *)iov; 915223132Stuexen msg.msg_iovlen = iovlen; 916249333Stuexen msg.msg_control = cmsgbuf; 917249333Stuexen msg.msg_controllen = sizeof(cmsgbuf); 918283702Stuexen msg.msg_flags = 0; 919249333Stuexen ret = recvmsg(sd, &msg, *flags); 920223132Stuexen *flags = msg.msg_flags; 921249333Stuexen if ((ret > 0) && 922223132Stuexen (msg.msg_controllen > 0) && 923223132Stuexen (infotype != NULL) && 924223132Stuexen (infolen != NULL) && 925223132Stuexen (*infolen > 0)) { 926223132Stuexen rcvinfo = NULL; 927223132Stuexen nxtinfo = NULL; 928223132Stuexen for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 929223132Stuexen if (cmsg->cmsg_level != IPPROTO_SCTP) { 930223132Stuexen continue; 931223132Stuexen } 932223132Stuexen if (cmsg->cmsg_type == SCTP_RCVINFO) { 933223132Stuexen rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg); 934249333Stuexen if (nxtinfo != NULL) { 935249333Stuexen break; 936249333Stuexen } else { 937249333Stuexen continue; 938249333Stuexen } 939223132Stuexen } 940223132Stuexen if (cmsg->cmsg_type == SCTP_NXTINFO) { 941223132Stuexen nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg); 942249333Stuexen if (rcvinfo != NULL) { 943249333Stuexen break; 944249333Stuexen } else { 945249333Stuexen continue; 946249333Stuexen } 947223132Stuexen } 948223132Stuexen } 949249333Stuexen if (rcvinfo != NULL) { 950249333Stuexen if ((nxtinfo != NULL) && (*infolen >= sizeof(struct sctp_recvv_rn))) { 951249333Stuexen struct sctp_recvv_rn *rn_info; 952165242Srrs 953249333Stuexen rn_info = (struct sctp_recvv_rn *)info; 954249333Stuexen rn_info->recvv_rcvinfo = *rcvinfo; 955249333Stuexen rn_info->recvv_nxtinfo = *nxtinfo; 956249333Stuexen *infolen = (socklen_t) sizeof(struct sctp_recvv_rn); 957249333Stuexen *infotype = SCTP_RECVV_RN; 958249333Stuexen } else if (*infolen >= sizeof(struct sctp_rcvinfo)) { 959249333Stuexen memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo)); 960249333Stuexen *infolen = (socklen_t) sizeof(struct sctp_rcvinfo); 961249333Stuexen *infotype = SCTP_RECVV_RCVINFO; 962223132Stuexen } 963249333Stuexen } else if (nxtinfo != NULL) { 964249333Stuexen if (*infolen >= sizeof(struct sctp_nxtinfo)) { 965223132Stuexen memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo)); 966223132Stuexen *infolen = (socklen_t) sizeof(struct sctp_nxtinfo); 967223132Stuexen *infotype = SCTP_RECVV_NXTINFO; 968223132Stuexen } 969223132Stuexen } 970223132Stuexen } 971249333Stuexen return (ret); 972223132Stuexen} 973223132Stuexen 974223132Stuexenssize_t 975223132Stuexensctp_sendv(int sd, 976223132Stuexen const struct iovec *iov, int iovcnt, 977223132Stuexen struct sockaddr *addrs, int addrcnt, 978223132Stuexen void *info, socklen_t infolen, unsigned int infotype, 979223132Stuexen int flags) 980165242Srrs{ 981223132Stuexen ssize_t ret; 982223132Stuexen int i; 983223152Stuexen socklen_t addr_len; 984223152Stuexen struct msghdr msg; 985223152Stuexen in_port_t port; 986223132Stuexen struct sctp_sendv_spa *spa_info; 987223132Stuexen struct cmsghdr *cmsg; 988223132Stuexen char *cmsgbuf; 989223132Stuexen struct sockaddr *addr; 990223132Stuexen struct sockaddr_in *addr_in; 991223132Stuexen struct sockaddr_in6 *addr_in6; 992294910Stuexen sctp_assoc_t *assoc_id; 993165242Srrs 994223152Stuexen if ((addrcnt < 0) || 995223152Stuexen (iovcnt < 0) || 996223154Stuexen ((addrs == NULL) && (addrcnt > 0)) || 997223154Stuexen ((addrs != NULL) && (addrcnt == 0)) || 998223152Stuexen ((iov == NULL) && (iovcnt > 0)) || 999223152Stuexen ((iov != NULL) && (iovcnt == 0))) { 1000223132Stuexen errno = EINVAL; 1001165242Srrs return (-1); 1002223132Stuexen } 1003223132Stuexen cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) + 1004223132Stuexen CMSG_SPACE(sizeof(struct sctp_prinfo)) + 1005223132Stuexen CMSG_SPACE(sizeof(struct sctp_authinfo)) + 1006228630Stuexen (size_t)addrcnt * CMSG_SPACE(sizeof(struct in6_addr))); 1007223132Stuexen if (cmsgbuf == NULL) { 1008242512Stuexen errno = ENOMEM; 1009223132Stuexen return (-1); 1010223132Stuexen } 1011294910Stuexen assoc_id = NULL; 1012223132Stuexen msg.msg_control = cmsgbuf; 1013223132Stuexen msg.msg_controllen = 0; 1014223132Stuexen cmsg = (struct cmsghdr *)cmsgbuf; 1015223132Stuexen switch (infotype) { 1016223152Stuexen case SCTP_SENDV_NOINFO: 1017223152Stuexen if ((infolen != 0) || (info != NULL)) { 1018223152Stuexen free(cmsgbuf); 1019223152Stuexen errno = EINVAL; 1020223152Stuexen return (-1); 1021223152Stuexen } 1022223152Stuexen break; 1023223132Stuexen case SCTP_SENDV_SNDINFO: 1024223152Stuexen if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) { 1025223132Stuexen free(cmsgbuf); 1026223132Stuexen errno = EINVAL; 1027223132Stuexen return (-1); 1028223132Stuexen } 1029223132Stuexen cmsg->cmsg_level = IPPROTO_SCTP; 1030223132Stuexen cmsg->cmsg_type = SCTP_SNDINFO; 1031223132Stuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); 1032223132Stuexen memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo)); 1033223132Stuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); 1034223132Stuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); 1035294910Stuexen assoc_id = &(((struct sctp_sndinfo *)info)->snd_assoc_id); 1036223132Stuexen break; 1037223132Stuexen case SCTP_SENDV_PRINFO: 1038223152Stuexen if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) { 1039223132Stuexen free(cmsgbuf); 1040223132Stuexen errno = EINVAL; 1041223132Stuexen return (-1); 1042223132Stuexen } 1043223132Stuexen cmsg->cmsg_level = IPPROTO_SCTP; 1044223132Stuexen cmsg->cmsg_type = SCTP_PRINFO; 1045223132Stuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); 1046223132Stuexen memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo)); 1047223132Stuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); 1048223132Stuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo))); 1049223132Stuexen break; 1050223132Stuexen case SCTP_SENDV_AUTHINFO: 1051223152Stuexen if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) { 1052223132Stuexen free(cmsgbuf); 1053223132Stuexen errno = EINVAL; 1054223132Stuexen return (-1); 1055223132Stuexen } 1056223132Stuexen cmsg->cmsg_level = IPPROTO_SCTP; 1057223132Stuexen cmsg->cmsg_type = SCTP_AUTHINFO; 1058223132Stuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo)); 1059223132Stuexen memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo)); 1060223132Stuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo)); 1061223132Stuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo))); 1062223132Stuexen break; 1063223132Stuexen case SCTP_SENDV_SPA: 1064223152Stuexen if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) { 1065223132Stuexen free(cmsgbuf); 1066223132Stuexen errno = EINVAL; 1067223132Stuexen return (-1); 1068223132Stuexen } 1069223132Stuexen spa_info = (struct sctp_sendv_spa *)info; 1070223132Stuexen if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) { 1071223132Stuexen cmsg->cmsg_level = IPPROTO_SCTP; 1072223132Stuexen cmsg->cmsg_type = SCTP_SNDINFO; 1073223132Stuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); 1074223132Stuexen memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo)); 1075223132Stuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); 1076223132Stuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); 1077294910Stuexen assoc_id = &(spa_info->sendv_sndinfo.snd_assoc_id); 1078223132Stuexen } 1079223132Stuexen if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) { 1080223132Stuexen cmsg->cmsg_level = IPPROTO_SCTP; 1081223132Stuexen cmsg->cmsg_type = SCTP_PRINFO; 1082223132Stuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); 1083223132Stuexen memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo)); 1084223132Stuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); 1085223132Stuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo))); 1086223132Stuexen } 1087223132Stuexen if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) { 1088223132Stuexen cmsg->cmsg_level = IPPROTO_SCTP; 1089223132Stuexen cmsg->cmsg_type = SCTP_AUTHINFO; 1090223132Stuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo)); 1091223132Stuexen memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo)); 1092223132Stuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo)); 1093223132Stuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo))); 1094223132Stuexen } 1095223132Stuexen break; 1096223132Stuexen default: 1097223132Stuexen free(cmsgbuf); 1098223132Stuexen errno = EINVAL; 1099223132Stuexen return (-1); 1100223132Stuexen } 1101223132Stuexen addr = addrs; 1102223152Stuexen msg.msg_name = NULL; 1103223152Stuexen msg.msg_namelen = 0; 1104223152Stuexen 1105223152Stuexen for (i = 0; i < addrcnt; i++) { 1106223132Stuexen switch (addr->sa_family) { 1107223132Stuexen case AF_INET: 1108223152Stuexen addr_len = (socklen_t) sizeof(struct sockaddr_in); 1109223152Stuexen addr_in = (struct sockaddr_in *)addr; 1110223152Stuexen if (addr_in->sin_len != addr_len) { 1111223152Stuexen free(cmsgbuf); 1112223152Stuexen errno = EINVAL; 1113223152Stuexen return (-1); 1114223152Stuexen } 1115223152Stuexen if (i == 0) { 1116223152Stuexen port = addr_in->sin_port; 1117223152Stuexen } else { 1118223152Stuexen if (port == addr_in->sin_port) { 1119223152Stuexen cmsg->cmsg_level = IPPROTO_SCTP; 1120223152Stuexen cmsg->cmsg_type = SCTP_DSTADDRV4; 1121223152Stuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); 1122223152Stuexen memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr)); 1123223152Stuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr)); 1124223152Stuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr))); 1125223152Stuexen } else { 1126223152Stuexen free(cmsgbuf); 1127223152Stuexen errno = EINVAL; 1128223152Stuexen return (-1); 1129223152Stuexen } 1130223152Stuexen } 1131223132Stuexen break; 1132223132Stuexen case AF_INET6: 1133223152Stuexen addr_len = (socklen_t) sizeof(struct sockaddr_in6); 1134223152Stuexen addr_in6 = (struct sockaddr_in6 *)addr; 1135223152Stuexen if (addr_in6->sin6_len != addr_len) { 1136223152Stuexen free(cmsgbuf); 1137223152Stuexen errno = EINVAL; 1138223152Stuexen return (-1); 1139223152Stuexen } 1140223152Stuexen if (i == 0) { 1141223152Stuexen port = addr_in6->sin6_port; 1142223152Stuexen } else { 1143223152Stuexen if (port == addr_in6->sin6_port) { 1144223152Stuexen cmsg->cmsg_level = IPPROTO_SCTP; 1145223152Stuexen cmsg->cmsg_type = SCTP_DSTADDRV6; 1146223152Stuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr)); 1147223152Stuexen memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr)); 1148223152Stuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr)); 1149223152Stuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr))); 1150223152Stuexen } else { 1151223152Stuexen free(cmsgbuf); 1152223152Stuexen errno = EINVAL; 1153223152Stuexen return (-1); 1154223152Stuexen } 1155223152Stuexen } 1156223132Stuexen break; 1157223132Stuexen default: 1158223132Stuexen free(cmsgbuf); 1159223132Stuexen errno = EINVAL; 1160223132Stuexen return (-1); 1161223132Stuexen } 1162223152Stuexen if (i == 0) { 1163223152Stuexen msg.msg_name = addr; 1164223152Stuexen msg.msg_namelen = addr_len; 1165223132Stuexen } 1166223152Stuexen addr = (struct sockaddr *)((caddr_t)addr + addr_len); 1167165242Srrs } 1168223132Stuexen if (msg.msg_controllen == 0) { 1169223132Stuexen msg.msg_control = NULL; 1170223132Stuexen } 1171223132Stuexen msg.msg_iov = (struct iovec *)iov; 1172223132Stuexen msg.msg_iovlen = iovcnt; 1173223132Stuexen msg.msg_flags = 0; 1174223132Stuexen ret = sendmsg(sd, &msg, flags); 1175223132Stuexen free(cmsgbuf); 1176294910Stuexen if ((ret >= 0) && (addrs != NULL) && (assoc_id != NULL)) { 1177294910Stuexen *assoc_id = sctp_getassocid(sd, addrs); 1178294910Stuexen } 1179223132Stuexen return (ret); 1180165242Srrs} 1181165242Srrs 1182165242Srrs 1183165242Srrs#if !defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT) 1184165242Srrs 1185165242Srrsint 1186165242Srrssctp_peeloff(int sd, sctp_assoc_t assoc_id) 1187165242Srrs{ 1188165242Srrs /* NOT supported, return invalid sd */ 1189165242Srrs errno = ENOTSUP; 1190165242Srrs return (-1); 1191165242Srrs} 1192165242Srrs 1193165242Srrs#endif 1194165242Srrs#if defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT) 1195165242Srrsint 1196165242Srrssctp_peeloff(int sd, sctp_assoc_t assoc_id) 1197165242Srrs{ 1198165242Srrs return (syscall(SYS_sctp_peeloff, sd, assoc_id)); 1199165242Srrs} 1200165242Srrs 1201165242Srrs#endif 1202166884Srrs 1203166885Srrs#undef SCTP_CONTROL_VEC_SIZE_RCV 1204