xref: /netbsd-src/lib/libc/net/sctp_sys_calls.c (revision ace5b9b5feb0e7608bd2da7a617428d2e1cf8aa3)
197b85c8cSrjs /*	$KAME: sctp_sys_calls.c,v 1.10 2005/03/06 16:04:16 itojun Exp $ */
2*ace5b9b5Schristos /*	$NetBSD: sctp_sys_calls.c,v 1.2 2024/01/20 14:52:48 christos Exp $ */
397b85c8cSrjs 
497b85c8cSrjs /*
597b85c8cSrjs  * Copyright (C) 2002, 2003, 2004 Cisco Systems Inc,
697b85c8cSrjs  * All rights reserved.
797b85c8cSrjs  *
897b85c8cSrjs  * Redistribution and use in source and binary forms, with or without
997b85c8cSrjs  * modification, are permitted provided that the following conditions
1097b85c8cSrjs  * are met:
1197b85c8cSrjs  * 1. Redistributions of source code must retain the above copyright
1297b85c8cSrjs  *    notice, this list of conditions and the following disclaimer.
1397b85c8cSrjs  * 2. Redistributions in binary form must reproduce the above copyright
1497b85c8cSrjs  *    notice, this list of conditions and the following disclaimer in the
1597b85c8cSrjs  *    documentation and/or other materials provided with the distribution.
1697b85c8cSrjs  * 3. Neither the name of the project nor the names of its contributors
1797b85c8cSrjs  *    may be used to endorse or promote products derived from this software
1897b85c8cSrjs  *    without specific prior written permission.
1997b85c8cSrjs  *
2097b85c8cSrjs  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2197b85c8cSrjs  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2297b85c8cSrjs  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2397b85c8cSrjs  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2497b85c8cSrjs  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2597b85c8cSrjs  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2697b85c8cSrjs  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2797b85c8cSrjs  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2897b85c8cSrjs  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2997b85c8cSrjs  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3097b85c8cSrjs  * SUCH DAMAGE.
3197b85c8cSrjs  */
3297b85c8cSrjs 
3397b85c8cSrjs #include <stdio.h>
3497b85c8cSrjs #include <string.h>
3597b85c8cSrjs #include <errno.h>
3697b85c8cSrjs #include <stdlib.h>
3797b85c8cSrjs #include <unistd.h>
3897b85c8cSrjs #include <sys/types.h>
3997b85c8cSrjs #include <sys/socket.h>
4097b85c8cSrjs #include <sys/errno.h>
4197b85c8cSrjs #include <sys/syscall.h>
4297b85c8cSrjs #include <sys/ioctl.h>
4397b85c8cSrjs #include <sys/uio.h>
4497b85c8cSrjs #include <netinet/in.h>
4597b85c8cSrjs #include <arpa/inet.h>
4697b85c8cSrjs #include <netinet/sctp_uio.h>
4797b85c8cSrjs #include <netinet/sctp.h>
4897b85c8cSrjs 
4997b85c8cSrjs #include <net/if_dl.h>
5097b85c8cSrjs 
5197b85c8cSrjs #ifndef IN6_IS_ADDR_V4MAPPED
5297b85c8cSrjs #define IN6_IS_ADDR_V4MAPPED(a)		     \
5397b85c8cSrjs 	((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) &&	\
5497b85c8cSrjs 	 (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) &&	\
5597b85c8cSrjs 	 (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff)))
5697b85c8cSrjs #endif
5797b85c8cSrjs 
5897b85c8cSrjs #define SCTP_CONTROL_VEC_SIZE_RCV	16384
5997b85c8cSrjs 
6097b85c8cSrjs #ifdef SCTP_DEBUG_PRINT_ADDRESS
6197b85c8cSrjs static void
SCTPPrintAnAddress(struct sockaddr * a)6297b85c8cSrjs SCTPPrintAnAddress(struct sockaddr *a)
6397b85c8cSrjs {
6497b85c8cSrjs 	char stringToPrint[256];
6597b85c8cSrjs 	u_short prt;
6697b85c8cSrjs 	char *srcaddr, *txt;
6797b85c8cSrjs 
6897b85c8cSrjs 	if (a == NULL) {
6997b85c8cSrjs 		printf("NULL\n");
7097b85c8cSrjs 		return;
7197b85c8cSrjs 	}
7297b85c8cSrjs 	if (a->sa_family == AF_INET) {
7397b85c8cSrjs 		srcaddr = (char *)&((struct sockaddr_in *)a)->sin_addr;
7497b85c8cSrjs 		txt = "IPv4 Address: ";
7597b85c8cSrjs 		prt = ntohs(((struct sockaddr_in *)a)->sin_port);
7697b85c8cSrjs 	} else if (a->sa_family == AF_INET6) {
7797b85c8cSrjs 		srcaddr = (char *)&((struct sockaddr_in6 *)a)->sin6_addr;
7897b85c8cSrjs 		prt = ntohs(((struct sockaddr_in6 *)a)->sin6_port);
7997b85c8cSrjs 		txt = "IPv6 Address: ";
8097b85c8cSrjs 	} else if (a->sa_family == AF_LINK) {
8197b85c8cSrjs 		int i;
8297b85c8cSrjs 		char tbuf[200];
8397b85c8cSrjs 		u_char adbuf[200];
8497b85c8cSrjs 		struct sockaddr_dl *dl;
8597b85c8cSrjs 
8697b85c8cSrjs 		dl = (struct sockaddr_dl *)a;
8797b85c8cSrjs 		strncpy(tbuf, dl->sdl_data, dl->sdl_nlen);
8897b85c8cSrjs 		tbuf[dl->sdl_nlen] = 0;
8997b85c8cSrjs 		printf("Intf:%s (len:%d)Interface index:%d type:%x(%d) ll-len:%d ",
9097b85c8cSrjs 		    tbuf, dl->sdl_nlen, dl->sdl_index, dl->sdl_type,
9197b85c8cSrjs 		    dl->sdl_type, dl->sdl_alen);
9297b85c8cSrjs 		memcpy(adbuf, LLADDR(dl), dl->sdl_alen);
9397b85c8cSrjs 		for (i = 0; i < dl->sdl_alen; i++){
9497b85c8cSrjs 			printf("%2.2x", adbuf[i]);
9597b85c8cSrjs 			if (i < (dl->sdl_alen - 1))
9697b85c8cSrjs 				printf(":");
9797b85c8cSrjs 		}
9897b85c8cSrjs 		printf("\n");
9997b85c8cSrjs 	/*	u_short	sdl_route[16];*/	/* source routing information */
10097b85c8cSrjs 		return;
10197b85c8cSrjs 	} else {
10297b85c8cSrjs 		return;
10397b85c8cSrjs 	}
10497b85c8cSrjs 	if (inet_ntop(a->sa_family, srcaddr, stringToPrint,
10597b85c8cSrjs 	    sizeof(stringToPrint))) {
10697b85c8cSrjs 		if (a->sa_family == AF_INET6) {
10797b85c8cSrjs 			printf("%s%s:%d scope:%d\n", txt, stringToPrint, prt,
10897b85c8cSrjs 			    ((struct sockaddr_in6 *)a)->sin6_scope_id);
10997b85c8cSrjs 		} else {
11097b85c8cSrjs 			printf("%s%s:%d\n", txt, stringToPrint, prt);
11197b85c8cSrjs 		}
11297b85c8cSrjs 
11397b85c8cSrjs 	} else {
11497b85c8cSrjs 		printf("%s unprintable?\n", txt);
11597b85c8cSrjs 	}
11697b85c8cSrjs }
11797b85c8cSrjs #endif /* SCTP_DEBUG_PRINT_ADDRESS */
11897b85c8cSrjs 
11997b85c8cSrjs void
in6_sin6_2_sin(struct sockaddr_in * sin,struct sockaddr_in6 * sin6)12097b85c8cSrjs in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
12197b85c8cSrjs {
12297b85c8cSrjs 	memset(sin, 0, sizeof(*sin));
12397b85c8cSrjs 	sin->sin_len = sizeof(struct sockaddr_in);
12497b85c8cSrjs 	sin->sin_family = AF_INET;
12597b85c8cSrjs 	sin->sin_port = sin6->sin6_port;
12697b85c8cSrjs 	sin->sin_addr.s_addr = sin6->sin6_addr.__u6_addr.__u6_addr32[3];
12797b85c8cSrjs }
12897b85c8cSrjs 
12997b85c8cSrjs int
sctp_connectx(int sd,struct sockaddr * addrs,int addrcnt,sctp_assoc_t * id)13097b85c8cSrjs sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt,
13197b85c8cSrjs 		sctp_assoc_t *id)
13297b85c8cSrjs {
13397b85c8cSrjs 	int i, ret, cnt;
13497b85c8cSrjs 	struct sockaddr *at;
13597b85c8cSrjs 	struct sctp_connectx_addrs sca;
13697b85c8cSrjs #if 0
13797b85c8cSrjs 	char *cpto;
13897b85c8cSrjs #endif
13997b85c8cSrjs 	size_t len;
14097b85c8cSrjs 
14197b85c8cSrjs 	at = addrs;
14297b85c8cSrjs 	cnt = 0;
14397b85c8cSrjs 	len = 0;
14497b85c8cSrjs 	/* validate all the addresses and get the size */
14597b85c8cSrjs 	for (i = 0; i < addrcnt; i++) {
14697b85c8cSrjs 		if (at->sa_family == AF_INET) {
14797b85c8cSrjs 			len += at->sa_len;
14897b85c8cSrjs 		} else if (at->sa_family == AF_INET6){
149*ace5b9b5Schristos 			if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)(void *)at)->sin6_addr)){
15097b85c8cSrjs 				len += sizeof(struct sockaddr_in);
15197b85c8cSrjs #if 0
15297b85c8cSrjs 				in6_sin6_2_sin((struct sockaddr_in *)cpto,
15397b85c8cSrjs 				    (struct sockaddr_in6 *)at);
15497b85c8cSrjs 				cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in));
15597b85c8cSrjs 				len += sizeof(struct sockaddr_in);
15697b85c8cSrjs #endif
15797b85c8cSrjs 			} else {
15897b85c8cSrjs 				len += at->sa_len;
15997b85c8cSrjs 			}
16097b85c8cSrjs 		} else {
16197b85c8cSrjs 			errno = EINVAL;
16297b85c8cSrjs 			return (-1);
16397b85c8cSrjs 		}
16497b85c8cSrjs 		at = (struct sockaddr *)((caddr_t)at + at->sa_len);
16597b85c8cSrjs 		cnt++;
16697b85c8cSrjs         }
16797b85c8cSrjs 	/* do we have any? */
16897b85c8cSrjs 	if (cnt == 0) {
16997b85c8cSrjs 		errno = EINVAL;
17097b85c8cSrjs 		return(-1);
17197b85c8cSrjs 	}
17297b85c8cSrjs 
17397b85c8cSrjs 	sca.cx_num = cnt;
174*ace5b9b5Schristos 	sca.cx_len = (int)len;
17597b85c8cSrjs 	sca.cx_addrs = addrs;
17697b85c8cSrjs 	ret = ioctl(sd, SIOCCONNECTX, (void *)&sca);
17797b85c8cSrjs 	if ((ret == 0) && (id != NULL)) {
17897b85c8cSrjs 		memcpy(id, &sca.cx_num, sizeof(sctp_assoc_t));
17997b85c8cSrjs 	}
18097b85c8cSrjs 	return (ret);
18197b85c8cSrjs }
18297b85c8cSrjs 
18397b85c8cSrjs int
sctp_bindx(int sd,struct sockaddr * addrs,int addrcnt,int flags)18497b85c8cSrjs sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags)
18597b85c8cSrjs {
18697b85c8cSrjs 	struct sctp_getaddresses *gaddrs;
18797b85c8cSrjs 	struct sockaddr *sa;
18897b85c8cSrjs 	int i, sz, fam, argsz;
18997b85c8cSrjs 
19097b85c8cSrjs 	if ((flags != SCTP_BINDX_ADD_ADDR) &&
19197b85c8cSrjs 	    (flags != SCTP_BINDX_REM_ADDR)) {
19297b85c8cSrjs 		errno = EFAULT;
19397b85c8cSrjs 		return(-1);
19497b85c8cSrjs 	}
19597b85c8cSrjs 	argsz = (sizeof(struct sockaddr_storage) +
19697b85c8cSrjs 	    sizeof(struct sctp_getaddresses));
19797b85c8cSrjs 	gaddrs = (struct sctp_getaddresses *)calloc(1, argsz);
19897b85c8cSrjs 	if (gaddrs == NULL) {
19997b85c8cSrjs 		errno = ENOMEM;
20097b85c8cSrjs 		return(-1);
20197b85c8cSrjs 	}
20297b85c8cSrjs 	gaddrs->sget_assoc_id = 0;
20397b85c8cSrjs 	sa = addrs;
20497b85c8cSrjs 	for (i = 0; i < addrcnt; i++) {
20597b85c8cSrjs 		sz = sa->sa_len;
20697b85c8cSrjs 		fam = sa->sa_family;
207*ace5b9b5Schristos 		((struct sockaddr_in *)(void *)&addrs[i])->sin_port = ((struct sockaddr_in *)(void *)sa)->sin_port;
20897b85c8cSrjs 		if ((fam != AF_INET) && (fam != AF_INET6)) {
20997b85c8cSrjs 			errno = EINVAL;
21097b85c8cSrjs 			return(-1);
21197b85c8cSrjs 		}
21297b85c8cSrjs 		memcpy(gaddrs->addr, sa, sz);
21397b85c8cSrjs 		if (setsockopt(sd, IPPROTO_SCTP, flags, gaddrs,
21497b85c8cSrjs 		    (unsigned int)argsz) != 0) {
21597b85c8cSrjs 			free(gaddrs);
21697b85c8cSrjs 			return(-1);
21797b85c8cSrjs 		}
21897b85c8cSrjs 		memset(gaddrs, 0, argsz);
21997b85c8cSrjs 		sa = (struct sockaddr *)((caddr_t)sa + sz);
22097b85c8cSrjs 	}
22197b85c8cSrjs 	free(gaddrs);
22297b85c8cSrjs 	return(0);
22397b85c8cSrjs }
22497b85c8cSrjs 
22597b85c8cSrjs 
22697b85c8cSrjs int
sctp_opt_info(int sd,sctp_assoc_t id,int opt,void * arg,socklen_t * size)22797b85c8cSrjs sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t *size)
22897b85c8cSrjs {
22997b85c8cSrjs 	if ((opt == SCTP_RTOINFO) ||
23097b85c8cSrjs  	    (opt == SCTP_ASSOCINFO) ||
23197b85c8cSrjs 	    (opt == SCTP_PRIMARY_ADDR) ||
23297b85c8cSrjs 	    (opt == SCTP_SET_PEER_PRIMARY_ADDR) ||
23397b85c8cSrjs 	    (opt == SCTP_PEER_ADDR_PARAMS) ||
23497b85c8cSrjs 	    (opt == SCTP_STATUS) ||
23597b85c8cSrjs 	    (opt == SCTP_GET_PEER_ADDR_INFO)) {
23697b85c8cSrjs 		*(sctp_assoc_t *)arg = id;
23797b85c8cSrjs 		return(getsockopt2(sd, IPPROTO_SCTP, opt, arg, size));
23897b85c8cSrjs 	} else {
23997b85c8cSrjs 		errno = EOPNOTSUPP;
24097b85c8cSrjs 		return(-1);
24197b85c8cSrjs 	}
24297b85c8cSrjs }
24397b85c8cSrjs 
24497b85c8cSrjs int
sctp_getpaddrs(int sd,sctp_assoc_t id,struct sockaddr ** raddrs)24597b85c8cSrjs sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs)
24697b85c8cSrjs {
24797b85c8cSrjs 	struct sctp_getaddresses *addrs;
24897b85c8cSrjs 	struct sockaddr *sa;
24997b85c8cSrjs 	struct sockaddr *re;
25097b85c8cSrjs 	sctp_assoc_t asoc;
25197b85c8cSrjs 	caddr_t lim;
25297b85c8cSrjs 	unsigned int siz;
25397b85c8cSrjs 	int cnt;
25497b85c8cSrjs 
25597b85c8cSrjs 	if (raddrs == NULL) {
25697b85c8cSrjs 		errno = EFAULT;
25797b85c8cSrjs 		return(-1);
25897b85c8cSrjs 	}
25997b85c8cSrjs 	asoc = id;
26097b85c8cSrjs 	siz = sizeof(sctp_assoc_t);
26197b85c8cSrjs 	if (getsockopt2(sd, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE,
26297b85c8cSrjs 	    &asoc, &siz) != 0) {
26397b85c8cSrjs 		return(-1);
26497b85c8cSrjs 	}
26597b85c8cSrjs 	siz = (unsigned int)asoc;
26697b85c8cSrjs 	siz += sizeof(struct sctp_getaddresses);
26797b85c8cSrjs 	addrs = calloc((unsigned long)1, (unsigned long)siz);
26897b85c8cSrjs 	if (addrs == NULL) {
26997b85c8cSrjs 		errno = ENOMEM;
27097b85c8cSrjs 		return(-1);
27197b85c8cSrjs 	}
27297b85c8cSrjs 	memset(addrs, 0, (size_t)siz);
27397b85c8cSrjs 	addrs->sget_assoc_id = id;
27497b85c8cSrjs 	/* Now lets get the array of addresses */
27597b85c8cSrjs 	if (getsockopt2(sd, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES,
27697b85c8cSrjs 	    addrs, &siz) != 0) {
27797b85c8cSrjs 		free(addrs);
27897b85c8cSrjs 		return(-1);
27997b85c8cSrjs 	}
28097b85c8cSrjs 	re = (struct sockaddr *)&addrs->addr[0];
28197b85c8cSrjs 	*raddrs = re;
28297b85c8cSrjs 	cnt = 0;
28397b85c8cSrjs 	sa = (struct sockaddr *)&addrs->addr[0];
28497b85c8cSrjs 	lim = (caddr_t)addrs + siz;
28597b85c8cSrjs 	while ((caddr_t)sa < lim) {
28697b85c8cSrjs 		cnt++;
28797b85c8cSrjs 		sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
28897b85c8cSrjs 		if (sa->sa_len == 0)
28997b85c8cSrjs 			break;
29097b85c8cSrjs 	}
29197b85c8cSrjs 	return(cnt);
29297b85c8cSrjs }
29397b85c8cSrjs 
sctp_freepaddrs(struct sockaddr * addrs)29497b85c8cSrjs void sctp_freepaddrs(struct sockaddr *addrs)
29597b85c8cSrjs {
29697b85c8cSrjs 	/* Take away the hidden association id */
29797b85c8cSrjs 	void *fr_addr;
29897b85c8cSrjs 	fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
29997b85c8cSrjs 	/* Now free it */
30097b85c8cSrjs 	free(fr_addr);
30197b85c8cSrjs }
30297b85c8cSrjs 
30397b85c8cSrjs int
sctp_getladdrs(int sd,sctp_assoc_t id,struct sockaddr ** raddrs)30497b85c8cSrjs sctp_getladdrs (int sd, sctp_assoc_t id, struct sockaddr **raddrs)
30597b85c8cSrjs {
30697b85c8cSrjs 	struct sctp_getaddresses *addrs;
30797b85c8cSrjs 	struct sockaddr *re;
30897b85c8cSrjs 	caddr_t lim;
30997b85c8cSrjs 	struct sockaddr *sa;
31097b85c8cSrjs 	int size_of_addresses;
311*ace5b9b5Schristos 	socklen_t siz;
31297b85c8cSrjs 	int cnt;
31397b85c8cSrjs 
31497b85c8cSrjs 	if (raddrs == NULL) {
31597b85c8cSrjs 		errno = EFAULT;
31697b85c8cSrjs 		return(-1);
31797b85c8cSrjs 	}
31897b85c8cSrjs 	size_of_addresses = 0;
31997b85c8cSrjs 	siz = sizeof(int);
32097b85c8cSrjs 	if (getsockopt2(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE,
32197b85c8cSrjs 	    &size_of_addresses, &siz) != 0) {
32297b85c8cSrjs 		return(-1);
32397b85c8cSrjs 	}
32497b85c8cSrjs 	if (size_of_addresses == 0) {
32597b85c8cSrjs 		errno = ENOTCONN;
32697b85c8cSrjs 		return(-1);
32797b85c8cSrjs 	}
328*ace5b9b5Schristos 	siz = (socklen_t)(size_of_addresses + sizeof(struct sockaddr_storage));
32997b85c8cSrjs 	siz += sizeof(struct sctp_getaddresses);
33097b85c8cSrjs 	addrs = calloc((unsigned long)1, (unsigned long)siz);
33197b85c8cSrjs 	if (addrs == NULL) {
33297b85c8cSrjs 		errno = ENOMEM;
33397b85c8cSrjs 		return(-1);
33497b85c8cSrjs 	}
33597b85c8cSrjs 	memset(addrs, 0, (size_t)siz);
33697b85c8cSrjs 	addrs->sget_assoc_id = id;
33797b85c8cSrjs 	/* Now lets get the array of addresses */
33897b85c8cSrjs 	if (getsockopt2(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs,
33997b85c8cSrjs 	    &siz) != 0) {
34097b85c8cSrjs 		free(addrs);
34197b85c8cSrjs 		return(-1);
34297b85c8cSrjs 	}
34397b85c8cSrjs 	re = (struct sockaddr *)&addrs->addr[0];
34497b85c8cSrjs 	*raddrs = re;
34597b85c8cSrjs 	cnt = 0;
34697b85c8cSrjs 	sa = (struct sockaddr *)&addrs->addr[0];
34797b85c8cSrjs 	lim = (caddr_t)addrs + siz;
34897b85c8cSrjs 	while ((caddr_t)sa < lim) {
34997b85c8cSrjs 		cnt++;
35097b85c8cSrjs 		sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
35197b85c8cSrjs 		if (sa->sa_len == 0)
35297b85c8cSrjs 			break;
35397b85c8cSrjs 	}
35497b85c8cSrjs 	return(cnt);
35597b85c8cSrjs }
35697b85c8cSrjs 
sctp_freeladdrs(struct sockaddr * addrs)35797b85c8cSrjs void sctp_freeladdrs(struct sockaddr *addrs)
35897b85c8cSrjs {
35997b85c8cSrjs 	/* Take away the hidden association id */
36097b85c8cSrjs 	void *fr_addr;
36197b85c8cSrjs 	fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
36297b85c8cSrjs 	/* Now free it */
36397b85c8cSrjs 	free(fr_addr);
36497b85c8cSrjs }
36597b85c8cSrjs 
36697b85c8cSrjs ssize_t
sctp_sendmsg(int s,const void * data,size_t len,const struct sockaddr * to,socklen_t tolen,u_int32_t ppid,u_int32_t flags,u_int16_t stream_no,u_int32_t timetolive,u_int32_t context)36797b85c8cSrjs sctp_sendmsg(int s,
36897b85c8cSrjs 	     const void *data,
36997b85c8cSrjs 	     size_t len,
37097b85c8cSrjs 	     const struct sockaddr *to,
37197b85c8cSrjs 	     socklen_t tolen __attribute__((unused)),
37297b85c8cSrjs 	     u_int32_t ppid,
37397b85c8cSrjs 	     u_int32_t flags,
37497b85c8cSrjs 	     u_int16_t stream_no,
37597b85c8cSrjs 	     u_int32_t timetolive,
37697b85c8cSrjs 	     u_int32_t context)
37797b85c8cSrjs {
378*ace5b9b5Schristos 	ssize_t sz;
37997b85c8cSrjs 	struct msghdr msg;
38097b85c8cSrjs 	struct iovec iov[2];
38197b85c8cSrjs 	char controlVector[256];
38297b85c8cSrjs 	struct sctp_sndrcvinfo *s_info;
38397b85c8cSrjs 	struct cmsghdr *cmsg;
38497b85c8cSrjs 	struct sockaddr *who=NULL;
38597b85c8cSrjs 	union {
38697b85c8cSrjs 		struct sockaddr_in in;
38797b85c8cSrjs 		struct sockaddr_in6 in6;
38897b85c8cSrjs 	} addr;
38997b85c8cSrjs 
39097b85c8cSrjs #if 0
39197b85c8cSrjs 	fprintf(io, "sctp_sendmsg(sd:%d, data:%x, len:%d, to:%x, tolen:%d, ppid:%x, flags:%x str:%d ttl:%d ctx:%x\n",
39297b85c8cSrjs 	    s, (u_int)data, (int)len, (u_int)to, (int)tolen, ppid, flags,
39397b85c8cSrjs 	    (int)stream_no, (int)timetolive, (u_int)context);
39497b85c8cSrjs 	fflush(io);
39597b85c8cSrjs #endif
39697b85c8cSrjs 	if (to) {
39797b85c8cSrjs 		if (to->sa_len == 0) {
39897b85c8cSrjs 			/*
39997b85c8cSrjs 			 * For the lazy app, that did not
40097b85c8cSrjs 			 * set sa_len, we attempt to set for them.
40197b85c8cSrjs 			 */
40297b85c8cSrjs 			switch (to->sa_family) {
40397b85c8cSrjs 			case AF_INET:
40497b85c8cSrjs 				memcpy(&addr, to, sizeof(struct sockaddr_in));
40597b85c8cSrjs 				addr.in.sin_len = sizeof(struct sockaddr_in);
40697b85c8cSrjs 				break;
40797b85c8cSrjs 			case AF_INET6:
40897b85c8cSrjs 				memcpy(&addr, to, sizeof(struct sockaddr_in6));
40997b85c8cSrjs 				addr.in6.sin6_len = sizeof(struct sockaddr_in6);
41097b85c8cSrjs 				break;
41197b85c8cSrjs 			default:
41297b85c8cSrjs 				errno = EAFNOSUPPORT;
41397b85c8cSrjs 				return -1;
41497b85c8cSrjs 			}
41597b85c8cSrjs 		} else {
41697b85c8cSrjs 			memcpy (&addr, to, to->sa_len);
41797b85c8cSrjs 		}
418*ace5b9b5Schristos 		who = (struct sockaddr *)(void *)&addr;
41997b85c8cSrjs 	}
42097b85c8cSrjs 	iov[0].iov_base = (void *)(unsigned long)data;
42197b85c8cSrjs 	iov[0].iov_len = len;
42297b85c8cSrjs 	iov[1].iov_base = NULL;
42397b85c8cSrjs 	iov[1].iov_len = 0;
42497b85c8cSrjs 
42597b85c8cSrjs 	if (to) {
42697b85c8cSrjs 		msg.msg_name = (caddr_t)who;
42797b85c8cSrjs 		msg.msg_namelen = who->sa_len;
42897b85c8cSrjs 	} else {
42997b85c8cSrjs 		msg.msg_name = (caddr_t)NULL;
43097b85c8cSrjs 		msg.msg_namelen = 0;
43197b85c8cSrjs 	}
43297b85c8cSrjs 	msg.msg_iov = iov;
43397b85c8cSrjs 	msg.msg_iovlen = 1;
43497b85c8cSrjs 	msg.msg_control = (caddr_t)controlVector;
43597b85c8cSrjs 
43697b85c8cSrjs 	cmsg = (struct cmsghdr *)controlVector;
43797b85c8cSrjs 
43897b85c8cSrjs 	cmsg->cmsg_level = IPPROTO_SCTP;
43997b85c8cSrjs 	cmsg->cmsg_type = SCTP_SNDRCV;
44097b85c8cSrjs 	cmsg->cmsg_len = CMSG_LEN (sizeof(struct sctp_sndrcvinfo) );
44197b85c8cSrjs 	s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
44297b85c8cSrjs 
44397b85c8cSrjs 	s_info->sinfo_stream = stream_no;
44497b85c8cSrjs 	s_info->sinfo_ssn = 0;
44597b85c8cSrjs 	s_info->sinfo_flags = flags;
44697b85c8cSrjs 	s_info->sinfo_ppid = ppid;
44797b85c8cSrjs 	s_info->sinfo_context = context;
44897b85c8cSrjs 	s_info->sinfo_assoc_id = 0;
44997b85c8cSrjs 	s_info->sinfo_timetolive = timetolive;
45097b85c8cSrjs 	errno = 0;
45197b85c8cSrjs 	msg.msg_controllen = cmsg->cmsg_len;
45297b85c8cSrjs 	sz = sendmsg(s, &msg, 0);
45397b85c8cSrjs 	return(sz);
45497b85c8cSrjs }
45597b85c8cSrjs 
45697b85c8cSrjs sctp_assoc_t
sctp_getassocid(int sd,struct sockaddr * sa)45797b85c8cSrjs sctp_getassocid(int sd, struct sockaddr *sa)
45897b85c8cSrjs {
45997b85c8cSrjs 	struct sctp_paddrparams sp;
46097b85c8cSrjs 	socklen_t siz;
46197b85c8cSrjs 
46297b85c8cSrjs 	/* First get the assoc id */
46397b85c8cSrjs 	siz = sizeof(struct sctp_paddrparams);
46497b85c8cSrjs 	memset(&sp, 0, sizeof(sp));
46597b85c8cSrjs 	memcpy((caddr_t)&sp.spp_address, sa, sa->sa_len);
46697b85c8cSrjs 	errno = 0;
46797b85c8cSrjs 	if (getsockopt2(sd, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &sp, &siz) != 0)
46897b85c8cSrjs 		return((sctp_assoc_t)0);
46997b85c8cSrjs 	/* We depend on the fact that 0 can never be returned */
47097b85c8cSrjs 	return(sp.spp_assoc_id);
47197b85c8cSrjs }
47297b85c8cSrjs 
47397b85c8cSrjs 
47497b85c8cSrjs 
47597b85c8cSrjs ssize_t
sctp_send(int sd,const void * data,size_t len,const struct sctp_sndrcvinfo * sinfo,int flags)47697b85c8cSrjs sctp_send(int sd, const void *data, size_t len,
47797b85c8cSrjs 	  const struct sctp_sndrcvinfo *sinfo,
47897b85c8cSrjs 	  int flags)
47997b85c8cSrjs {
480*ace5b9b5Schristos 	ssize_t sz;
48197b85c8cSrjs 	struct msghdr msg;
48297b85c8cSrjs 	struct iovec iov[2];
48397b85c8cSrjs 	struct sctp_sndrcvinfo *s_info;
48497b85c8cSrjs 	char controlVector[256];
48597b85c8cSrjs 	struct cmsghdr *cmsg;
48697b85c8cSrjs 
48797b85c8cSrjs 	iov[0].iov_base = (void *)(unsigned long)data;
48897b85c8cSrjs 	iov[0].iov_len = len;
48997b85c8cSrjs 	iov[1].iov_base = NULL;
49097b85c8cSrjs 	iov[1].iov_len = 0;
49197b85c8cSrjs 
49297b85c8cSrjs 	msg.msg_name = 0;
49397b85c8cSrjs 	msg.msg_namelen = 0;
49497b85c8cSrjs 	msg.msg_iov = iov;
49597b85c8cSrjs 	msg.msg_iovlen = 1;
49697b85c8cSrjs 	msg.msg_control = (caddr_t)controlVector;
49797b85c8cSrjs 
49897b85c8cSrjs 	cmsg = (struct cmsghdr *)controlVector;
49997b85c8cSrjs 
50097b85c8cSrjs 	cmsg->cmsg_level = IPPROTO_SCTP;
50197b85c8cSrjs 	cmsg->cmsg_type = SCTP_SNDRCV;
50297b85c8cSrjs 	cmsg->cmsg_len = CMSG_LEN (sizeof(struct sctp_sndrcvinfo) );
50397b85c8cSrjs 	s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
50497b85c8cSrjs 	/* copy in the data */
50597b85c8cSrjs 	*s_info = *sinfo;
50697b85c8cSrjs 	errno = 0;
50797b85c8cSrjs 	msg.msg_controllen = cmsg->cmsg_len;
50897b85c8cSrjs 	sz = sendmsg(sd, &msg, flags);
50997b85c8cSrjs 	return(sz);
51097b85c8cSrjs }
51197b85c8cSrjs 
51297b85c8cSrjs 
51397b85c8cSrjs ssize_t
sctp_sendx(int sd,const void * msg,size_t len,struct sockaddr * addrs,int addrcnt,struct sctp_sndrcvinfo * sinfo,int flags)51497b85c8cSrjs sctp_sendx(int sd, const void *msg, size_t len,
51597b85c8cSrjs 	   struct sockaddr *addrs, int addrcnt,
51697b85c8cSrjs 	   struct sctp_sndrcvinfo *sinfo,
51797b85c8cSrjs 	   int flags)
51897b85c8cSrjs {
519*ace5b9b5Schristos 	int i, cnt, saved_errno;
520*ace5b9b5Schristos 	ssize_t ret;
52197b85c8cSrjs 	int add_len;
52297b85c8cSrjs 	struct sockaddr *at;
52397b85c8cSrjs 	struct sctp_connectx_addrs sca;
52497b85c8cSrjs 
52597b85c8cSrjs 	len = 0;
52697b85c8cSrjs 	at = addrs;
52797b85c8cSrjs 	cnt = 0;
52897b85c8cSrjs 	/* validate all the addresses and get the size */
52997b85c8cSrjs 	for (i = 0; i < addrcnt; i++) {
53097b85c8cSrjs 		if (at->sa_family == AF_INET) {
53197b85c8cSrjs 			add_len = sizeof(struct sockaddr_in);
53297b85c8cSrjs 		} else if (at->sa_family == AF_INET6) {
53397b85c8cSrjs 			add_len = sizeof(struct sockaddr_in6);
53497b85c8cSrjs 		} else {
53597b85c8cSrjs 			errno = EINVAL;
53697b85c8cSrjs 			return (-1);
53797b85c8cSrjs 		}
53897b85c8cSrjs 		len += add_len;
53997b85c8cSrjs 		at = (struct sockaddr *)((caddr_t)at + add_len);
54097b85c8cSrjs 		cnt++;
54197b85c8cSrjs 	}
54297b85c8cSrjs 	/* do we have any? */
54397b85c8cSrjs 	if (cnt == 0) {
54497b85c8cSrjs 		errno = EINVAL;
54597b85c8cSrjs 		return(-1);
54697b85c8cSrjs 	}
54797b85c8cSrjs 
54897b85c8cSrjs 	sca.cx_num = cnt;
549*ace5b9b5Schristos 	sca.cx_len = (int)len;
55097b85c8cSrjs 	sca.cx_addrs = addrs;
55197b85c8cSrjs 	ret = ioctl(sd, SIOCCONNECTXDEL, (void *)&sca);
55297b85c8cSrjs 	if (ret != 0) {
55397b85c8cSrjs 		return(ret);
55497b85c8cSrjs 	}
55597b85c8cSrjs 	sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs);
55697b85c8cSrjs 	if (sinfo->sinfo_assoc_id == 0) {
55797b85c8cSrjs 		printf("Huh, can't get associd? TSNH!\n");
55897b85c8cSrjs 		(void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
55997b85c8cSrjs 				 (unsigned int)addrs->sa_len);
56097b85c8cSrjs 		errno = ENOENT;
56197b85c8cSrjs 		return (-1);
56297b85c8cSrjs 	}
56397b85c8cSrjs 	ret = sctp_send(sd, msg, len, sinfo, flags);
56497b85c8cSrjs 	saved_errno = errno;
56597b85c8cSrjs 	(void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
56697b85c8cSrjs 			 (unsigned int)addrs->sa_len);
56797b85c8cSrjs 
56897b85c8cSrjs 	errno = saved_errno;
56997b85c8cSrjs 	return (ret);
57097b85c8cSrjs }
57197b85c8cSrjs 
57297b85c8cSrjs ssize_t
sctp_sendmsgx(int sd,const void * msg,size_t len,struct sockaddr * addrs,int addrcnt,u_int32_t ppid,u_int32_t flags,u_int16_t stream_no,u_int32_t timetolive,u_int32_t context)57397b85c8cSrjs sctp_sendmsgx(int sd,
57497b85c8cSrjs 	      const void *msg,
57597b85c8cSrjs 	      size_t len,
57697b85c8cSrjs 	      struct sockaddr *addrs,
57797b85c8cSrjs 	      int addrcnt,
57897b85c8cSrjs 	      u_int32_t ppid,
57997b85c8cSrjs 	      u_int32_t flags,
58097b85c8cSrjs 	      u_int16_t stream_no,
58197b85c8cSrjs 	      u_int32_t timetolive,
58297b85c8cSrjs 	      u_int32_t context)
58397b85c8cSrjs {
58497b85c8cSrjs 	struct sctp_sndrcvinfo sinfo;
58597b85c8cSrjs 
58697b85c8cSrjs 	memset((void *) &sinfo, 0, sizeof(struct sctp_sndrcvinfo));
58797b85c8cSrjs 	sinfo.sinfo_ppid       = ppid;
58897b85c8cSrjs 	sinfo.sinfo_flags      = flags;
58997b85c8cSrjs 	sinfo.sinfo_ssn        = stream_no;
59097b85c8cSrjs 	sinfo.sinfo_timetolive = timetolive;
59197b85c8cSrjs 	sinfo.sinfo_context    = context;
59297b85c8cSrjs 	return sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0);
59397b85c8cSrjs }
59497b85c8cSrjs 
59597b85c8cSrjs ssize_t
sctp_recvmsg(int s,void * dbuf,size_t len,struct sockaddr * from,socklen_t * fromlen,struct sctp_sndrcvinfo * sinfo,int * msg_flags)59697b85c8cSrjs sctp_recvmsg (int s,
59797b85c8cSrjs 	      void *dbuf,
59897b85c8cSrjs 	      size_t len,
59997b85c8cSrjs 	      struct sockaddr *from,
60097b85c8cSrjs 	      socklen_t *fromlen,
60197b85c8cSrjs 	      struct sctp_sndrcvinfo *sinfo,
60297b85c8cSrjs 	      int *msg_flags)
60397b85c8cSrjs {
60497b85c8cSrjs 	struct sctp_sndrcvinfo *s_info;
60597b85c8cSrjs 	ssize_t sz;
60697b85c8cSrjs 	struct msghdr msg;
60797b85c8cSrjs 	struct iovec iov[2];
60897b85c8cSrjs 	char controlVector[2048];
60997b85c8cSrjs 	struct cmsghdr *cmsg;
61097b85c8cSrjs 	iov[0].iov_base = dbuf;
61197b85c8cSrjs 	iov[0].iov_len = len;
61297b85c8cSrjs 	iov[1].iov_base = NULL;
61397b85c8cSrjs 	iov[1].iov_len = 0;
61497b85c8cSrjs 	msg.msg_name = (caddr_t)from;
61597b85c8cSrjs 	msg.msg_namelen = *fromlen;
61697b85c8cSrjs 	msg.msg_iov = iov;
61797b85c8cSrjs 	msg.msg_iovlen = 1;
61897b85c8cSrjs 	msg.msg_control = (caddr_t)controlVector;
61997b85c8cSrjs 	msg.msg_controllen = sizeof(controlVector);
62097b85c8cSrjs 	errno = 0;
62197b85c8cSrjs 	sz = recvmsg(s, &msg, 0);
62297b85c8cSrjs 
62397b85c8cSrjs 	s_info = NULL;
62497b85c8cSrjs 	len = sz;
62597b85c8cSrjs 	*msg_flags = msg.msg_flags;
62697b85c8cSrjs 	*fromlen = msg.msg_namelen;
62797b85c8cSrjs 	if ((msg.msg_controllen) && sinfo) {
62897b85c8cSrjs 		/* parse through and see if we find
62997b85c8cSrjs 		 * the sctp_sndrcvinfo (if the user wants it).
63097b85c8cSrjs 		 */
63197b85c8cSrjs 		cmsg = (struct cmsghdr *)controlVector;
63297b85c8cSrjs 		while (cmsg) {
63397b85c8cSrjs 			if (cmsg->cmsg_level == IPPROTO_SCTP) {
63497b85c8cSrjs 				if (cmsg->cmsg_type == SCTP_SNDRCV) {
63597b85c8cSrjs 					/* Got it */
63697b85c8cSrjs 					s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
63797b85c8cSrjs 					/* Copy it to the user */
63897b85c8cSrjs 					*sinfo = *s_info;
63997b85c8cSrjs 					break;
64097b85c8cSrjs 				}
64197b85c8cSrjs 			}
64297b85c8cSrjs 			cmsg = CMSG_NXTHDR(&msg, cmsg);
64397b85c8cSrjs 		}
64497b85c8cSrjs 	}
64597b85c8cSrjs 	return(sz);
64697b85c8cSrjs }
64797b85c8cSrjs 
64897b85c8cSrjs ssize_t
sctp_recvv(int sd,const struct iovec * iov,int iovlen,struct sockaddr * from,socklen_t * fromlen,void * info,socklen_t * infolen,unsigned int * infotype,int * flags)64997b85c8cSrjs sctp_recvv(int sd,
65097b85c8cSrjs     const struct iovec *iov,
65197b85c8cSrjs     int iovlen,
65297b85c8cSrjs     struct sockaddr *from,
65397b85c8cSrjs     socklen_t * fromlen,
65497b85c8cSrjs     void *info,
65597b85c8cSrjs     socklen_t * infolen,
65697b85c8cSrjs     unsigned int *infotype,
65797b85c8cSrjs     int *flags)
65897b85c8cSrjs {
65997b85c8cSrjs 	char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV];
66097b85c8cSrjs 	struct msghdr msg;
66197b85c8cSrjs 	struct cmsghdr *cmsg;
66297b85c8cSrjs 	ssize_t ret;
66397b85c8cSrjs 	struct sctp_rcvinfo *rcvinfo;
66497b85c8cSrjs 	struct sctp_nxtinfo *nxtinfo;
66597b85c8cSrjs 
66697b85c8cSrjs 	if (((info != NULL) && (infolen == NULL)) ||
66797b85c8cSrjs 	    ((info == NULL) && (infolen != NULL) && (*infolen != 0)) ||
66897b85c8cSrjs 	    ((info != NULL) && (infotype == NULL))) {
66997b85c8cSrjs 		errno = EINVAL;
67097b85c8cSrjs 		return (-1);
67197b85c8cSrjs 	}
67297b85c8cSrjs 	if (infotype) {
67397b85c8cSrjs 		*infotype = SCTP_RECVV_NOINFO;
67497b85c8cSrjs 	}
67597b85c8cSrjs 	msg.msg_name = from;
67697b85c8cSrjs 	if (fromlen == NULL) {
67797b85c8cSrjs 		msg.msg_namelen = 0;
67897b85c8cSrjs 	} else {
67997b85c8cSrjs 		msg.msg_namelen = *fromlen;
68097b85c8cSrjs 	}
68197b85c8cSrjs 	msg.msg_iov = __UNCONST(iov);
68297b85c8cSrjs 	msg.msg_iovlen = iovlen;
68397b85c8cSrjs 	msg.msg_control = cmsgbuf;
68497b85c8cSrjs 	msg.msg_controllen = sizeof(cmsgbuf);
68597b85c8cSrjs 	msg.msg_flags = 0;
68697b85c8cSrjs 	ret = recvmsg(sd, &msg, *flags);
68797b85c8cSrjs 	*flags = msg.msg_flags;
68897b85c8cSrjs 	if ((ret > 0) &&
68997b85c8cSrjs 	    (msg.msg_controllen > 0) &&
69097b85c8cSrjs 	    (infotype != NULL) &&
69197b85c8cSrjs 	    (infolen != NULL) &&
69297b85c8cSrjs 	    (*infolen > 0)) {
69397b85c8cSrjs 		rcvinfo = NULL;
69497b85c8cSrjs 		nxtinfo = NULL;
69597b85c8cSrjs 		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
69697b85c8cSrjs 			if (cmsg->cmsg_level != IPPROTO_SCTP) {
69797b85c8cSrjs 				continue;
69897b85c8cSrjs 			}
69997b85c8cSrjs 			if (cmsg->cmsg_type == SCTP_RCVINFO) {
70097b85c8cSrjs 				rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg);
70197b85c8cSrjs 				if (nxtinfo != NULL) {
70297b85c8cSrjs 					break;
70397b85c8cSrjs 				} else {
70497b85c8cSrjs 					continue;
70597b85c8cSrjs 				}
70697b85c8cSrjs 			}
70797b85c8cSrjs 			if (cmsg->cmsg_type == SCTP_NXTINFO) {
70897b85c8cSrjs 				nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg);
70997b85c8cSrjs 				if (rcvinfo != NULL) {
71097b85c8cSrjs 					break;
71197b85c8cSrjs 				} else {
71297b85c8cSrjs 					continue;
71397b85c8cSrjs 				}
71497b85c8cSrjs 			}
71597b85c8cSrjs 		}
71697b85c8cSrjs 		if (rcvinfo != NULL) {
71797b85c8cSrjs 			if ((nxtinfo != NULL) && (*infolen >= sizeof(struct sctp_recvv_rn))) {
71897b85c8cSrjs 				struct sctp_recvv_rn *rn_info;
71997b85c8cSrjs 
72097b85c8cSrjs 				rn_info = (struct sctp_recvv_rn *)info;
72197b85c8cSrjs 				rn_info->recvv_rcvinfo = *rcvinfo;
72297b85c8cSrjs 				rn_info->recvv_nxtinfo = *nxtinfo;
72397b85c8cSrjs 				*infolen = (socklen_t) sizeof(struct sctp_recvv_rn);
72497b85c8cSrjs 				*infotype = SCTP_RECVV_RN;
72597b85c8cSrjs 			} else if (*infolen >= sizeof(struct sctp_rcvinfo)) {
72697b85c8cSrjs 				memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo));
72797b85c8cSrjs 				*infolen = (socklen_t) sizeof(struct sctp_rcvinfo);
72897b85c8cSrjs 				*infotype = SCTP_RECVV_RCVINFO;
72997b85c8cSrjs 			}
73097b85c8cSrjs 		} else if (nxtinfo != NULL) {
73197b85c8cSrjs 			if (*infolen >= sizeof(struct sctp_nxtinfo)) {
73297b85c8cSrjs 				memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo));
73397b85c8cSrjs 				*infolen = (socklen_t) sizeof(struct sctp_nxtinfo);
73497b85c8cSrjs 				*infotype = SCTP_RECVV_NXTINFO;
73597b85c8cSrjs 			}
73697b85c8cSrjs 		}
73797b85c8cSrjs 	}
73897b85c8cSrjs 	return (ret);
73997b85c8cSrjs }
74097b85c8cSrjs 
74197b85c8cSrjs ssize_t
sctp_sendv(int sd,const struct iovec * iov,int iovcnt,struct sockaddr * addrs,int addrcnt,void * info,socklen_t infolen,unsigned int infotype,int flags)74297b85c8cSrjs sctp_sendv(int sd,
74397b85c8cSrjs     const struct iovec *iov, int iovcnt,
74497b85c8cSrjs     struct sockaddr *addrs, int addrcnt,
74597b85c8cSrjs     void *info, socklen_t infolen, unsigned int infotype,
74697b85c8cSrjs     int flags)
74797b85c8cSrjs {
74897b85c8cSrjs 	ssize_t ret;
74997b85c8cSrjs 	int i;
75097b85c8cSrjs 	socklen_t addr_len;
75197b85c8cSrjs 	struct msghdr msg;
75297b85c8cSrjs 	in_port_t port;
75397b85c8cSrjs 	struct sctp_sendv_spa *spa_info;
75497b85c8cSrjs 	struct cmsghdr *cmsg;
75597b85c8cSrjs 	char *cmsgbuf;
75697b85c8cSrjs 	struct sockaddr *addr;
75797b85c8cSrjs 	struct sockaddr_in *addr_in;
75897b85c8cSrjs 	struct sockaddr_in6 *addr_in6;
75997b85c8cSrjs 	void *assoc_id_ptr;
76097b85c8cSrjs 	sctp_assoc_t assoc_id;
76197b85c8cSrjs 
76297b85c8cSrjs 	if ((addrcnt < 0) ||
76397b85c8cSrjs 	    (iovcnt < 0) ||
76497b85c8cSrjs 	    ((addrs == NULL) && (addrcnt > 0)) ||
76597b85c8cSrjs 	    ((addrs != NULL) && (addrcnt == 0)) ||
76697b85c8cSrjs 	    ((iov == NULL) && (iovcnt > 0)) ||
76797b85c8cSrjs 	    ((iov != NULL) && (iovcnt == 0))) {
76897b85c8cSrjs 		errno = EINVAL;
76997b85c8cSrjs 		return (-1);
77097b85c8cSrjs 	}
77197b85c8cSrjs 	cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) +
77297b85c8cSrjs 	    CMSG_SPACE(sizeof(struct sctp_prinfo)) +
77397b85c8cSrjs 	    CMSG_SPACE(sizeof(struct sctp_authinfo)) +
77497b85c8cSrjs 	    (size_t)addrcnt * CMSG_SPACE(sizeof(struct in6_addr)));
77597b85c8cSrjs 	if (cmsgbuf == NULL) {
77697b85c8cSrjs 		errno = ENOMEM;
77797b85c8cSrjs 		return (-1);
77897b85c8cSrjs 	}
77997b85c8cSrjs 	assoc_id_ptr = NULL;
78097b85c8cSrjs 	msg.msg_control = cmsgbuf;
78197b85c8cSrjs 	msg.msg_controllen = 0;
78297b85c8cSrjs 	cmsg = (struct cmsghdr *)cmsgbuf;
78397b85c8cSrjs 	switch (infotype) {
78497b85c8cSrjs 	case SCTP_SENDV_NOINFO:
78597b85c8cSrjs 		if ((infolen != 0) || (info != NULL)) {
78697b85c8cSrjs 			free(cmsgbuf);
78797b85c8cSrjs 			errno = EINVAL;
78897b85c8cSrjs 			return (-1);
78997b85c8cSrjs 		}
79097b85c8cSrjs 		break;
79197b85c8cSrjs 	case SCTP_SENDV_SNDINFO:
79297b85c8cSrjs 		if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) {
79397b85c8cSrjs 			free(cmsgbuf);
79497b85c8cSrjs 			errno = EINVAL;
79597b85c8cSrjs 			return (-1);
79697b85c8cSrjs 		}
79797b85c8cSrjs 		cmsg->cmsg_level = IPPROTO_SCTP;
79897b85c8cSrjs 		cmsg->cmsg_type = SCTP_SNDINFO;
79997b85c8cSrjs 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
80097b85c8cSrjs 		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo));
80197b85c8cSrjs 		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
80297b85c8cSrjs 		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
80397b85c8cSrjs 		assoc_id_ptr = &(((struct sctp_sndinfo *)info)->snd_assoc_id);
80497b85c8cSrjs 		break;
80597b85c8cSrjs 	case SCTP_SENDV_PRINFO:
80697b85c8cSrjs 		if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) {
80797b85c8cSrjs 			free(cmsgbuf);
80897b85c8cSrjs 			errno = EINVAL;
80997b85c8cSrjs 			return (-1);
81097b85c8cSrjs 		}
81197b85c8cSrjs 		cmsg->cmsg_level = IPPROTO_SCTP;
81297b85c8cSrjs 		cmsg->cmsg_type = SCTP_PRINFO;
81397b85c8cSrjs 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
81497b85c8cSrjs 		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo));
81597b85c8cSrjs 		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
81697b85c8cSrjs 		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
81797b85c8cSrjs 		break;
81897b85c8cSrjs 	case SCTP_SENDV_AUTHINFO:
81997b85c8cSrjs 		if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) {
82097b85c8cSrjs 			free(cmsgbuf);
82197b85c8cSrjs 			errno = EINVAL;
82297b85c8cSrjs 			return (-1);
82397b85c8cSrjs 		}
82497b85c8cSrjs 		cmsg->cmsg_level = IPPROTO_SCTP;
82597b85c8cSrjs 		cmsg->cmsg_type = SCTP_AUTHINFO;
82697b85c8cSrjs 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
82797b85c8cSrjs 		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo));
82897b85c8cSrjs 		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
82997b85c8cSrjs 		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
83097b85c8cSrjs 		break;
83197b85c8cSrjs 	case SCTP_SENDV_SPA:
83297b85c8cSrjs 		if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) {
83397b85c8cSrjs 			free(cmsgbuf);
83497b85c8cSrjs 			errno = EINVAL;
83597b85c8cSrjs 			return (-1);
83697b85c8cSrjs 		}
83797b85c8cSrjs 		spa_info = (struct sctp_sendv_spa *)info;
83897b85c8cSrjs 		if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) {
83997b85c8cSrjs 			cmsg->cmsg_level = IPPROTO_SCTP;
84097b85c8cSrjs 			cmsg->cmsg_type = SCTP_SNDINFO;
84197b85c8cSrjs 			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
84297b85c8cSrjs 			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo));
84397b85c8cSrjs 			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
84497b85c8cSrjs 			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
84597b85c8cSrjs 			assoc_id_ptr = &(spa_info->sendv_sndinfo.snd_assoc_id);
84697b85c8cSrjs 		}
84797b85c8cSrjs 		if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) {
84897b85c8cSrjs 			cmsg->cmsg_level = IPPROTO_SCTP;
84997b85c8cSrjs 			cmsg->cmsg_type = SCTP_PRINFO;
85097b85c8cSrjs 			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
85197b85c8cSrjs 			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo));
85297b85c8cSrjs 			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
85397b85c8cSrjs 			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
85497b85c8cSrjs 		}
85597b85c8cSrjs 		if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) {
85697b85c8cSrjs 			cmsg->cmsg_level = IPPROTO_SCTP;
85797b85c8cSrjs 			cmsg->cmsg_type = SCTP_AUTHINFO;
85897b85c8cSrjs 			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
85997b85c8cSrjs 			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo));
86097b85c8cSrjs 			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
86197b85c8cSrjs 			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
86297b85c8cSrjs 		}
86397b85c8cSrjs 		break;
86497b85c8cSrjs 	default:
86597b85c8cSrjs 		free(cmsgbuf);
86697b85c8cSrjs 		errno = EINVAL;
86797b85c8cSrjs 		return (-1);
86897b85c8cSrjs 	}
86997b85c8cSrjs 	addr = addrs;
87097b85c8cSrjs 	msg.msg_name = NULL;
87197b85c8cSrjs 	msg.msg_namelen = 0;
87297b85c8cSrjs 
87397b85c8cSrjs 	for (i = 0; i < addrcnt; i++) {
87497b85c8cSrjs 		switch (addr->sa_family) {
87597b85c8cSrjs 		case AF_INET:
87697b85c8cSrjs 			addr_len = (socklen_t) sizeof(struct sockaddr_in);
877*ace5b9b5Schristos 			addr_in = (struct sockaddr_in *)(void *)addr;
87897b85c8cSrjs 			if (addr_in->sin_len != addr_len) {
87997b85c8cSrjs 				free(cmsgbuf);
88097b85c8cSrjs 				errno = EINVAL;
88197b85c8cSrjs 				return (-1);
88297b85c8cSrjs 			}
88397b85c8cSrjs 			if (i == 0) {
88497b85c8cSrjs 				port = addr_in->sin_port;
88597b85c8cSrjs 			} else {
88697b85c8cSrjs 				if (port == addr_in->sin_port) {
88797b85c8cSrjs 					cmsg->cmsg_level = IPPROTO_SCTP;
88897b85c8cSrjs 					cmsg->cmsg_type = SCTP_DSTADDRV4;
88997b85c8cSrjs 					cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
89097b85c8cSrjs 					memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr));
89197b85c8cSrjs 					msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr));
89297b85c8cSrjs 					cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr)));
89397b85c8cSrjs 				} else {
89497b85c8cSrjs 					free(cmsgbuf);
89597b85c8cSrjs 					errno = EINVAL;
89697b85c8cSrjs 					return (-1);
89797b85c8cSrjs 				}
89897b85c8cSrjs 			}
89997b85c8cSrjs 			break;
90097b85c8cSrjs 		case AF_INET6:
90197b85c8cSrjs 			addr_len = (socklen_t) sizeof(struct sockaddr_in6);
902*ace5b9b5Schristos 			addr_in6 = (struct sockaddr_in6 *)(void *)addr;
90397b85c8cSrjs 			if (addr_in6->sin6_len != addr_len) {
90497b85c8cSrjs 				free(cmsgbuf);
90597b85c8cSrjs 				errno = EINVAL;
90697b85c8cSrjs 				return (-1);
90797b85c8cSrjs 			}
90897b85c8cSrjs 			if (i == 0) {
90997b85c8cSrjs 				port = addr_in6->sin6_port;
91097b85c8cSrjs 			} else {
91197b85c8cSrjs 				if (port == addr_in6->sin6_port) {
91297b85c8cSrjs 					cmsg->cmsg_level = IPPROTO_SCTP;
91397b85c8cSrjs 					cmsg->cmsg_type = SCTP_DSTADDRV6;
91497b85c8cSrjs 					cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr));
91597b85c8cSrjs 					memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr));
91697b85c8cSrjs 					msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr));
91797b85c8cSrjs 					cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr)));
91897b85c8cSrjs 				} else {
91997b85c8cSrjs 					free(cmsgbuf);
92097b85c8cSrjs 					errno = EINVAL;
92197b85c8cSrjs 					return (-1);
92297b85c8cSrjs 				}
92397b85c8cSrjs 			}
92497b85c8cSrjs 			break;
92597b85c8cSrjs 		default:
92697b85c8cSrjs 			free(cmsgbuf);
92797b85c8cSrjs 			errno = EINVAL;
92897b85c8cSrjs 			return (-1);
92997b85c8cSrjs 		}
93097b85c8cSrjs 		if (i == 0) {
93197b85c8cSrjs 			msg.msg_name = addr;
93297b85c8cSrjs 			msg.msg_namelen = addr_len;
93397b85c8cSrjs 		}
93497b85c8cSrjs 		addr = (struct sockaddr *)((caddr_t)addr + addr_len);
93597b85c8cSrjs 	}
93697b85c8cSrjs 	if (msg.msg_controllen == 0) {
93797b85c8cSrjs 		msg.msg_control = NULL;
93897b85c8cSrjs 	}
93997b85c8cSrjs 	msg.msg_iov = __UNCONST(iov);
94097b85c8cSrjs 	msg.msg_iovlen = iovcnt;
94197b85c8cSrjs 	msg.msg_flags = 0;
94297b85c8cSrjs 	ret = sendmsg(sd, &msg, flags);
94397b85c8cSrjs 	free(cmsgbuf);
94497b85c8cSrjs 	if ((ret >= 0) && (addrs != NULL) && (assoc_id_ptr != NULL)) {
94597b85c8cSrjs 		assoc_id = sctp_getassocid(sd, addrs);
94697b85c8cSrjs 		memcpy(assoc_id_ptr, &assoc_id, sizeof(assoc_id));
94797b85c8cSrjs 	}
94897b85c8cSrjs 	return (ret);
94997b85c8cSrjs }
95097b85c8cSrjs 
95197b85c8cSrjs int
sctp_peeloff(int sd,sctp_assoc_t assoc_id)95297b85c8cSrjs sctp_peeloff(int sd, sctp_assoc_t assoc_id)
95397b85c8cSrjs {
95497b85c8cSrjs 	int ret;
95597b85c8cSrjs 	uint32_t val;
95697b85c8cSrjs 
95797b85c8cSrjs 	val = assoc_id;
95897b85c8cSrjs 	ret = ioctl(sd, SIOCPEELOFF, &val);
95997b85c8cSrjs 	if (ret == -1)
96097b85c8cSrjs 		return ret;
96197b85c8cSrjs 	else
96297b85c8cSrjs 		return (int) val;
96397b85c8cSrjs }
96497b85c8cSrjs 
965