Home | History | Annotate | Line # | Download | only in net
      1 /*	$KAME: sctp_sys_calls.c,v 1.10 2005/03/06 16:04:16 itojun Exp $ */
      2 /*	$NetBSD: sctp_sys_calls.c,v 1.2 2024/01/20 14:52:48 christos Exp $ */
      3 
      4 /*
      5  * Copyright (C) 2002, 2003, 2004 Cisco Systems Inc,
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. Neither the name of the project nor the names of its contributors
     17  *    may be used to endorse or promote products derived from this software
     18  *    without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     30  * SUCH DAMAGE.
     31  */
     32 
     33 #include <stdio.h>
     34 #include <string.h>
     35 #include <errno.h>
     36 #include <stdlib.h>
     37 #include <unistd.h>
     38 #include <sys/types.h>
     39 #include <sys/socket.h>
     40 #include <sys/errno.h>
     41 #include <sys/syscall.h>
     42 #include <sys/ioctl.h>
     43 #include <sys/uio.h>
     44 #include <netinet/in.h>
     45 #include <arpa/inet.h>
     46 #include <netinet/sctp_uio.h>
     47 #include <netinet/sctp.h>
     48 
     49 #include <net/if_dl.h>
     50 
     51 #ifndef IN6_IS_ADDR_V4MAPPED
     52 #define IN6_IS_ADDR_V4MAPPED(a)		     \
     53 	((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) &&	\
     54 	 (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) &&	\
     55 	 (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff)))
     56 #endif
     57 
     58 #define SCTP_CONTROL_VEC_SIZE_RCV	16384
     59 
     60 #ifdef SCTP_DEBUG_PRINT_ADDRESS
     61 static void
     62 SCTPPrintAnAddress(struct sockaddr *a)
     63 {
     64 	char stringToPrint[256];
     65 	u_short prt;
     66 	char *srcaddr, *txt;
     67 
     68 	if (a == NULL) {
     69 		printf("NULL\n");
     70 		return;
     71 	}
     72 	if (a->sa_family == AF_INET) {
     73 		srcaddr = (char *)&((struct sockaddr_in *)a)->sin_addr;
     74 		txt = "IPv4 Address: ";
     75 		prt = ntohs(((struct sockaddr_in *)a)->sin_port);
     76 	} else if (a->sa_family == AF_INET6) {
     77 		srcaddr = (char *)&((struct sockaddr_in6 *)a)->sin6_addr;
     78 		prt = ntohs(((struct sockaddr_in6 *)a)->sin6_port);
     79 		txt = "IPv6 Address: ";
     80 	} else if (a->sa_family == AF_LINK) {
     81 		int i;
     82 		char tbuf[200];
     83 		u_char adbuf[200];
     84 		struct sockaddr_dl *dl;
     85 
     86 		dl = (struct sockaddr_dl *)a;
     87 		strncpy(tbuf, dl->sdl_data, dl->sdl_nlen);
     88 		tbuf[dl->sdl_nlen] = 0;
     89 		printf("Intf:%s (len:%d)Interface index:%d type:%x(%d) ll-len:%d ",
     90 		    tbuf, dl->sdl_nlen, dl->sdl_index, dl->sdl_type,
     91 		    dl->sdl_type, dl->sdl_alen);
     92 		memcpy(adbuf, LLADDR(dl), dl->sdl_alen);
     93 		for (i = 0; i < dl->sdl_alen; i++){
     94 			printf("%2.2x", adbuf[i]);
     95 			if (i < (dl->sdl_alen - 1))
     96 				printf(":");
     97 		}
     98 		printf("\n");
     99 	/*	u_short	sdl_route[16];*/	/* source routing information */
    100 		return;
    101 	} else {
    102 		return;
    103 	}
    104 	if (inet_ntop(a->sa_family, srcaddr, stringToPrint,
    105 	    sizeof(stringToPrint))) {
    106 		if (a->sa_family == AF_INET6) {
    107 			printf("%s%s:%d scope:%d\n", txt, stringToPrint, prt,
    108 			    ((struct sockaddr_in6 *)a)->sin6_scope_id);
    109 		} else {
    110 			printf("%s%s:%d\n", txt, stringToPrint, prt);
    111 		}
    112 
    113 	} else {
    114 		printf("%s unprintable?\n", txt);
    115 	}
    116 }
    117 #endif /* SCTP_DEBUG_PRINT_ADDRESS */
    118 
    119 void
    120 in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
    121 {
    122 	memset(sin, 0, sizeof(*sin));
    123 	sin->sin_len = sizeof(struct sockaddr_in);
    124 	sin->sin_family = AF_INET;
    125 	sin->sin_port = sin6->sin6_port;
    126 	sin->sin_addr.s_addr = sin6->sin6_addr.__u6_addr.__u6_addr32[3];
    127 }
    128 
    129 int
    130 sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt,
    131 		sctp_assoc_t *id)
    132 {
    133 	int i, ret, cnt;
    134 	struct sockaddr *at;
    135 	struct sctp_connectx_addrs sca;
    136 #if 0
    137 	char *cpto;
    138 #endif
    139 	size_t len;
    140 
    141 	at = addrs;
    142 	cnt = 0;
    143 	len = 0;
    144 	/* validate all the addresses and get the size */
    145 	for (i = 0; i < addrcnt; i++) {
    146 		if (at->sa_family == AF_INET) {
    147 			len += at->sa_len;
    148 		} else if (at->sa_family == AF_INET6){
    149 			if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)(void *)at)->sin6_addr)){
    150 				len += sizeof(struct sockaddr_in);
    151 #if 0
    152 				in6_sin6_2_sin((struct sockaddr_in *)cpto,
    153 				    (struct sockaddr_in6 *)at);
    154 				cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in));
    155 				len += sizeof(struct sockaddr_in);
    156 #endif
    157 			} else {
    158 				len += at->sa_len;
    159 			}
    160 		} else {
    161 			errno = EINVAL;
    162 			return (-1);
    163 		}
    164 		at = (struct sockaddr *)((caddr_t)at + at->sa_len);
    165 		cnt++;
    166         }
    167 	/* do we have any? */
    168 	if (cnt == 0) {
    169 		errno = EINVAL;
    170 		return(-1);
    171 	}
    172 
    173 	sca.cx_num = cnt;
    174 	sca.cx_len = (int)len;
    175 	sca.cx_addrs = addrs;
    176 	ret = ioctl(sd, SIOCCONNECTX, (void *)&sca);
    177 	if ((ret == 0) && (id != NULL)) {
    178 		memcpy(id, &sca.cx_num, sizeof(sctp_assoc_t));
    179 	}
    180 	return (ret);
    181 }
    182 
    183 int
    184 sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags)
    185 {
    186 	struct sctp_getaddresses *gaddrs;
    187 	struct sockaddr *sa;
    188 	int i, sz, fam, argsz;
    189 
    190 	if ((flags != SCTP_BINDX_ADD_ADDR) &&
    191 	    (flags != SCTP_BINDX_REM_ADDR)) {
    192 		errno = EFAULT;
    193 		return(-1);
    194 	}
    195 	argsz = (sizeof(struct sockaddr_storage) +
    196 	    sizeof(struct sctp_getaddresses));
    197 	gaddrs = (struct sctp_getaddresses *)calloc(1, argsz);
    198 	if (gaddrs == NULL) {
    199 		errno = ENOMEM;
    200 		return(-1);
    201 	}
    202 	gaddrs->sget_assoc_id = 0;
    203 	sa = addrs;
    204 	for (i = 0; i < addrcnt; i++) {
    205 		sz = sa->sa_len;
    206 		fam = sa->sa_family;
    207 		((struct sockaddr_in *)(void *)&addrs[i])->sin_port = ((struct sockaddr_in *)(void *)sa)->sin_port;
    208 		if ((fam != AF_INET) && (fam != AF_INET6)) {
    209 			errno = EINVAL;
    210 			return(-1);
    211 		}
    212 		memcpy(gaddrs->addr, sa, sz);
    213 		if (setsockopt(sd, IPPROTO_SCTP, flags, gaddrs,
    214 		    (unsigned int)argsz) != 0) {
    215 			free(gaddrs);
    216 			return(-1);
    217 		}
    218 		memset(gaddrs, 0, argsz);
    219 		sa = (struct sockaddr *)((caddr_t)sa + sz);
    220 	}
    221 	free(gaddrs);
    222 	return(0);
    223 }
    224 
    225 
    226 int
    227 sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t *size)
    228 {
    229 	if ((opt == SCTP_RTOINFO) ||
    230  	    (opt == SCTP_ASSOCINFO) ||
    231 	    (opt == SCTP_PRIMARY_ADDR) ||
    232 	    (opt == SCTP_SET_PEER_PRIMARY_ADDR) ||
    233 	    (opt == SCTP_PEER_ADDR_PARAMS) ||
    234 	    (opt == SCTP_STATUS) ||
    235 	    (opt == SCTP_GET_PEER_ADDR_INFO)) {
    236 		*(sctp_assoc_t *)arg = id;
    237 		return(getsockopt2(sd, IPPROTO_SCTP, opt, arg, size));
    238 	} else {
    239 		errno = EOPNOTSUPP;
    240 		return(-1);
    241 	}
    242 }
    243 
    244 int
    245 sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs)
    246 {
    247 	struct sctp_getaddresses *addrs;
    248 	struct sockaddr *sa;
    249 	struct sockaddr *re;
    250 	sctp_assoc_t asoc;
    251 	caddr_t lim;
    252 	unsigned int siz;
    253 	int cnt;
    254 
    255 	if (raddrs == NULL) {
    256 		errno = EFAULT;
    257 		return(-1);
    258 	}
    259 	asoc = id;
    260 	siz = sizeof(sctp_assoc_t);
    261 	if (getsockopt2(sd, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE,
    262 	    &asoc, &siz) != 0) {
    263 		return(-1);
    264 	}
    265 	siz = (unsigned int)asoc;
    266 	siz += sizeof(struct sctp_getaddresses);
    267 	addrs = calloc((unsigned long)1, (unsigned long)siz);
    268 	if (addrs == NULL) {
    269 		errno = ENOMEM;
    270 		return(-1);
    271 	}
    272 	memset(addrs, 0, (size_t)siz);
    273 	addrs->sget_assoc_id = id;
    274 	/* Now lets get the array of addresses */
    275 	if (getsockopt2(sd, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES,
    276 	    addrs, &siz) != 0) {
    277 		free(addrs);
    278 		return(-1);
    279 	}
    280 	re = (struct sockaddr *)&addrs->addr[0];
    281 	*raddrs = re;
    282 	cnt = 0;
    283 	sa = (struct sockaddr *)&addrs->addr[0];
    284 	lim = (caddr_t)addrs + siz;
    285 	while ((caddr_t)sa < lim) {
    286 		cnt++;
    287 		sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
    288 		if (sa->sa_len == 0)
    289 			break;
    290 	}
    291 	return(cnt);
    292 }
    293 
    294 void sctp_freepaddrs(struct sockaddr *addrs)
    295 {
    296 	/* Take away the hidden association id */
    297 	void *fr_addr;
    298 	fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
    299 	/* Now free it */
    300 	free(fr_addr);
    301 }
    302 
    303 int
    304 sctp_getladdrs (int sd, sctp_assoc_t id, struct sockaddr **raddrs)
    305 {
    306 	struct sctp_getaddresses *addrs;
    307 	struct sockaddr *re;
    308 	caddr_t lim;
    309 	struct sockaddr *sa;
    310 	int size_of_addresses;
    311 	socklen_t siz;
    312 	int cnt;
    313 
    314 	if (raddrs == NULL) {
    315 		errno = EFAULT;
    316 		return(-1);
    317 	}
    318 	size_of_addresses = 0;
    319 	siz = sizeof(int);
    320 	if (getsockopt2(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE,
    321 	    &size_of_addresses, &siz) != 0) {
    322 		return(-1);
    323 	}
    324 	if (size_of_addresses == 0) {
    325 		errno = ENOTCONN;
    326 		return(-1);
    327 	}
    328 	siz = (socklen_t)(size_of_addresses + sizeof(struct sockaddr_storage));
    329 	siz += sizeof(struct sctp_getaddresses);
    330 	addrs = calloc((unsigned long)1, (unsigned long)siz);
    331 	if (addrs == NULL) {
    332 		errno = ENOMEM;
    333 		return(-1);
    334 	}
    335 	memset(addrs, 0, (size_t)siz);
    336 	addrs->sget_assoc_id = id;
    337 	/* Now lets get the array of addresses */
    338 	if (getsockopt2(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs,
    339 	    &siz) != 0) {
    340 		free(addrs);
    341 		return(-1);
    342 	}
    343 	re = (struct sockaddr *)&addrs->addr[0];
    344 	*raddrs = re;
    345 	cnt = 0;
    346 	sa = (struct sockaddr *)&addrs->addr[0];
    347 	lim = (caddr_t)addrs + siz;
    348 	while ((caddr_t)sa < lim) {
    349 		cnt++;
    350 		sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
    351 		if (sa->sa_len == 0)
    352 			break;
    353 	}
    354 	return(cnt);
    355 }
    356 
    357 void sctp_freeladdrs(struct sockaddr *addrs)
    358 {
    359 	/* Take away the hidden association id */
    360 	void *fr_addr;
    361 	fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
    362 	/* Now free it */
    363 	free(fr_addr);
    364 }
    365 
    366 ssize_t
    367 sctp_sendmsg(int s,
    368 	     const void *data,
    369 	     size_t len,
    370 	     const struct sockaddr *to,
    371 	     socklen_t tolen __attribute__((unused)),
    372 	     u_int32_t ppid,
    373 	     u_int32_t flags,
    374 	     u_int16_t stream_no,
    375 	     u_int32_t timetolive,
    376 	     u_int32_t context)
    377 {
    378 	ssize_t sz;
    379 	struct msghdr msg;
    380 	struct iovec iov[2];
    381 	char controlVector[256];
    382 	struct sctp_sndrcvinfo *s_info;
    383 	struct cmsghdr *cmsg;
    384 	struct sockaddr *who=NULL;
    385 	union {
    386 		struct sockaddr_in in;
    387 		struct sockaddr_in6 in6;
    388 	} addr;
    389 
    390 #if 0
    391 	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",
    392 	    s, (u_int)data, (int)len, (u_int)to, (int)tolen, ppid, flags,
    393 	    (int)stream_no, (int)timetolive, (u_int)context);
    394 	fflush(io);
    395 #endif
    396 	if (to) {
    397 		if (to->sa_len == 0) {
    398 			/*
    399 			 * For the lazy app, that did not
    400 			 * set sa_len, we attempt to set for them.
    401 			 */
    402 			switch (to->sa_family) {
    403 			case AF_INET:
    404 				memcpy(&addr, to, sizeof(struct sockaddr_in));
    405 				addr.in.sin_len = sizeof(struct sockaddr_in);
    406 				break;
    407 			case AF_INET6:
    408 				memcpy(&addr, to, sizeof(struct sockaddr_in6));
    409 				addr.in6.sin6_len = sizeof(struct sockaddr_in6);
    410 				break;
    411 			default:
    412 				errno = EAFNOSUPPORT;
    413 				return -1;
    414 			}
    415 		} else {
    416 			memcpy (&addr, to, to->sa_len);
    417 		}
    418 		who = (struct sockaddr *)(void *)&addr;
    419 	}
    420 	iov[0].iov_base = (void *)(unsigned long)data;
    421 	iov[0].iov_len = len;
    422 	iov[1].iov_base = NULL;
    423 	iov[1].iov_len = 0;
    424 
    425 	if (to) {
    426 		msg.msg_name = (caddr_t)who;
    427 		msg.msg_namelen = who->sa_len;
    428 	} else {
    429 		msg.msg_name = (caddr_t)NULL;
    430 		msg.msg_namelen = 0;
    431 	}
    432 	msg.msg_iov = iov;
    433 	msg.msg_iovlen = 1;
    434 	msg.msg_control = (caddr_t)controlVector;
    435 
    436 	cmsg = (struct cmsghdr *)controlVector;
    437 
    438 	cmsg->cmsg_level = IPPROTO_SCTP;
    439 	cmsg->cmsg_type = SCTP_SNDRCV;
    440 	cmsg->cmsg_len = CMSG_LEN (sizeof(struct sctp_sndrcvinfo) );
    441 	s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
    442 
    443 	s_info->sinfo_stream = stream_no;
    444 	s_info->sinfo_ssn = 0;
    445 	s_info->sinfo_flags = flags;
    446 	s_info->sinfo_ppid = ppid;
    447 	s_info->sinfo_context = context;
    448 	s_info->sinfo_assoc_id = 0;
    449 	s_info->sinfo_timetolive = timetolive;
    450 	errno = 0;
    451 	msg.msg_controllen = cmsg->cmsg_len;
    452 	sz = sendmsg(s, &msg, 0);
    453 	return(sz);
    454 }
    455 
    456 sctp_assoc_t
    457 sctp_getassocid(int sd, struct sockaddr *sa)
    458 {
    459 	struct sctp_paddrparams sp;
    460 	socklen_t siz;
    461 
    462 	/* First get the assoc id */
    463 	siz = sizeof(struct sctp_paddrparams);
    464 	memset(&sp, 0, sizeof(sp));
    465 	memcpy((caddr_t)&sp.spp_address, sa, sa->sa_len);
    466 	errno = 0;
    467 	if (getsockopt2(sd, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &sp, &siz) != 0)
    468 		return((sctp_assoc_t)0);
    469 	/* We depend on the fact that 0 can never be returned */
    470 	return(sp.spp_assoc_id);
    471 }
    472 
    473 
    474 
    475 ssize_t
    476 sctp_send(int sd, const void *data, size_t len,
    477 	  const struct sctp_sndrcvinfo *sinfo,
    478 	  int flags)
    479 {
    480 	ssize_t sz;
    481 	struct msghdr msg;
    482 	struct iovec iov[2];
    483 	struct sctp_sndrcvinfo *s_info;
    484 	char controlVector[256];
    485 	struct cmsghdr *cmsg;
    486 
    487 	iov[0].iov_base = (void *)(unsigned long)data;
    488 	iov[0].iov_len = len;
    489 	iov[1].iov_base = NULL;
    490 	iov[1].iov_len = 0;
    491 
    492 	msg.msg_name = 0;
    493 	msg.msg_namelen = 0;
    494 	msg.msg_iov = iov;
    495 	msg.msg_iovlen = 1;
    496 	msg.msg_control = (caddr_t)controlVector;
    497 
    498 	cmsg = (struct cmsghdr *)controlVector;
    499 
    500 	cmsg->cmsg_level = IPPROTO_SCTP;
    501 	cmsg->cmsg_type = SCTP_SNDRCV;
    502 	cmsg->cmsg_len = CMSG_LEN (sizeof(struct sctp_sndrcvinfo) );
    503 	s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
    504 	/* copy in the data */
    505 	*s_info = *sinfo;
    506 	errno = 0;
    507 	msg.msg_controllen = cmsg->cmsg_len;
    508 	sz = sendmsg(sd, &msg, flags);
    509 	return(sz);
    510 }
    511 
    512 
    513 ssize_t
    514 sctp_sendx(int sd, const void *msg, size_t len,
    515 	   struct sockaddr *addrs, int addrcnt,
    516 	   struct sctp_sndrcvinfo *sinfo,
    517 	   int flags)
    518 {
    519 	int i, cnt, saved_errno;
    520 	ssize_t ret;
    521 	int add_len;
    522 	struct sockaddr *at;
    523 	struct sctp_connectx_addrs sca;
    524 
    525 	len = 0;
    526 	at = addrs;
    527 	cnt = 0;
    528 	/* validate all the addresses and get the size */
    529 	for (i = 0; i < addrcnt; i++) {
    530 		if (at->sa_family == AF_INET) {
    531 			add_len = sizeof(struct sockaddr_in);
    532 		} else if (at->sa_family == AF_INET6) {
    533 			add_len = sizeof(struct sockaddr_in6);
    534 		} else {
    535 			errno = EINVAL;
    536 			return (-1);
    537 		}
    538 		len += add_len;
    539 		at = (struct sockaddr *)((caddr_t)at + add_len);
    540 		cnt++;
    541 	}
    542 	/* do we have any? */
    543 	if (cnt == 0) {
    544 		errno = EINVAL;
    545 		return(-1);
    546 	}
    547 
    548 	sca.cx_num = cnt;
    549 	sca.cx_len = (int)len;
    550 	sca.cx_addrs = addrs;
    551 	ret = ioctl(sd, SIOCCONNECTXDEL, (void *)&sca);
    552 	if (ret != 0) {
    553 		return(ret);
    554 	}
    555 	sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs);
    556 	if (sinfo->sinfo_assoc_id == 0) {
    557 		printf("Huh, can't get associd? TSNH!\n");
    558 		(void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
    559 				 (unsigned int)addrs->sa_len);
    560 		errno = ENOENT;
    561 		return (-1);
    562 	}
    563 	ret = sctp_send(sd, msg, len, sinfo, flags);
    564 	saved_errno = errno;
    565 	(void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
    566 			 (unsigned int)addrs->sa_len);
    567 
    568 	errno = saved_errno;
    569 	return (ret);
    570 }
    571 
    572 ssize_t
    573 sctp_sendmsgx(int sd,
    574 	      const void *msg,
    575 	      size_t len,
    576 	      struct sockaddr *addrs,
    577 	      int addrcnt,
    578 	      u_int32_t ppid,
    579 	      u_int32_t flags,
    580 	      u_int16_t stream_no,
    581 	      u_int32_t timetolive,
    582 	      u_int32_t context)
    583 {
    584 	struct sctp_sndrcvinfo sinfo;
    585 
    586 	memset((void *) &sinfo, 0, sizeof(struct sctp_sndrcvinfo));
    587 	sinfo.sinfo_ppid       = ppid;
    588 	sinfo.sinfo_flags      = flags;
    589 	sinfo.sinfo_ssn        = stream_no;
    590 	sinfo.sinfo_timetolive = timetolive;
    591 	sinfo.sinfo_context    = context;
    592 	return sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0);
    593 }
    594 
    595 ssize_t
    596 sctp_recvmsg (int s,
    597 	      void *dbuf,
    598 	      size_t len,
    599 	      struct sockaddr *from,
    600 	      socklen_t *fromlen,
    601 	      struct sctp_sndrcvinfo *sinfo,
    602 	      int *msg_flags)
    603 {
    604 	struct sctp_sndrcvinfo *s_info;
    605 	ssize_t sz;
    606 	struct msghdr msg;
    607 	struct iovec iov[2];
    608 	char controlVector[2048];
    609 	struct cmsghdr *cmsg;
    610 	iov[0].iov_base = dbuf;
    611 	iov[0].iov_len = len;
    612 	iov[1].iov_base = NULL;
    613 	iov[1].iov_len = 0;
    614 	msg.msg_name = (caddr_t)from;
    615 	msg.msg_namelen = *fromlen;
    616 	msg.msg_iov = iov;
    617 	msg.msg_iovlen = 1;
    618 	msg.msg_control = (caddr_t)controlVector;
    619 	msg.msg_controllen = sizeof(controlVector);
    620 	errno = 0;
    621 	sz = recvmsg(s, &msg, 0);
    622 
    623 	s_info = NULL;
    624 	len = sz;
    625 	*msg_flags = msg.msg_flags;
    626 	*fromlen = msg.msg_namelen;
    627 	if ((msg.msg_controllen) && sinfo) {
    628 		/* parse through and see if we find
    629 		 * the sctp_sndrcvinfo (if the user wants it).
    630 		 */
    631 		cmsg = (struct cmsghdr *)controlVector;
    632 		while (cmsg) {
    633 			if (cmsg->cmsg_level == IPPROTO_SCTP) {
    634 				if (cmsg->cmsg_type == SCTP_SNDRCV) {
    635 					/* Got it */
    636 					s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
    637 					/* Copy it to the user */
    638 					*sinfo = *s_info;
    639 					break;
    640 				}
    641 			}
    642 			cmsg = CMSG_NXTHDR(&msg, cmsg);
    643 		}
    644 	}
    645 	return(sz);
    646 }
    647 
    648 ssize_t
    649 sctp_recvv(int sd,
    650     const struct iovec *iov,
    651     int iovlen,
    652     struct sockaddr *from,
    653     socklen_t * fromlen,
    654     void *info,
    655     socklen_t * infolen,
    656     unsigned int *infotype,
    657     int *flags)
    658 {
    659 	char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV];
    660 	struct msghdr msg;
    661 	struct cmsghdr *cmsg;
    662 	ssize_t ret;
    663 	struct sctp_rcvinfo *rcvinfo;
    664 	struct sctp_nxtinfo *nxtinfo;
    665 
    666 	if (((info != NULL) && (infolen == NULL)) ||
    667 	    ((info == NULL) && (infolen != NULL) && (*infolen != 0)) ||
    668 	    ((info != NULL) && (infotype == NULL))) {
    669 		errno = EINVAL;
    670 		return (-1);
    671 	}
    672 	if (infotype) {
    673 		*infotype = SCTP_RECVV_NOINFO;
    674 	}
    675 	msg.msg_name = from;
    676 	if (fromlen == NULL) {
    677 		msg.msg_namelen = 0;
    678 	} else {
    679 		msg.msg_namelen = *fromlen;
    680 	}
    681 	msg.msg_iov = __UNCONST(iov);
    682 	msg.msg_iovlen = iovlen;
    683 	msg.msg_control = cmsgbuf;
    684 	msg.msg_controllen = sizeof(cmsgbuf);
    685 	msg.msg_flags = 0;
    686 	ret = recvmsg(sd, &msg, *flags);
    687 	*flags = msg.msg_flags;
    688 	if ((ret > 0) &&
    689 	    (msg.msg_controllen > 0) &&
    690 	    (infotype != NULL) &&
    691 	    (infolen != NULL) &&
    692 	    (*infolen > 0)) {
    693 		rcvinfo = NULL;
    694 		nxtinfo = NULL;
    695 		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
    696 			if (cmsg->cmsg_level != IPPROTO_SCTP) {
    697 				continue;
    698 			}
    699 			if (cmsg->cmsg_type == SCTP_RCVINFO) {
    700 				rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg);
    701 				if (nxtinfo != NULL) {
    702 					break;
    703 				} else {
    704 					continue;
    705 				}
    706 			}
    707 			if (cmsg->cmsg_type == SCTP_NXTINFO) {
    708 				nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg);
    709 				if (rcvinfo != NULL) {
    710 					break;
    711 				} else {
    712 					continue;
    713 				}
    714 			}
    715 		}
    716 		if (rcvinfo != NULL) {
    717 			if ((nxtinfo != NULL) && (*infolen >= sizeof(struct sctp_recvv_rn))) {
    718 				struct sctp_recvv_rn *rn_info;
    719 
    720 				rn_info = (struct sctp_recvv_rn *)info;
    721 				rn_info->recvv_rcvinfo = *rcvinfo;
    722 				rn_info->recvv_nxtinfo = *nxtinfo;
    723 				*infolen = (socklen_t) sizeof(struct sctp_recvv_rn);
    724 				*infotype = SCTP_RECVV_RN;
    725 			} else if (*infolen >= sizeof(struct sctp_rcvinfo)) {
    726 				memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo));
    727 				*infolen = (socklen_t) sizeof(struct sctp_rcvinfo);
    728 				*infotype = SCTP_RECVV_RCVINFO;
    729 			}
    730 		} else if (nxtinfo != NULL) {
    731 			if (*infolen >= sizeof(struct sctp_nxtinfo)) {
    732 				memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo));
    733 				*infolen = (socklen_t) sizeof(struct sctp_nxtinfo);
    734 				*infotype = SCTP_RECVV_NXTINFO;
    735 			}
    736 		}
    737 	}
    738 	return (ret);
    739 }
    740 
    741 ssize_t
    742 sctp_sendv(int sd,
    743     const struct iovec *iov, int iovcnt,
    744     struct sockaddr *addrs, int addrcnt,
    745     void *info, socklen_t infolen, unsigned int infotype,
    746     int flags)
    747 {
    748 	ssize_t ret;
    749 	int i;
    750 	socklen_t addr_len;
    751 	struct msghdr msg;
    752 	in_port_t port;
    753 	struct sctp_sendv_spa *spa_info;
    754 	struct cmsghdr *cmsg;
    755 	char *cmsgbuf;
    756 	struct sockaddr *addr;
    757 	struct sockaddr_in *addr_in;
    758 	struct sockaddr_in6 *addr_in6;
    759 	void *assoc_id_ptr;
    760 	sctp_assoc_t assoc_id;
    761 
    762 	if ((addrcnt < 0) ||
    763 	    (iovcnt < 0) ||
    764 	    ((addrs == NULL) && (addrcnt > 0)) ||
    765 	    ((addrs != NULL) && (addrcnt == 0)) ||
    766 	    ((iov == NULL) && (iovcnt > 0)) ||
    767 	    ((iov != NULL) && (iovcnt == 0))) {
    768 		errno = EINVAL;
    769 		return (-1);
    770 	}
    771 	cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) +
    772 	    CMSG_SPACE(sizeof(struct sctp_prinfo)) +
    773 	    CMSG_SPACE(sizeof(struct sctp_authinfo)) +
    774 	    (size_t)addrcnt * CMSG_SPACE(sizeof(struct in6_addr)));
    775 	if (cmsgbuf == NULL) {
    776 		errno = ENOMEM;
    777 		return (-1);
    778 	}
    779 	assoc_id_ptr = NULL;
    780 	msg.msg_control = cmsgbuf;
    781 	msg.msg_controllen = 0;
    782 	cmsg = (struct cmsghdr *)cmsgbuf;
    783 	switch (infotype) {
    784 	case SCTP_SENDV_NOINFO:
    785 		if ((infolen != 0) || (info != NULL)) {
    786 			free(cmsgbuf);
    787 			errno = EINVAL;
    788 			return (-1);
    789 		}
    790 		break;
    791 	case SCTP_SENDV_SNDINFO:
    792 		if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) {
    793 			free(cmsgbuf);
    794 			errno = EINVAL;
    795 			return (-1);
    796 		}
    797 		cmsg->cmsg_level = IPPROTO_SCTP;
    798 		cmsg->cmsg_type = SCTP_SNDINFO;
    799 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
    800 		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo));
    801 		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
    802 		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
    803 		assoc_id_ptr = &(((struct sctp_sndinfo *)info)->snd_assoc_id);
    804 		break;
    805 	case SCTP_SENDV_PRINFO:
    806 		if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) {
    807 			free(cmsgbuf);
    808 			errno = EINVAL;
    809 			return (-1);
    810 		}
    811 		cmsg->cmsg_level = IPPROTO_SCTP;
    812 		cmsg->cmsg_type = SCTP_PRINFO;
    813 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
    814 		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo));
    815 		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
    816 		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
    817 		break;
    818 	case SCTP_SENDV_AUTHINFO:
    819 		if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) {
    820 			free(cmsgbuf);
    821 			errno = EINVAL;
    822 			return (-1);
    823 		}
    824 		cmsg->cmsg_level = IPPROTO_SCTP;
    825 		cmsg->cmsg_type = SCTP_AUTHINFO;
    826 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
    827 		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo));
    828 		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
    829 		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
    830 		break;
    831 	case SCTP_SENDV_SPA:
    832 		if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) {
    833 			free(cmsgbuf);
    834 			errno = EINVAL;
    835 			return (-1);
    836 		}
    837 		spa_info = (struct sctp_sendv_spa *)info;
    838 		if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) {
    839 			cmsg->cmsg_level = IPPROTO_SCTP;
    840 			cmsg->cmsg_type = SCTP_SNDINFO;
    841 			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
    842 			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo));
    843 			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
    844 			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
    845 			assoc_id_ptr = &(spa_info->sendv_sndinfo.snd_assoc_id);
    846 		}
    847 		if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) {
    848 			cmsg->cmsg_level = IPPROTO_SCTP;
    849 			cmsg->cmsg_type = SCTP_PRINFO;
    850 			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
    851 			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo));
    852 			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
    853 			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
    854 		}
    855 		if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) {
    856 			cmsg->cmsg_level = IPPROTO_SCTP;
    857 			cmsg->cmsg_type = SCTP_AUTHINFO;
    858 			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
    859 			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo));
    860 			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
    861 			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
    862 		}
    863 		break;
    864 	default:
    865 		free(cmsgbuf);
    866 		errno = EINVAL;
    867 		return (-1);
    868 	}
    869 	addr = addrs;
    870 	msg.msg_name = NULL;
    871 	msg.msg_namelen = 0;
    872 
    873 	for (i = 0; i < addrcnt; i++) {
    874 		switch (addr->sa_family) {
    875 		case AF_INET:
    876 			addr_len = (socklen_t) sizeof(struct sockaddr_in);
    877 			addr_in = (struct sockaddr_in *)(void *)addr;
    878 			if (addr_in->sin_len != addr_len) {
    879 				free(cmsgbuf);
    880 				errno = EINVAL;
    881 				return (-1);
    882 			}
    883 			if (i == 0) {
    884 				port = addr_in->sin_port;
    885 			} else {
    886 				if (port == addr_in->sin_port) {
    887 					cmsg->cmsg_level = IPPROTO_SCTP;
    888 					cmsg->cmsg_type = SCTP_DSTADDRV4;
    889 					cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
    890 					memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr));
    891 					msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr));
    892 					cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr)));
    893 				} else {
    894 					free(cmsgbuf);
    895 					errno = EINVAL;
    896 					return (-1);
    897 				}
    898 			}
    899 			break;
    900 		case AF_INET6:
    901 			addr_len = (socklen_t) sizeof(struct sockaddr_in6);
    902 			addr_in6 = (struct sockaddr_in6 *)(void *)addr;
    903 			if (addr_in6->sin6_len != addr_len) {
    904 				free(cmsgbuf);
    905 				errno = EINVAL;
    906 				return (-1);
    907 			}
    908 			if (i == 0) {
    909 				port = addr_in6->sin6_port;
    910 			} else {
    911 				if (port == addr_in6->sin6_port) {
    912 					cmsg->cmsg_level = IPPROTO_SCTP;
    913 					cmsg->cmsg_type = SCTP_DSTADDRV6;
    914 					cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr));
    915 					memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr));
    916 					msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr));
    917 					cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr)));
    918 				} else {
    919 					free(cmsgbuf);
    920 					errno = EINVAL;
    921 					return (-1);
    922 				}
    923 			}
    924 			break;
    925 		default:
    926 			free(cmsgbuf);
    927 			errno = EINVAL;
    928 			return (-1);
    929 		}
    930 		if (i == 0) {
    931 			msg.msg_name = addr;
    932 			msg.msg_namelen = addr_len;
    933 		}
    934 		addr = (struct sockaddr *)((caddr_t)addr + addr_len);
    935 	}
    936 	if (msg.msg_controllen == 0) {
    937 		msg.msg_control = NULL;
    938 	}
    939 	msg.msg_iov = __UNCONST(iov);
    940 	msg.msg_iovlen = iovcnt;
    941 	msg.msg_flags = 0;
    942 	ret = sendmsg(sd, &msg, flags);
    943 	free(cmsgbuf);
    944 	if ((ret >= 0) && (addrs != NULL) && (assoc_id_ptr != NULL)) {
    945 		assoc_id = sctp_getassocid(sd, addrs);
    946 		memcpy(assoc_id_ptr, &assoc_id, sizeof(assoc_id));
    947 	}
    948 	return (ret);
    949 }
    950 
    951 int
    952 sctp_peeloff(int sd, sctp_assoc_t assoc_id)
    953 {
    954 	int ret;
    955 	uint32_t val;
    956 
    957 	val = assoc_id;
    958 	ret = ioctl(sd, SIOCPEELOFF, &val);
    959 	if (ret == -1)
    960 		return ret;
    961 	else
    962 		return (int) val;
    963 }
    964 
    965