148f65f00SMichael Tuexen /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 448f65f00SMichael Tuexen * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 543dc9e2fSMichael Tuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. 643dc9e2fSMichael Tuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. 7d6dda9b2SRandall Stewart * 8d6dda9b2SRandall Stewart * Redistribution and use in source and binary forms, with or without 948f65f00SMichael Tuexen * modification, are permitted provided that the following conditions are met: 10d6dda9b2SRandall Stewart * 1148f65f00SMichael Tuexen * a) Redistributions of source code must retain the above copyright notice, 1248f65f00SMichael Tuexen * this list of conditions and the following disclaimer. 1348f65f00SMichael Tuexen * 1448f65f00SMichael Tuexen * b) Redistributions in binary form must reproduce the above copyright 1548f65f00SMichael Tuexen * notice, this list of conditions and the following disclaimer in 1648f65f00SMichael Tuexen * the documentation and/or other materials provided with the distribution. 1748f65f00SMichael Tuexen * 1848f65f00SMichael Tuexen * c) Neither the name of Cisco Systems, Inc. nor the names of its 1948f65f00SMichael Tuexen * contributors may be used to endorse or promote products derived 2048f65f00SMichael Tuexen * from this software without specific prior written permission. 2148f65f00SMichael Tuexen * 2248f65f00SMichael Tuexen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2348f65f00SMichael Tuexen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 2448f65f00SMichael Tuexen * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2548f65f00SMichael Tuexen * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 2648f65f00SMichael Tuexen * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2748f65f00SMichael Tuexen * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2848f65f00SMichael Tuexen * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2948f65f00SMichael Tuexen * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3048f65f00SMichael Tuexen * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3148f65f00SMichael Tuexen * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3248f65f00SMichael Tuexen * THE POSSIBILITY OF SUCH DAMAGE. 33d6dda9b2SRandall Stewart */ 3448f65f00SMichael Tuexen 35d6dda9b2SRandall Stewart #include <sys/cdefs.h> 36d6dda9b2SRandall Stewart __FBSDID("$FreeBSD$"); 3743dc9e2fSMichael Tuexen 38ed82c2edSMichael Tuexen #include <stdbool.h> 39f82d3b39SMichael Tuexen #include <stddef.h> 40d6dda9b2SRandall Stewart #include <stdio.h> 41d6dda9b2SRandall Stewart #include <string.h> 42d6dda9b2SRandall Stewart #include <errno.h> 43d6dda9b2SRandall Stewart #include <stdlib.h> 44d6dda9b2SRandall Stewart #include <unistd.h> 45d6dda9b2SRandall Stewart #include <sys/types.h> 46d6dda9b2SRandall Stewart #include <sys/socket.h> 47d6dda9b2SRandall Stewart #include <sys/errno.h> 48d6dda9b2SRandall Stewart #include <sys/syscall.h> 49d6dda9b2SRandall Stewart #include <sys/uio.h> 50d6dda9b2SRandall Stewart #include <netinet/in.h> 51d6dda9b2SRandall Stewart #include <arpa/inet.h> 52d6dda9b2SRandall Stewart #include <netinet/sctp_uio.h> 53d6dda9b2SRandall Stewart #include <netinet/sctp.h> 54d6dda9b2SRandall Stewart 55d6dda9b2SRandall Stewart #ifndef IN6_IS_ADDR_V4MAPPED 56d6dda9b2SRandall Stewart #define IN6_IS_ADDR_V4MAPPED(a) \ 573d36ac98SRebecca Cran ((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \ 583d36ac98SRebecca Cran (*(const uint32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \ 593d36ac98SRebecca Cran (*(const uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) 60d6dda9b2SRandall Stewart #endif 61d6dda9b2SRandall Stewart 62d6dda9b2SRandall Stewart #define SCTP_CONTROL_VEC_SIZE_RCV 16384 63d6dda9b2SRandall Stewart 64d6dda9b2SRandall Stewart 65d6dda9b2SRandall Stewart static void 66d6dda9b2SRandall Stewart in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 67d6dda9b2SRandall Stewart { 68d6dda9b2SRandall Stewart bzero(sin, sizeof(*sin)); 69d6dda9b2SRandall Stewart sin->sin_len = sizeof(struct sockaddr_in); 70d6dda9b2SRandall Stewart sin->sin_family = AF_INET; 71d6dda9b2SRandall Stewart sin->sin_port = sin6->sin6_port; 72d6dda9b2SRandall Stewart sin->sin_addr.s_addr = sin6->sin6_addr.__u6_addr.__u6_addr32[3]; 73d6dda9b2SRandall Stewart } 74d6dda9b2SRandall Stewart 75d6dda9b2SRandall Stewart int 76d6dda9b2SRandall Stewart sctp_getaddrlen(sa_family_t family) 77d6dda9b2SRandall Stewart { 78e2e7c62eSMichael Tuexen int ret, sd; 79d6dda9b2SRandall Stewart socklen_t siz; 80d6dda9b2SRandall Stewart struct sctp_assoc_value av; 81d6dda9b2SRandall Stewart 82d6dda9b2SRandall Stewart av.assoc_value = family; 83d6dda9b2SRandall Stewart siz = sizeof(av); 84d6dda9b2SRandall Stewart #if defined(AF_INET) 85d6dda9b2SRandall Stewart sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 86d6dda9b2SRandall Stewart #elif defined(AF_INET6) 87d6dda9b2SRandall Stewart sd = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP); 88e2e7c62eSMichael Tuexen #else 89e2e7c62eSMichael Tuexen sd = -1; 90d6dda9b2SRandall Stewart #endif 91d6dda9b2SRandall Stewart if (sd == -1) { 92a593094eSRandall Stewart return (-1); 93d6dda9b2SRandall Stewart } 94e2e7c62eSMichael Tuexen ret = getsockopt(sd, IPPROTO_SCTP, SCTP_GET_ADDR_LEN, &av, &siz); 95d6dda9b2SRandall Stewart close(sd); 96e2e7c62eSMichael Tuexen if (ret == 0) { 97d6dda9b2SRandall Stewart return ((int)av.assoc_value); 98d6dda9b2SRandall Stewart } else { 99a593094eSRandall Stewart return (-1); 100d6dda9b2SRandall Stewart } 101d6dda9b2SRandall Stewart } 102d6dda9b2SRandall Stewart 103d6dda9b2SRandall Stewart int 1042c356be2SRandall Stewart sctp_connectx(int sd, const struct sockaddr *addrs, int addrcnt, 1052c356be2SRandall Stewart sctp_assoc_t *id) 106d6dda9b2SRandall Stewart { 1077f15a8dfSMichael Tuexen char *buf; 10810e6d832SMichael Tuexen int i, ret, *aa; 109d6dda9b2SRandall Stewart char *cpto; 110d6dda9b2SRandall Stewart const struct sockaddr *at; 11110e6d832SMichael Tuexen size_t len; 112d6dda9b2SRandall Stewart 1132c356be2SRandall Stewart /* validate the address count and list */ 1142c356be2SRandall Stewart if ((addrs == NULL) || (addrcnt <= 0)) { 1152c356be2SRandall Stewart errno = EINVAL; 1162c356be2SRandall Stewart return (-1); 1172c356be2SRandall Stewart } 1187f15a8dfSMichael Tuexen if ((buf = malloc(sizeof(int) + (size_t)addrcnt * sizeof(struct sockaddr_in6))) == NULL) { 1197f15a8dfSMichael Tuexen errno = E2BIG; 1207f15a8dfSMichael Tuexen return (-1); 1217f15a8dfSMichael Tuexen } 12210e6d832SMichael Tuexen len = sizeof(int); 123d6dda9b2SRandall Stewart at = addrs; 1247f15a8dfSMichael Tuexen cpto = buf + sizeof(int); 125d6dda9b2SRandall Stewart /* validate all the addresses and get the size */ 126d6dda9b2SRandall Stewart for (i = 0; i < addrcnt; i++) { 12793409822SMichael Tuexen switch (at->sa_family) { 12893409822SMichael Tuexen case AF_INET: 12925d63f19SRandall Stewart if (at->sa_len != sizeof(struct sockaddr_in)) { 1307f15a8dfSMichael Tuexen free(buf); 13125d63f19SRandall Stewart errno = EINVAL; 13225d63f19SRandall Stewart return (-1); 13325d63f19SRandall Stewart } 13493409822SMichael Tuexen memcpy(cpto, at, sizeof(struct sockaddr_in)); 13593409822SMichael Tuexen cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in)); 13693409822SMichael Tuexen len += sizeof(struct sockaddr_in); 13793409822SMichael Tuexen break; 13893409822SMichael Tuexen case AF_INET6: 13925d63f19SRandall Stewart if (at->sa_len != sizeof(struct sockaddr_in6)) { 1407f15a8dfSMichael Tuexen free(buf); 14125d63f19SRandall Stewart errno = EINVAL; 14225d63f19SRandall Stewart return (-1); 14325d63f19SRandall Stewart } 144d6dda9b2SRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)at)->sin6_addr)) { 145d6dda9b2SRandall Stewart in6_sin6_2_sin((struct sockaddr_in *)cpto, (struct sockaddr_in6 *)at); 146d6dda9b2SRandall Stewart cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in)); 147d6dda9b2SRandall Stewart len += sizeof(struct sockaddr_in); 148d6dda9b2SRandall Stewart } else { 14993409822SMichael Tuexen memcpy(cpto, at, sizeof(struct sockaddr_in6)); 15093409822SMichael Tuexen cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in6)); 15193409822SMichael Tuexen len += sizeof(struct sockaddr_in6); 152d6dda9b2SRandall Stewart } 15393409822SMichael Tuexen break; 15493409822SMichael Tuexen default: 1557f15a8dfSMichael Tuexen free(buf); 156d6dda9b2SRandall Stewart errno = EINVAL; 157d6dda9b2SRandall Stewart return (-1); 158d6dda9b2SRandall Stewart } 1597f15a8dfSMichael Tuexen at = (struct sockaddr *)((caddr_t)at + at->sa_len); 160d6dda9b2SRandall Stewart } 161d6dda9b2SRandall Stewart aa = (int *)buf; 1627f15a8dfSMichael Tuexen *aa = addrcnt; 163d6dda9b2SRandall Stewart ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X, (void *)buf, 164d6dda9b2SRandall Stewart (socklen_t)len); 1657f15a8dfSMichael Tuexen if ((ret == 0) && (id != NULL)) { 1667f15a8dfSMichael Tuexen *id = *(sctp_assoc_t *)buf; 16742551e99SRandall Stewart } 16810e6d832SMichael Tuexen free(buf); 169d6dda9b2SRandall Stewart return (ret); 170d6dda9b2SRandall Stewart } 171d6dda9b2SRandall Stewart 172d6dda9b2SRandall Stewart int 173d6dda9b2SRandall Stewart sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags) 174d6dda9b2SRandall Stewart { 175d6dda9b2SRandall Stewart struct sockaddr *sa; 1761b649582SRandall Stewart struct sockaddr_in *sin; 1771b649582SRandall Stewart struct sockaddr_in6 *sin6; 1785dc6a815SMichael Tuexen int i; 179ed82c2edSMichael Tuexen uint16_t sport; 180ed82c2edSMichael Tuexen bool fix_port; 181d6dda9b2SRandall Stewart 1822c356be2SRandall Stewart /* validate the flags */ 183d6dda9b2SRandall Stewart if ((flags != SCTP_BINDX_ADD_ADDR) && 184d6dda9b2SRandall Stewart (flags != SCTP_BINDX_REM_ADDR)) { 185d6dda9b2SRandall Stewart errno = EFAULT; 186d6dda9b2SRandall Stewart return (-1); 187d6dda9b2SRandall Stewart } 1882c356be2SRandall Stewart /* validate the address count and list */ 1892c356be2SRandall Stewart if ((addrcnt <= 0) || (addrs == NULL)) { 1902c356be2SRandall Stewart errno = EINVAL; 1912c356be2SRandall Stewart return (-1); 1922c356be2SRandall Stewart } 193ed82c2edSMichael Tuexen sport = 0; 194ed82c2edSMichael Tuexen fix_port = false; 1951b649582SRandall Stewart /* First pre-screen the addresses */ 196d6dda9b2SRandall Stewart sa = addrs; 197d6dda9b2SRandall Stewart for (i = 0; i < addrcnt; i++) { 19893409822SMichael Tuexen switch (sa->sa_family) { 19993409822SMichael Tuexen case AF_INET: 20093409822SMichael Tuexen if (sa->sa_len != sizeof(struct sockaddr_in)) { 20193409822SMichael Tuexen errno = EINVAL; 20293409822SMichael Tuexen return (-1); 20393409822SMichael Tuexen } 2041b649582SRandall Stewart sin = (struct sockaddr_in *)sa; 2051b649582SRandall Stewart if (sin->sin_port) { 2061b649582SRandall Stewart /* non-zero port, check or save */ 2071b649582SRandall Stewart if (sport) { 2081b649582SRandall Stewart /* Check against our port */ 2091b649582SRandall Stewart if (sport != sin->sin_port) { 21093409822SMichael Tuexen errno = EINVAL; 21193409822SMichael Tuexen return (-1); 2121b649582SRandall Stewart } 2131b649582SRandall Stewart } else { 2141b649582SRandall Stewart /* save off the port */ 2151b649582SRandall Stewart sport = sin->sin_port; 216ed82c2edSMichael Tuexen fix_port = (i > 0); 2171b649582SRandall Stewart } 2181b649582SRandall Stewart } 21993409822SMichael Tuexen break; 22093409822SMichael Tuexen case AF_INET6: 22193409822SMichael Tuexen if (sa->sa_len != sizeof(struct sockaddr_in6)) { 22293409822SMichael Tuexen errno = EINVAL; 22393409822SMichael Tuexen return (-1); 22493409822SMichael Tuexen } 2251b649582SRandall Stewart sin6 = (struct sockaddr_in6 *)sa; 2261b649582SRandall Stewart if (sin6->sin6_port) { 2271b649582SRandall Stewart /* non-zero port, check or save */ 2281b649582SRandall Stewart if (sport) { 2291b649582SRandall Stewart /* Check against our port */ 2301b649582SRandall Stewart if (sport != sin6->sin6_port) { 23193409822SMichael Tuexen errno = EINVAL; 23293409822SMichael Tuexen return (-1); 2331b649582SRandall Stewart } 2341b649582SRandall Stewart } else { 2351b649582SRandall Stewart /* save off the port */ 2361b649582SRandall Stewart sport = sin6->sin6_port; 237ed82c2edSMichael Tuexen fix_port = (i > 0); 2381b649582SRandall Stewart } 2391b649582SRandall Stewart } 24093409822SMichael Tuexen break; 24193409822SMichael Tuexen default: 24293409822SMichael Tuexen /* Invalid address family specified. */ 2431dd0c905SMichael Tuexen errno = EAFNOSUPPORT; 24493409822SMichael Tuexen return (-1); 2451b649582SRandall Stewart } 2465dc6a815SMichael Tuexen sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 2471b649582SRandall Stewart } 24893409822SMichael Tuexen sa = addrs; 24993409822SMichael Tuexen for (i = 0; i < addrcnt; i++) { 2501dd0c905SMichael Tuexen /* 2511dd0c905SMichael Tuexen * Now, if there was a port mentioned, assure that the first 2521dd0c905SMichael Tuexen * address has that port to make sure it fails or succeeds 2531dd0c905SMichael Tuexen * correctly. 2541dd0c905SMichael Tuexen */ 255ed82c2edSMichael Tuexen if (fix_port) { 256ed82c2edSMichael Tuexen switch (sa->sa_family) { 2571dd0c905SMichael Tuexen case AF_INET: 258ed82c2edSMichael Tuexen ((struct sockaddr_in *)sa)->sin_port = sport; 2591dd0c905SMichael Tuexen break; 2601dd0c905SMichael Tuexen case AF_INET6: 261ed82c2edSMichael Tuexen ((struct sockaddr_in6 *)sa)->sin6_port = sport; 2621dd0c905SMichael Tuexen break; 2631dd0c905SMichael Tuexen } 264ed82c2edSMichael Tuexen fix_port = false; 2651dd0c905SMichael Tuexen } 266ed82c2edSMichael Tuexen if (setsockopt(sd, IPPROTO_SCTP, flags, sa, sa->sa_len) != 0) { 267d6dda9b2SRandall Stewart return (-1); 268d6dda9b2SRandall Stewart } 2695dc6a815SMichael Tuexen sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 270d6dda9b2SRandall Stewart } 271d6dda9b2SRandall Stewart return (0); 272d6dda9b2SRandall Stewart } 273d6dda9b2SRandall Stewart 274d6dda9b2SRandall Stewart int 275d6dda9b2SRandall Stewart sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t *size) 276d6dda9b2SRandall Stewart { 277d6dda9b2SRandall Stewart if (arg == NULL) { 278602afc03SRandall Stewart errno = EINVAL; 279602afc03SRandall Stewart return (-1); 280d6dda9b2SRandall Stewart } 281b71f5853SMichael Tuexen if ((id == SCTP_CURRENT_ASSOC) || 282b71f5853SMichael Tuexen (id == SCTP_ALL_ASSOC)) { 283b71f5853SMichael Tuexen errno = EINVAL; 284b71f5853SMichael Tuexen return (-1); 285b71f5853SMichael Tuexen } 2861b649582SRandall Stewart switch (opt) { 2871b649582SRandall Stewart case SCTP_RTOINFO: 2881b649582SRandall Stewart ((struct sctp_rtoinfo *)arg)->srto_assoc_id = id; 2891b649582SRandall Stewart break; 2901b649582SRandall Stewart case SCTP_ASSOCINFO: 2911b649582SRandall Stewart ((struct sctp_assocparams *)arg)->sasoc_assoc_id = id; 2921b649582SRandall Stewart break; 2931b649582SRandall Stewart case SCTP_DEFAULT_SEND_PARAM: 2941b649582SRandall Stewart ((struct sctp_assocparams *)arg)->sasoc_assoc_id = id; 2951b649582SRandall Stewart break; 2961b649582SRandall Stewart case SCTP_PRIMARY_ADDR: 2971b649582SRandall Stewart ((struct sctp_setprim *)arg)->ssp_assoc_id = id; 2981b649582SRandall Stewart break; 2991b649582SRandall Stewart case SCTP_PEER_ADDR_PARAMS: 3001b649582SRandall Stewart ((struct sctp_paddrparams *)arg)->spp_assoc_id = id; 3011b649582SRandall Stewart break; 3021b649582SRandall Stewart case SCTP_MAXSEG: 3031b649582SRandall Stewart ((struct sctp_assoc_value *)arg)->assoc_id = id; 3041b649582SRandall Stewart break; 3051b649582SRandall Stewart case SCTP_AUTH_KEY: 3061b649582SRandall Stewart ((struct sctp_authkey *)arg)->sca_assoc_id = id; 3071b649582SRandall Stewart break; 3081b649582SRandall Stewart case SCTP_AUTH_ACTIVE_KEY: 3091b649582SRandall Stewart ((struct sctp_authkeyid *)arg)->scact_assoc_id = id; 3101b649582SRandall Stewart break; 3111b649582SRandall Stewart case SCTP_DELAYED_SACK: 3121b649582SRandall Stewart ((struct sctp_sack_info *)arg)->sack_assoc_id = id; 3131b649582SRandall Stewart break; 3141b649582SRandall Stewart case SCTP_CONTEXT: 3151b649582SRandall Stewart ((struct sctp_assoc_value *)arg)->assoc_id = id; 3161b649582SRandall Stewart break; 3171b649582SRandall Stewart case SCTP_STATUS: 3181b649582SRandall Stewart ((struct sctp_status *)arg)->sstat_assoc_id = id; 3191b649582SRandall Stewart break; 3201b649582SRandall Stewart case SCTP_GET_PEER_ADDR_INFO: 3211b649582SRandall Stewart ((struct sctp_paddrinfo *)arg)->spinfo_assoc_id = id; 3221b649582SRandall Stewart break; 3231b649582SRandall Stewart case SCTP_PEER_AUTH_CHUNKS: 3241b649582SRandall Stewart ((struct sctp_authchunks *)arg)->gauth_assoc_id = id; 3251b649582SRandall Stewart break; 3261b649582SRandall Stewart case SCTP_LOCAL_AUTH_CHUNKS: 3271b649582SRandall Stewart ((struct sctp_authchunks *)arg)->gauth_assoc_id = id; 3281b649582SRandall Stewart break; 32948f65f00SMichael Tuexen case SCTP_TIMEOUTS: 33048f65f00SMichael Tuexen ((struct sctp_timeouts *)arg)->stimo_assoc_id = id; 33148f65f00SMichael Tuexen break; 332e2e7c62eSMichael Tuexen case SCTP_EVENT: 333e2e7c62eSMichael Tuexen ((struct sctp_event *)arg)->se_assoc_id = id; 334e2e7c62eSMichael Tuexen break; 33513aae0bfSMichael Tuexen case SCTP_DEFAULT_SNDINFO: 33613aae0bfSMichael Tuexen ((struct sctp_sndinfo *)arg)->snd_assoc_id = id; 33713aae0bfSMichael Tuexen break; 33813aae0bfSMichael Tuexen case SCTP_DEFAULT_PRINFO: 33913aae0bfSMichael Tuexen ((struct sctp_default_prinfo *)arg)->pr_assoc_id = id; 34013aae0bfSMichael Tuexen break; 341ca85e948SMichael Tuexen case SCTP_PEER_ADDR_THLDS: 342ca85e948SMichael Tuexen ((struct sctp_paddrthlds *)arg)->spt_assoc_id = id; 343ca85e948SMichael Tuexen break; 344c9c58059SMichael Tuexen case SCTP_REMOTE_UDP_ENCAPS_PORT: 345c9c58059SMichael Tuexen ((struct sctp_udpencaps *)arg)->sue_assoc_id = id; 346c9c58059SMichael Tuexen break; 347f342355aSMichael Tuexen case SCTP_ECN_SUPPORTED: 348f342355aSMichael Tuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 349f342355aSMichael Tuexen break; 350dd973b0eSMichael Tuexen case SCTP_PR_SUPPORTED: 351dd973b0eSMichael Tuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 352dd973b0eSMichael Tuexen break; 353c79bec9cSMichael Tuexen case SCTP_AUTH_SUPPORTED: 354c79bec9cSMichael Tuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 355c79bec9cSMichael Tuexen break; 356c79bec9cSMichael Tuexen case SCTP_ASCONF_SUPPORTED: 357c79bec9cSMichael Tuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 358c79bec9cSMichael Tuexen break; 359317e00efSMichael Tuexen case SCTP_RECONFIG_SUPPORTED: 360317e00efSMichael Tuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 361317e00efSMichael Tuexen break; 362caea9879SMichael Tuexen case SCTP_NRSACK_SUPPORTED: 363caea9879SMichael Tuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 364caea9879SMichael Tuexen break; 365cb9b8e6fSMichael Tuexen case SCTP_PKTDROP_SUPPORTED: 366cb9b8e6fSMichael Tuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 367cb9b8e6fSMichael Tuexen break; 368bb2c20c1SMichael Tuexen case SCTP_MAX_BURST: 369bb2c20c1SMichael Tuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 370bb2c20c1SMichael Tuexen break; 3717c9b6492SMichael Tuexen case SCTP_ENABLE_STREAM_RESET: 3727c9b6492SMichael Tuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 3737c9b6492SMichael Tuexen break; 374f0396ad1SMichael Tuexen case SCTP_PR_STREAM_STATUS: 375f0396ad1SMichael Tuexen ((struct sctp_prstatus *)arg)->sprstat_assoc_id = id; 376f0396ad1SMichael Tuexen break; 377f0396ad1SMichael Tuexen case SCTP_PR_ASSOC_STATUS: 378f0396ad1SMichael Tuexen ((struct sctp_prstatus *)arg)->sprstat_assoc_id = id; 379f0396ad1SMichael Tuexen break; 38059b6d5beSMichael Tuexen case SCTP_MAX_CWND: 38159b6d5beSMichael Tuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 38259b6d5beSMichael Tuexen break; 3831b649582SRandall Stewart default: 3841b649582SRandall Stewart break; 3851b649582SRandall Stewart } 386d6dda9b2SRandall Stewart return (getsockopt(sd, IPPROTO_SCTP, opt, arg, size)); 387d6dda9b2SRandall Stewart } 388d6dda9b2SRandall Stewart 389d6dda9b2SRandall Stewart int 390d6dda9b2SRandall Stewart sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs) 391d6dda9b2SRandall Stewart { 392d6dda9b2SRandall Stewart struct sctp_getaddresses *addrs; 393d6dda9b2SRandall Stewart struct sockaddr *sa; 394d6dda9b2SRandall Stewart caddr_t lim; 3955dc6a815SMichael Tuexen socklen_t opt_len; 396dabd8bf9SMichael Tuexen uint32_t size_of_addresses; 397d6dda9b2SRandall Stewart int cnt; 398d6dda9b2SRandall Stewart 399d6dda9b2SRandall Stewart if (raddrs == NULL) { 400d6dda9b2SRandall Stewart errno = EFAULT; 401d6dda9b2SRandall Stewart return (-1); 402d6dda9b2SRandall Stewart } 403dabd8bf9SMichael Tuexen /* When calling getsockopt(), the value contains the assoc_id. */ 404dabd8bf9SMichael Tuexen size_of_addresses = (uint32_t)id; 405dabd8bf9SMichael Tuexen opt_len = (socklen_t)sizeof(uint32_t); 406d6dda9b2SRandall Stewart if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE, 407dabd8bf9SMichael Tuexen &size_of_addresses, &opt_len) != 0) { 408*db0ac6deSCy Schubert if (errno == ENOENT) { 409*db0ac6deSCy Schubert return (0); 410*db0ac6deSCy Schubert } else { 411d6dda9b2SRandall Stewart return (-1); 412d6dda9b2SRandall Stewart } 413*db0ac6deSCy Schubert } 414dabd8bf9SMichael Tuexen opt_len = (socklen_t)((size_t)size_of_addresses + sizeof(struct sctp_getaddresses)); 4155dc6a815SMichael Tuexen addrs = calloc(1, (size_t)opt_len); 416d6dda9b2SRandall Stewart if (addrs == NULL) { 4174ed0ebf6SMichael Tuexen errno = ENOMEM; 418d6dda9b2SRandall Stewart return (-1); 419d6dda9b2SRandall Stewart } 420d6dda9b2SRandall Stewart addrs->sget_assoc_id = id; 421d6dda9b2SRandall Stewart /* Now lets get the array of addresses */ 422d6dda9b2SRandall Stewart if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES, 4235dc6a815SMichael Tuexen addrs, &opt_len) != 0) { 424d6dda9b2SRandall Stewart free(addrs); 425d6dda9b2SRandall Stewart return (-1); 426d6dda9b2SRandall Stewart } 427c5d9e5c9SMichael Tuexen *raddrs = &addrs->addr[0].sa; 428d6dda9b2SRandall Stewart cnt = 0; 429c5d9e5c9SMichael Tuexen sa = &addrs->addr[0].sa; 4305dc6a815SMichael Tuexen lim = (caddr_t)addrs + opt_len; 431d6dda9b2SRandall Stewart while (((caddr_t)sa < lim) && (sa->sa_len > 0)) { 432d6dda9b2SRandall Stewart sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 433d6dda9b2SRandall Stewart cnt++; 434d6dda9b2SRandall Stewart } 435d6dda9b2SRandall Stewart return (cnt); 436d6dda9b2SRandall Stewart } 437d6dda9b2SRandall Stewart 438d6dda9b2SRandall Stewart void 439d6dda9b2SRandall Stewart sctp_freepaddrs(struct sockaddr *addrs) 440d6dda9b2SRandall Stewart { 441d6dda9b2SRandall Stewart void *fr_addr; 442d6dda9b2SRandall Stewart 4437f15a8dfSMichael Tuexen /* Take away the hidden association id */ 444c5d9e5c9SMichael Tuexen fr_addr = (void *)((caddr_t)addrs - offsetof(struct sctp_getaddresses, addr)); 445d6dda9b2SRandall Stewart /* Now free it */ 446d6dda9b2SRandall Stewart free(fr_addr); 447d6dda9b2SRandall Stewart } 448d6dda9b2SRandall Stewart 449d6dda9b2SRandall Stewart int 450d6dda9b2SRandall Stewart sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs) 451d6dda9b2SRandall Stewart { 452d6dda9b2SRandall Stewart struct sctp_getaddresses *addrs; 453d6dda9b2SRandall Stewart struct sockaddr *sa; 454dabd8bf9SMichael Tuexen caddr_t lim; 4555dc6a815SMichael Tuexen socklen_t opt_len; 456dabd8bf9SMichael Tuexen uint32_t size_of_addresses; 457d6dda9b2SRandall Stewart int cnt; 458d6dda9b2SRandall Stewart 459d6dda9b2SRandall Stewart if (raddrs == NULL) { 460d6dda9b2SRandall Stewart errno = EFAULT; 461d6dda9b2SRandall Stewart return (-1); 462d6dda9b2SRandall Stewart } 463d6dda9b2SRandall Stewart size_of_addresses = 0; 464dabd8bf9SMichael Tuexen opt_len = (socklen_t)sizeof(uint32_t); 465d6dda9b2SRandall Stewart if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE, 4665dc6a815SMichael Tuexen &size_of_addresses, &opt_len) != 0) { 467d6dda9b2SRandall Stewart return (-1); 468d6dda9b2SRandall Stewart } 469dabd8bf9SMichael Tuexen opt_len = (socklen_t)((size_t)size_of_addresses + sizeof(struct sctp_getaddresses)); 4705dc6a815SMichael Tuexen addrs = calloc(1, (size_t)opt_len); 471d6dda9b2SRandall Stewart if (addrs == NULL) { 472d6dda9b2SRandall Stewart errno = ENOMEM; 473d6dda9b2SRandall Stewart return (-1); 474d6dda9b2SRandall Stewart } 475d6dda9b2SRandall Stewart addrs->sget_assoc_id = id; 476d6dda9b2SRandall Stewart /* Now lets get the array of addresses */ 477d6dda9b2SRandall Stewart if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs, 4785dc6a815SMichael Tuexen &opt_len) != 0) { 479d6dda9b2SRandall Stewart free(addrs); 480d6dda9b2SRandall Stewart return (-1); 481d6dda9b2SRandall Stewart } 482071966e8SMichael Tuexen if (size_of_addresses == 0) { 483071966e8SMichael Tuexen free(addrs); 484071966e8SMichael Tuexen return (0); 485071966e8SMichael Tuexen } 486c5d9e5c9SMichael Tuexen *raddrs = &addrs->addr[0].sa; 487d6dda9b2SRandall Stewart cnt = 0; 488c5d9e5c9SMichael Tuexen sa = &addrs->addr[0].sa; 4895dc6a815SMichael Tuexen lim = (caddr_t)addrs + opt_len; 490d6dda9b2SRandall Stewart while (((caddr_t)sa < lim) && (sa->sa_len > 0)) { 491d6dda9b2SRandall Stewart sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 492d6dda9b2SRandall Stewart cnt++; 493d6dda9b2SRandall Stewart } 494d6dda9b2SRandall Stewart return (cnt); 495d6dda9b2SRandall Stewart } 496d6dda9b2SRandall Stewart 497d6dda9b2SRandall Stewart void 498d6dda9b2SRandall Stewart sctp_freeladdrs(struct sockaddr *addrs) 499d6dda9b2SRandall Stewart { 500d6dda9b2SRandall Stewart void *fr_addr; 501d6dda9b2SRandall Stewart 5027f15a8dfSMichael Tuexen /* Take away the hidden association id */ 503c5d9e5c9SMichael Tuexen fr_addr = (void *)((caddr_t)addrs - offsetof(struct sctp_getaddresses, addr)); 504d6dda9b2SRandall Stewart /* Now free it */ 505d6dda9b2SRandall Stewart free(fr_addr); 506d6dda9b2SRandall Stewart } 507d6dda9b2SRandall Stewart 508d6dda9b2SRandall Stewart ssize_t 509d6dda9b2SRandall Stewart sctp_sendmsg(int s, 510d6dda9b2SRandall Stewart const void *data, 511d6dda9b2SRandall Stewart size_t len, 512d6dda9b2SRandall Stewart const struct sockaddr *to, 513002b1f0bSRandall Stewart socklen_t tolen, 5143d36ac98SRebecca Cran uint32_t ppid, 5153d36ac98SRebecca Cran uint32_t flags, 5163d36ac98SRebecca Cran uint16_t stream_no, 5173d36ac98SRebecca Cran uint32_t timetolive, 5183d36ac98SRebecca Cran uint32_t context) 519d6dda9b2SRandall Stewart { 520d6dda9b2SRandall Stewart #ifdef SYS_sctp_generic_sendmsg 521d6dda9b2SRandall Stewart struct sctp_sndrcvinfo sinfo; 522d6dda9b2SRandall Stewart 523539bb45aSMichael Tuexen memset(&sinfo, 0, sizeof(struct sctp_sndrcvinfo)); 524d6dda9b2SRandall Stewart sinfo.sinfo_ppid = ppid; 525d6dda9b2SRandall Stewart sinfo.sinfo_flags = flags; 526d6dda9b2SRandall Stewart sinfo.sinfo_stream = stream_no; 527d6dda9b2SRandall Stewart sinfo.sinfo_timetolive = timetolive; 528d6dda9b2SRandall Stewart sinfo.sinfo_context = context; 529d6dda9b2SRandall Stewart sinfo.sinfo_assoc_id = 0; 530d6dda9b2SRandall Stewart return (syscall(SYS_sctp_generic_sendmsg, s, 531d6dda9b2SRandall Stewart data, len, to, tolen, &sinfo, 0)); 532d6dda9b2SRandall Stewart #else 533d6dda9b2SRandall Stewart struct msghdr msg; 5347f15a8dfSMichael Tuexen struct sctp_sndrcvinfo *sinfo; 53548f65f00SMichael Tuexen struct iovec iov; 5367f15a8dfSMichael Tuexen char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; 537d6dda9b2SRandall Stewart struct cmsghdr *cmsg; 538d6dda9b2SRandall Stewart struct sockaddr *who = NULL; 539d6dda9b2SRandall Stewart union { 540d6dda9b2SRandall Stewart struct sockaddr_in in; 541d6dda9b2SRandall Stewart struct sockaddr_in6 in6; 542d6dda9b2SRandall Stewart } addr; 543d6dda9b2SRandall Stewart 54448f65f00SMichael Tuexen if ((tolen > 0) && 54548f65f00SMichael Tuexen ((to == NULL) || (tolen < sizeof(struct sockaddr)))) { 546002b1f0bSRandall Stewart errno = EINVAL; 5474224e03aSMichael Tuexen return (-1); 548002b1f0bSRandall Stewart } 5497f15a8dfSMichael Tuexen if ((to != NULL) && (tolen > 0)) { 5507f15a8dfSMichael Tuexen switch (to->sa_family) { 5517f15a8dfSMichael Tuexen case AF_INET: 552002b1f0bSRandall Stewart if (tolen != sizeof(struct sockaddr_in)) { 553002b1f0bSRandall Stewart errno = EINVAL; 5544224e03aSMichael Tuexen return (-1); 555002b1f0bSRandall Stewart } 55648f65f00SMichael Tuexen if ((to->sa_len > 0) && 55748f65f00SMichael Tuexen (to->sa_len != sizeof(struct sockaddr_in))) { 558002b1f0bSRandall Stewart errno = EINVAL; 5594224e03aSMichael Tuexen return (-1); 560002b1f0bSRandall Stewart } 561d6dda9b2SRandall Stewart memcpy(&addr, to, sizeof(struct sockaddr_in)); 562d6dda9b2SRandall Stewart addr.in.sin_len = sizeof(struct sockaddr_in); 5637f15a8dfSMichael Tuexen break; 5647f15a8dfSMichael Tuexen case AF_INET6: 565002b1f0bSRandall Stewart if (tolen != sizeof(struct sockaddr_in6)) { 566002b1f0bSRandall Stewart errno = EINVAL; 5674224e03aSMichael Tuexen return (-1); 568002b1f0bSRandall Stewart } 56948f65f00SMichael Tuexen if ((to->sa_len > 0) && 57048f65f00SMichael Tuexen (to->sa_len != sizeof(struct sockaddr_in6))) { 571002b1f0bSRandall Stewart errno = EINVAL; 5724224e03aSMichael Tuexen return (-1); 573002b1f0bSRandall Stewart } 574d6dda9b2SRandall Stewart memcpy(&addr, to, sizeof(struct sockaddr_in6)); 575d6dda9b2SRandall Stewart addr.in6.sin6_len = sizeof(struct sockaddr_in6); 5767f15a8dfSMichael Tuexen break; 5777f15a8dfSMichael Tuexen default: 578002b1f0bSRandall Stewart errno = EAFNOSUPPORT; 5794224e03aSMichael Tuexen return (-1); 580d6dda9b2SRandall Stewart } 581d6dda9b2SRandall Stewart who = (struct sockaddr *)&addr; 582d6dda9b2SRandall Stewart } 583df2fca7bSMichael Tuexen 58448f65f00SMichael Tuexen iov.iov_base = (char *)data; 58548f65f00SMichael Tuexen iov.iov_len = len; 586d6dda9b2SRandall Stewart 587002b1f0bSRandall Stewart if (who) { 588d6dda9b2SRandall Stewart msg.msg_name = (caddr_t)who; 589d6dda9b2SRandall Stewart msg.msg_namelen = who->sa_len; 590d6dda9b2SRandall Stewart } else { 591d6dda9b2SRandall Stewart msg.msg_name = (caddr_t)NULL; 592d6dda9b2SRandall Stewart msg.msg_namelen = 0; 593d6dda9b2SRandall Stewart } 59448f65f00SMichael Tuexen msg.msg_iov = &iov; 595d6dda9b2SRandall Stewart msg.msg_iovlen = 1; 5967f15a8dfSMichael Tuexen msg.msg_control = cmsgbuf; 5977f15a8dfSMichael Tuexen msg.msg_controllen = CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); 5982b8a4d80SMichael Tuexen msg.msg_flags = 0; 5997f15a8dfSMichael Tuexen cmsg = (struct cmsghdr *)cmsgbuf; 600d6dda9b2SRandall Stewart cmsg->cmsg_level = IPPROTO_SCTP; 601d6dda9b2SRandall Stewart cmsg->cmsg_type = SCTP_SNDRCV; 602d6dda9b2SRandall Stewart cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 6037f15a8dfSMichael Tuexen sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); 604c79bec9cSMichael Tuexen memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo)); 6057f15a8dfSMichael Tuexen sinfo->sinfo_stream = stream_no; 6067f15a8dfSMichael Tuexen sinfo->sinfo_ssn = 0; 6077f15a8dfSMichael Tuexen sinfo->sinfo_flags = flags; 6087f15a8dfSMichael Tuexen sinfo->sinfo_ppid = ppid; 6097f15a8dfSMichael Tuexen sinfo->sinfo_context = context; 6107f15a8dfSMichael Tuexen sinfo->sinfo_assoc_id = 0; 6117f15a8dfSMichael Tuexen sinfo->sinfo_timetolive = timetolive; 6127f15a8dfSMichael Tuexen return (sendmsg(s, &msg, 0)); 613d6dda9b2SRandall Stewart #endif 614d6dda9b2SRandall Stewart } 615d6dda9b2SRandall Stewart 616d6dda9b2SRandall Stewart 617d6dda9b2SRandall Stewart sctp_assoc_t 618d6dda9b2SRandall Stewart sctp_getassocid(int sd, struct sockaddr *sa) 619d6dda9b2SRandall Stewart { 620b54d3a6cSRandall Stewart struct sctp_paddrinfo sp; 621066f54d8SCraig Rodrigues socklen_t siz; 622d6dda9b2SRandall Stewart 623d6dda9b2SRandall Stewart /* First get the assoc id */ 624b54d3a6cSRandall Stewart siz = sizeof(sp); 625d6dda9b2SRandall Stewart memset(&sp, 0, sizeof(sp)); 626b54d3a6cSRandall Stewart memcpy((caddr_t)&sp.spinfo_address, sa, sa->sa_len); 627d6dda9b2SRandall Stewart if (getsockopt(sd, IPPROTO_SCTP, 628b54d3a6cSRandall Stewart SCTP_GET_PEER_ADDR_INFO, &sp, &siz) != 0) { 6297f15a8dfSMichael Tuexen /* We depend on the fact that 0 can never be returned */ 630d6dda9b2SRandall Stewart return ((sctp_assoc_t)0); 631d6dda9b2SRandall Stewart } 632b54d3a6cSRandall Stewart return (sp.spinfo_assoc_id); 633d6dda9b2SRandall Stewart } 634d6dda9b2SRandall Stewart 635d6dda9b2SRandall Stewart ssize_t 636d6dda9b2SRandall Stewart sctp_send(int sd, const void *data, size_t len, 637d6dda9b2SRandall Stewart const struct sctp_sndrcvinfo *sinfo, 638d6dda9b2SRandall Stewart int flags) 639d6dda9b2SRandall Stewart { 640d6dda9b2SRandall Stewart 641d6dda9b2SRandall Stewart #ifdef SYS_sctp_generic_sendmsg 642d6dda9b2SRandall Stewart struct sockaddr *to = NULL; 643d6dda9b2SRandall Stewart 644d6dda9b2SRandall Stewart return (syscall(SYS_sctp_generic_sendmsg, sd, 645d6dda9b2SRandall Stewart data, len, to, 0, sinfo, flags)); 646d6dda9b2SRandall Stewart #else 647d6dda9b2SRandall Stewart struct msghdr msg; 64848f65f00SMichael Tuexen struct iovec iov; 6497f15a8dfSMichael Tuexen char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; 650d6dda9b2SRandall Stewart struct cmsghdr *cmsg; 651d6dda9b2SRandall Stewart 652d6dda9b2SRandall Stewart if (sinfo == NULL) { 653b54d3a6cSRandall Stewart errno = EINVAL; 654b54d3a6cSRandall Stewart return (-1); 655d6dda9b2SRandall Stewart } 65648f65f00SMichael Tuexen iov.iov_base = (char *)data; 65748f65f00SMichael Tuexen iov.iov_len = len; 658d6dda9b2SRandall Stewart 6597f15a8dfSMichael Tuexen msg.msg_name = NULL; 660d6dda9b2SRandall Stewart msg.msg_namelen = 0; 66148f65f00SMichael Tuexen msg.msg_iov = &iov; 662d6dda9b2SRandall Stewart msg.msg_iovlen = 1; 6637f15a8dfSMichael Tuexen msg.msg_control = cmsgbuf; 6647f15a8dfSMichael Tuexen msg.msg_controllen = CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); 6652b8a4d80SMichael Tuexen msg.msg_flags = 0; 6667f15a8dfSMichael Tuexen cmsg = (struct cmsghdr *)cmsgbuf; 667d6dda9b2SRandall Stewart cmsg->cmsg_level = IPPROTO_SCTP; 668d6dda9b2SRandall Stewart cmsg->cmsg_type = SCTP_SNDRCV; 669d6dda9b2SRandall Stewart cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 6707f15a8dfSMichael Tuexen memcpy(CMSG_DATA(cmsg), sinfo, sizeof(struct sctp_sndrcvinfo)); 6717f15a8dfSMichael Tuexen return (sendmsg(sd, &msg, flags)); 672d6dda9b2SRandall Stewart #endif 673d6dda9b2SRandall Stewart } 674d6dda9b2SRandall Stewart 675d6dda9b2SRandall Stewart 676d6dda9b2SRandall Stewart 677d6dda9b2SRandall Stewart ssize_t 678d6dda9b2SRandall Stewart sctp_sendx(int sd, const void *msg, size_t msg_len, 679d6dda9b2SRandall Stewart struct sockaddr *addrs, int addrcnt, 680d6dda9b2SRandall Stewart struct sctp_sndrcvinfo *sinfo, 681d6dda9b2SRandall Stewart int flags) 682d6dda9b2SRandall Stewart { 683335a2d00SRandall Stewart struct sctp_sndrcvinfo __sinfo; 684d6dda9b2SRandall Stewart ssize_t ret; 685d6dda9b2SRandall Stewart int i, cnt, *aa, saved_errno; 686d6dda9b2SRandall Stewart char *buf; 6875dc6a815SMichael Tuexen int no_end_cx = 0; 6885dc6a815SMichael Tuexen size_t len, add_len; 689d6dda9b2SRandall Stewart struct sockaddr *at; 690d6dda9b2SRandall Stewart 6911b649582SRandall Stewart if (addrs == NULL) { 6921b649582SRandall Stewart errno = EINVAL; 6931b649582SRandall Stewart return (-1); 6941b649582SRandall Stewart } 695804cf641SRandall Stewart #ifdef SYS_sctp_generic_sendmsg 69648f65f00SMichael Tuexen if (addrcnt == 1) { 697804cf641SRandall Stewart socklen_t l; 69832d0a77dSMichael Tuexen ssize_t ret; 699804cf641SRandall Stewart 700804cf641SRandall Stewart /* 701804cf641SRandall Stewart * Quick way, we don't need to do a connectx so lets use the 702804cf641SRandall Stewart * syscall directly. 703804cf641SRandall Stewart */ 704804cf641SRandall Stewart l = addrs->sa_len; 70532d0a77dSMichael Tuexen ret = syscall(SYS_sctp_generic_sendmsg, sd, 70632d0a77dSMichael Tuexen msg, msg_len, addrs, l, sinfo, flags); 70732d0a77dSMichael Tuexen if ((ret >= 0) && (sinfo != NULL)) { 70832d0a77dSMichael Tuexen sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs); 70932d0a77dSMichael Tuexen } 71032d0a77dSMichael Tuexen return (ret); 711804cf641SRandall Stewart } 712804cf641SRandall Stewart #endif 713b54d3a6cSRandall Stewart 714d6dda9b2SRandall Stewart len = sizeof(int); 715d6dda9b2SRandall Stewart at = addrs; 716d6dda9b2SRandall Stewart cnt = 0; 717d6dda9b2SRandall Stewart /* validate all the addresses and get the size */ 718d6dda9b2SRandall Stewart for (i = 0; i < addrcnt; i++) { 719d6dda9b2SRandall Stewart if (at->sa_family == AF_INET) { 720d6dda9b2SRandall Stewart add_len = sizeof(struct sockaddr_in); 721d6dda9b2SRandall Stewart } else if (at->sa_family == AF_INET6) { 722d6dda9b2SRandall Stewart add_len = sizeof(struct sockaddr_in6); 723d6dda9b2SRandall Stewart } else { 724d6dda9b2SRandall Stewart errno = EINVAL; 725d6dda9b2SRandall Stewart return (-1); 726d6dda9b2SRandall Stewart } 727d6dda9b2SRandall Stewart len += add_len; 728d6dda9b2SRandall Stewart at = (struct sockaddr *)((caddr_t)at + add_len); 729d6dda9b2SRandall Stewart cnt++; 730d6dda9b2SRandall Stewart } 731d6dda9b2SRandall Stewart /* do we have any? */ 732d6dda9b2SRandall Stewart if (cnt == 0) { 733d6dda9b2SRandall Stewart errno = EINVAL; 734d6dda9b2SRandall Stewart return (-1); 735d6dda9b2SRandall Stewart } 736d6dda9b2SRandall Stewart buf = malloc(len); 737d6dda9b2SRandall Stewart if (buf == NULL) { 7384ed0ebf6SMichael Tuexen errno = ENOMEM; 739b54d3a6cSRandall Stewart return (-1); 740d6dda9b2SRandall Stewart } 741d6dda9b2SRandall Stewart aa = (int *)buf; 742d6dda9b2SRandall Stewart *aa = cnt; 743d6dda9b2SRandall Stewart aa++; 7445dc6a815SMichael Tuexen memcpy((caddr_t)aa, addrs, (size_t)(len - sizeof(int))); 745d6dda9b2SRandall Stewart ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_DELAYED, (void *)buf, 746d6dda9b2SRandall Stewart (socklen_t)len); 747d6dda9b2SRandall Stewart 748d6dda9b2SRandall Stewart free(buf); 749d6dda9b2SRandall Stewart if (ret != 0) { 750d6dda9b2SRandall Stewart if (errno == EALREADY) { 751ecf4b67aSRebecca Cran no_end_cx = 1; 752d6dda9b2SRandall Stewart goto continue_send; 753d6dda9b2SRandall Stewart } 754d6dda9b2SRandall Stewart return (ret); 755d6dda9b2SRandall Stewart } 756d6dda9b2SRandall Stewart continue_send: 757335a2d00SRandall Stewart if (sinfo == NULL) { 758335a2d00SRandall Stewart sinfo = &__sinfo; 759335a2d00SRandall Stewart memset(&__sinfo, 0, sizeof(__sinfo)); 760335a2d00SRandall Stewart } 761d6dda9b2SRandall Stewart sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs); 762d6dda9b2SRandall Stewart if (sinfo->sinfo_assoc_id == 0) { 763d6dda9b2SRandall Stewart (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs, 764d6dda9b2SRandall Stewart (socklen_t)addrs->sa_len); 765d6dda9b2SRandall Stewart errno = ENOENT; 766d6dda9b2SRandall Stewart return (-1); 767d6dda9b2SRandall Stewart } 768d6dda9b2SRandall Stewart ret = sctp_send(sd, msg, msg_len, sinfo, flags); 769d6dda9b2SRandall Stewart saved_errno = errno; 770d6dda9b2SRandall Stewart if (no_end_cx == 0) 771d6dda9b2SRandall Stewart (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs, 772d6dda9b2SRandall Stewart (socklen_t)addrs->sa_len); 773d6dda9b2SRandall Stewart 774d6dda9b2SRandall Stewart errno = saved_errno; 775d6dda9b2SRandall Stewart return (ret); 776d6dda9b2SRandall Stewart } 777d6dda9b2SRandall Stewart 778d6dda9b2SRandall Stewart ssize_t 779d6dda9b2SRandall Stewart sctp_sendmsgx(int sd, 780d6dda9b2SRandall Stewart const void *msg, 781d6dda9b2SRandall Stewart size_t len, 782d6dda9b2SRandall Stewart struct sockaddr *addrs, 783d6dda9b2SRandall Stewart int addrcnt, 7843d36ac98SRebecca Cran uint32_t ppid, 7853d36ac98SRebecca Cran uint32_t flags, 7863d36ac98SRebecca Cran uint16_t stream_no, 7873d36ac98SRebecca Cran uint32_t timetolive, 7883d36ac98SRebecca Cran uint32_t context) 789d6dda9b2SRandall Stewart { 790d6dda9b2SRandall Stewart struct sctp_sndrcvinfo sinfo; 791d6dda9b2SRandall Stewart 792d6dda9b2SRandall Stewart memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo)); 793d6dda9b2SRandall Stewart sinfo.sinfo_ppid = ppid; 794d6dda9b2SRandall Stewart sinfo.sinfo_flags = flags; 795159efc33SMichael Tuexen sinfo.sinfo_stream = stream_no; 796d6dda9b2SRandall Stewart sinfo.sinfo_timetolive = timetolive; 797d6dda9b2SRandall Stewart sinfo.sinfo_context = context; 7984224e03aSMichael Tuexen return (sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0)); 799d6dda9b2SRandall Stewart } 800d6dda9b2SRandall Stewart 801d6dda9b2SRandall Stewart ssize_t 802d6dda9b2SRandall Stewart sctp_recvmsg(int s, 803d6dda9b2SRandall Stewart void *dbuf, 804d6dda9b2SRandall Stewart size_t len, 805d6dda9b2SRandall Stewart struct sockaddr *from, 806d6dda9b2SRandall Stewart socklen_t *fromlen, 807d6dda9b2SRandall Stewart struct sctp_sndrcvinfo *sinfo, 808d6dda9b2SRandall Stewart int *msg_flags) 809d6dda9b2SRandall Stewart { 810d6dda9b2SRandall Stewart #ifdef SYS_sctp_generic_recvmsg 81148f65f00SMichael Tuexen struct iovec iov; 812d6dda9b2SRandall Stewart 81348f65f00SMichael Tuexen iov.iov_base = dbuf; 81448f65f00SMichael Tuexen iov.iov_len = len; 815d6dda9b2SRandall Stewart return (syscall(SYS_sctp_generic_recvmsg, s, 81648f65f00SMichael Tuexen &iov, 1, from, fromlen, sinfo, msg_flags)); 817d6dda9b2SRandall Stewart #else 818d6dda9b2SRandall Stewart ssize_t sz; 819d6dda9b2SRandall Stewart struct msghdr msg; 82048f65f00SMichael Tuexen struct iovec iov; 8217f15a8dfSMichael Tuexen char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV]; 822d6dda9b2SRandall Stewart struct cmsghdr *cmsg; 823d6dda9b2SRandall Stewart 824d6dda9b2SRandall Stewart if (msg_flags == NULL) { 825d6dda9b2SRandall Stewart errno = EINVAL; 826d6dda9b2SRandall Stewart return (-1); 827d6dda9b2SRandall Stewart } 82848f65f00SMichael Tuexen iov.iov_base = dbuf; 82948f65f00SMichael Tuexen iov.iov_len = len; 830d6dda9b2SRandall Stewart msg.msg_name = (caddr_t)from; 831d6dda9b2SRandall Stewart if (fromlen == NULL) 832d6dda9b2SRandall Stewart msg.msg_namelen = 0; 833d6dda9b2SRandall Stewart else 834d6dda9b2SRandall Stewart msg.msg_namelen = *fromlen; 83548f65f00SMichael Tuexen msg.msg_iov = &iov; 836d6dda9b2SRandall Stewart msg.msg_iovlen = 1; 8377f15a8dfSMichael Tuexen msg.msg_control = cmsgbuf; 8387f15a8dfSMichael Tuexen msg.msg_controllen = sizeof(cmsgbuf); 8392b8a4d80SMichael Tuexen msg.msg_flags = 0; 8402c356be2SRandall Stewart sz = recvmsg(s, &msg, *msg_flags); 84148f65f00SMichael Tuexen *msg_flags = msg.msg_flags; 84248f65f00SMichael Tuexen if (sz <= 0) { 843d6dda9b2SRandall Stewart return (sz); 84448f65f00SMichael Tuexen } 84548f65f00SMichael Tuexen if (sinfo) { 846d6dda9b2SRandall Stewart sinfo->sinfo_assoc_id = 0; 84748f65f00SMichael Tuexen } 8487f15a8dfSMichael Tuexen if ((msg.msg_controllen > 0) && (sinfo != NULL)) { 849d6dda9b2SRandall Stewart /* 850d6dda9b2SRandall Stewart * parse through and see if we find the sctp_sndrcvinfo (if 851d6dda9b2SRandall Stewart * the user wants it). 852d6dda9b2SRandall Stewart */ 8537f15a8dfSMichael Tuexen for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 8547f15a8dfSMichael Tuexen if (cmsg->cmsg_level != IPPROTO_SCTP) { 8557f15a8dfSMichael Tuexen continue; 856d6dda9b2SRandall Stewart } 857d6dda9b2SRandall Stewart if (cmsg->cmsg_type == SCTP_SNDRCV) { 8587f15a8dfSMichael Tuexen memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_sndrcvinfo)); 859d6dda9b2SRandall Stewart break; 8607f15a8dfSMichael Tuexen } 8617f15a8dfSMichael Tuexen if (cmsg->cmsg_type == SCTP_EXTRCV) { 862d6dda9b2SRandall Stewart /* 8637f15a8dfSMichael Tuexen * Let's hope that the user provided enough 8647f15a8dfSMichael Tuexen * enough memory. At least he asked for more 8657f15a8dfSMichael Tuexen * information. 866d6dda9b2SRandall Stewart */ 8677f15a8dfSMichael Tuexen memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_extrcvinfo)); 868d6dda9b2SRandall Stewart break; 869d6dda9b2SRandall Stewart } 870d6dda9b2SRandall Stewart } 871d6dda9b2SRandall Stewart } 872d6dda9b2SRandall Stewart return (sz); 873d6dda9b2SRandall Stewart #endif 874d6dda9b2SRandall Stewart } 875d6dda9b2SRandall Stewart 876e2e7c62eSMichael Tuexen ssize_t 877e2e7c62eSMichael Tuexen sctp_recvv(int sd, 878e2e7c62eSMichael Tuexen const struct iovec *iov, 879e2e7c62eSMichael Tuexen int iovlen, 880e2e7c62eSMichael Tuexen struct sockaddr *from, 881e2e7c62eSMichael Tuexen socklen_t *fromlen, 882e2e7c62eSMichael Tuexen void *info, 883e2e7c62eSMichael Tuexen socklen_t *infolen, 884e2e7c62eSMichael Tuexen unsigned int *infotype, 885e2e7c62eSMichael Tuexen int *flags) 886d6dda9b2SRandall Stewart { 8877f15a8dfSMichael Tuexen char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV]; 888e2e7c62eSMichael Tuexen struct msghdr msg; 889e2e7c62eSMichael Tuexen struct cmsghdr *cmsg; 8907f15a8dfSMichael Tuexen ssize_t ret; 891e2e7c62eSMichael Tuexen struct sctp_rcvinfo *rcvinfo; 892e2e7c62eSMichael Tuexen struct sctp_nxtinfo *nxtinfo; 893d6dda9b2SRandall Stewart 8940d958bd4SMichael Tuexen if (((info != NULL) && (infolen == NULL)) || 8950b064106SMichael Tuexen ((info == NULL) && (infolen != NULL) && (*infolen != 0)) || 8960b064106SMichael Tuexen ((info != NULL) && (infotype == NULL))) { 8970b064106SMichael Tuexen errno = EINVAL; 8980b064106SMichael Tuexen return (-1); 8990b064106SMichael Tuexen } 900e2e7c62eSMichael Tuexen if (infotype) { 901e2e7c62eSMichael Tuexen *infotype = SCTP_RECVV_NOINFO; 902e2e7c62eSMichael Tuexen } 903e2e7c62eSMichael Tuexen msg.msg_name = from; 904e2e7c62eSMichael Tuexen if (fromlen == NULL) { 905e2e7c62eSMichael Tuexen msg.msg_namelen = 0; 906d6dda9b2SRandall Stewart } else { 907e2e7c62eSMichael Tuexen msg.msg_namelen = *fromlen; 908d6dda9b2SRandall Stewart } 909e2e7c62eSMichael Tuexen msg.msg_iov = (struct iovec *)iov; 910e2e7c62eSMichael Tuexen msg.msg_iovlen = iovlen; 9117f15a8dfSMichael Tuexen msg.msg_control = cmsgbuf; 9127f15a8dfSMichael Tuexen msg.msg_controllen = sizeof(cmsgbuf); 9132b8a4d80SMichael Tuexen msg.msg_flags = 0; 9147f15a8dfSMichael Tuexen ret = recvmsg(sd, &msg, *flags); 915e2e7c62eSMichael Tuexen *flags = msg.msg_flags; 9167f15a8dfSMichael Tuexen if ((ret > 0) && 917e2e7c62eSMichael Tuexen (msg.msg_controllen > 0) && 918e2e7c62eSMichael Tuexen (infotype != NULL) && 919e2e7c62eSMichael Tuexen (infolen != NULL) && 920e2e7c62eSMichael Tuexen (*infolen > 0)) { 921e2e7c62eSMichael Tuexen rcvinfo = NULL; 922e2e7c62eSMichael Tuexen nxtinfo = NULL; 923e2e7c62eSMichael Tuexen for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 924e2e7c62eSMichael Tuexen if (cmsg->cmsg_level != IPPROTO_SCTP) { 925e2e7c62eSMichael Tuexen continue; 926e2e7c62eSMichael Tuexen } 927e2e7c62eSMichael Tuexen if (cmsg->cmsg_type == SCTP_RCVINFO) { 928e2e7c62eSMichael Tuexen rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg); 9297f15a8dfSMichael Tuexen if (nxtinfo != NULL) { 9307f15a8dfSMichael Tuexen break; 9317f15a8dfSMichael Tuexen } else { 9327f15a8dfSMichael Tuexen continue; 9337f15a8dfSMichael Tuexen } 934e2e7c62eSMichael Tuexen } 935e2e7c62eSMichael Tuexen if (cmsg->cmsg_type == SCTP_NXTINFO) { 936e2e7c62eSMichael Tuexen nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg); 9377f15a8dfSMichael Tuexen if (rcvinfo != NULL) { 938e2e7c62eSMichael Tuexen break; 9397f15a8dfSMichael Tuexen } else { 9407f15a8dfSMichael Tuexen continue; 941e2e7c62eSMichael Tuexen } 942e2e7c62eSMichael Tuexen } 9437f15a8dfSMichael Tuexen } 9447f15a8dfSMichael Tuexen if (rcvinfo != NULL) { 9457f15a8dfSMichael Tuexen if ((nxtinfo != NULL) && (*infolen >= sizeof(struct sctp_recvv_rn))) { 946e2e7c62eSMichael Tuexen struct sctp_recvv_rn *rn_info; 947e2e7c62eSMichael Tuexen 948e2e7c62eSMichael Tuexen rn_info = (struct sctp_recvv_rn *)info; 949e2e7c62eSMichael Tuexen rn_info->recvv_rcvinfo = *rcvinfo; 950e2e7c62eSMichael Tuexen rn_info->recvv_nxtinfo = *nxtinfo; 951e2e7c62eSMichael Tuexen *infolen = (socklen_t)sizeof(struct sctp_recvv_rn); 952e2e7c62eSMichael Tuexen *infotype = SCTP_RECVV_RN; 9537f15a8dfSMichael Tuexen } else if (*infolen >= sizeof(struct sctp_rcvinfo)) { 954e2e7c62eSMichael Tuexen memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo)); 955e2e7c62eSMichael Tuexen *infolen = (socklen_t)sizeof(struct sctp_rcvinfo); 956e2e7c62eSMichael Tuexen *infotype = SCTP_RECVV_RCVINFO; 957e2e7c62eSMichael Tuexen } 9587f15a8dfSMichael Tuexen } else if (nxtinfo != NULL) { 9597f15a8dfSMichael Tuexen if (*infolen >= sizeof(struct sctp_nxtinfo)) { 960e2e7c62eSMichael Tuexen memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo)); 961e2e7c62eSMichael Tuexen *infolen = (socklen_t)sizeof(struct sctp_nxtinfo); 962e2e7c62eSMichael Tuexen *infotype = SCTP_RECVV_NXTINFO; 963e2e7c62eSMichael Tuexen } 964e2e7c62eSMichael Tuexen } 965e2e7c62eSMichael Tuexen } 9667f15a8dfSMichael Tuexen return (ret); 967d6dda9b2SRandall Stewart } 968d6dda9b2SRandall Stewart 969e2e7c62eSMichael Tuexen ssize_t 970e2e7c62eSMichael Tuexen sctp_sendv(int sd, 971e2e7c62eSMichael Tuexen const struct iovec *iov, int iovcnt, 972e2e7c62eSMichael Tuexen struct sockaddr *addrs, int addrcnt, 973e2e7c62eSMichael Tuexen void *info, socklen_t infolen, unsigned int infotype, 974e2e7c62eSMichael Tuexen int flags) 975e2e7c62eSMichael Tuexen { 976e2e7c62eSMichael Tuexen ssize_t ret; 977e2e7c62eSMichael Tuexen int i; 9780b064106SMichael Tuexen socklen_t addr_len; 979e2e7c62eSMichael Tuexen struct msghdr msg; 9800b064106SMichael Tuexen in_port_t port; 9810b064106SMichael Tuexen struct sctp_sendv_spa *spa_info; 982e2e7c62eSMichael Tuexen struct cmsghdr *cmsg; 983e2e7c62eSMichael Tuexen char *cmsgbuf; 984e2e7c62eSMichael Tuexen struct sockaddr *addr; 985e2e7c62eSMichael Tuexen struct sockaddr_in *addr_in; 986e2e7c62eSMichael Tuexen struct sockaddr_in6 *addr_in6; 987c7f6ce28SMichael Tuexen sctp_assoc_t *assoc_id; 988e2e7c62eSMichael Tuexen 9890b064106SMichael Tuexen if ((addrcnt < 0) || 9900b064106SMichael Tuexen (iovcnt < 0) || 991c67a03f9SMichael Tuexen ((addrs == NULL) && (addrcnt > 0)) || 992c67a03f9SMichael Tuexen ((addrs != NULL) && (addrcnt == 0)) || 9930b064106SMichael Tuexen ((iov == NULL) && (iovcnt > 0)) || 9940b064106SMichael Tuexen ((iov != NULL) && (iovcnt == 0))) { 995e2e7c62eSMichael Tuexen errno = EINVAL; 996e2e7c62eSMichael Tuexen return (-1); 997e2e7c62eSMichael Tuexen } 998e2e7c62eSMichael Tuexen cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) + 999e2e7c62eSMichael Tuexen CMSG_SPACE(sizeof(struct sctp_prinfo)) + 1000e2e7c62eSMichael Tuexen CMSG_SPACE(sizeof(struct sctp_authinfo)) + 10015dc6a815SMichael Tuexen (size_t)addrcnt * CMSG_SPACE(sizeof(struct in6_addr))); 1002e2e7c62eSMichael Tuexen if (cmsgbuf == NULL) { 10034ed0ebf6SMichael Tuexen errno = ENOMEM; 1004e2e7c62eSMichael Tuexen return (-1); 1005e2e7c62eSMichael Tuexen } 1006c7f6ce28SMichael Tuexen assoc_id = NULL; 1007e2e7c62eSMichael Tuexen msg.msg_control = cmsgbuf; 1008e2e7c62eSMichael Tuexen msg.msg_controllen = 0; 1009e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)cmsgbuf; 1010e2e7c62eSMichael Tuexen switch (infotype) { 10110b064106SMichael Tuexen case SCTP_SENDV_NOINFO: 10120b064106SMichael Tuexen if ((infolen != 0) || (info != NULL)) { 10130b064106SMichael Tuexen free(cmsgbuf); 10140b064106SMichael Tuexen errno = EINVAL; 10150b064106SMichael Tuexen return (-1); 10160b064106SMichael Tuexen } 10170b064106SMichael Tuexen break; 1018e2e7c62eSMichael Tuexen case SCTP_SENDV_SNDINFO: 10190b064106SMichael Tuexen if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) { 1020e2e7c62eSMichael Tuexen free(cmsgbuf); 1021e2e7c62eSMichael Tuexen errno = EINVAL; 1022e2e7c62eSMichael Tuexen return (-1); 1023e2e7c62eSMichael Tuexen } 1024e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1025e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_SNDINFO; 1026e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); 1027e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo)); 1028e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); 1029e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); 1030c7f6ce28SMichael Tuexen assoc_id = &(((struct sctp_sndinfo *)info)->snd_assoc_id); 1031e2e7c62eSMichael Tuexen break; 1032e2e7c62eSMichael Tuexen case SCTP_SENDV_PRINFO: 10330b064106SMichael Tuexen if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) { 1034e2e7c62eSMichael Tuexen free(cmsgbuf); 1035e2e7c62eSMichael Tuexen errno = EINVAL; 1036e2e7c62eSMichael Tuexen return (-1); 1037e2e7c62eSMichael Tuexen } 1038e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1039e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_PRINFO; 1040e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); 1041e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo)); 1042e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); 1043e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo))); 1044e2e7c62eSMichael Tuexen break; 1045e2e7c62eSMichael Tuexen case SCTP_SENDV_AUTHINFO: 10460b064106SMichael Tuexen if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) { 1047e2e7c62eSMichael Tuexen free(cmsgbuf); 1048e2e7c62eSMichael Tuexen errno = EINVAL; 1049e2e7c62eSMichael Tuexen return (-1); 1050e2e7c62eSMichael Tuexen } 1051e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1052e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_AUTHINFO; 1053e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo)); 1054e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo)); 1055e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo)); 1056e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo))); 1057e2e7c62eSMichael Tuexen break; 1058e2e7c62eSMichael Tuexen case SCTP_SENDV_SPA: 10590b064106SMichael Tuexen if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) { 1060e2e7c62eSMichael Tuexen free(cmsgbuf); 1061e2e7c62eSMichael Tuexen errno = EINVAL; 1062e2e7c62eSMichael Tuexen return (-1); 1063e2e7c62eSMichael Tuexen } 1064e2e7c62eSMichael Tuexen spa_info = (struct sctp_sendv_spa *)info; 1065e2e7c62eSMichael Tuexen if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) { 1066e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1067e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_SNDINFO; 1068e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); 1069e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo)); 1070e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); 1071e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); 1072c7f6ce28SMichael Tuexen assoc_id = &(spa_info->sendv_sndinfo.snd_assoc_id); 1073e2e7c62eSMichael Tuexen } 1074e2e7c62eSMichael Tuexen if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) { 1075e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1076e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_PRINFO; 1077e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); 1078e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo)); 1079e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); 1080e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo))); 1081e2e7c62eSMichael Tuexen } 1082e2e7c62eSMichael Tuexen if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) { 1083e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1084e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_AUTHINFO; 1085e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo)); 1086e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo)); 1087e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo)); 1088e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo))); 1089e2e7c62eSMichael Tuexen } 1090e2e7c62eSMichael Tuexen break; 1091e2e7c62eSMichael Tuexen default: 1092e2e7c62eSMichael Tuexen free(cmsgbuf); 1093e2e7c62eSMichael Tuexen errno = EINVAL; 1094e2e7c62eSMichael Tuexen return (-1); 1095e2e7c62eSMichael Tuexen } 1096e2e7c62eSMichael Tuexen addr = addrs; 10970b064106SMichael Tuexen msg.msg_name = NULL; 10980b064106SMichael Tuexen msg.msg_namelen = 0; 10990b064106SMichael Tuexen 11000b064106SMichael Tuexen for (i = 0; i < addrcnt; i++) { 1101e2e7c62eSMichael Tuexen switch (addr->sa_family) { 1102e2e7c62eSMichael Tuexen case AF_INET: 11030b064106SMichael Tuexen addr_len = (socklen_t)sizeof(struct sockaddr_in); 11040b064106SMichael Tuexen addr_in = (struct sockaddr_in *)addr; 11050b064106SMichael Tuexen if (addr_in->sin_len != addr_len) { 1106e2e7c62eSMichael Tuexen free(cmsgbuf); 1107e2e7c62eSMichael Tuexen errno = EINVAL; 1108e2e7c62eSMichael Tuexen return (-1); 1109e2e7c62eSMichael Tuexen } 11100b064106SMichael Tuexen if (i == 0) { 11110b064106SMichael Tuexen port = addr_in->sin_port; 1112e2e7c62eSMichael Tuexen } else { 11130b064106SMichael Tuexen if (port == addr_in->sin_port) { 1114e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1115e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_DSTADDRV4; 1116e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); 1117e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr)); 1118e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr)); 1119e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr))); 11200b064106SMichael Tuexen } else { 11210b064106SMichael Tuexen free(cmsgbuf); 11220b064106SMichael Tuexen errno = EINVAL; 11230b064106SMichael Tuexen return (-1); 11240b064106SMichael Tuexen } 11250b064106SMichael Tuexen } 1126e2e7c62eSMichael Tuexen break; 1127e2e7c62eSMichael Tuexen case AF_INET6: 11280b064106SMichael Tuexen addr_len = (socklen_t)sizeof(struct sockaddr_in6); 1129e2e7c62eSMichael Tuexen addr_in6 = (struct sockaddr_in6 *)addr; 11300b064106SMichael Tuexen if (addr_in6->sin6_len != addr_len) { 11310b064106SMichael Tuexen free(cmsgbuf); 11320b064106SMichael Tuexen errno = EINVAL; 11330b064106SMichael Tuexen return (-1); 11340b064106SMichael Tuexen } 11350b064106SMichael Tuexen if (i == 0) { 11360b064106SMichael Tuexen port = addr_in6->sin6_port; 11370b064106SMichael Tuexen } else { 11380b064106SMichael Tuexen if (port == addr_in6->sin6_port) { 1139e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1140e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_DSTADDRV6; 1141e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr)); 1142e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr)); 1143e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr)); 1144e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr))); 11450b064106SMichael Tuexen } else { 11460b064106SMichael Tuexen free(cmsgbuf); 11470b064106SMichael Tuexen errno = EINVAL; 11480b064106SMichael Tuexen return (-1); 11490b064106SMichael Tuexen } 11500b064106SMichael Tuexen } 1151e2e7c62eSMichael Tuexen break; 1152e2e7c62eSMichael Tuexen default: 1153e2e7c62eSMichael Tuexen free(cmsgbuf); 1154e2e7c62eSMichael Tuexen errno = EINVAL; 1155e2e7c62eSMichael Tuexen return (-1); 1156e2e7c62eSMichael Tuexen } 11570b064106SMichael Tuexen if (i == 0) { 11580b064106SMichael Tuexen msg.msg_name = addr; 11590b064106SMichael Tuexen msg.msg_namelen = addr_len; 11600b064106SMichael Tuexen } 1161e2e7c62eSMichael Tuexen addr = (struct sockaddr *)((caddr_t)addr + addr_len); 1162e2e7c62eSMichael Tuexen } 11630b064106SMichael Tuexen if (msg.msg_controllen == 0) { 11640b064106SMichael Tuexen msg.msg_control = NULL; 1165e2e7c62eSMichael Tuexen } 1166e2e7c62eSMichael Tuexen msg.msg_iov = (struct iovec *)iov; 1167e2e7c62eSMichael Tuexen msg.msg_iovlen = iovcnt; 1168e2e7c62eSMichael Tuexen msg.msg_flags = 0; 1169e2e7c62eSMichael Tuexen ret = sendmsg(sd, &msg, flags); 1170e2e7c62eSMichael Tuexen free(cmsgbuf); 1171c7f6ce28SMichael Tuexen if ((ret >= 0) && (addrs != NULL) && (assoc_id != NULL)) { 1172c7f6ce28SMichael Tuexen *assoc_id = sctp_getassocid(sd, addrs); 1173c7f6ce28SMichael Tuexen } 1174e2e7c62eSMichael Tuexen return (ret); 1175e2e7c62eSMichael Tuexen } 1176e2e7c62eSMichael Tuexen 1177d6dda9b2SRandall Stewart 1178d6dda9b2SRandall Stewart #if !defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT) 1179d6dda9b2SRandall Stewart 1180d6dda9b2SRandall Stewart int 1181d6dda9b2SRandall Stewart sctp_peeloff(int sd, sctp_assoc_t assoc_id) 1182d6dda9b2SRandall Stewart { 1183d6dda9b2SRandall Stewart /* NOT supported, return invalid sd */ 1184d6dda9b2SRandall Stewart errno = ENOTSUP; 1185d6dda9b2SRandall Stewart return (-1); 1186d6dda9b2SRandall Stewart } 1187d6dda9b2SRandall Stewart 1188d6dda9b2SRandall Stewart #endif 1189d6dda9b2SRandall Stewart #if defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT) 1190d6dda9b2SRandall Stewart int 1191d6dda9b2SRandall Stewart sctp_peeloff(int sd, sctp_assoc_t assoc_id) 1192d6dda9b2SRandall Stewart { 1193d6dda9b2SRandall Stewart return (syscall(SYS_sctp_peeloff, sd, assoc_id)); 1194d6dda9b2SRandall Stewart } 1195d6dda9b2SRandall Stewart 1196d6dda9b2SRandall Stewart #endif 1197804cf641SRandall Stewart 11982c0d559dSRandall Stewart #undef SCTP_CONTROL_VEC_SIZE_RCV 1199