148f65f00SMichael Tuexen /*- 248f65f00SMichael Tuexen * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 348f65f00SMichael Tuexen * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved. 448f65f00SMichael Tuexen * Copyright (c) 2008-2011, 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$"); 35d6dda9b2SRandall Stewart #include <stdio.h> 36d6dda9b2SRandall Stewart #include <string.h> 37d6dda9b2SRandall Stewart #include <errno.h> 38d6dda9b2SRandall Stewart #include <stdlib.h> 39d6dda9b2SRandall Stewart #include <unistd.h> 40d6dda9b2SRandall Stewart #include <sys/types.h> 41d6dda9b2SRandall Stewart #include <sys/socket.h> 42d6dda9b2SRandall Stewart #include <sys/errno.h> 43d6dda9b2SRandall Stewart #include <sys/syscall.h> 44d6dda9b2SRandall Stewart #include <sys/uio.h> 45d6dda9b2SRandall Stewart #include <netinet/in.h> 46d6dda9b2SRandall Stewart #include <arpa/inet.h> 47d6dda9b2SRandall Stewart #include <netinet/sctp_uio.h> 48d6dda9b2SRandall Stewart #include <netinet/sctp.h> 49d6dda9b2SRandall Stewart 50d6dda9b2SRandall Stewart #include <net/if_dl.h> 51d6dda9b2SRandall Stewart 52d6dda9b2SRandall Stewart #ifndef IN6_IS_ADDR_V4MAPPED 53d6dda9b2SRandall Stewart #define IN6_IS_ADDR_V4MAPPED(a) \ 543d36ac98SRebecca Cran ((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \ 553d36ac98SRebecca Cran (*(const uint32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \ 563d36ac98SRebecca Cran (*(const uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) 57d6dda9b2SRandall Stewart #endif 58d6dda9b2SRandall Stewart 59804cf641SRandall Stewart 60d6dda9b2SRandall Stewart #define SCTP_CONTROL_VEC_SIZE_SND 8192 61d6dda9b2SRandall Stewart #define SCTP_CONTROL_VEC_SIZE_RCV 16384 62804cf641SRandall Stewart #define SCTP_STACK_BUF_SIZE 2048 63d6dda9b2SRandall Stewart 64d6dda9b2SRandall Stewart #ifdef SCTP_DEBUG_PRINT_ADDRESS 65804cf641SRandall Stewart 66804cf641SRandall Stewart #define SCTP_STRING_BUF_SZ 256 67804cf641SRandall Stewart 68d6dda9b2SRandall Stewart static void 69d6dda9b2SRandall Stewart SCTPPrintAnAddress(struct sockaddr *a) 70d6dda9b2SRandall Stewart { 71804cf641SRandall Stewart char stringToPrint[SCTP_STRING_BUF_SZ]; 72d6dda9b2SRandall Stewart u_short prt; 73d6dda9b2SRandall Stewart char *srcaddr, *txt; 74d6dda9b2SRandall Stewart 75d6dda9b2SRandall Stewart if (a == NULL) { 76d6dda9b2SRandall Stewart printf("NULL\n"); 77d6dda9b2SRandall Stewart return; 78d6dda9b2SRandall Stewart } 79d6dda9b2SRandall Stewart if (a->sa_family == AF_INET) { 80d6dda9b2SRandall Stewart srcaddr = (char *)&((struct sockaddr_in *)a)->sin_addr; 81d6dda9b2SRandall Stewart txt = "IPv4 Address: "; 82d6dda9b2SRandall Stewart prt = ntohs(((struct sockaddr_in *)a)->sin_port); 83d6dda9b2SRandall Stewart } else if (a->sa_family == AF_INET6) { 84d6dda9b2SRandall Stewart srcaddr = (char *)&((struct sockaddr_in6 *)a)->sin6_addr; 85d6dda9b2SRandall Stewart prt = ntohs(((struct sockaddr_in6 *)a)->sin6_port); 86d6dda9b2SRandall Stewart txt = "IPv6 Address: "; 87d6dda9b2SRandall Stewart } else if (a->sa_family == AF_LINK) { 88d6dda9b2SRandall Stewart int i; 89804cf641SRandall Stewart char tbuf[SCTP_STRING_BUF_SZ]; 90804cf641SRandall Stewart u_char adbuf[SCTP_STRING_BUF_SZ]; 91d6dda9b2SRandall Stewart struct sockaddr_dl *dl; 92d6dda9b2SRandall Stewart 93d6dda9b2SRandall Stewart dl = (struct sockaddr_dl *)a; 94d6dda9b2SRandall Stewart strncpy(tbuf, dl->sdl_data, dl->sdl_nlen); 95d6dda9b2SRandall Stewart tbuf[dl->sdl_nlen] = 0; 96d6dda9b2SRandall Stewart printf("Intf:%s (len:%d)Interface index:%d type:%x(%d) ll-len:%d ", 97d6dda9b2SRandall Stewart tbuf, 98d6dda9b2SRandall Stewart dl->sdl_nlen, 99d6dda9b2SRandall Stewart dl->sdl_index, 100d6dda9b2SRandall Stewart dl->sdl_type, 101d6dda9b2SRandall Stewart dl->sdl_type, 102d6dda9b2SRandall Stewart dl->sdl_alen 103d6dda9b2SRandall Stewart ); 104d6dda9b2SRandall Stewart memcpy(adbuf, LLADDR(dl), dl->sdl_alen); 105d6dda9b2SRandall Stewart for (i = 0; i < dl->sdl_alen; i++) { 106d6dda9b2SRandall Stewart printf("%2.2x", adbuf[i]); 107d6dda9b2SRandall Stewart if (i < (dl->sdl_alen - 1)) 108d6dda9b2SRandall Stewart printf(":"); 109d6dda9b2SRandall Stewart } 110d6dda9b2SRandall Stewart printf("\n"); 111d6dda9b2SRandall Stewart return; 112d6dda9b2SRandall Stewart } else { 113d6dda9b2SRandall Stewart return; 114d6dda9b2SRandall Stewart } 115d6dda9b2SRandall Stewart if (inet_ntop(a->sa_family, srcaddr, stringToPrint, sizeof(stringToPrint))) { 116d6dda9b2SRandall Stewart if (a->sa_family == AF_INET6) { 117d6dda9b2SRandall Stewart printf("%s%s:%d scope:%d\n", 118d6dda9b2SRandall Stewart txt, stringToPrint, prt, 119d6dda9b2SRandall Stewart ((struct sockaddr_in6 *)a)->sin6_scope_id); 120d6dda9b2SRandall Stewart } else { 121d6dda9b2SRandall Stewart printf("%s%s:%d\n", txt, stringToPrint, prt); 122d6dda9b2SRandall Stewart } 123d6dda9b2SRandall Stewart 124d6dda9b2SRandall Stewart } else { 125d6dda9b2SRandall Stewart printf("%s unprintable?\n", txt); 126d6dda9b2SRandall Stewart } 127d6dda9b2SRandall Stewart } 128d6dda9b2SRandall Stewart 129d6dda9b2SRandall Stewart #endif /* SCTP_DEBUG_PRINT_ADDRESS */ 130d6dda9b2SRandall Stewart 131d6dda9b2SRandall Stewart static void 132d6dda9b2SRandall Stewart in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 133d6dda9b2SRandall Stewart { 134d6dda9b2SRandall Stewart bzero(sin, sizeof(*sin)); 135d6dda9b2SRandall Stewart sin->sin_len = sizeof(struct sockaddr_in); 136d6dda9b2SRandall Stewart sin->sin_family = AF_INET; 137d6dda9b2SRandall Stewart sin->sin_port = sin6->sin6_port; 138d6dda9b2SRandall Stewart sin->sin_addr.s_addr = sin6->sin6_addr.__u6_addr.__u6_addr32[3]; 139d6dda9b2SRandall Stewart } 140d6dda9b2SRandall Stewart 141d6dda9b2SRandall Stewart int 142d6dda9b2SRandall Stewart sctp_getaddrlen(sa_family_t family) 143d6dda9b2SRandall Stewart { 144e2e7c62eSMichael Tuexen int ret, sd; 145d6dda9b2SRandall Stewart socklen_t siz; 146d6dda9b2SRandall Stewart struct sctp_assoc_value av; 147d6dda9b2SRandall Stewart 148d6dda9b2SRandall Stewart av.assoc_value = family; 149d6dda9b2SRandall Stewart siz = sizeof(av); 150d6dda9b2SRandall Stewart #if defined(AF_INET) 151d6dda9b2SRandall Stewart sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 152d6dda9b2SRandall Stewart #elif defined(AF_INET6) 153d6dda9b2SRandall Stewart sd = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP); 154e2e7c62eSMichael Tuexen #else 155e2e7c62eSMichael Tuexen sd = -1; 156d6dda9b2SRandall Stewart #endif 157d6dda9b2SRandall Stewart if (sd == -1) { 158a593094eSRandall Stewart return (-1); 159d6dda9b2SRandall Stewart } 160e2e7c62eSMichael Tuexen ret = getsockopt(sd, IPPROTO_SCTP, SCTP_GET_ADDR_LEN, &av, &siz); 161d6dda9b2SRandall Stewart close(sd); 162e2e7c62eSMichael Tuexen if (ret == 0) { 163d6dda9b2SRandall Stewart return ((int)av.assoc_value); 164d6dda9b2SRandall Stewart } else { 165a593094eSRandall Stewart return (-1); 166d6dda9b2SRandall Stewart } 167d6dda9b2SRandall Stewart } 168d6dda9b2SRandall Stewart 169d6dda9b2SRandall Stewart int 1702c356be2SRandall Stewart sctp_connectx(int sd, const struct sockaddr *addrs, int addrcnt, 1712c356be2SRandall Stewart sctp_assoc_t * id) 172d6dda9b2SRandall Stewart { 173804cf641SRandall Stewart char buf[SCTP_STACK_BUF_SIZE]; 174d6dda9b2SRandall Stewart int i, ret, cnt, *aa; 175d6dda9b2SRandall Stewart char *cpto; 176d6dda9b2SRandall Stewart const struct sockaddr *at; 17742551e99SRandall Stewart sctp_assoc_t *p_id; 1782c356be2SRandall Stewart size_t len = sizeof(int); 179d6dda9b2SRandall Stewart 1802c356be2SRandall Stewart /* validate the address count and list */ 1812c356be2SRandall Stewart if ((addrs == NULL) || (addrcnt <= 0)) { 1822c356be2SRandall Stewart errno = EINVAL; 1832c356be2SRandall Stewart return (-1); 1842c356be2SRandall Stewart } 185d6dda9b2SRandall Stewart at = addrs; 186d6dda9b2SRandall Stewart cnt = 0; 187d6dda9b2SRandall Stewart cpto = ((caddr_t)buf + sizeof(int)); 188d6dda9b2SRandall Stewart /* validate all the addresses and get the size */ 189d6dda9b2SRandall Stewart for (i = 0; i < addrcnt; i++) { 190d6dda9b2SRandall Stewart if (at->sa_family == AF_INET) { 19125d63f19SRandall Stewart if (at->sa_len != sizeof(struct sockaddr_in)) { 19225d63f19SRandall Stewart errno = EINVAL; 19325d63f19SRandall Stewart return (-1); 19425d63f19SRandall Stewart } 195d6dda9b2SRandall Stewart memcpy(cpto, at, at->sa_len); 196d6dda9b2SRandall Stewart cpto = ((caddr_t)cpto + at->sa_len); 197d6dda9b2SRandall Stewart len += at->sa_len; 198d6dda9b2SRandall Stewart } else if (at->sa_family == AF_INET6) { 19925d63f19SRandall Stewart if (at->sa_len != sizeof(struct sockaddr_in6)) { 20025d63f19SRandall Stewart errno = EINVAL; 20125d63f19SRandall Stewart return (-1); 20225d63f19SRandall Stewart } 203d6dda9b2SRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)at)->sin6_addr)) { 204d6dda9b2SRandall Stewart len += sizeof(struct sockaddr_in); 205d6dda9b2SRandall Stewart in6_sin6_2_sin((struct sockaddr_in *)cpto, (struct sockaddr_in6 *)at); 206d6dda9b2SRandall Stewart cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in)); 207d6dda9b2SRandall Stewart len += sizeof(struct sockaddr_in); 208d6dda9b2SRandall Stewart } else { 209d6dda9b2SRandall Stewart memcpy(cpto, at, at->sa_len); 210d6dda9b2SRandall Stewart cpto = ((caddr_t)cpto + at->sa_len); 211d6dda9b2SRandall Stewart len += at->sa_len; 212d6dda9b2SRandall Stewart } 213d6dda9b2SRandall Stewart } else { 214d6dda9b2SRandall Stewart errno = EINVAL; 215d6dda9b2SRandall Stewart return (-1); 216d6dda9b2SRandall Stewart } 217d6dda9b2SRandall Stewart if (len > (sizeof(buf) - sizeof(int))) { 218d6dda9b2SRandall Stewart /* Never enough memory */ 21925d63f19SRandall Stewart errno = E2BIG; 220f1d30539SMatt Jacob return (-1); 221d6dda9b2SRandall Stewart } 222d6dda9b2SRandall Stewart at = (struct sockaddr *)((caddr_t)at + at->sa_len); 223d6dda9b2SRandall Stewart cnt++; 224d6dda9b2SRandall Stewart } 225d6dda9b2SRandall Stewart /* do we have any? */ 226d6dda9b2SRandall Stewart if (cnt == 0) { 227d6dda9b2SRandall Stewart errno = EINVAL; 228d6dda9b2SRandall Stewart return (-1); 229d6dda9b2SRandall Stewart } 230d6dda9b2SRandall Stewart aa = (int *)buf; 231d6dda9b2SRandall Stewart *aa = cnt; 232d6dda9b2SRandall Stewart ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X, (void *)buf, 233d6dda9b2SRandall Stewart (socklen_t) len); 23442551e99SRandall Stewart if ((ret == 0) && id) { 23542551e99SRandall Stewart p_id = (sctp_assoc_t *) buf; 23642551e99SRandall Stewart *id = *p_id; 23742551e99SRandall Stewart } 238d6dda9b2SRandall Stewart return (ret); 239d6dda9b2SRandall Stewart } 240d6dda9b2SRandall Stewart 241d6dda9b2SRandall Stewart int 242d6dda9b2SRandall Stewart sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags) 243d6dda9b2SRandall Stewart { 244d6dda9b2SRandall Stewart struct sctp_getaddresses *gaddrs; 245d6dda9b2SRandall Stewart struct sockaddr *sa; 2461b649582SRandall Stewart struct sockaddr_in *sin; 2471b649582SRandall Stewart struct sockaddr_in6 *sin6; 24825d63f19SRandall Stewart int i, sz, argsz; 2491b649582SRandall Stewart uint16_t sport = 0; 250d6dda9b2SRandall Stewart 2512c356be2SRandall Stewart /* validate the flags */ 252d6dda9b2SRandall Stewart if ((flags != SCTP_BINDX_ADD_ADDR) && 253d6dda9b2SRandall Stewart (flags != SCTP_BINDX_REM_ADDR)) { 254d6dda9b2SRandall Stewart errno = EFAULT; 255d6dda9b2SRandall Stewart return (-1); 256d6dda9b2SRandall Stewart } 2572c356be2SRandall Stewart /* validate the address count and list */ 2582c356be2SRandall Stewart if ((addrcnt <= 0) || (addrs == NULL)) { 2592c356be2SRandall Stewart errno = EINVAL; 2602c356be2SRandall Stewart return (-1); 2612c356be2SRandall Stewart } 262d6dda9b2SRandall Stewart argsz = (sizeof(struct sockaddr_storage) + 263d6dda9b2SRandall Stewart sizeof(struct sctp_getaddresses)); 264d6dda9b2SRandall Stewart gaddrs = (struct sctp_getaddresses *)calloc(1, argsz); 265d6dda9b2SRandall Stewart if (gaddrs == NULL) { 266d6dda9b2SRandall Stewart errno = ENOMEM; 267d6dda9b2SRandall Stewart return (-1); 268d6dda9b2SRandall Stewart } 2691b649582SRandall Stewart /* First pre-screen the addresses */ 270d6dda9b2SRandall Stewart sa = addrs; 271d6dda9b2SRandall Stewart for (i = 0; i < addrcnt; i++) { 272d6dda9b2SRandall Stewart sz = sa->sa_len; 27325d63f19SRandall Stewart if (sa->sa_family == AF_INET) { 27425d63f19SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in)) 27525d63f19SRandall Stewart goto out_error; 2761b649582SRandall Stewart sin = (struct sockaddr_in *)sa; 2771b649582SRandall Stewart if (sin->sin_port) { 2781b649582SRandall Stewart /* non-zero port, check or save */ 2791b649582SRandall Stewart if (sport) { 2801b649582SRandall Stewart /* Check against our port */ 2811b649582SRandall Stewart if (sport != sin->sin_port) { 2821b649582SRandall Stewart goto out_error; 2831b649582SRandall Stewart } 2841b649582SRandall Stewart } else { 2851b649582SRandall Stewart /* save off the port */ 2861b649582SRandall Stewart sport = sin->sin_port; 2871b649582SRandall Stewart } 2881b649582SRandall Stewart } 2891b649582SRandall Stewart } else if (sa->sa_family == AF_INET6) { 2901b649582SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in6)) 2911b649582SRandall Stewart goto out_error; 2921b649582SRandall Stewart sin6 = (struct sockaddr_in6 *)sa; 2931b649582SRandall Stewart if (sin6->sin6_port) { 2941b649582SRandall Stewart /* non-zero port, check or save */ 2951b649582SRandall Stewart if (sport) { 2961b649582SRandall Stewart /* Check against our port */ 2971b649582SRandall Stewart if (sport != sin6->sin6_port) { 2981b649582SRandall Stewart goto out_error; 2991b649582SRandall Stewart } 3001b649582SRandall Stewart } else { 3011b649582SRandall Stewart /* save off the port */ 3021b649582SRandall Stewart sport = sin6->sin6_port; 3031b649582SRandall Stewart } 3041b649582SRandall Stewart } 3051b649582SRandall Stewart } else { 3061b649582SRandall Stewart /* invalid address family specified */ 3071b649582SRandall Stewart goto out_error; 3081b649582SRandall Stewart } 3091b649582SRandall Stewart 31045d35a30SRebecca Cran sa = (struct sockaddr *)((caddr_t)sa + sz); 3111b649582SRandall Stewart } 3121b649582SRandall Stewart sa = addrs; 3131b649582SRandall Stewart /* 3141b649582SRandall Stewart * Now if there was a port mentioned, assure that the first address 3151b649582SRandall Stewart * has that port to make sure it fails or succeeds correctly. 3161b649582SRandall Stewart */ 3171b649582SRandall Stewart if (sport) { 3181b649582SRandall Stewart sin = (struct sockaddr_in *)sa; 3191b649582SRandall Stewart sin->sin_port = sport; 3201b649582SRandall Stewart } 3211b649582SRandall Stewart for (i = 0; i < addrcnt; i++) { 3221b649582SRandall Stewart sz = sa->sa_len; 3231b649582SRandall Stewart if (sa->sa_family == AF_INET) { 3241b649582SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in)) 3251b649582SRandall Stewart goto out_error; 32625d63f19SRandall Stewart } else if (sa->sa_family == AF_INET6) { 32725d63f19SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in6)) 32825d63f19SRandall Stewart goto out_error; 32925d63f19SRandall Stewart } else { 33025d63f19SRandall Stewart /* invalid address family specified */ 33125d63f19SRandall Stewart out_error: 332a593094eSRandall Stewart free(gaddrs); 333d6dda9b2SRandall Stewart errno = EINVAL; 334d6dda9b2SRandall Stewart return (-1); 335d6dda9b2SRandall Stewart } 33625d63f19SRandall Stewart memset(gaddrs, 0, argsz); 33725d63f19SRandall Stewart gaddrs->sget_assoc_id = 0; 338d6dda9b2SRandall Stewart memcpy(gaddrs->addr, sa, sz); 33925d63f19SRandall Stewart if (setsockopt(sd, IPPROTO_SCTP, flags, gaddrs, 34025d63f19SRandall Stewart (socklen_t) argsz) != 0) { 341d6dda9b2SRandall Stewart free(gaddrs); 342d6dda9b2SRandall Stewart return (-1); 343d6dda9b2SRandall Stewart } 344d6dda9b2SRandall Stewart sa = (struct sockaddr *)((caddr_t)sa + sz); 345d6dda9b2SRandall Stewart } 346d6dda9b2SRandall Stewart free(gaddrs); 347d6dda9b2SRandall Stewart return (0); 348d6dda9b2SRandall Stewart } 349d6dda9b2SRandall Stewart 350d6dda9b2SRandall Stewart 351d6dda9b2SRandall Stewart int 352d6dda9b2SRandall Stewart sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t * size) 353d6dda9b2SRandall Stewart { 354d6dda9b2SRandall Stewart if (arg == NULL) { 355602afc03SRandall Stewart errno = EINVAL; 356602afc03SRandall Stewart return (-1); 357d6dda9b2SRandall Stewart } 3581b649582SRandall Stewart switch (opt) { 3591b649582SRandall Stewart case SCTP_RTOINFO: 3601b649582SRandall Stewart ((struct sctp_rtoinfo *)arg)->srto_assoc_id = id; 3611b649582SRandall Stewart break; 3621b649582SRandall Stewart case SCTP_ASSOCINFO: 3631b649582SRandall Stewart ((struct sctp_assocparams *)arg)->sasoc_assoc_id = id; 3641b649582SRandall Stewart break; 3651b649582SRandall Stewart case SCTP_DEFAULT_SEND_PARAM: 3661b649582SRandall Stewart ((struct sctp_assocparams *)arg)->sasoc_assoc_id = id; 3671b649582SRandall Stewart break; 3681b649582SRandall Stewart case SCTP_PRIMARY_ADDR: 3691b649582SRandall Stewart ((struct sctp_setprim *)arg)->ssp_assoc_id = id; 3701b649582SRandall Stewart break; 3711b649582SRandall Stewart case SCTP_PEER_ADDR_PARAMS: 3721b649582SRandall Stewart ((struct sctp_paddrparams *)arg)->spp_assoc_id = id; 3731b649582SRandall Stewart break; 3741b649582SRandall Stewart case SCTP_MAXSEG: 3751b649582SRandall Stewart ((struct sctp_assoc_value *)arg)->assoc_id = id; 3761b649582SRandall Stewart break; 3771b649582SRandall Stewart case SCTP_AUTH_KEY: 3781b649582SRandall Stewart ((struct sctp_authkey *)arg)->sca_assoc_id = id; 3791b649582SRandall Stewart break; 3801b649582SRandall Stewart case SCTP_AUTH_ACTIVE_KEY: 3811b649582SRandall Stewart ((struct sctp_authkeyid *)arg)->scact_assoc_id = id; 3821b649582SRandall Stewart break; 3831b649582SRandall Stewart case SCTP_DELAYED_SACK: 3841b649582SRandall Stewart ((struct sctp_sack_info *)arg)->sack_assoc_id = id; 3851b649582SRandall Stewart break; 3861b649582SRandall Stewart case SCTP_CONTEXT: 3871b649582SRandall Stewart ((struct sctp_assoc_value *)arg)->assoc_id = id; 3881b649582SRandall Stewart break; 3891b649582SRandall Stewart case SCTP_STATUS: 3901b649582SRandall Stewart ((struct sctp_status *)arg)->sstat_assoc_id = id; 3911b649582SRandall Stewart break; 3921b649582SRandall Stewart case SCTP_GET_PEER_ADDR_INFO: 3931b649582SRandall Stewart ((struct sctp_paddrinfo *)arg)->spinfo_assoc_id = id; 3941b649582SRandall Stewart break; 3951b649582SRandall Stewart case SCTP_PEER_AUTH_CHUNKS: 3961b649582SRandall Stewart ((struct sctp_authchunks *)arg)->gauth_assoc_id = id; 3971b649582SRandall Stewart break; 3981b649582SRandall Stewart case SCTP_LOCAL_AUTH_CHUNKS: 3991b649582SRandall Stewart ((struct sctp_authchunks *)arg)->gauth_assoc_id = id; 4001b649582SRandall Stewart break; 40148f65f00SMichael Tuexen case SCTP_TIMEOUTS: 40248f65f00SMichael Tuexen ((struct sctp_timeouts *)arg)->stimo_assoc_id = id; 40348f65f00SMichael Tuexen break; 404e2e7c62eSMichael Tuexen case SCTP_EVENT: 405e2e7c62eSMichael Tuexen ((struct sctp_event *)arg)->se_assoc_id = id; 406e2e7c62eSMichael Tuexen break; 40713aae0bfSMichael Tuexen case SCTP_DEFAULT_SNDINFO: 40813aae0bfSMichael Tuexen ((struct sctp_sndinfo *)arg)->snd_assoc_id = id; 40913aae0bfSMichael Tuexen break; 41013aae0bfSMichael Tuexen case SCTP_DEFAULT_PRINFO: 41113aae0bfSMichael Tuexen ((struct sctp_default_prinfo *)arg)->pr_assoc_id = id; 41213aae0bfSMichael Tuexen break; 413ca85e948SMichael Tuexen case SCTP_PEER_ADDR_THLDS: 414ca85e948SMichael Tuexen ((struct sctp_paddrthlds *)arg)->spt_assoc_id = id; 415ca85e948SMichael Tuexen break; 416*c9c58059SMichael Tuexen case SCTP_REMOTE_UDP_ENCAPS_PORT: 417*c9c58059SMichael Tuexen ((struct sctp_udpencaps *)arg)->sue_assoc_id = id; 418*c9c58059SMichael Tuexen break; 419bb2c20c1SMichael Tuexen case SCTP_MAX_BURST: 420bb2c20c1SMichael Tuexen ((struct sctp_assoc_value *)arg)->assoc_id = id; 421bb2c20c1SMichael Tuexen break; 4221b649582SRandall Stewart default: 4231b649582SRandall Stewart break; 4241b649582SRandall Stewart } 425d6dda9b2SRandall Stewart return (getsockopt(sd, IPPROTO_SCTP, opt, arg, size)); 426d6dda9b2SRandall Stewart } 427d6dda9b2SRandall Stewart 428d6dda9b2SRandall Stewart int 429d6dda9b2SRandall Stewart sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs) 430d6dda9b2SRandall Stewart { 431d6dda9b2SRandall Stewart struct sctp_getaddresses *addrs; 432d6dda9b2SRandall Stewart struct sockaddr *sa; 433d6dda9b2SRandall Stewart struct sockaddr *re; 434d6dda9b2SRandall Stewart sctp_assoc_t asoc; 435d6dda9b2SRandall Stewart caddr_t lim; 4362cbcccc7SRandall Stewart socklen_t siz; 437d6dda9b2SRandall Stewart int cnt; 438d6dda9b2SRandall Stewart 439d6dda9b2SRandall Stewart if (raddrs == NULL) { 440d6dda9b2SRandall Stewart errno = EFAULT; 441d6dda9b2SRandall Stewart return (-1); 442d6dda9b2SRandall Stewart } 443d6dda9b2SRandall Stewart asoc = id; 444d6dda9b2SRandall Stewart siz = sizeof(sctp_assoc_t); 445d6dda9b2SRandall Stewart if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE, 4462cbcccc7SRandall Stewart &asoc, &siz) != 0) { 447d6dda9b2SRandall Stewart return (-1); 448d6dda9b2SRandall Stewart } 449d6dda9b2SRandall Stewart /* size required is returned in 'asoc' */ 450804cf641SRandall Stewart siz = (size_t)asoc; 451d6dda9b2SRandall Stewart siz += sizeof(struct sctp_getaddresses); 452804cf641SRandall Stewart addrs = calloc(1, siz); 453d6dda9b2SRandall Stewart if (addrs == NULL) { 454d6dda9b2SRandall Stewart return (-1); 455d6dda9b2SRandall Stewart } 456d6dda9b2SRandall Stewart addrs->sget_assoc_id = id; 457d6dda9b2SRandall Stewart /* Now lets get the array of addresses */ 458d6dda9b2SRandall Stewart if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES, 4592cbcccc7SRandall Stewart addrs, &siz) != 0) { 460d6dda9b2SRandall Stewart free(addrs); 461d6dda9b2SRandall Stewart return (-1); 462d6dda9b2SRandall Stewart } 463d6dda9b2SRandall Stewart re = (struct sockaddr *)&addrs->addr[0]; 464d6dda9b2SRandall Stewart *raddrs = re; 465d6dda9b2SRandall Stewart cnt = 0; 466d6dda9b2SRandall Stewart sa = (struct sockaddr *)&addrs->addr[0]; 467d6dda9b2SRandall Stewart lim = (caddr_t)addrs + siz; 468d6dda9b2SRandall Stewart while (((caddr_t)sa < lim) && (sa->sa_len > 0)) { 469d6dda9b2SRandall Stewart sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 470d6dda9b2SRandall Stewart cnt++; 471d6dda9b2SRandall Stewart } 472d6dda9b2SRandall Stewart return (cnt); 473d6dda9b2SRandall Stewart } 474d6dda9b2SRandall Stewart 475d6dda9b2SRandall Stewart void 476d6dda9b2SRandall Stewart sctp_freepaddrs(struct sockaddr *addrs) 477d6dda9b2SRandall Stewart { 478d6dda9b2SRandall Stewart /* Take away the hidden association id */ 479d6dda9b2SRandall Stewart void *fr_addr; 480d6dda9b2SRandall Stewart 481d6dda9b2SRandall Stewart fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t)); 482d6dda9b2SRandall Stewart /* Now free it */ 483d6dda9b2SRandall Stewart free(fr_addr); 484d6dda9b2SRandall Stewart } 485d6dda9b2SRandall Stewart 486d6dda9b2SRandall Stewart int 487d6dda9b2SRandall Stewart sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs) 488d6dda9b2SRandall Stewart { 489d6dda9b2SRandall Stewart struct sctp_getaddresses *addrs; 490d6dda9b2SRandall Stewart struct sockaddr *re; 491d6dda9b2SRandall Stewart caddr_t lim; 492d6dda9b2SRandall Stewart struct sockaddr *sa; 493d6dda9b2SRandall Stewart int size_of_addresses; 4942cbcccc7SRandall Stewart socklen_t siz; 495d6dda9b2SRandall Stewart int cnt; 496d6dda9b2SRandall Stewart 497d6dda9b2SRandall Stewart if (raddrs == NULL) { 498d6dda9b2SRandall Stewart errno = EFAULT; 499d6dda9b2SRandall Stewart return (-1); 500d6dda9b2SRandall Stewart } 501d6dda9b2SRandall Stewart size_of_addresses = 0; 502d6dda9b2SRandall Stewart siz = sizeof(int); 503d6dda9b2SRandall Stewart if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE, 5042cbcccc7SRandall Stewart &size_of_addresses, &siz) != 0) { 505d6dda9b2SRandall Stewart errno = ENOMEM; 506d6dda9b2SRandall Stewart return (-1); 507d6dda9b2SRandall Stewart } 508d6dda9b2SRandall Stewart if (size_of_addresses == 0) { 509d6dda9b2SRandall Stewart errno = ENOTCONN; 510d6dda9b2SRandall Stewart return (-1); 511d6dda9b2SRandall Stewart } 512d6dda9b2SRandall Stewart siz = size_of_addresses + sizeof(struct sockaddr_storage); 513d6dda9b2SRandall Stewart siz += sizeof(struct sctp_getaddresses); 514804cf641SRandall Stewart addrs = calloc(1, siz); 515d6dda9b2SRandall Stewart if (addrs == NULL) { 516d6dda9b2SRandall Stewart errno = ENOMEM; 517d6dda9b2SRandall Stewart return (-1); 518d6dda9b2SRandall Stewart } 519d6dda9b2SRandall Stewart addrs->sget_assoc_id = id; 520d6dda9b2SRandall Stewart /* Now lets get the array of addresses */ 521d6dda9b2SRandall Stewart if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs, 5222cbcccc7SRandall Stewart &siz) != 0) { 523d6dda9b2SRandall Stewart free(addrs); 524d6dda9b2SRandall Stewart errno = ENOMEM; 525d6dda9b2SRandall Stewart return (-1); 526d6dda9b2SRandall Stewart } 527d6dda9b2SRandall Stewart re = (struct sockaddr *)&addrs->addr[0]; 528d6dda9b2SRandall Stewart *raddrs = re; 529d6dda9b2SRandall Stewart cnt = 0; 530d6dda9b2SRandall Stewart sa = (struct sockaddr *)&addrs->addr[0]; 531d6dda9b2SRandall Stewart lim = (caddr_t)addrs + siz; 532d6dda9b2SRandall Stewart while (((caddr_t)sa < lim) && (sa->sa_len > 0)) { 533d6dda9b2SRandall Stewart sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); 534d6dda9b2SRandall Stewart cnt++; 535d6dda9b2SRandall Stewart } 536d6dda9b2SRandall Stewart return (cnt); 537d6dda9b2SRandall Stewart } 538d6dda9b2SRandall Stewart 539d6dda9b2SRandall Stewart void 540d6dda9b2SRandall Stewart sctp_freeladdrs(struct sockaddr *addrs) 541d6dda9b2SRandall Stewart { 542d6dda9b2SRandall Stewart /* Take away the hidden association id */ 543d6dda9b2SRandall Stewart void *fr_addr; 544d6dda9b2SRandall Stewart 545d6dda9b2SRandall Stewart fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t)); 546d6dda9b2SRandall Stewart /* Now free it */ 547d6dda9b2SRandall Stewart free(fr_addr); 548d6dda9b2SRandall Stewart } 549d6dda9b2SRandall Stewart 550d6dda9b2SRandall Stewart 551d6dda9b2SRandall Stewart ssize_t 552d6dda9b2SRandall Stewart sctp_sendmsg(int s, 553d6dda9b2SRandall Stewart const void *data, 554d6dda9b2SRandall Stewart size_t len, 555d6dda9b2SRandall Stewart const struct sockaddr *to, 556002b1f0bSRandall Stewart socklen_t tolen, 5573d36ac98SRebecca Cran uint32_t ppid, 5583d36ac98SRebecca Cran uint32_t flags, 5593d36ac98SRebecca Cran uint16_t stream_no, 5603d36ac98SRebecca Cran uint32_t timetolive, 5613d36ac98SRebecca Cran uint32_t context) 562d6dda9b2SRandall Stewart { 563d6dda9b2SRandall Stewart #ifdef SYS_sctp_generic_sendmsg 564d6dda9b2SRandall Stewart struct sctp_sndrcvinfo sinfo; 565d6dda9b2SRandall Stewart 566d6dda9b2SRandall Stewart sinfo.sinfo_ppid = ppid; 567d6dda9b2SRandall Stewart sinfo.sinfo_flags = flags; 568d6dda9b2SRandall Stewart sinfo.sinfo_stream = stream_no; 569d6dda9b2SRandall Stewart sinfo.sinfo_timetolive = timetolive; 570d6dda9b2SRandall Stewart sinfo.sinfo_context = context; 571d6dda9b2SRandall Stewart sinfo.sinfo_assoc_id = 0; 572d6dda9b2SRandall Stewart return (syscall(SYS_sctp_generic_sendmsg, s, 573d6dda9b2SRandall Stewart data, len, to, tolen, &sinfo, 0)); 574d6dda9b2SRandall Stewart #else 575d6dda9b2SRandall Stewart ssize_t sz; 576d6dda9b2SRandall Stewart struct msghdr msg; 577d6dda9b2SRandall Stewart struct sctp_sndrcvinfo *s_info; 57848f65f00SMichael Tuexen struct iovec iov; 579d6dda9b2SRandall Stewart char controlVector[SCTP_CONTROL_VEC_SIZE_RCV]; 580d6dda9b2SRandall Stewart struct cmsghdr *cmsg; 581d6dda9b2SRandall Stewart struct sockaddr *who = NULL; 582d6dda9b2SRandall Stewart union { 583d6dda9b2SRandall Stewart struct sockaddr_in in; 584d6dda9b2SRandall Stewart struct sockaddr_in6 in6; 585d6dda9b2SRandall Stewart } addr; 586d6dda9b2SRandall Stewart 58748f65f00SMichael Tuexen if ((tolen > 0) && 58848f65f00SMichael Tuexen ((to == NULL) || (tolen < sizeof(struct sockaddr)))) { 589002b1f0bSRandall Stewart errno = EINVAL; 590002b1f0bSRandall Stewart return -1; 591002b1f0bSRandall Stewart } 592002b1f0bSRandall Stewart if (to && (tolen > 0)) { 593d6dda9b2SRandall Stewart if (to->sa_family == AF_INET) { 594002b1f0bSRandall Stewart if (tolen != sizeof(struct sockaddr_in)) { 595002b1f0bSRandall Stewart errno = EINVAL; 596002b1f0bSRandall Stewart return -1; 597002b1f0bSRandall Stewart } 59848f65f00SMichael Tuexen if ((to->sa_len > 0) && 59948f65f00SMichael Tuexen (to->sa_len != sizeof(struct sockaddr_in))) { 600002b1f0bSRandall Stewart errno = EINVAL; 601002b1f0bSRandall Stewart return -1; 602002b1f0bSRandall Stewart } 603d6dda9b2SRandall Stewart memcpy(&addr, to, sizeof(struct sockaddr_in)); 604d6dda9b2SRandall Stewart addr.in.sin_len = sizeof(struct sockaddr_in); 605d6dda9b2SRandall Stewart } else if (to->sa_family == AF_INET6) { 606002b1f0bSRandall Stewart if (tolen != sizeof(struct sockaddr_in6)) { 607002b1f0bSRandall Stewart errno = EINVAL; 608002b1f0bSRandall Stewart return -1; 609002b1f0bSRandall Stewart } 61048f65f00SMichael Tuexen if ((to->sa_len > 0) && 61148f65f00SMichael Tuexen (to->sa_len != sizeof(struct sockaddr_in6))) { 612002b1f0bSRandall Stewart errno = EINVAL; 613002b1f0bSRandall Stewart return -1; 614002b1f0bSRandall Stewart } 615d6dda9b2SRandall Stewart memcpy(&addr, to, sizeof(struct sockaddr_in6)); 616d6dda9b2SRandall Stewart addr.in6.sin6_len = sizeof(struct sockaddr_in6); 617d6dda9b2SRandall Stewart } else { 618002b1f0bSRandall Stewart errno = EAFNOSUPPORT; 619002b1f0bSRandall Stewart return -1; 620d6dda9b2SRandall Stewart } 621d6dda9b2SRandall Stewart who = (struct sockaddr *)&addr; 622d6dda9b2SRandall Stewart } 62348f65f00SMichael Tuexen iov.iov_base = (char *)data; 62448f65f00SMichael Tuexen iov.iov_len = len; 625d6dda9b2SRandall Stewart 626002b1f0bSRandall Stewart if (who) { 627d6dda9b2SRandall Stewart msg.msg_name = (caddr_t)who; 628d6dda9b2SRandall Stewart msg.msg_namelen = who->sa_len; 629d6dda9b2SRandall Stewart } else { 630d6dda9b2SRandall Stewart msg.msg_name = (caddr_t)NULL; 631d6dda9b2SRandall Stewart msg.msg_namelen = 0; 632d6dda9b2SRandall Stewart } 63348f65f00SMichael Tuexen msg.msg_iov = &iov; 634d6dda9b2SRandall Stewart msg.msg_iovlen = 1; 635d6dda9b2SRandall Stewart msg.msg_control = (caddr_t)controlVector; 636d6dda9b2SRandall Stewart 637d6dda9b2SRandall Stewart cmsg = (struct cmsghdr *)controlVector; 638d6dda9b2SRandall Stewart 639d6dda9b2SRandall Stewart cmsg->cmsg_level = IPPROTO_SCTP; 640d6dda9b2SRandall Stewart cmsg->cmsg_type = SCTP_SNDRCV; 641d6dda9b2SRandall Stewart cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 642d6dda9b2SRandall Stewart s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); 643d6dda9b2SRandall Stewart 644d6dda9b2SRandall Stewart s_info->sinfo_stream = stream_no; 645d6dda9b2SRandall Stewart s_info->sinfo_ssn = 0; 646d6dda9b2SRandall Stewart s_info->sinfo_flags = flags; 647d6dda9b2SRandall Stewart s_info->sinfo_ppid = ppid; 648d6dda9b2SRandall Stewart s_info->sinfo_context = context; 649d6dda9b2SRandall Stewart s_info->sinfo_assoc_id = 0; 650d6dda9b2SRandall Stewart s_info->sinfo_timetolive = timetolive; 651d6dda9b2SRandall Stewart errno = 0; 652d6dda9b2SRandall Stewart msg.msg_controllen = cmsg->cmsg_len; 653d6dda9b2SRandall Stewart sz = sendmsg(s, &msg, 0); 654d6dda9b2SRandall Stewart return (sz); 655d6dda9b2SRandall Stewart #endif 656d6dda9b2SRandall Stewart } 657d6dda9b2SRandall Stewart 658d6dda9b2SRandall Stewart 659d6dda9b2SRandall Stewart sctp_assoc_t 660d6dda9b2SRandall Stewart sctp_getassocid(int sd, struct sockaddr *sa) 661d6dda9b2SRandall Stewart { 662b54d3a6cSRandall Stewart struct sctp_paddrinfo sp; 663066f54d8SCraig Rodrigues socklen_t siz; 664d6dda9b2SRandall Stewart 665d6dda9b2SRandall Stewart /* First get the assoc id */ 666b54d3a6cSRandall Stewart siz = sizeof(sp); 667d6dda9b2SRandall Stewart memset(&sp, 0, sizeof(sp)); 668b54d3a6cSRandall Stewart memcpy((caddr_t)&sp.spinfo_address, sa, sa->sa_len); 669d6dda9b2SRandall Stewart errno = 0; 670d6dda9b2SRandall Stewart if (getsockopt(sd, IPPROTO_SCTP, 671b54d3a6cSRandall Stewart SCTP_GET_PEER_ADDR_INFO, &sp, &siz) != 0) { 672d6dda9b2SRandall Stewart return ((sctp_assoc_t) 0); 673d6dda9b2SRandall Stewart } 674d6dda9b2SRandall Stewart /* We depend on the fact that 0 can never be returned */ 675b54d3a6cSRandall Stewart return (sp.spinfo_assoc_id); 676d6dda9b2SRandall Stewart } 677d6dda9b2SRandall Stewart 678d6dda9b2SRandall Stewart ssize_t 679d6dda9b2SRandall Stewart sctp_send(int sd, const void *data, size_t len, 680d6dda9b2SRandall Stewart const struct sctp_sndrcvinfo *sinfo, 681d6dda9b2SRandall Stewart int flags) 682d6dda9b2SRandall Stewart { 683d6dda9b2SRandall Stewart 684d6dda9b2SRandall Stewart #ifdef SYS_sctp_generic_sendmsg 685d6dda9b2SRandall Stewart struct sockaddr *to = NULL; 686d6dda9b2SRandall Stewart 687d6dda9b2SRandall Stewart return (syscall(SYS_sctp_generic_sendmsg, sd, 688d6dda9b2SRandall Stewart data, len, to, 0, sinfo, flags)); 689d6dda9b2SRandall Stewart #else 690d6dda9b2SRandall Stewart ssize_t sz; 691d6dda9b2SRandall Stewart struct msghdr msg; 69248f65f00SMichael Tuexen struct iovec iov; 693d6dda9b2SRandall Stewart struct sctp_sndrcvinfo *s_info; 694d6dda9b2SRandall Stewart char controlVector[SCTP_CONTROL_VEC_SIZE_SND]; 695d6dda9b2SRandall Stewart struct cmsghdr *cmsg; 696d6dda9b2SRandall Stewart 697d6dda9b2SRandall Stewart if (sinfo == NULL) { 698b54d3a6cSRandall Stewart errno = EINVAL; 699b54d3a6cSRandall Stewart return (-1); 700d6dda9b2SRandall Stewart } 70148f65f00SMichael Tuexen iov.iov_base = (char *)data; 70248f65f00SMichael Tuexen iov.iov_len = len; 703d6dda9b2SRandall Stewart 704d6dda9b2SRandall Stewart msg.msg_name = 0; 705d6dda9b2SRandall Stewart msg.msg_namelen = 0; 70648f65f00SMichael Tuexen msg.msg_iov = &iov; 707d6dda9b2SRandall Stewart msg.msg_iovlen = 1; 708d6dda9b2SRandall Stewart msg.msg_control = (caddr_t)controlVector; 709d6dda9b2SRandall Stewart 710d6dda9b2SRandall Stewart cmsg = (struct cmsghdr *)controlVector; 711d6dda9b2SRandall Stewart 712d6dda9b2SRandall Stewart cmsg->cmsg_level = IPPROTO_SCTP; 713d6dda9b2SRandall Stewart cmsg->cmsg_type = SCTP_SNDRCV; 714d6dda9b2SRandall Stewart cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 715d6dda9b2SRandall Stewart s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); 716d6dda9b2SRandall Stewart /* copy in the data */ 717d6dda9b2SRandall Stewart *s_info = *sinfo; 718d6dda9b2SRandall Stewart errno = 0; 719d6dda9b2SRandall Stewart msg.msg_controllen = cmsg->cmsg_len; 720d6dda9b2SRandall Stewart sz = sendmsg(sd, &msg, flags); 721d6dda9b2SRandall Stewart return (sz); 722d6dda9b2SRandall Stewart #endif 723d6dda9b2SRandall Stewart } 724d6dda9b2SRandall Stewart 725d6dda9b2SRandall Stewart 726d6dda9b2SRandall Stewart 727d6dda9b2SRandall Stewart ssize_t 728d6dda9b2SRandall Stewart sctp_sendx(int sd, const void *msg, size_t msg_len, 729d6dda9b2SRandall Stewart struct sockaddr *addrs, int addrcnt, 730d6dda9b2SRandall Stewart struct sctp_sndrcvinfo *sinfo, 731d6dda9b2SRandall Stewart int flags) 732d6dda9b2SRandall Stewart { 733335a2d00SRandall Stewart struct sctp_sndrcvinfo __sinfo; 734d6dda9b2SRandall Stewart ssize_t ret; 735d6dda9b2SRandall Stewart int i, cnt, *aa, saved_errno; 736d6dda9b2SRandall Stewart char *buf; 737d6dda9b2SRandall Stewart int add_len, len, no_end_cx = 0; 738d6dda9b2SRandall Stewart struct sockaddr *at; 739d6dda9b2SRandall Stewart 7401b649582SRandall Stewart if (addrs == NULL) { 7411b649582SRandall Stewart errno = EINVAL; 7421b649582SRandall Stewart return (-1); 7431b649582SRandall Stewart } 744804cf641SRandall Stewart #ifdef SYS_sctp_generic_sendmsg 74548f65f00SMichael Tuexen if (addrcnt == 1) { 746804cf641SRandall Stewart socklen_t l; 747804cf641SRandall Stewart 748804cf641SRandall Stewart /* 749804cf641SRandall Stewart * Quick way, we don't need to do a connectx so lets use the 750804cf641SRandall Stewart * syscall directly. 751804cf641SRandall Stewart */ 752804cf641SRandall Stewart l = addrs->sa_len; 753804cf641SRandall Stewart return (syscall(SYS_sctp_generic_sendmsg, sd, 754804cf641SRandall Stewart msg, msg_len, addrs, l, sinfo, flags)); 755804cf641SRandall Stewart } 756804cf641SRandall Stewart #endif 757b54d3a6cSRandall Stewart 758d6dda9b2SRandall Stewart len = sizeof(int); 759d6dda9b2SRandall Stewart at = addrs; 760d6dda9b2SRandall Stewart cnt = 0; 761d6dda9b2SRandall Stewart /* validate all the addresses and get the size */ 762d6dda9b2SRandall Stewart for (i = 0; i < addrcnt; i++) { 763d6dda9b2SRandall Stewart if (at->sa_family == AF_INET) { 764d6dda9b2SRandall Stewart add_len = sizeof(struct sockaddr_in); 765d6dda9b2SRandall Stewart } else if (at->sa_family == AF_INET6) { 766d6dda9b2SRandall Stewart add_len = sizeof(struct sockaddr_in6); 767d6dda9b2SRandall Stewart } else { 768d6dda9b2SRandall Stewart errno = EINVAL; 769d6dda9b2SRandall Stewart return (-1); 770d6dda9b2SRandall Stewart } 771d6dda9b2SRandall Stewart len += add_len; 772d6dda9b2SRandall Stewart at = (struct sockaddr *)((caddr_t)at + add_len); 773d6dda9b2SRandall Stewart cnt++; 774d6dda9b2SRandall Stewart } 775d6dda9b2SRandall Stewart /* do we have any? */ 776d6dda9b2SRandall Stewart if (cnt == 0) { 777d6dda9b2SRandall Stewart errno = EINVAL; 778d6dda9b2SRandall Stewart return (-1); 779d6dda9b2SRandall Stewart } 780d6dda9b2SRandall Stewart buf = malloc(len); 781d6dda9b2SRandall Stewart if (buf == NULL) { 782b54d3a6cSRandall Stewart return (-1); 783d6dda9b2SRandall Stewart } 784d6dda9b2SRandall Stewart aa = (int *)buf; 785d6dda9b2SRandall Stewart *aa = cnt; 786d6dda9b2SRandall Stewart aa++; 787d6dda9b2SRandall Stewart memcpy((caddr_t)aa, addrs, (len - sizeof(int))); 788d6dda9b2SRandall Stewart ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_DELAYED, (void *)buf, 789d6dda9b2SRandall Stewart (socklen_t) len); 790d6dda9b2SRandall Stewart 791d6dda9b2SRandall Stewart free(buf); 792d6dda9b2SRandall Stewart if (ret != 0) { 793d6dda9b2SRandall Stewart if (errno == EALREADY) { 794ecf4b67aSRebecca Cran no_end_cx = 1; 795d6dda9b2SRandall Stewart goto continue_send; 796d6dda9b2SRandall Stewart } 797d6dda9b2SRandall Stewart return (ret); 798d6dda9b2SRandall Stewart } 799d6dda9b2SRandall Stewart continue_send: 800335a2d00SRandall Stewart if (sinfo == NULL) { 801335a2d00SRandall Stewart sinfo = &__sinfo; 802335a2d00SRandall Stewart memset(&__sinfo, 0, sizeof(__sinfo)); 803335a2d00SRandall Stewart } 804d6dda9b2SRandall Stewart sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs); 805d6dda9b2SRandall Stewart if (sinfo->sinfo_assoc_id == 0) { 806d6dda9b2SRandall Stewart printf("Huh, can't get associd? TSNH!\n"); 807d6dda9b2SRandall Stewart (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs, 808d6dda9b2SRandall Stewart (socklen_t) addrs->sa_len); 809d6dda9b2SRandall Stewart errno = ENOENT; 810d6dda9b2SRandall Stewart return (-1); 811d6dda9b2SRandall Stewart } 812d6dda9b2SRandall Stewart ret = sctp_send(sd, msg, msg_len, sinfo, flags); 813d6dda9b2SRandall Stewart saved_errno = errno; 814d6dda9b2SRandall Stewart if (no_end_cx == 0) 815d6dda9b2SRandall Stewart (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs, 816d6dda9b2SRandall Stewart (socklen_t) addrs->sa_len); 817d6dda9b2SRandall Stewart 818d6dda9b2SRandall Stewart errno = saved_errno; 819d6dda9b2SRandall Stewart return (ret); 820d6dda9b2SRandall Stewart } 821d6dda9b2SRandall Stewart 822d6dda9b2SRandall Stewart ssize_t 823d6dda9b2SRandall Stewart sctp_sendmsgx(int sd, 824d6dda9b2SRandall Stewart const void *msg, 825d6dda9b2SRandall Stewart size_t len, 826d6dda9b2SRandall Stewart struct sockaddr *addrs, 827d6dda9b2SRandall Stewart int addrcnt, 8283d36ac98SRebecca Cran uint32_t ppid, 8293d36ac98SRebecca Cran uint32_t flags, 8303d36ac98SRebecca Cran uint16_t stream_no, 8313d36ac98SRebecca Cran uint32_t timetolive, 8323d36ac98SRebecca Cran uint32_t context) 833d6dda9b2SRandall Stewart { 834d6dda9b2SRandall Stewart struct sctp_sndrcvinfo sinfo; 835d6dda9b2SRandall Stewart 836d6dda9b2SRandall Stewart memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo)); 837d6dda9b2SRandall Stewart sinfo.sinfo_ppid = ppid; 838d6dda9b2SRandall Stewart sinfo.sinfo_flags = flags; 839d6dda9b2SRandall Stewart sinfo.sinfo_ssn = stream_no; 840d6dda9b2SRandall Stewart sinfo.sinfo_timetolive = timetolive; 841d6dda9b2SRandall Stewart sinfo.sinfo_context = context; 842d6dda9b2SRandall Stewart return sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0); 843d6dda9b2SRandall Stewart } 844d6dda9b2SRandall Stewart 845d6dda9b2SRandall Stewart ssize_t 846d6dda9b2SRandall Stewart sctp_recvmsg(int s, 847d6dda9b2SRandall Stewart void *dbuf, 848d6dda9b2SRandall Stewart size_t len, 849d6dda9b2SRandall Stewart struct sockaddr *from, 850d6dda9b2SRandall Stewart socklen_t * fromlen, 851d6dda9b2SRandall Stewart struct sctp_sndrcvinfo *sinfo, 852d6dda9b2SRandall Stewart int *msg_flags) 853d6dda9b2SRandall Stewart { 854d6dda9b2SRandall Stewart #ifdef SYS_sctp_generic_recvmsg 85548f65f00SMichael Tuexen struct iovec iov; 856d6dda9b2SRandall Stewart 85748f65f00SMichael Tuexen iov.iov_base = dbuf; 85848f65f00SMichael Tuexen iov.iov_len = len; 859d6dda9b2SRandall Stewart return (syscall(SYS_sctp_generic_recvmsg, s, 86048f65f00SMichael Tuexen &iov, 1, from, fromlen, sinfo, msg_flags)); 861d6dda9b2SRandall Stewart #else 862d6dda9b2SRandall Stewart struct sctp_sndrcvinfo *s_info; 863d6dda9b2SRandall Stewart ssize_t sz; 864d6dda9b2SRandall Stewart int sinfo_found = 0; 865d6dda9b2SRandall Stewart struct msghdr msg; 86648f65f00SMichael Tuexen struct iovec iov; 867d6dda9b2SRandall Stewart char controlVector[SCTP_CONTROL_VEC_SIZE_RCV]; 868d6dda9b2SRandall Stewart struct cmsghdr *cmsg; 869d6dda9b2SRandall Stewart 870d6dda9b2SRandall Stewart if (msg_flags == NULL) { 871d6dda9b2SRandall Stewart errno = EINVAL; 872d6dda9b2SRandall Stewart return (-1); 873d6dda9b2SRandall Stewart } 874d6dda9b2SRandall Stewart msg.msg_flags = 0; 87548f65f00SMichael Tuexen iov.iov_base = dbuf; 87648f65f00SMichael Tuexen iov.iov_len = len; 877d6dda9b2SRandall Stewart msg.msg_name = (caddr_t)from; 878d6dda9b2SRandall Stewart if (fromlen == NULL) 879d6dda9b2SRandall Stewart msg.msg_namelen = 0; 880d6dda9b2SRandall Stewart else 881d6dda9b2SRandall Stewart msg.msg_namelen = *fromlen; 88248f65f00SMichael Tuexen msg.msg_iov = &iov; 883d6dda9b2SRandall Stewart msg.msg_iovlen = 1; 884d6dda9b2SRandall Stewart msg.msg_control = (caddr_t)controlVector; 885d6dda9b2SRandall Stewart msg.msg_controllen = sizeof(controlVector); 886d6dda9b2SRandall Stewart errno = 0; 8872c356be2SRandall Stewart sz = recvmsg(s, &msg, *msg_flags); 88848f65f00SMichael Tuexen *msg_flags = msg.msg_flags; 88948f65f00SMichael Tuexen if (sz <= 0) { 890d6dda9b2SRandall Stewart return (sz); 89148f65f00SMichael Tuexen } 892d6dda9b2SRandall Stewart s_info = NULL; 893d6dda9b2SRandall Stewart len = sz; 89448f65f00SMichael Tuexen if (sinfo) { 895d6dda9b2SRandall Stewart sinfo->sinfo_assoc_id = 0; 89648f65f00SMichael Tuexen } 897d6dda9b2SRandall Stewart if ((msg.msg_controllen) && sinfo) { 898d6dda9b2SRandall Stewart /* 899d6dda9b2SRandall Stewart * parse through and see if we find the sctp_sndrcvinfo (if 900d6dda9b2SRandall Stewart * the user wants it). 901d6dda9b2SRandall Stewart */ 902d6dda9b2SRandall Stewart cmsg = (struct cmsghdr *)controlVector; 903d6dda9b2SRandall Stewart while (cmsg) { 904d6dda9b2SRandall Stewart if ((cmsg->cmsg_len == 0) || (cmsg->cmsg_len > msg.msg_controllen)) { 905d6dda9b2SRandall Stewart break; 906d6dda9b2SRandall Stewart } 907d6dda9b2SRandall Stewart if (cmsg->cmsg_level == IPPROTO_SCTP) { 908d6dda9b2SRandall Stewart if (cmsg->cmsg_type == SCTP_SNDRCV) { 909d6dda9b2SRandall Stewart /* Got it */ 910d6dda9b2SRandall Stewart s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); 911d6dda9b2SRandall Stewart /* Copy it to the user */ 912d6dda9b2SRandall Stewart if (sinfo) 913d6dda9b2SRandall Stewart *sinfo = *s_info; 914d6dda9b2SRandall Stewart sinfo_found = 1; 915d6dda9b2SRandall Stewart break; 916d6dda9b2SRandall Stewart } else if (cmsg->cmsg_type == SCTP_EXTRCV) { 917d6dda9b2SRandall Stewart /* 918d6dda9b2SRandall Stewart * Got it, presumably the user has 919d6dda9b2SRandall Stewart * asked for this extra info, so the 920d6dda9b2SRandall Stewart * structure holds more room :-D 921d6dda9b2SRandall Stewart */ 922d6dda9b2SRandall Stewart s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); 923d6dda9b2SRandall Stewart /* Copy it to the user */ 924d6dda9b2SRandall Stewart if (sinfo) { 925d6dda9b2SRandall Stewart memcpy(sinfo, s_info, sizeof(struct sctp_extrcvinfo)); 926d6dda9b2SRandall Stewart } 927d6dda9b2SRandall Stewart sinfo_found = 1; 928d6dda9b2SRandall Stewart break; 929d6dda9b2SRandall Stewart 930d6dda9b2SRandall Stewart } 931d6dda9b2SRandall Stewart } 932d6dda9b2SRandall Stewart cmsg = CMSG_NXTHDR(&msg, cmsg); 933d6dda9b2SRandall Stewart } 934d6dda9b2SRandall Stewart } 935d6dda9b2SRandall Stewart return (sz); 936d6dda9b2SRandall Stewart #endif 937d6dda9b2SRandall Stewart } 938d6dda9b2SRandall Stewart 939e2e7c62eSMichael Tuexen ssize_t 940e2e7c62eSMichael Tuexen sctp_recvv(int sd, 941e2e7c62eSMichael Tuexen const struct iovec *iov, 942e2e7c62eSMichael Tuexen int iovlen, 943e2e7c62eSMichael Tuexen struct sockaddr *from, 944e2e7c62eSMichael Tuexen socklen_t * fromlen, 945e2e7c62eSMichael Tuexen void *info, 946e2e7c62eSMichael Tuexen socklen_t * infolen, 947e2e7c62eSMichael Tuexen unsigned int *infotype, 948e2e7c62eSMichael Tuexen int *flags) 949d6dda9b2SRandall Stewart { 950e2e7c62eSMichael Tuexen char ctlbuf[SCTP_CONTROL_VEC_SIZE_RCV]; 951e2e7c62eSMichael Tuexen struct msghdr msg; 952e2e7c62eSMichael Tuexen struct cmsghdr *cmsg; 953e2e7c62eSMichael Tuexen ssize_t n; 954e2e7c62eSMichael Tuexen struct sctp_rcvinfo *rcvinfo; 955e2e7c62eSMichael Tuexen struct sctp_nxtinfo *nxtinfo; 956d6dda9b2SRandall Stewart 9570b064106SMichael Tuexen if (((info != NULL) && (infolen == NULL)) | 9580b064106SMichael Tuexen ((info == NULL) && (infolen != NULL) && (*infolen != 0)) || 9590b064106SMichael Tuexen ((info != NULL) && (infotype == NULL))) { 9600b064106SMichael Tuexen errno = EINVAL; 9610b064106SMichael Tuexen return (-1); 9620b064106SMichael Tuexen } 963e2e7c62eSMichael Tuexen if (infotype) { 964e2e7c62eSMichael Tuexen *infotype = SCTP_RECVV_NOINFO; 965e2e7c62eSMichael Tuexen } 966e2e7c62eSMichael Tuexen msg.msg_name = from; 967e2e7c62eSMichael Tuexen if (fromlen == NULL) { 968e2e7c62eSMichael Tuexen msg.msg_namelen = 0; 969d6dda9b2SRandall Stewart } else { 970e2e7c62eSMichael Tuexen msg.msg_namelen = *fromlen; 971d6dda9b2SRandall Stewart } 972e2e7c62eSMichael Tuexen msg.msg_iov = (struct iovec *)iov; 973e2e7c62eSMichael Tuexen msg.msg_iovlen = iovlen; 974e2e7c62eSMichael Tuexen msg.msg_control = ctlbuf; 975e2e7c62eSMichael Tuexen msg.msg_controllen = sizeof(ctlbuf); 976e2e7c62eSMichael Tuexen errno = 0; 977e2e7c62eSMichael Tuexen n = recvmsg(sd, &msg, *flags); 978e2e7c62eSMichael Tuexen *flags = msg.msg_flags; 979e2e7c62eSMichael Tuexen if ((n > 0) && 980e2e7c62eSMichael Tuexen (msg.msg_controllen > 0) && 981e2e7c62eSMichael Tuexen (infotype != NULL) && 982e2e7c62eSMichael Tuexen (infolen != NULL) && 983e2e7c62eSMichael Tuexen (*infolen > 0)) { 984e2e7c62eSMichael Tuexen rcvinfo = NULL; 985e2e7c62eSMichael Tuexen nxtinfo = NULL; 986e2e7c62eSMichael Tuexen for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 987e2e7c62eSMichael Tuexen if (cmsg->cmsg_level != IPPROTO_SCTP) { 988e2e7c62eSMichael Tuexen continue; 989e2e7c62eSMichael Tuexen } 990e2e7c62eSMichael Tuexen if (cmsg->cmsg_type == SCTP_RCVINFO) { 991e2e7c62eSMichael Tuexen rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg); 992e2e7c62eSMichael Tuexen } 993e2e7c62eSMichael Tuexen if (cmsg->cmsg_type == SCTP_NXTINFO) { 994e2e7c62eSMichael Tuexen nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg); 995e2e7c62eSMichael Tuexen } 996e2e7c62eSMichael Tuexen if (rcvinfo && nxtinfo) { 997e2e7c62eSMichael Tuexen break; 998e2e7c62eSMichael Tuexen } 999e2e7c62eSMichael Tuexen } 1000e2e7c62eSMichael Tuexen if (rcvinfo) { 1001e2e7c62eSMichael Tuexen if (nxtinfo) { 1002e2e7c62eSMichael Tuexen if (*infolen >= sizeof(struct sctp_recvv_rn)) { 1003e2e7c62eSMichael Tuexen struct sctp_recvv_rn *rn_info; 1004e2e7c62eSMichael Tuexen 1005e2e7c62eSMichael Tuexen rn_info = (struct sctp_recvv_rn *)info; 1006e2e7c62eSMichael Tuexen rn_info->recvv_rcvinfo = *rcvinfo; 1007e2e7c62eSMichael Tuexen rn_info->recvv_nxtinfo = *nxtinfo; 1008e2e7c62eSMichael Tuexen *infolen = (socklen_t) sizeof(struct sctp_recvv_rn); 1009e2e7c62eSMichael Tuexen *infotype = SCTP_RECVV_RN; 1010e2e7c62eSMichael Tuexen } 1011e2e7c62eSMichael Tuexen } else { 1012e2e7c62eSMichael Tuexen if (*infolen >= sizeof(struct sctp_rcvinfo)) { 1013e2e7c62eSMichael Tuexen memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo)); 1014e2e7c62eSMichael Tuexen *infolen = (socklen_t) sizeof(struct sctp_rcvinfo); 1015e2e7c62eSMichael Tuexen *infotype = SCTP_RECVV_RCVINFO; 1016e2e7c62eSMichael Tuexen } 1017e2e7c62eSMichael Tuexen } 1018e2e7c62eSMichael Tuexen } else if (nxtinfo) { 1019e2e7c62eSMichael Tuexen if (*infolen >= sizeof(struct sctp_rcvinfo)) { 1020e2e7c62eSMichael Tuexen memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo)); 1021e2e7c62eSMichael Tuexen *infolen = (socklen_t) sizeof(struct sctp_nxtinfo); 1022e2e7c62eSMichael Tuexen *infotype = SCTP_RECVV_NXTINFO; 1023e2e7c62eSMichael Tuexen } 1024e2e7c62eSMichael Tuexen } 1025e2e7c62eSMichael Tuexen } 1026e2e7c62eSMichael Tuexen return (n); 1027d6dda9b2SRandall Stewart } 1028d6dda9b2SRandall Stewart 1029e2e7c62eSMichael Tuexen ssize_t 1030e2e7c62eSMichael Tuexen sctp_sendv(int sd, 1031e2e7c62eSMichael Tuexen const struct iovec *iov, int iovcnt, 1032e2e7c62eSMichael Tuexen struct sockaddr *addrs, int addrcnt, 1033e2e7c62eSMichael Tuexen void *info, socklen_t infolen, unsigned int infotype, 1034e2e7c62eSMichael Tuexen int flags) 1035e2e7c62eSMichael Tuexen { 1036e2e7c62eSMichael Tuexen ssize_t ret; 1037e2e7c62eSMichael Tuexen int i; 10380b064106SMichael Tuexen socklen_t addr_len; 1039e2e7c62eSMichael Tuexen struct msghdr msg; 10400b064106SMichael Tuexen in_port_t port; 10410b064106SMichael Tuexen struct sctp_sendv_spa *spa_info; 1042e2e7c62eSMichael Tuexen struct cmsghdr *cmsg; 1043e2e7c62eSMichael Tuexen char *cmsgbuf; 1044e2e7c62eSMichael Tuexen struct sockaddr *addr; 1045e2e7c62eSMichael Tuexen struct sockaddr_in *addr_in; 1046e2e7c62eSMichael Tuexen struct sockaddr_in6 *addr_in6; 1047e2e7c62eSMichael Tuexen 10480b064106SMichael Tuexen if ((addrcnt < 0) || 10490b064106SMichael Tuexen (iovcnt < 0) || 1050c67a03f9SMichael Tuexen ((addrs == NULL) && (addrcnt > 0)) || 1051c67a03f9SMichael Tuexen ((addrs != NULL) && (addrcnt == 0)) || 10520b064106SMichael Tuexen ((iov == NULL) && (iovcnt > 0)) || 10530b064106SMichael Tuexen ((iov != NULL) && (iovcnt == 0))) { 1054e2e7c62eSMichael Tuexen errno = EINVAL; 1055e2e7c62eSMichael Tuexen return (-1); 1056e2e7c62eSMichael Tuexen } 1057e2e7c62eSMichael Tuexen cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) + 1058e2e7c62eSMichael Tuexen CMSG_SPACE(sizeof(struct sctp_prinfo)) + 1059e2e7c62eSMichael Tuexen CMSG_SPACE(sizeof(struct sctp_authinfo)) + 1060e2e7c62eSMichael Tuexen addrcnt * CMSG_SPACE(sizeof(struct in6_addr))); 1061e2e7c62eSMichael Tuexen if (cmsgbuf == NULL) { 1062e2e7c62eSMichael Tuexen errno = ENOBUFS; 1063e2e7c62eSMichael Tuexen return (-1); 1064e2e7c62eSMichael Tuexen } 1065e2e7c62eSMichael Tuexen msg.msg_control = cmsgbuf; 1066e2e7c62eSMichael Tuexen msg.msg_controllen = 0; 1067e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)cmsgbuf; 1068e2e7c62eSMichael Tuexen switch (infotype) { 10690b064106SMichael Tuexen case SCTP_SENDV_NOINFO: 10700b064106SMichael Tuexen if ((infolen != 0) || (info != NULL)) { 10710b064106SMichael Tuexen free(cmsgbuf); 10720b064106SMichael Tuexen errno = EINVAL; 10730b064106SMichael Tuexen return (-1); 10740b064106SMichael Tuexen } 10750b064106SMichael Tuexen break; 1076e2e7c62eSMichael Tuexen case SCTP_SENDV_SNDINFO: 10770b064106SMichael Tuexen if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) { 1078e2e7c62eSMichael Tuexen free(cmsgbuf); 1079e2e7c62eSMichael Tuexen errno = EINVAL; 1080e2e7c62eSMichael Tuexen return (-1); 1081e2e7c62eSMichael Tuexen } 1082e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1083e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_SNDINFO; 1084e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); 1085e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo)); 1086e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); 1087e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); 1088e2e7c62eSMichael Tuexen break; 1089e2e7c62eSMichael Tuexen case SCTP_SENDV_PRINFO: 10900b064106SMichael Tuexen if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) { 1091e2e7c62eSMichael Tuexen free(cmsgbuf); 1092e2e7c62eSMichael Tuexen errno = EINVAL; 1093e2e7c62eSMichael Tuexen return (-1); 1094e2e7c62eSMichael Tuexen } 1095e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1096e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_PRINFO; 1097e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); 1098e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo)); 1099e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); 1100e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo))); 1101e2e7c62eSMichael Tuexen break; 1102e2e7c62eSMichael Tuexen case SCTP_SENDV_AUTHINFO: 11030b064106SMichael Tuexen if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) { 1104e2e7c62eSMichael Tuexen free(cmsgbuf); 1105e2e7c62eSMichael Tuexen errno = EINVAL; 1106e2e7c62eSMichael Tuexen return (-1); 1107e2e7c62eSMichael Tuexen } 1108e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1109e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_AUTHINFO; 1110e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo)); 1111e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo)); 1112e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo)); 1113e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo))); 1114e2e7c62eSMichael Tuexen break; 1115e2e7c62eSMichael Tuexen case SCTP_SENDV_SPA: 11160b064106SMichael Tuexen if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) { 1117e2e7c62eSMichael Tuexen free(cmsgbuf); 1118e2e7c62eSMichael Tuexen errno = EINVAL; 1119e2e7c62eSMichael Tuexen return (-1); 1120e2e7c62eSMichael Tuexen } 1121e2e7c62eSMichael Tuexen spa_info = (struct sctp_sendv_spa *)info; 1122e2e7c62eSMichael Tuexen if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) { 1123e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1124e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_SNDINFO; 1125e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); 1126e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo)); 1127e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); 1128e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); 1129e2e7c62eSMichael Tuexen } 1130e2e7c62eSMichael Tuexen if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) { 1131e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1132e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_PRINFO; 1133e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); 1134e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo)); 1135e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); 1136e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo))); 1137e2e7c62eSMichael Tuexen } 1138e2e7c62eSMichael Tuexen if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) { 1139e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1140e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_AUTHINFO; 1141e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo)); 1142e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo)); 1143e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo)); 1144e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo))); 1145e2e7c62eSMichael Tuexen } 1146e2e7c62eSMichael Tuexen break; 1147e2e7c62eSMichael Tuexen default: 1148e2e7c62eSMichael Tuexen free(cmsgbuf); 1149e2e7c62eSMichael Tuexen errno = EINVAL; 1150e2e7c62eSMichael Tuexen return (-1); 1151e2e7c62eSMichael Tuexen } 1152e2e7c62eSMichael Tuexen addr = addrs; 11530b064106SMichael Tuexen msg.msg_name = NULL; 11540b064106SMichael Tuexen msg.msg_namelen = 0; 11550b064106SMichael Tuexen 11560b064106SMichael Tuexen for (i = 0; i < addrcnt; i++) { 1157e2e7c62eSMichael Tuexen switch (addr->sa_family) { 1158e2e7c62eSMichael Tuexen case AF_INET: 11590b064106SMichael Tuexen addr_len = (socklen_t) sizeof(struct sockaddr_in); 11600b064106SMichael Tuexen addr_in = (struct sockaddr_in *)addr; 11610b064106SMichael Tuexen if (addr_in->sin_len != addr_len) { 1162e2e7c62eSMichael Tuexen free(cmsgbuf); 1163e2e7c62eSMichael Tuexen errno = EINVAL; 1164e2e7c62eSMichael Tuexen return (-1); 1165e2e7c62eSMichael Tuexen } 11660b064106SMichael Tuexen if (i == 0) { 11670b064106SMichael Tuexen port = addr_in->sin_port; 1168e2e7c62eSMichael Tuexen } else { 11690b064106SMichael Tuexen if (port == addr_in->sin_port) { 1170e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1171e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_DSTADDRV4; 1172e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); 1173e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr)); 1174e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr)); 1175e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr))); 11760b064106SMichael Tuexen } else { 11770b064106SMichael Tuexen free(cmsgbuf); 11780b064106SMichael Tuexen errno = EINVAL; 11790b064106SMichael Tuexen return (-1); 11800b064106SMichael Tuexen } 11810b064106SMichael Tuexen } 1182e2e7c62eSMichael Tuexen break; 1183e2e7c62eSMichael Tuexen case AF_INET6: 11840b064106SMichael Tuexen addr_len = (socklen_t) sizeof(struct sockaddr_in6); 1185e2e7c62eSMichael Tuexen addr_in6 = (struct sockaddr_in6 *)addr; 11860b064106SMichael Tuexen if (addr_in6->sin6_len != addr_len) { 11870b064106SMichael Tuexen free(cmsgbuf); 11880b064106SMichael Tuexen errno = EINVAL; 11890b064106SMichael Tuexen return (-1); 11900b064106SMichael Tuexen } 11910b064106SMichael Tuexen if (i == 0) { 11920b064106SMichael Tuexen port = addr_in6->sin6_port; 11930b064106SMichael Tuexen } else { 11940b064106SMichael Tuexen if (port == addr_in6->sin6_port) { 1195e2e7c62eSMichael Tuexen cmsg->cmsg_level = IPPROTO_SCTP; 1196e2e7c62eSMichael Tuexen cmsg->cmsg_type = SCTP_DSTADDRV6; 1197e2e7c62eSMichael Tuexen cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr)); 1198e2e7c62eSMichael Tuexen memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr)); 1199e2e7c62eSMichael Tuexen msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr)); 1200e2e7c62eSMichael Tuexen cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr))); 12010b064106SMichael Tuexen } else { 12020b064106SMichael Tuexen free(cmsgbuf); 12030b064106SMichael Tuexen errno = EINVAL; 12040b064106SMichael Tuexen return (-1); 12050b064106SMichael Tuexen } 12060b064106SMichael Tuexen } 1207e2e7c62eSMichael Tuexen break; 1208e2e7c62eSMichael Tuexen default: 1209e2e7c62eSMichael Tuexen free(cmsgbuf); 1210e2e7c62eSMichael Tuexen errno = EINVAL; 1211e2e7c62eSMichael Tuexen return (-1); 1212e2e7c62eSMichael Tuexen } 12130b064106SMichael Tuexen if (i == 0) { 12140b064106SMichael Tuexen msg.msg_name = addr; 12150b064106SMichael Tuexen msg.msg_namelen = addr_len; 12160b064106SMichael Tuexen } 1217e2e7c62eSMichael Tuexen addr = (struct sockaddr *)((caddr_t)addr + addr_len); 1218e2e7c62eSMichael Tuexen } 12190b064106SMichael Tuexen if (msg.msg_controllen == 0) { 12200b064106SMichael Tuexen msg.msg_control = NULL; 1221e2e7c62eSMichael Tuexen } 1222e2e7c62eSMichael Tuexen msg.msg_iov = (struct iovec *)iov; 1223e2e7c62eSMichael Tuexen msg.msg_iovlen = iovcnt; 1224e2e7c62eSMichael Tuexen msg.msg_flags = 0; 1225e2e7c62eSMichael Tuexen ret = sendmsg(sd, &msg, flags); 1226e2e7c62eSMichael Tuexen free(cmsgbuf); 1227e2e7c62eSMichael Tuexen return (ret); 1228e2e7c62eSMichael Tuexen } 1229e2e7c62eSMichael Tuexen 1230d6dda9b2SRandall Stewart 1231d6dda9b2SRandall Stewart #if !defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT) 1232d6dda9b2SRandall Stewart 1233d6dda9b2SRandall Stewart int 1234d6dda9b2SRandall Stewart sctp_peeloff(int sd, sctp_assoc_t assoc_id) 1235d6dda9b2SRandall Stewart { 1236d6dda9b2SRandall Stewart /* NOT supported, return invalid sd */ 1237d6dda9b2SRandall Stewart errno = ENOTSUP; 1238d6dda9b2SRandall Stewart return (-1); 1239d6dda9b2SRandall Stewart } 1240d6dda9b2SRandall Stewart 1241d6dda9b2SRandall Stewart #endif 1242d6dda9b2SRandall Stewart #if defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT) 1243d6dda9b2SRandall Stewart int 1244d6dda9b2SRandall Stewart sctp_peeloff(int sd, sctp_assoc_t assoc_id) 1245d6dda9b2SRandall Stewart { 1246d6dda9b2SRandall Stewart return (syscall(SYS_sctp_peeloff, sd, assoc_id)); 1247d6dda9b2SRandall Stewart } 1248d6dda9b2SRandall Stewart 1249d6dda9b2SRandall Stewart #endif 1250804cf641SRandall Stewart 1251804cf641SRandall Stewart 12522c0d559dSRandall Stewart #undef SCTP_CONTROL_VEC_SIZE_SND 12532c0d559dSRandall Stewart #undef SCTP_CONTROL_VEC_SIZE_RCV 12542c0d559dSRandall Stewart #undef SCTP_STACK_BUF_SIZE 1255