148f65f00SMichael Tuexen /*- 248f65f00SMichael Tuexen * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 343dc9e2fSMichael Tuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. 443dc9e2fSMichael Tuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. 5d6dda9b2SRandall Stewart * 6d6dda9b2SRandall Stewart * Redistribution and use in source and binary forms, with or without 748f65f00SMichael Tuexen * modification, are permitted provided that the following conditions are met: 8d6dda9b2SRandall Stewart * 948f65f00SMichael Tuexen * a) Redistributions of source code must retain the above copyright notice, 1048f65f00SMichael Tuexen * this list of conditions and the following disclaimer. 1148f65f00SMichael Tuexen * 1248f65f00SMichael Tuexen * b) Redistributions in binary form must reproduce the above copyright 1348f65f00SMichael Tuexen * notice, this list of conditions and the following disclaimer in 1448f65f00SMichael Tuexen * the documentation and/or other materials provided with the distribution. 1548f65f00SMichael Tuexen * 1648f65f00SMichael Tuexen * c) Neither the name of Cisco Systems, Inc. nor the names of its 1748f65f00SMichael Tuexen * contributors may be used to endorse or promote products derived 1848f65f00SMichael Tuexen * from this software without specific prior written permission. 1948f65f00SMichael Tuexen * 2048f65f00SMichael Tuexen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2148f65f00SMichael Tuexen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 2248f65f00SMichael Tuexen * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2348f65f00SMichael Tuexen * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 2448f65f00SMichael Tuexen * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2548f65f00SMichael Tuexen * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2648f65f00SMichael Tuexen * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2748f65f00SMichael Tuexen * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2848f65f00SMichael Tuexen * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2948f65f00SMichael Tuexen * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3048f65f00SMichael Tuexen * THE POSSIBILITY OF SUCH DAMAGE. 31d6dda9b2SRandall Stewart */ 3248f65f00SMichael Tuexen 33d6dda9b2SRandall Stewart #include <sys/cdefs.h> 34d6dda9b2SRandall Stewart __FBSDID("$FreeBSD$"); 3543dc9e2fSMichael Tuexen 36d6dda9b2SRandall Stewart #include <stdio.h> 37d6dda9b2SRandall Stewart #include <string.h> 38d6dda9b2SRandall Stewart #include <errno.h> 39d6dda9b2SRandall Stewart #include <stdlib.h> 40d6dda9b2SRandall Stewart #include <unistd.h> 41d6dda9b2SRandall Stewart #include <sys/types.h> 42d6dda9b2SRandall Stewart #include <sys/socket.h> 43d6dda9b2SRandall Stewart #include <sys/errno.h> 44d6dda9b2SRandall Stewart #include <sys/syscall.h> 45d6dda9b2SRandall Stewart #include <sys/uio.h> 46d6dda9b2SRandall Stewart #include <netinet/in.h> 47d6dda9b2SRandall Stewart #include <arpa/inet.h> 48d6dda9b2SRandall Stewart #include <netinet/sctp_uio.h> 49d6dda9b2SRandall Stewart #include <netinet/sctp.h> 50d6dda9b2SRandall Stewart 51d6dda9b2SRandall Stewart #ifndef IN6_IS_ADDR_V4MAPPED 52d6dda9b2SRandall Stewart #define IN6_IS_ADDR_V4MAPPED(a) \ 533d36ac98SRebecca Cran ((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \ 543d36ac98SRebecca Cran (*(const uint32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \ 553d36ac98SRebecca Cran (*(const uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) 56d6dda9b2SRandall Stewart #endif 57d6dda9b2SRandall Stewart 58d6dda9b2SRandall Stewart #define SCTP_CONTROL_VEC_SIZE_RCV 16384 59d6dda9b2SRandall Stewart 60d6dda9b2SRandall Stewart 61d6dda9b2SRandall Stewart static void 62d6dda9b2SRandall Stewart in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 63d6dda9b2SRandall Stewart { 64d6dda9b2SRandall Stewart bzero(sin, sizeof(*sin)); 65d6dda9b2SRandall Stewart sin->sin_len = sizeof(struct sockaddr_in); 66d6dda9b2SRandall Stewart sin->sin_family = AF_INET; 67d6dda9b2SRandall Stewart sin->sin_port = sin6->sin6_port; 68d6dda9b2SRandall Stewart sin->sin_addr.s_addr = sin6->sin6_addr.__u6_addr.__u6_addr32[3]; 69d6dda9b2SRandall Stewart } 70d6dda9b2SRandall Stewart 71d6dda9b2SRandall Stewart int 72d6dda9b2SRandall Stewart sctp_getaddrlen(sa_family_t family) 73d6dda9b2SRandall Stewart { 74e2e7c62eSMichael Tuexen int ret, sd; 75d6dda9b2SRandall Stewart socklen_t siz; 76d6dda9b2SRandall Stewart struct sctp_assoc_value av; 77d6dda9b2SRandall Stewart 78d6dda9b2SRandall Stewart av.assoc_value = family; 79d6dda9b2SRandall Stewart siz = sizeof(av); 80d6dda9b2SRandall Stewart #if defined(AF_INET) 81d6dda9b2SRandall Stewart sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 82d6dda9b2SRandall Stewart #elif defined(AF_INET6) 83d6dda9b2SRandall Stewart sd = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP); 84e2e7c62eSMichael Tuexen #else 85e2e7c62eSMichael Tuexen sd = -1; 86d6dda9b2SRandall Stewart #endif 87d6dda9b2SRandall Stewart if (sd == -1) { 88a593094eSRandall Stewart return (-1); 89d6dda9b2SRandall Stewart } 90e2e7c62eSMichael Tuexen ret = getsockopt(sd, IPPROTO_SCTP, SCTP_GET_ADDR_LEN, &av, &siz); 91d6dda9b2SRandall Stewart close(sd); 92e2e7c62eSMichael Tuexen if (ret == 0) { 93d6dda9b2SRandall Stewart return ((int)av.assoc_value); 94d6dda9b2SRandall Stewart } else { 95a593094eSRandall Stewart return (-1); 96d6dda9b2SRandall Stewart } 97d6dda9b2SRandall Stewart } 98d6dda9b2SRandall Stewart 99d6dda9b2SRandall Stewart int 1002c356be2SRandall Stewart sctp_connectx(int sd, const struct sockaddr *addrs, int addrcnt, 1012c356be2SRandall Stewart sctp_assoc_t * id) 102d6dda9b2SRandall Stewart { 1037f15a8dfSMichael Tuexen char *buf; 104d6dda9b2SRandall Stewart int i, ret, cnt, *aa; 105d6dda9b2SRandall Stewart char *cpto; 106d6dda9b2SRandall Stewart const struct sockaddr *at; 1072c356be2SRandall Stewart size_t len = sizeof(int); 108d6dda9b2SRandall Stewart 1092c356be2SRandall Stewart /* validate the address count and list */ 1102c356be2SRandall Stewart if ((addrs == NULL) || (addrcnt <= 0)) { 1112c356be2SRandall Stewart errno = EINVAL; 1122c356be2SRandall Stewart return (-1); 1132c356be2SRandall Stewart } 1147f15a8dfSMichael Tuexen if ((buf = malloc(sizeof(int) + (size_t)addrcnt * sizeof(struct sockaddr_in6))) == NULL) { 1157f15a8dfSMichael Tuexen errno = E2BIG; 1167f15a8dfSMichael Tuexen return (-1); 1177f15a8dfSMichael Tuexen } 118d6dda9b2SRandall Stewart at = addrs; 119d6dda9b2SRandall Stewart cnt = 0; 1207f15a8dfSMichael Tuexen cpto = buf + sizeof(int); 121d6dda9b2SRandall Stewart /* validate all the addresses and get the size */ 122d6dda9b2SRandall Stewart for (i = 0; i < addrcnt; i++) { 12393409822SMichael Tuexen switch (at->sa_family) { 12493409822SMichael Tuexen case AF_INET: 12525d63f19SRandall Stewart if (at->sa_len != sizeof(struct sockaddr_in)) { 1267f15a8dfSMichael Tuexen free(buf); 12725d63f19SRandall Stewart errno = EINVAL; 12825d63f19SRandall Stewart return (-1); 12925d63f19SRandall Stewart } 13093409822SMichael Tuexen memcpy(cpto, at, sizeof(struct sockaddr_in)); 13193409822SMichael Tuexen cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in)); 13293409822SMichael Tuexen len += sizeof(struct sockaddr_in); 13393409822SMichael Tuexen break; 13493409822SMichael Tuexen case AF_INET6: 13525d63f19SRandall Stewart if (at->sa_len != sizeof(struct sockaddr_in6)) { 1367f15a8dfSMichael Tuexen free(buf); 13725d63f19SRandall Stewart errno = EINVAL; 13825d63f19SRandall Stewart return (-1); 13925d63f19SRandall Stewart } 140d6dda9b2SRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)at)->sin6_addr)) { 141d6dda9b2SRandall Stewart in6_sin6_2_sin((struct sockaddr_in *)cpto, (struct sockaddr_in6 *)at); 142d6dda9b2SRandall Stewart cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in)); 143d6dda9b2SRandall Stewart len += sizeof(struct sockaddr_in); 144d6dda9b2SRandall Stewart } else { 14593409822SMichael Tuexen memcpy(cpto, at, sizeof(struct sockaddr_in6)); 14693409822SMichael Tuexen cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in6)); 14793409822SMichael Tuexen len += sizeof(struct sockaddr_in6); 148d6dda9b2SRandall Stewart } 14993409822SMichael Tuexen break; 15093409822SMichael Tuexen default: 1517f15a8dfSMichael Tuexen free(buf); 152d6dda9b2SRandall Stewart errno = EINVAL; 153d6dda9b2SRandall Stewart return (-1); 154d6dda9b2SRandall Stewart } 1557f15a8dfSMichael Tuexen at = (struct sockaddr *)((caddr_t)at + at->sa_len); 156d6dda9b2SRandall Stewart } 157d6dda9b2SRandall Stewart aa = (int *)buf; 1587f15a8dfSMichael Tuexen *aa = addrcnt; 159d6dda9b2SRandall Stewart ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X, (void *)buf, 160d6dda9b2SRandall Stewart (socklen_t) len); 1617f15a8dfSMichael Tuexen if ((ret == 0) && (id != NULL)) { 1627f15a8dfSMichael Tuexen *id = *(sctp_assoc_t *) buf; 16342551e99SRandall Stewart } 164d6dda9b2SRandall Stewart return (ret); 165d6dda9b2SRandall Stewart } 166d6dda9b2SRandall Stewart 167d6dda9b2SRandall Stewart int 168d6dda9b2SRandall Stewart sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags) 169d6dda9b2SRandall Stewart { 170d6dda9b2SRandall Stewart struct sctp_getaddresses *gaddrs; 171d6dda9b2SRandall Stewart struct sockaddr *sa; 1721b649582SRandall Stewart struct sockaddr_in *sin; 1731b649582SRandall Stewart struct sockaddr_in6 *sin6; 1745dc6a815SMichael Tuexen int i; 1755dc6a815SMichael Tuexen size_t argsz; 1761b649582SRandall Stewart uint16_t sport = 0; 177d6dda9b2SRandall Stewart 1782c356be2SRandall Stewart /* validate the flags */ 179d6dda9b2SRandall Stewart if ((flags != SCTP_BINDX_ADD_ADDR) && 180d6dda9b2SRandall Stewart (flags != SCTP_BINDX_REM_ADDR)) { 181d6dda9b2SRandall Stewart errno = EFAULT; 182d6dda9b2SRandall Stewart return (-1); 183d6dda9b2SRandall Stewart } 1842c356be2SRandall Stewart /* validate the address count and list */ 1852c356be2SRandall Stewart if ((addrcnt <= 0) || (addrs == NULL)) { 1862c356be2SRandall Stewart errno = EINVAL; 1872c356be2SRandall Stewart return (-1); 1882c356be2SRandall Stewart } 1891b649582SRandall Stewart /* First pre-screen the addresses */ 190d6dda9b2SRandall Stewart sa = addrs; 191d6dda9b2SRandall Stewart for (i = 0; i < addrcnt; i++) { 19293409822SMichael Tuexen switch (sa->sa_family) { 19393409822SMichael Tuexen case AF_INET: 19493409822SMichael Tuexen if (sa->sa_len != sizeof(struct sockaddr_in)) { 19593409822SMichael Tuexen errno = EINVAL; 19693409822SMichael Tuexen return (-1); 19793409822SMichael Tuexen } 1981b649582SRandall Stewart sin = (struct sockaddr_in *)sa; 1991b649582SRandall Stewart if (sin->sin_port) { 2001b649582SRandall Stewart /* non-zero port, check or save */ 2011b649582SRandall Stewart if (sport) { 2021b649582SRandall Stewart /* Check against our port */ 2031b649582SRandall Stewart if (sport != sin->sin_port) { 20493409822SMichael Tuexen errno = EINVAL; 20593409822SMichael Tuexen return (-1); 2061b649582SRandall Stewart } 2071b649582SRandall Stewart } else { 2081b649582SRandall Stewart /* save off the port */ 2091b649582SRandall Stewart sport = sin->sin_port; 2101b649582SRandall Stewart } 2111b649582SRandall Stewart } 21293409822SMichael Tuexen break; 21393409822SMichael Tuexen case AF_INET6: 21493409822SMichael Tuexen if (sa->sa_len != sizeof(struct sockaddr_in6)) { 21593409822SMichael Tuexen errno = EINVAL; 21693409822SMichael Tuexen return (-1); 21793409822SMichael Tuexen } 2181b649582SRandall Stewart sin6 = (struct sockaddr_in6 *)sa; 2191b649582SRandall Stewart if (sin6->sin6_port) { 2201b649582SRandall Stewart /* non-zero port, check or save */ 2211b649582SRandall Stewart if (sport) { 2221b649582SRandall Stewart /* Check against our port */ 2231b649582SRandall Stewart if (sport != sin6->sin6_port) { 22493409822SMichael Tuexen errno = EINVAL; 22593409822SMichael Tuexen return (-1); 2261b649582SRandall Stewart } 2271b649582SRandall Stewart } else { 2281b649582SRandall Stewart /* save off the port */ 2291b649582SRandall Stewart sport = sin6->sin6_port; 2301b649582SRandall Stewart } 2311b649582SRandall Stewart } 23293409822SMichael Tuexen break; 23393409822SMichael Tuexen default: 23493409822SMichael Tuexen /* Invalid address family specified. */ 23593409822SMichael Tuexen errno = EINVAL; 23693409822SMichael Tuexen return (-1); 2371b649582SRandall Stewart } 2385dc6a815SMichael Tuexen sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 2391b649582SRandall Stewart } 2401b649582SRandall Stewart /* 2411b649582SRandall Stewart * Now if there was a port mentioned, assure that the first address 2421b649582SRandall Stewart * has that port to make sure it fails or succeeds correctly. 2431b649582SRandall Stewart */ 2441b649582SRandall Stewart if (sport) { 2451b649582SRandall Stewart sin = (struct sockaddr_in *)sa; 2461b649582SRandall Stewart sin->sin_port = sport; 2471b649582SRandall Stewart } 24893409822SMichael Tuexen argsz = sizeof(struct sctp_getaddresses) + 24993409822SMichael Tuexen sizeof(struct sockaddr_storage); 25093409822SMichael Tuexen if ((gaddrs = (struct sctp_getaddresses *)malloc(argsz)) == NULL) { 25193409822SMichael Tuexen errno = ENOMEM; 252d6dda9b2SRandall Stewart return (-1); 253d6dda9b2SRandall Stewart } 25493409822SMichael Tuexen sa = addrs; 25593409822SMichael Tuexen for (i = 0; i < addrcnt; i++) { 25625d63f19SRandall Stewart memset(gaddrs, 0, argsz); 25725d63f19SRandall Stewart gaddrs->sget_assoc_id = 0; 2585dc6a815SMichael Tuexen memcpy(gaddrs->addr, sa, sa->sa_len); 25925d63f19SRandall Stewart if (setsockopt(sd, IPPROTO_SCTP, flags, gaddrs, 26025d63f19SRandall Stewart (socklen_t) argsz) != 0) { 261d6dda9b2SRandall Stewart free(gaddrs); 262d6dda9b2SRandall Stewart return (-1); 263d6dda9b2SRandall Stewart } 2645dc6a815SMichael Tuexen sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 265d6dda9b2SRandall Stewart } 266d6dda9b2SRandall Stewart free(gaddrs); 267d6dda9b2SRandall Stewart return (0); 268d6dda9b2SRandall Stewart } 269d6dda9b2SRandall Stewart 270d6dda9b2SRandall Stewart int 271d6dda9b2SRandall Stewart sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t * size) 272d6dda9b2SRandall Stewart { 273d6dda9b2SRandall Stewart if (arg == NULL) { 274602afc03SRandall Stewart errno = EINVAL; 275602afc03SRandall Stewart return (-1); 276d6dda9b2SRandall Stewart } 277*b71f5853SMichael Tuexen if ((id == SCTP_CURRENT_ASSOC) || 278*b71f5853SMichael Tuexen (id == SCTP_ALL_ASSOC)) { 279*b71f5853SMichael Tuexen errno = EINVAL; 280*b71f5853SMichael Tuexen return (-1); 281*b71f5853SMichael Tuexen } 2821b649582SRandall Stewart switch (opt) { 2831b649582SRandall Stewart case SCTP_RTOINFO: 2841b649582SRandall Stewart ((struct sctp_rtoinfo *)arg)->srto_assoc_id = id; 2851b649582SRandall Stewart break; 2861b649582SRandall Stewart case SCTP_ASSOCINFO: 2871b649582SRandall Stewart ((struct sctp_assocparams *)arg)->sasoc_assoc_id = id; 2881b649582SRandall Stewart break; 2891b649582SRandall Stewart case SCTP_DEFAULT_SEND_PARAM: 2901b649582SRandall Stewart ((struct sctp_assocparams *)arg)->sasoc_assoc_id = id; 2911b649582SRandall Stewart break; 2921b649582SRandall Stewart case SCTP_PRIMARY_ADDR: 2931b649582SRandall Stewart ((struct sctp_setprim *)arg)->ssp_assoc_id = id; 2941b649582SRandall Stewart break; 2951b649582SRandall Stewart case SCTP_PEER_ADDR_PARAMS: 2961b649582SRandall Stewart ((struct sctp_paddrparams *)arg)->spp_assoc_id = id; 2971b649582SRandall Stewart break; 2981b649582SRandall Stewart case SCTP_MAXSEG: 2991b649582SRandall Stewart ((struct sctp_assoc_value *)arg)->assoc_id = id; 3001b649582SRandall Stewart break; 3011b649582SRandall Stewart case SCTP_AUTH_KEY: 3021b649582SRandall Stewart ((struct sctp_authkey *)arg)->sca_assoc_id = id; 3031b649582SRandall Stewart break; 3041b649582SRandall Stewart case SCTP_AUTH_ACTIVE_KEY: 3051b649582SRandall Stewart ((struct sctp_authkeyid *)arg)->scact_assoc_id = id; 3061b649582SRandall Stewart break; 3071b649582SRandall Stewart case SCTP_DELAYED_SACK: 3081b649582SRandall Stewart ((struct sctp_sack_info *)arg)->sack_assoc_id = id; 3091b649582SRandall Stewart break; 3101b649582SRandall Stewart case SCTP_CONTEXT: 3111b649582SRandall Stewart ((struct sctp_assoc_value *)arg)->assoc_id = id; 3121b649582SRandall Stewart break; 3131b649582SRandall Stewart case SCTP_STATUS: 3141b649582SRandall Stewart ((struct sctp_status *)arg)->sstat_assoc_id = id; 3151b649582SRandall Stewart break; 3161b649582SRandall Stewart case SCTP_GET_PEER_ADDR_INFO: 3171b649582SRandall Stewart ((struct sctp_paddrinfo *)arg)->spinfo_assoc_id = id; 3181b649582SRandall Stewart break; 3191b649582SRandall Stewart case SCTP_PEER_AUTH_CHUNKS: 3201b649582SRandall Stewart ((struct sctp_authchunks *)arg)->gauth_assoc_id = id; 3211b649582SRandall Stewart break; 3221b649582SRandall Stewart case SCTP_LOCAL_AUTH_CHUNKS: 3231b649582SRandall Stewart ((struct sctp_authchunks *)arg)->gauth_assoc_id = id; 3241b649582SRandall Stewart break; 32548f65f00SMichael Tuexen case SCTP_TIMEOUTS: 32648f65f00SMichael Tuexen ((struct sctp_timeouts *)arg)->stimo_assoc_id = id; 32748f65f00SMichael Tuexen break; 328e2e7c62eSMichael Tuexen case SCTP_EVENT: 329e2e7c62eSMichael Tuexen ((struct sctp_event *)arg)->se_assoc_id = id; 330e2e7c62eSMichael Tuexen break; 33113aae0bfSMichael Tuexen case SCTP_DEFAULT_SNDINFO: 33213aae0bfSMichael Tuexen ((struct sctp_sndinfo *)arg)->snd_assoc_id = id; 33313aae0bfSMichael Tuexen break; 33413aae0bfSMichael Tuexen case SCTP_DEFAULT_PRINFO: 33513aae0bfSMichael Tuexen ((struct sctp_default_prinfo *)arg)->pr_assoc_id = id; 33613aae0bfSMichael Tuexen break; 337ca85e948SMichael Tuexen case SCTP_PEER_ADDR_THLDS: 338ca85e948SMichael Tuexen ((struct sctp_paddrthlds *)arg)->spt_assoc_id = id; 339ca85e948SMichael Tuexen break; 340c9c58059SMichael Tuexen case SCTP_REMOTE_UDP_ENCAPS_PORT: 341c9c58059SMichael Tuexen ((struct sctp_udpencaps *)arg)->sue_assoc_id = id; 342c9c58059SMichael Tuexen break; 343bb2c20c1SMichael Tuexen case SCTP_MAX_BURST: 344bb2c20c1SMichael Tuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 345bb2c20c1SMichael Tuexen break; 3467c9b6492SMichael Tuexen case SCTP_ENABLE_STREAM_RESET: 3477c9b6492SMichael Tuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 3487c9b6492SMichael Tuexen break; 3491b649582SRandall Stewart default: 3501b649582SRandall Stewart break; 3511b649582SRandall Stewart } 352d6dda9b2SRandall Stewart return (getsockopt(sd, IPPROTO_SCTP, opt, arg, size)); 353d6dda9b2SRandall Stewart } 354d6dda9b2SRandall Stewart 355d6dda9b2SRandall Stewart int 356d6dda9b2SRandall Stewart sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs) 357d6dda9b2SRandall Stewart { 358d6dda9b2SRandall Stewart struct sctp_getaddresses *addrs; 359d6dda9b2SRandall Stewart struct sockaddr *sa; 360d6dda9b2SRandall Stewart sctp_assoc_t asoc; 361d6dda9b2SRandall Stewart caddr_t lim; 3625dc6a815SMichael Tuexen socklen_t opt_len; 363d6dda9b2SRandall Stewart int cnt; 364d6dda9b2SRandall Stewart 365d6dda9b2SRandall Stewart if (raddrs == NULL) { 366d6dda9b2SRandall Stewart errno = EFAULT; 367d6dda9b2SRandall Stewart return (-1); 368d6dda9b2SRandall Stewart } 369d6dda9b2SRandall Stewart asoc = id; 3705dc6a815SMichael Tuexen opt_len = (socklen_t) sizeof(sctp_assoc_t); 371d6dda9b2SRandall Stewart if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE, 3725dc6a815SMichael Tuexen &asoc, &opt_len) != 0) { 373d6dda9b2SRandall Stewart return (-1); 374d6dda9b2SRandall Stewart } 375d6dda9b2SRandall Stewart /* size required is returned in 'asoc' */ 3765dc6a815SMichael Tuexen opt_len = (socklen_t) ((size_t)asoc + sizeof(struct sctp_getaddresses)); 3775dc6a815SMichael Tuexen addrs = calloc(1, (size_t)opt_len); 378d6dda9b2SRandall Stewart if (addrs == NULL) { 3794ed0ebf6SMichael Tuexen errno = ENOMEM; 380d6dda9b2SRandall Stewart return (-1); 381d6dda9b2SRandall Stewart } 382d6dda9b2SRandall Stewart addrs->sget_assoc_id = id; 383d6dda9b2SRandall Stewart /* Now lets get the array of addresses */ 384d6dda9b2SRandall Stewart if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES, 3855dc6a815SMichael Tuexen addrs, &opt_len) != 0) { 386d6dda9b2SRandall Stewart free(addrs); 387d6dda9b2SRandall Stewart return (-1); 388d6dda9b2SRandall Stewart } 3895dc6a815SMichael Tuexen *raddrs = (struct sockaddr *)&addrs->addr[0]; 390d6dda9b2SRandall Stewart cnt = 0; 391d6dda9b2SRandall Stewart sa = (struct sockaddr *)&addrs->addr[0]; 3925dc6a815SMichael Tuexen lim = (caddr_t)addrs + opt_len; 393d6dda9b2SRandall Stewart while (((caddr_t)sa < lim) && (sa->sa_len > 0)) { 394d6dda9b2SRandall Stewart sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 395d6dda9b2SRandall Stewart cnt++; 396d6dda9b2SRandall Stewart } 397d6dda9b2SRandall Stewart return (cnt); 398d6dda9b2SRandall Stewart } 399d6dda9b2SRandall Stewart 400d6dda9b2SRandall Stewart void 401d6dda9b2SRandall Stewart sctp_freepaddrs(struct sockaddr *addrs) 402d6dda9b2SRandall Stewart { 403d6dda9b2SRandall Stewart void *fr_addr; 404d6dda9b2SRandall Stewart 4057f15a8dfSMichael Tuexen /* Take away the hidden association id */ 406d6dda9b2SRandall Stewart fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t)); 407d6dda9b2SRandall Stewart /* Now free it */ 408d6dda9b2SRandall Stewart free(fr_addr); 409d6dda9b2SRandall Stewart } 410d6dda9b2SRandall Stewart 411d6dda9b2SRandall Stewart int 412d6dda9b2SRandall Stewart sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs) 413d6dda9b2SRandall Stewart { 414d6dda9b2SRandall Stewart struct sctp_getaddresses *addrs; 415d6dda9b2SRandall Stewart caddr_t lim; 416d6dda9b2SRandall Stewart struct sockaddr *sa; 4175dc6a815SMichael Tuexen size_t size_of_addresses; 4185dc6a815SMichael Tuexen socklen_t opt_len; 419d6dda9b2SRandall Stewart int cnt; 420d6dda9b2SRandall Stewart 421d6dda9b2SRandall Stewart if (raddrs == NULL) { 422d6dda9b2SRandall Stewart errno = EFAULT; 423d6dda9b2SRandall Stewart return (-1); 424d6dda9b2SRandall Stewart } 425d6dda9b2SRandall Stewart size_of_addresses = 0; 4265dc6a815SMichael Tuexen opt_len = (socklen_t) sizeof(int); 427d6dda9b2SRandall Stewart if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE, 4285dc6a815SMichael Tuexen &size_of_addresses, &opt_len) != 0) { 429d6dda9b2SRandall Stewart errno = ENOMEM; 430d6dda9b2SRandall Stewart return (-1); 431d6dda9b2SRandall Stewart } 432d6dda9b2SRandall Stewart if (size_of_addresses == 0) { 433d6dda9b2SRandall Stewart errno = ENOTCONN; 434d6dda9b2SRandall Stewart return (-1); 435d6dda9b2SRandall Stewart } 4365dc6a815SMichael Tuexen opt_len = (socklen_t) (size_of_addresses + 4375dc6a815SMichael Tuexen sizeof(struct sockaddr_storage) + 4385dc6a815SMichael Tuexen sizeof(struct sctp_getaddresses)); 4395dc6a815SMichael Tuexen addrs = calloc(1, (size_t)opt_len); 440d6dda9b2SRandall Stewart if (addrs == NULL) { 441d6dda9b2SRandall Stewart errno = ENOMEM; 442d6dda9b2SRandall Stewart return (-1); 443d6dda9b2SRandall Stewart } 444d6dda9b2SRandall Stewart addrs->sget_assoc_id = id; 445d6dda9b2SRandall Stewart /* Now lets get the array of addresses */ 446d6dda9b2SRandall Stewart if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs, 4475dc6a815SMichael Tuexen &opt_len) != 0) { 448d6dda9b2SRandall Stewart free(addrs); 449d6dda9b2SRandall Stewart errno = ENOMEM; 450d6dda9b2SRandall Stewart return (-1); 451d6dda9b2SRandall Stewart } 4525dc6a815SMichael Tuexen *raddrs = (struct sockaddr *)&addrs->addr[0]; 453d6dda9b2SRandall Stewart cnt = 0; 454d6dda9b2SRandall Stewart sa = (struct sockaddr *)&addrs->addr[0]; 4555dc6a815SMichael Tuexen lim = (caddr_t)addrs + opt_len; 456d6dda9b2SRandall Stewart while (((caddr_t)sa < lim) && (sa->sa_len > 0)) { 457d6dda9b2SRandall Stewart sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 458d6dda9b2SRandall Stewart cnt++; 459d6dda9b2SRandall Stewart } 460d6dda9b2SRandall Stewart return (cnt); 461d6dda9b2SRandall Stewart } 462d6dda9b2SRandall Stewart 463d6dda9b2SRandall Stewart void 464d6dda9b2SRandall Stewart sctp_freeladdrs(struct sockaddr *addrs) 465d6dda9b2SRandall Stewart { 466d6dda9b2SRandall Stewart void *fr_addr; 467d6dda9b2SRandall Stewart 4687f15a8dfSMichael Tuexen /* Take away the hidden association id */ 469d6dda9b2SRandall Stewart fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t)); 470d6dda9b2SRandall Stewart /* Now free it */ 471d6dda9b2SRandall Stewart free(fr_addr); 472d6dda9b2SRandall Stewart } 473d6dda9b2SRandall Stewart 474d6dda9b2SRandall Stewart ssize_t 475d6dda9b2SRandall Stewart sctp_sendmsg(int s, 476d6dda9b2SRandall Stewart const void *data, 477d6dda9b2SRandall Stewart size_t len, 478d6dda9b2SRandall Stewart const struct sockaddr *to, 479002b1f0bSRandall Stewart socklen_t tolen, 4803d36ac98SRebecca Cran uint32_t ppid, 4813d36ac98SRebecca Cran uint32_t flags, 4823d36ac98SRebecca Cran uint16_t stream_no, 4833d36ac98SRebecca Cran uint32_t timetolive, 4843d36ac98SRebecca Cran uint32_t context) 485d6dda9b2SRandall Stewart { 486d6dda9b2SRandall Stewart #ifdef SYS_sctp_generic_sendmsg 487d6dda9b2SRandall Stewart struct sctp_sndrcvinfo sinfo; 488d6dda9b2SRandall Stewart 489539bb45aSMichael Tuexen memset(&sinfo, 0, sizeof(struct sctp_sndrcvinfo)); 490d6dda9b2SRandall Stewart sinfo.sinfo_ppid = ppid; 491d6dda9b2SRandall Stewart sinfo.sinfo_flags = flags; 492d6dda9b2SRandall Stewart sinfo.sinfo_stream = stream_no; 493d6dda9b2SRandall Stewart sinfo.sinfo_timetolive = timetolive; 494d6dda9b2SRandall Stewart sinfo.sinfo_context = context; 495d6dda9b2SRandall Stewart sinfo.sinfo_assoc_id = 0; 496d6dda9b2SRandall Stewart return (syscall(SYS_sctp_generic_sendmsg, s, 497d6dda9b2SRandall Stewart data, len, to, tolen, &sinfo, 0)); 498d6dda9b2SRandall Stewart #else 499d6dda9b2SRandall Stewart struct msghdr msg; 5007f15a8dfSMichael Tuexen struct sctp_sndrcvinfo *sinfo; 50148f65f00SMichael Tuexen struct iovec iov; 5027f15a8dfSMichael Tuexen char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; 503d6dda9b2SRandall Stewart struct cmsghdr *cmsg; 504d6dda9b2SRandall Stewart struct sockaddr *who = NULL; 505d6dda9b2SRandall Stewart union { 506d6dda9b2SRandall Stewart struct sockaddr_in in; 507d6dda9b2SRandall Stewart struct sockaddr_in6 in6; 508d6dda9b2SRandall Stewart } addr; 509d6dda9b2SRandall Stewart 51048f65f00SMichael Tuexen if ((tolen > 0) && 51148f65f00SMichael Tuexen ((to == NULL) || (tolen < sizeof(struct sockaddr)))) { 512002b1f0bSRandall Stewart errno = EINVAL; 5134224e03aSMichael Tuexen return (-1); 514002b1f0bSRandall Stewart } 5157f15a8dfSMichael Tuexen if ((to != NULL) && (tolen > 0)) { 5167f15a8dfSMichael Tuexen switch (to->sa_family) { 5177f15a8dfSMichael Tuexen case AF_INET: 518002b1f0bSRandall Stewart if (tolen != sizeof(struct sockaddr_in)) { 519002b1f0bSRandall Stewart errno = EINVAL; 5204224e03aSMichael Tuexen return (-1); 521002b1f0bSRandall Stewart } 52248f65f00SMichael Tuexen if ((to->sa_len > 0) && 52348f65f00SMichael Tuexen (to->sa_len != sizeof(struct sockaddr_in))) { 524002b1f0bSRandall Stewart errno = EINVAL; 5254224e03aSMichael Tuexen return (-1); 526002b1f0bSRandall Stewart } 527d6dda9b2SRandall Stewart memcpy(&addr, to, sizeof(struct sockaddr_in)); 528d6dda9b2SRandall Stewart addr.in.sin_len = sizeof(struct sockaddr_in); 5297f15a8dfSMichael Tuexen break; 5307f15a8dfSMichael Tuexen case AF_INET6: 531002b1f0bSRandall Stewart if (tolen != sizeof(struct sockaddr_in6)) { 532002b1f0bSRandall Stewart errno = EINVAL; 5334224e03aSMichael Tuexen return (-1); 534002b1f0bSRandall Stewart } 53548f65f00SMichael Tuexen if ((to->sa_len > 0) && 53648f65f00SMichael Tuexen (to->sa_len != sizeof(struct sockaddr_in6))) { 537002b1f0bSRandall Stewart errno = EINVAL; 5384224e03aSMichael Tuexen return (-1); 539002b1f0bSRandall Stewart } 540d6dda9b2SRandall Stewart memcpy(&addr, to, sizeof(struct sockaddr_in6)); 541d6dda9b2SRandall Stewart addr.in6.sin6_len = sizeof(struct sockaddr_in6); 5427f15a8dfSMichael Tuexen break; 5437f15a8dfSMichael Tuexen default: 544002b1f0bSRandall Stewart errno = EAFNOSUPPORT; 5454224e03aSMichael Tuexen return (-1); 546d6dda9b2SRandall Stewart } 547d6dda9b2SRandall Stewart who = (struct sockaddr *)&addr; 548d6dda9b2SRandall Stewart } 54948f65f00SMichael Tuexen iov.iov_base = (char *)data; 55048f65f00SMichael Tuexen iov.iov_len = len; 551d6dda9b2SRandall Stewart 552002b1f0bSRandall Stewart if (who) { 553d6dda9b2SRandall Stewart msg.msg_name = (caddr_t)who; 554d6dda9b2SRandall Stewart msg.msg_namelen = who->sa_len; 555d6dda9b2SRandall Stewart } else { 556d6dda9b2SRandall Stewart msg.msg_name = (caddr_t)NULL; 557d6dda9b2SRandall Stewart msg.msg_namelen = 0; 558d6dda9b2SRandall Stewart } 55948f65f00SMichael Tuexen msg.msg_iov = &iov; 560d6dda9b2SRandall Stewart msg.msg_iovlen = 1; 5617f15a8dfSMichael Tuexen msg.msg_control = cmsgbuf; 5627f15a8dfSMichael Tuexen msg.msg_controllen = CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); 5637f15a8dfSMichael Tuexen cmsg = (struct cmsghdr *)cmsgbuf; 564d6dda9b2SRandall Stewart cmsg->cmsg_level = IPPROTO_SCTP; 565d6dda9b2SRandall Stewart cmsg->cmsg_type = SCTP_SNDRCV; 566d6dda9b2SRandall Stewart cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 5677f15a8dfSMichael Tuexen sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); 5687f15a8dfSMichael Tuexen sinfo->sinfo_stream = stream_no; 5697f15a8dfSMichael Tuexen sinfo->sinfo_ssn = 0; 5707f15a8dfSMichael Tuexen sinfo->sinfo_flags = flags; 5717f15a8dfSMichael Tuexen sinfo->sinfo_ppid = ppid; 5727f15a8dfSMichael Tuexen sinfo->sinfo_context = context; 5737f15a8dfSMichael Tuexen sinfo->sinfo_assoc_id = 0; 5747f15a8dfSMichael Tuexen sinfo->sinfo_timetolive = timetolive; 5757f15a8dfSMichael Tuexen return (sendmsg(s, &msg, 0)); 576d6dda9b2SRandall Stewart #endif 577d6dda9b2SRandall Stewart } 578d6dda9b2SRandall Stewart 579d6dda9b2SRandall Stewart 580d6dda9b2SRandall Stewart sctp_assoc_t 581d6dda9b2SRandall Stewart sctp_getassocid(int sd, struct sockaddr *sa) 582d6dda9b2SRandall Stewart { 583b54d3a6cSRandall Stewart struct sctp_paddrinfo sp; 584066f54d8SCraig Rodrigues socklen_t siz; 585d6dda9b2SRandall Stewart 586d6dda9b2SRandall Stewart /* First get the assoc id */ 587b54d3a6cSRandall Stewart siz = sizeof(sp); 588d6dda9b2SRandall Stewart memset(&sp, 0, sizeof(sp)); 589b54d3a6cSRandall Stewart memcpy((caddr_t)&sp.spinfo_address, sa, sa->sa_len); 590d6dda9b2SRandall Stewart if (getsockopt(sd, IPPROTO_SCTP, 591b54d3a6cSRandall Stewart SCTP_GET_PEER_ADDR_INFO, &sp, &siz) != 0) { 5927f15a8dfSMichael Tuexen /* We depend on the fact that 0 can never be returned */ 593d6dda9b2SRandall Stewart return ((sctp_assoc_t) 0); 594d6dda9b2SRandall Stewart } 595b54d3a6cSRandall Stewart return (sp.spinfo_assoc_id); 596d6dda9b2SRandall Stewart } 597d6dda9b2SRandall Stewart 598d6dda9b2SRandall Stewart ssize_t 599d6dda9b2SRandall Stewart sctp_send(int sd, const void *data, size_t len, 600d6dda9b2SRandall Stewart const struct sctp_sndrcvinfo *sinfo, 601d6dda9b2SRandall Stewart int flags) 602d6dda9b2SRandall Stewart { 603d6dda9b2SRandall Stewart 604d6dda9b2SRandall Stewart #ifdef SYS_sctp_generic_sendmsg 605d6dda9b2SRandall Stewart struct sockaddr *to = NULL; 606d6dda9b2SRandall Stewart 607d6dda9b2SRandall Stewart return (syscall(SYS_sctp_generic_sendmsg, sd, 608d6dda9b2SRandall Stewart data, len, to, 0, sinfo, flags)); 609d6dda9b2SRandall Stewart #else 610d6dda9b2SRandall Stewart struct msghdr msg; 61148f65f00SMichael Tuexen struct iovec iov; 6127f15a8dfSMichael Tuexen char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; 613d6dda9b2SRandall Stewart struct cmsghdr *cmsg; 614d6dda9b2SRandall Stewart 615d6dda9b2SRandall Stewart if (sinfo == NULL) { 616b54d3a6cSRandall Stewart errno = EINVAL; 617b54d3a6cSRandall Stewart return (-1); 618d6dda9b2SRandall Stewart } 61948f65f00SMichael Tuexen iov.iov_base = (char *)data; 62048f65f00SMichael Tuexen iov.iov_len = len; 621d6dda9b2SRandall Stewart 6227f15a8dfSMichael Tuexen msg.msg_name = NULL; 623d6dda9b2SRandall Stewart msg.msg_namelen = 0; 62448f65f00SMichael Tuexen msg.msg_iov = &iov; 625d6dda9b2SRandall Stewart msg.msg_iovlen = 1; 6267f15a8dfSMichael Tuexen msg.msg_control = cmsgbuf; 6277f15a8dfSMichael Tuexen msg.msg_controllen = CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); 6287f15a8dfSMichael Tuexen cmsg = (struct cmsghdr *)cmsgbuf; 629d6dda9b2SRandall Stewart cmsg->cmsg_level = IPPROTO_SCTP; 630d6dda9b2SRandall Stewart cmsg->cmsg_type = SCTP_SNDRCV; 631d6dda9b2SRandall Stewart cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 6327f15a8dfSMichael Tuexen memcpy(CMSG_DATA(cmsg), sinfo, sizeof(struct sctp_sndrcvinfo)); 6337f15a8dfSMichael Tuexen return (sendmsg(sd, &msg, flags)); 634d6dda9b2SRandall Stewart #endif 635d6dda9b2SRandall Stewart } 636d6dda9b2SRandall Stewart 637d6dda9b2SRandall Stewart 638d6dda9b2SRandall Stewart 639d6dda9b2SRandall Stewart ssize_t 640d6dda9b2SRandall Stewart sctp_sendx(int sd, const void *msg, size_t msg_len, 641d6dda9b2SRandall Stewart struct sockaddr *addrs, int addrcnt, 642d6dda9b2SRandall Stewart struct sctp_sndrcvinfo *sinfo, 643d6dda9b2SRandall Stewart int flags) 644d6dda9b2SRandall Stewart { 645335a2d00SRandall Stewart struct sctp_sndrcvinfo __sinfo; 646d6dda9b2SRandall Stewart ssize_t ret; 647d6dda9b2SRandall Stewart int i, cnt, *aa, saved_errno; 648d6dda9b2SRandall Stewart char *buf; 6495dc6a815SMichael Tuexen int no_end_cx = 0; 6505dc6a815SMichael Tuexen size_t len, add_len; 651d6dda9b2SRandall Stewart struct sockaddr *at; 652d6dda9b2SRandall Stewart 6531b649582SRandall Stewart if (addrs == NULL) { 6541b649582SRandall Stewart errno = EINVAL; 6551b649582SRandall Stewart return (-1); 6561b649582SRandall Stewart } 657804cf641SRandall Stewart #ifdef SYS_sctp_generic_sendmsg 65848f65f00SMichael Tuexen if (addrcnt == 1) { 659804cf641SRandall Stewart socklen_t l; 660804cf641SRandall Stewart 661804cf641SRandall Stewart /* 662804cf641SRandall Stewart * Quick way, we don't need to do a connectx so lets use the 663804cf641SRandall Stewart * syscall directly. 664804cf641SRandall Stewart */ 665804cf641SRandall Stewart l = addrs->sa_len; 666804cf641SRandall Stewart return (syscall(SYS_sctp_generic_sendmsg, sd, 667804cf641SRandall Stewart msg, msg_len, addrs, l, sinfo, flags)); 668804cf641SRandall Stewart } 669804cf641SRandall Stewart #endif 670b54d3a6cSRandall Stewart 671d6dda9b2SRandall Stewart len = sizeof(int); 672d6dda9b2SRandall Stewart at = addrs; 673d6dda9b2SRandall Stewart cnt = 0; 674d6dda9b2SRandall Stewart /* validate all the addresses and get the size */ 675d6dda9b2SRandall Stewart for (i = 0; i < addrcnt; i++) { 676d6dda9b2SRandall Stewart if (at->sa_family == AF_INET) { 677d6dda9b2SRandall Stewart add_len = sizeof(struct sockaddr_in); 678d6dda9b2SRandall Stewart } else if (at->sa_family == AF_INET6) { 679d6dda9b2SRandall Stewart add_len = sizeof(struct sockaddr_in6); 680d6dda9b2SRandall Stewart } else { 681d6dda9b2SRandall Stewart errno = EINVAL; 682d6dda9b2SRandall Stewart return (-1); 683d6dda9b2SRandall Stewart } 684d6dda9b2SRandall Stewart len += add_len; 685d6dda9b2SRandall Stewart at = (struct sockaddr *)((caddr_t)at + add_len); 686d6dda9b2SRandall Stewart cnt++; 687d6dda9b2SRandall Stewart } 688d6dda9b2SRandall Stewart /* do we have any? */ 689d6dda9b2SRandall Stewart if (cnt == 0) { 690d6dda9b2SRandall Stewart errno = EINVAL; 691d6dda9b2SRandall Stewart return (-1); 692d6dda9b2SRandall Stewart } 693d6dda9b2SRandall Stewart buf = malloc(len); 694d6dda9b2SRandall Stewart if (buf == NULL) { 6954ed0ebf6SMichael Tuexen errno = ENOMEM; 696b54d3a6cSRandall Stewart return (-1); 697d6dda9b2SRandall Stewart } 698d6dda9b2SRandall Stewart aa = (int *)buf; 699d6dda9b2SRandall Stewart *aa = cnt; 700d6dda9b2SRandall Stewart aa++; 7015dc6a815SMichael Tuexen memcpy((caddr_t)aa, addrs, (size_t)(len - sizeof(int))); 702d6dda9b2SRandall Stewart ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_DELAYED, (void *)buf, 703d6dda9b2SRandall Stewart (socklen_t) len); 704d6dda9b2SRandall Stewart 705d6dda9b2SRandall Stewart free(buf); 706d6dda9b2SRandall Stewart if (ret != 0) { 707d6dda9b2SRandall Stewart if (errno == EALREADY) { 708ecf4b67aSRebecca Cran no_end_cx = 1; 709d6dda9b2SRandall Stewart goto continue_send; 710d6dda9b2SRandall Stewart } 711d6dda9b2SRandall Stewart return (ret); 712d6dda9b2SRandall Stewart } 713d6dda9b2SRandall Stewart continue_send: 714335a2d00SRandall Stewart if (sinfo == NULL) { 715335a2d00SRandall Stewart sinfo = &__sinfo; 716335a2d00SRandall Stewart memset(&__sinfo, 0, sizeof(__sinfo)); 717335a2d00SRandall Stewart } 718d6dda9b2SRandall Stewart sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs); 719d6dda9b2SRandall Stewart if (sinfo->sinfo_assoc_id == 0) { 720d6dda9b2SRandall Stewart (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs, 721d6dda9b2SRandall Stewart (socklen_t) addrs->sa_len); 722d6dda9b2SRandall Stewart errno = ENOENT; 723d6dda9b2SRandall Stewart return (-1); 724d6dda9b2SRandall Stewart } 725d6dda9b2SRandall Stewart ret = sctp_send(sd, msg, msg_len, sinfo, flags); 726d6dda9b2SRandall Stewart saved_errno = errno; 727d6dda9b2SRandall Stewart if (no_end_cx == 0) 728d6dda9b2SRandall Stewart (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs, 729d6dda9b2SRandall Stewart (socklen_t) addrs->sa_len); 730d6dda9b2SRandall Stewart 731d6dda9b2SRandall Stewart errno = saved_errno; 732d6dda9b2SRandall Stewart return (ret); 733d6dda9b2SRandall Stewart } 734d6dda9b2SRandall Stewart 735d6dda9b2SRandall Stewart ssize_t 736d6dda9b2SRandall Stewart sctp_sendmsgx(int sd, 737d6dda9b2SRandall Stewart const void *msg, 738d6dda9b2SRandall Stewart size_t len, 739d6dda9b2SRandall Stewart struct sockaddr *addrs, 740d6dda9b2SRandall Stewart int addrcnt, 7413d36ac98SRebecca Cran uint32_t ppid, 7423d36ac98SRebecca Cran uint32_t flags, 7433d36ac98SRebecca Cran uint16_t stream_no, 7443d36ac98SRebecca Cran uint32_t timetolive, 7453d36ac98SRebecca Cran uint32_t context) 746d6dda9b2SRandall Stewart { 747d6dda9b2SRandall Stewart struct sctp_sndrcvinfo sinfo; 748d6dda9b2SRandall Stewart 749d6dda9b2SRandall Stewart memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo)); 750d6dda9b2SRandall Stewart sinfo.sinfo_ppid = ppid; 751d6dda9b2SRandall Stewart sinfo.sinfo_flags = flags; 752d6dda9b2SRandall Stewart sinfo.sinfo_ssn = stream_no; 753d6dda9b2SRandall Stewart sinfo.sinfo_timetolive = timetolive; 754d6dda9b2SRandall Stewart sinfo.sinfo_context = context; 7554224e03aSMichael Tuexen return (sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0)); 756d6dda9b2SRandall Stewart } 757d6dda9b2SRandall Stewart 758d6dda9b2SRandall Stewart ssize_t 759d6dda9b2SRandall Stewart sctp_recvmsg(int s, 760d6dda9b2SRandall Stewart void *dbuf, 761d6dda9b2SRandall Stewart size_t len, 762d6dda9b2SRandall Stewart struct sockaddr *from, 763d6dda9b2SRandall Stewart socklen_t * fromlen, 764d6dda9b2SRandall Stewart struct sctp_sndrcvinfo *sinfo, 765d6dda9b2SRandall Stewart int *msg_flags) 766d6dda9b2SRandall Stewart { 767d6dda9b2SRandall Stewart #ifdef SYS_sctp_generic_recvmsg 76848f65f00SMichael Tuexen struct iovec iov; 769d6dda9b2SRandall Stewart 77048f65f00SMichael Tuexen iov.iov_base = dbuf; 77148f65f00SMichael Tuexen iov.iov_len = len; 772d6dda9b2SRandall Stewart return (syscall(SYS_sctp_generic_recvmsg, s, 77348f65f00SMichael Tuexen &iov, 1, from, fromlen, sinfo, msg_flags)); 774d6dda9b2SRandall Stewart #else 775d6dda9b2SRandall Stewart ssize_t sz; 776d6dda9b2SRandall Stewart struct msghdr msg; 77748f65f00SMichael Tuexen struct iovec iov; 7787f15a8dfSMichael Tuexen char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV]; 779d6dda9b2SRandall Stewart struct cmsghdr *cmsg; 780d6dda9b2SRandall Stewart 781d6dda9b2SRandall Stewart if (msg_flags == NULL) { 782d6dda9b2SRandall Stewart errno = EINVAL; 783d6dda9b2SRandall Stewart return (-1); 784d6dda9b2SRandall Stewart } 785d6dda9b2SRandall Stewart msg.msg_flags = 0; 78648f65f00SMichael Tuexen iov.iov_base = dbuf; 78748f65f00SMichael Tuexen iov.iov_len = len; 788d6dda9b2SRandall Stewart msg.msg_name = (caddr_t)from; 789d6dda9b2SRandall Stewart if (fromlen == NULL) 790d6dda9b2SRandall Stewart msg.msg_namelen = 0; 791d6dda9b2SRandall Stewart else 792d6dda9b2SRandall Stewart msg.msg_namelen = *fromlen; 79348f65f00SMichael Tuexen msg.msg_iov = &iov; 794d6dda9b2SRandall Stewart msg.msg_iovlen = 1; 7957f15a8dfSMichael Tuexen msg.msg_control = cmsgbuf; 7967f15a8dfSMichael Tuexen msg.msg_controllen = sizeof(cmsgbuf); 7972c356be2SRandall Stewart sz = recvmsg(s, &msg, *msg_flags); 79848f65f00SMichael Tuexen *msg_flags = msg.msg_flags; 79948f65f00SMichael Tuexen if (sz <= 0) { 800d6dda9b2SRandall Stewart return (sz); 80148f65f00SMichael Tuexen } 80248f65f00SMichael Tuexen if (sinfo) { 803d6dda9b2SRandall Stewart sinfo->sinfo_assoc_id = 0; 80448f65f00SMichael Tuexen } 8057f15a8dfSMichael Tuexen if ((msg.msg_controllen > 0) && (sinfo != NULL)) { 806d6dda9b2SRandall Stewart /* 807d6dda9b2SRandall Stewart * parse through and see if we find the sctp_sndrcvinfo (if 808d6dda9b2SRandall Stewart * the user wants it). 809d6dda9b2SRandall Stewart */ 8107f15a8dfSMichael Tuexen for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 8117f15a8dfSMichael Tuexen if (cmsg->cmsg_level != IPPROTO_SCTP) { 8127f15a8dfSMichael Tuexen continue; 813d6dda9b2SRandall Stewart } 814d6dda9b2SRandall Stewart if (cmsg->cmsg_type == SCTP_SNDRCV) { 8157f15a8dfSMichael Tuexen memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_sndrcvinfo)); 816d6dda9b2SRandall Stewart break; 8177f15a8dfSMichael Tuexen } 8187f15a8dfSMichael Tuexen if (cmsg->cmsg_type == SCTP_EXTRCV) { 819d6dda9b2SRandall Stewart /* 8207f15a8dfSMichael Tuexen * Let's hope that the user provided enough 8217f15a8dfSMichael Tuexen * enough memory. At least he asked for more 8227f15a8dfSMichael Tuexen * information. 823d6dda9b2SRandall Stewart */ 8247f15a8dfSMichael Tuexen memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_extrcvinfo)); 825d6dda9b2SRandall Stewart break; 826d6dda9b2SRandall Stewart } 827d6dda9b2SRandall Stewart } 828d6dda9b2SRandall Stewart } 829d6dda9b2SRandall Stewart return (sz); 830d6dda9b2SRandall Stewart #endif 831d6dda9b2SRandall Stewart } 832d6dda9b2SRandall Stewart 833e2e7c62eSMichael Tuexen ssize_t 834e2e7c62eSMichael Tuexen sctp_recvv(int sd, 835e2e7c62eSMichael Tuexen const struct iovec *iov, 836e2e7c62eSMichael Tuexen int iovlen, 837e2e7c62eSMichael Tuexen struct sockaddr *from, 838e2e7c62eSMichael Tuexen socklen_t * fromlen, 839e2e7c62eSMichael Tuexen void *info, 840e2e7c62eSMichael Tuexen socklen_t * infolen, 841e2e7c62eSMichael Tuexen unsigned int *infotype, 842e2e7c62eSMichael Tuexen int *flags) 843d6dda9b2SRandall Stewart { 8447f15a8dfSMichael Tuexen char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV]; 845e2e7c62eSMichael Tuexen struct msghdr msg; 846e2e7c62eSMichael Tuexen struct cmsghdr *cmsg; 8477f15a8dfSMichael Tuexen ssize_t ret; 848e2e7c62eSMichael Tuexen struct sctp_rcvinfo *rcvinfo; 849e2e7c62eSMichael Tuexen struct sctp_nxtinfo *nxtinfo; 850d6dda9b2SRandall Stewart 8510b064106SMichael Tuexen if (((info != NULL) && (infolen == NULL)) | 8520b064106SMichael Tuexen ((info == NULL) && (infolen != NULL) && (*infolen != 0)) || 8530b064106SMichael Tuexen ((info != NULL) && (infotype == NULL))) { 8540b064106SMichael Tuexen errno = EINVAL; 8550b064106SMichael Tuexen return (-1); 8560b064106SMichael Tuexen } 857e2e7c62eSMichael Tuexen if (infotype) { 858e2e7c62eSMichael Tuexen *infotype = SCTP_RECVV_NOINFO; 859e2e7c62eSMichael Tuexen } 860e2e7c62eSMichael Tuexen msg.msg_name = from; 861e2e7c62eSMichael Tuexen if (fromlen == NULL) { 862e2e7c62eSMichael Tuexen msg.msg_namelen = 0; 863d6dda9b2SRandall Stewart } else { 864e2e7c62eSMichael Tuexen msg.msg_namelen = *fromlen; 865d6dda9b2SRandall Stewart } 866e2e7c62eSMichael Tuexen msg.msg_iov = (struct iovec *)iov; 867e2e7c62eSMichael Tuexen msg.msg_iovlen = iovlen; 8687f15a8dfSMichael Tuexen msg.msg_control = cmsgbuf; 8697f15a8dfSMichael Tuexen msg.msg_controllen = sizeof(cmsgbuf); 8707f15a8dfSMichael Tuexen ret = recvmsg(sd, &msg, *flags); 871e2e7c62eSMichael Tuexen *flags = msg.msg_flags; 8727f15a8dfSMichael Tuexen if ((ret > 0) && 873e2e7c62eSMichael Tuexen (msg.msg_controllen > 0) && 874e2e7c62eSMichael Tuexen (infotype != NULL) && 875e2e7c62eSMichael Tuexen (infolen != NULL) && 876e2e7c62eSMichael Tuexen (*infolen > 0)) { 877e2e7c62eSMichael Tuexen rcvinfo = NULL; 878e2e7c62eSMichael Tuexen nxtinfo = NULL; 879e2e7c62eSMichael Tuexen for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 880e2e7c62eSMichael Tuexen if (cmsg->cmsg_level != IPPROTO_SCTP) { 881e2e7c62eSMichael Tuexen continue; 882e2e7c62eSMichael Tuexen } 883e2e7c62eSMichael Tuexen if (cmsg->cmsg_type == SCTP_RCVINFO) { 884e2e7c62eSMichael Tuexen rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg); 8857f15a8dfSMichael Tuexen if (nxtinfo != NULL) { 8867f15a8dfSMichael Tuexen break; 8877f15a8dfSMichael Tuexen } else { 8887f15a8dfSMichael Tuexen continue; 8897f15a8dfSMichael Tuexen } 890e2e7c62eSMichael Tuexen } 891e2e7c62eSMichael Tuexen if (cmsg->cmsg_type == SCTP_NXTINFO) { 892e2e7c62eSMichael Tuexen nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg); 8937f15a8dfSMichael Tuexen if (rcvinfo != NULL) { 894e2e7c62eSMichael Tuexen break; 8957f15a8dfSMichael Tuexen } else { 8967f15a8dfSMichael Tuexen continue; 897e2e7c62eSMichael Tuexen } 898e2e7c62eSMichael Tuexen } 8997f15a8dfSMichael Tuexen } 9007f15a8dfSMichael Tuexen if (rcvinfo != NULL) { 9017f15a8dfSMichael Tuexen if ((nxtinfo != NULL) && (*infolen >= sizeof(struct sctp_recvv_rn))) { 902e2e7c62eSMichael Tuexen struct sctp_recvv_rn *rn_info; 903e2e7c62eSMichael Tuexen 904e2e7c62eSMichael Tuexen rn_info = (struct sctp_recvv_rn *)info; 905e2e7c62eSMichael Tuexen rn_info->recvv_rcvinfo = *rcvinfo; 906e2e7c62eSMichael Tuexen rn_info->recvv_nxtinfo = *nxtinfo; 907e2e7c62eSMichael Tuexen *infolen = (socklen_t) sizeof(struct sctp_recvv_rn); 908e2e7c62eSMichael Tuexen *infotype = SCTP_RECVV_RN; 9097f15a8dfSMichael Tuexen } else if (*infolen >= sizeof(struct sctp_rcvinfo)) { 910e2e7c62eSMichael Tuexen memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo)); 911e2e7c62eSMichael Tuexen *infolen = (socklen_t) sizeof(struct sctp_rcvinfo); 912e2e7c62eSMichael Tuexen *infotype = SCTP_RECVV_RCVINFO; 913e2e7c62eSMichael Tuexen } 9147f15a8dfSMichael Tuexen } else if (nxtinfo != NULL) { 9157f15a8dfSMichael Tuexen if (*infolen >= sizeof(struct sctp_nxtinfo)) { 916e2e7c62eSMichael Tuexen memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo)); 917e2e7c62eSMichael Tuexen *infolen = (socklen_t) sizeof(struct sctp_nxtinfo); 918e2e7c62eSMichael Tuexen *infotype = SCTP_RECVV_NXTINFO; 919e2e7c62eSMichael Tuexen } 920e2e7c62eSMichael Tuexen } 921e2e7c62eSMichael Tuexen } 9227f15a8dfSMichael Tuexen return (ret); 923d6dda9b2SRandall Stewart } 924d6dda9b2SRandall Stewart 925e2e7c62eSMichael Tuexen ssize_t 926e2e7c62eSMichael Tuexen sctp_sendv(int sd, 927e2e7c62eSMichael Tuexen const struct iovec *iov, int iovcnt, 928e2e7c62eSMichael Tuexen struct sockaddr *addrs, int addrcnt, 929e2e7c62eSMichael Tuexen void *info, socklen_t infolen, unsigned int infotype, 930e2e7c62eSMichael Tuexen int flags) 931e2e7c62eSMichael Tuexen { 932e2e7c62eSMichael Tuexen ssize_t ret; 933e2e7c62eSMichael Tuexen int i; 9340b064106SMichael Tuexen socklen_t addr_len; 935e2e7c62eSMichael Tuexen struct msghdr msg; 9360b064106SMichael Tuexen in_port_t port; 9370b064106SMichael Tuexen struct sctp_sendv_spa *spa_info; 938e2e7c62eSMichael Tuexen struct cmsghdr *cmsg; 939e2e7c62eSMichael Tuexen char *cmsgbuf; 940e2e7c62eSMichael Tuexen struct sockaddr *addr; 941e2e7c62eSMichael Tuexen struct sockaddr_in *addr_in; 942e2e7c62eSMichael Tuexen struct sockaddr_in6 *addr_in6; 943e2e7c62eSMichael Tuexen 9440b064106SMichael Tuexen if ((addrcnt < 0) || 9450b064106SMichael Tuexen (iovcnt < 0) || 946c67a03f9SMichael Tuexen ((addrs == NULL) && (addrcnt > 0)) || 947c67a03f9SMichael Tuexen ((addrs != NULL) && (addrcnt == 0)) || 9480b064106SMichael Tuexen ((iov == NULL) && (iovcnt > 0)) || 9490b064106SMichael Tuexen ((iov != NULL) && (iovcnt == 0))) { 950e2e7c62eSMichael Tuexen errno = EINVAL; 951e2e7c62eSMichael Tuexen return (-1); 952e2e7c62eSMichael Tuexen } 953e2e7c62eSMichael Tuexen cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) + 954e2e7c62eSMichael Tuexen CMSG_SPACE(sizeof(struct sctp_prinfo)) + 955e2e7c62eSMichael Tuexen CMSG_SPACE(sizeof(struct sctp_authinfo)) + 9565dc6a815SMichael Tuexen (size_t)addrcnt * CMSG_SPACE(sizeof(struct in6_addr))); 957e2e7c62eSMichael Tuexen if (cmsgbuf == NULL) { 9584ed0ebf6SMichael Tuexen errno = ENOMEM; 959e2e7c62eSMichael Tuexen return (-1); 960e2e7c62eSMichael Tuexen } 961e2e7c62eSMichael Tuexen msg.msg_control = cmsgbuf; 962e2e7c62eSMichael Tuexen msg.msg_controllen = 0; 963e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)cmsgbuf; 964e2e7c62eSMichael Tuexen switch (infotype) { 9650b064106SMichael Tuexen case SCTP_SENDV_NOINFO: 9660b064106SMichael Tuexen if ((infolen != 0) || (info != NULL)) { 9670b064106SMichael Tuexen free(cmsgbuf); 9680b064106SMichael Tuexen errno = EINVAL; 9690b064106SMichael Tuexen return (-1); 9700b064106SMichael Tuexen } 9710b064106SMichael Tuexen break; 972e2e7c62eSMichael Tuexen case SCTP_SENDV_SNDINFO: 9730b064106SMichael Tuexen if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) { 974e2e7c62eSMichael Tuexen free(cmsgbuf); 975e2e7c62eSMichael Tuexen errno = EINVAL; 976e2e7c62eSMichael Tuexen return (-1); 977e2e7c62eSMichael Tuexen } 978e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 979e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_SNDINFO; 980e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); 981e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo)); 982e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); 983e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); 984e2e7c62eSMichael Tuexen break; 985e2e7c62eSMichael Tuexen case SCTP_SENDV_PRINFO: 9860b064106SMichael Tuexen if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) { 987e2e7c62eSMichael Tuexen free(cmsgbuf); 988e2e7c62eSMichael Tuexen errno = EINVAL; 989e2e7c62eSMichael Tuexen return (-1); 990e2e7c62eSMichael Tuexen } 991e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 992e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_PRINFO; 993e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); 994e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo)); 995e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); 996e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo))); 997e2e7c62eSMichael Tuexen break; 998e2e7c62eSMichael Tuexen case SCTP_SENDV_AUTHINFO: 9990b064106SMichael Tuexen if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) { 1000e2e7c62eSMichael Tuexen free(cmsgbuf); 1001e2e7c62eSMichael Tuexen errno = EINVAL; 1002e2e7c62eSMichael Tuexen return (-1); 1003e2e7c62eSMichael Tuexen } 1004e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1005e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_AUTHINFO; 1006e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo)); 1007e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo)); 1008e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo)); 1009e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo))); 1010e2e7c62eSMichael Tuexen break; 1011e2e7c62eSMichael Tuexen case SCTP_SENDV_SPA: 10120b064106SMichael Tuexen if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) { 1013e2e7c62eSMichael Tuexen free(cmsgbuf); 1014e2e7c62eSMichael Tuexen errno = EINVAL; 1015e2e7c62eSMichael Tuexen return (-1); 1016e2e7c62eSMichael Tuexen } 1017e2e7c62eSMichael Tuexen spa_info = (struct sctp_sendv_spa *)info; 1018e2e7c62eSMichael Tuexen if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) { 1019e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1020e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_SNDINFO; 1021e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); 1022e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo)); 1023e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); 1024e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); 1025e2e7c62eSMichael Tuexen } 1026e2e7c62eSMichael Tuexen if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) { 1027e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1028e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_PRINFO; 1029e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); 1030e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo)); 1031e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); 1032e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo))); 1033e2e7c62eSMichael Tuexen } 1034e2e7c62eSMichael Tuexen if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) { 1035e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1036e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_AUTHINFO; 1037e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo)); 1038e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo)); 1039e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo)); 1040e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo))); 1041e2e7c62eSMichael Tuexen } 1042e2e7c62eSMichael Tuexen break; 1043e2e7c62eSMichael Tuexen default: 1044e2e7c62eSMichael Tuexen free(cmsgbuf); 1045e2e7c62eSMichael Tuexen errno = EINVAL; 1046e2e7c62eSMichael Tuexen return (-1); 1047e2e7c62eSMichael Tuexen } 1048e2e7c62eSMichael Tuexen addr = addrs; 10490b064106SMichael Tuexen msg.msg_name = NULL; 10500b064106SMichael Tuexen msg.msg_namelen = 0; 10510b064106SMichael Tuexen 10520b064106SMichael Tuexen for (i = 0; i < addrcnt; i++) { 1053e2e7c62eSMichael Tuexen switch (addr->sa_family) { 1054e2e7c62eSMichael Tuexen case AF_INET: 10550b064106SMichael Tuexen addr_len = (socklen_t) sizeof(struct sockaddr_in); 10560b064106SMichael Tuexen addr_in = (struct sockaddr_in *)addr; 10570b064106SMichael Tuexen if (addr_in->sin_len != addr_len) { 1058e2e7c62eSMichael Tuexen free(cmsgbuf); 1059e2e7c62eSMichael Tuexen errno = EINVAL; 1060e2e7c62eSMichael Tuexen return (-1); 1061e2e7c62eSMichael Tuexen } 10620b064106SMichael Tuexen if (i == 0) { 10630b064106SMichael Tuexen port = addr_in->sin_port; 1064e2e7c62eSMichael Tuexen } else { 10650b064106SMichael Tuexen if (port == addr_in->sin_port) { 1066e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1067e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_DSTADDRV4; 1068e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); 1069e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr)); 1070e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr)); 1071e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr))); 10720b064106SMichael Tuexen } else { 10730b064106SMichael Tuexen free(cmsgbuf); 10740b064106SMichael Tuexen errno = EINVAL; 10750b064106SMichael Tuexen return (-1); 10760b064106SMichael Tuexen } 10770b064106SMichael Tuexen } 1078e2e7c62eSMichael Tuexen break; 1079e2e7c62eSMichael Tuexen case AF_INET6: 10800b064106SMichael Tuexen addr_len = (socklen_t) sizeof(struct sockaddr_in6); 1081e2e7c62eSMichael Tuexen addr_in6 = (struct sockaddr_in6 *)addr; 10820b064106SMichael Tuexen if (addr_in6->sin6_len != addr_len) { 10830b064106SMichael Tuexen free(cmsgbuf); 10840b064106SMichael Tuexen errno = EINVAL; 10850b064106SMichael Tuexen return (-1); 10860b064106SMichael Tuexen } 10870b064106SMichael Tuexen if (i == 0) { 10880b064106SMichael Tuexen port = addr_in6->sin6_port; 10890b064106SMichael Tuexen } else { 10900b064106SMichael Tuexen if (port == addr_in6->sin6_port) { 1091e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1092e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_DSTADDRV6; 1093e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr)); 1094e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr)); 1095e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr)); 1096e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr))); 10970b064106SMichael Tuexen } else { 10980b064106SMichael Tuexen free(cmsgbuf); 10990b064106SMichael Tuexen errno = EINVAL; 11000b064106SMichael Tuexen return (-1); 11010b064106SMichael Tuexen } 11020b064106SMichael Tuexen } 1103e2e7c62eSMichael Tuexen break; 1104e2e7c62eSMichael Tuexen default: 1105e2e7c62eSMichael Tuexen free(cmsgbuf); 1106e2e7c62eSMichael Tuexen errno = EINVAL; 1107e2e7c62eSMichael Tuexen return (-1); 1108e2e7c62eSMichael Tuexen } 11090b064106SMichael Tuexen if (i == 0) { 11100b064106SMichael Tuexen msg.msg_name = addr; 11110b064106SMichael Tuexen msg.msg_namelen = addr_len; 11120b064106SMichael Tuexen } 1113e2e7c62eSMichael Tuexen addr = (struct sockaddr *)((caddr_t)addr + addr_len); 1114e2e7c62eSMichael Tuexen } 11150b064106SMichael Tuexen if (msg.msg_controllen == 0) { 11160b064106SMichael Tuexen msg.msg_control = NULL; 1117e2e7c62eSMichael Tuexen } 1118e2e7c62eSMichael Tuexen msg.msg_iov = (struct iovec *)iov; 1119e2e7c62eSMichael Tuexen msg.msg_iovlen = iovcnt; 1120e2e7c62eSMichael Tuexen msg.msg_flags = 0; 1121e2e7c62eSMichael Tuexen ret = sendmsg(sd, &msg, flags); 1122e2e7c62eSMichael Tuexen free(cmsgbuf); 1123e2e7c62eSMichael Tuexen return (ret); 1124e2e7c62eSMichael Tuexen } 1125e2e7c62eSMichael Tuexen 1126d6dda9b2SRandall Stewart 1127d6dda9b2SRandall Stewart #if !defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT) 1128d6dda9b2SRandall Stewart 1129d6dda9b2SRandall Stewart int 1130d6dda9b2SRandall Stewart sctp_peeloff(int sd, sctp_assoc_t assoc_id) 1131d6dda9b2SRandall Stewart { 1132d6dda9b2SRandall Stewart /* NOT supported, return invalid sd */ 1133d6dda9b2SRandall Stewart errno = ENOTSUP; 1134d6dda9b2SRandall Stewart return (-1); 1135d6dda9b2SRandall Stewart } 1136d6dda9b2SRandall Stewart 1137d6dda9b2SRandall Stewart #endif 1138d6dda9b2SRandall Stewart #if defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT) 1139d6dda9b2SRandall Stewart int 1140d6dda9b2SRandall Stewart sctp_peeloff(int sd, sctp_assoc_t assoc_id) 1141d6dda9b2SRandall Stewart { 1142d6dda9b2SRandall Stewart return (syscall(SYS_sctp_peeloff, sd, assoc_id)); 1143d6dda9b2SRandall Stewart } 1144d6dda9b2SRandall Stewart 1145d6dda9b2SRandall Stewart #endif 1146804cf641SRandall Stewart 11472c0d559dSRandall Stewart #undef SCTP_CONTROL_VEC_SIZE_RCV 1148