Home | History | Annotate | Line # | Download | only in net
sctp_sys_calls.c revision 1.1.2.2
      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.1.2.2 2018/09/06 06:55:19 pgoyette 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 *)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 = 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 *)&addrs[i])->sin_port = ((struct sockaddr_in *)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 	unsigned int 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 = 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 	int 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 *)&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 	int 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, ret, cnt, saved_errno;
    520 	int add_len;
    521 	struct sockaddr *at;
    522 	struct sctp_connectx_addrs sca;
    523 
    524 	len = 0;
    525 	at = addrs;
    526 	cnt = 0;
    527 	/* validate all the addresses and get the size */
    528 	for (i = 0; i < addrcnt; i++) {
    529 		if (at->sa_family == AF_INET) {
    530 			add_len = sizeof(struct sockaddr_in);
    531 		} else if (at->sa_family == AF_INET6) {
    532 			add_len = sizeof(struct sockaddr_in6);
    533 		} else {
    534 			errno = EINVAL;
    535 			return (-1);
    536 		}
    537 		len += add_len;
    538 		at = (struct sockaddr *)((caddr_t)at + add_len);
    539 		cnt++;
    540 	}
    541 	/* do we have any? */
    542 	if (cnt == 0) {
    543 		errno = EINVAL;
    544 		return(-1);
    545 	}
    546 
    547 	sca.cx_num = cnt;
    548 	sca.cx_len = len;
    549 	sca.cx_addrs = addrs;
    550 	ret = ioctl(sd, SIOCCONNECTXDEL, (void *)&sca);
    551 	if (ret != 0) {
    552 		return(ret);
    553 	}
    554 	sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs);
    555 	if (sinfo->sinfo_assoc_id == 0) {
    556 		printf("Huh, can't get associd? TSNH!\n");
    557 		(void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
    558 				 (unsigned int)addrs->sa_len);
    559 		errno = ENOENT;
    560 		return (-1);
    561 	}
    562 	ret = sctp_send(sd, msg, len, sinfo, flags);
    563 	saved_errno = errno;
    564 	(void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
    565 			 (unsigned int)addrs->sa_len);
    566 
    567 	errno = saved_errno;
    568 	return (ret);
    569 }
    570 
    571 ssize_t
    572 sctp_sendmsgx(int sd,
    573 	      const void *msg,
    574 	      size_t len,
    575 	      struct sockaddr *addrs,
    576 	      int addrcnt,
    577 	      u_int32_t ppid,
    578 	      u_int32_t flags,
    579 	      u_int16_t stream_no,
    580 	      u_int32_t timetolive,
    581 	      u_int32_t context)
    582 {
    583 	struct sctp_sndrcvinfo sinfo;
    584 
    585 	memset((void *) &sinfo, 0, sizeof(struct sctp_sndrcvinfo));
    586 	sinfo.sinfo_ppid       = ppid;
    587 	sinfo.sinfo_flags      = flags;
    588 	sinfo.sinfo_ssn        = stream_no;
    589 	sinfo.sinfo_timetolive = timetolive;
    590 	sinfo.sinfo_context    = context;
    591 	return sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0);
    592 }
    593 
    594 ssize_t
    595 sctp_recvmsg (int s,
    596 	      void *dbuf,
    597 	      size_t len,
    598 	      struct sockaddr *from,
    599 	      socklen_t *fromlen,
    600 	      struct sctp_sndrcvinfo *sinfo,
    601 	      int *msg_flags)
    602 {
    603 	struct sctp_sndrcvinfo *s_info;
    604 	ssize_t sz;
    605 	struct msghdr msg;
    606 	struct iovec iov[2];
    607 	char controlVector[2048];
    608 	struct cmsghdr *cmsg;
    609 	iov[0].iov_base = dbuf;
    610 	iov[0].iov_len = len;
    611 	iov[1].iov_base = NULL;
    612 	iov[1].iov_len = 0;
    613 	msg.msg_name = (caddr_t)from;
    614 	msg.msg_namelen = *fromlen;
    615 	msg.msg_iov = iov;
    616 	msg.msg_iovlen = 1;
    617 	msg.msg_control = (caddr_t)controlVector;
    618 	msg.msg_controllen = sizeof(controlVector);
    619 	errno = 0;
    620 	sz = recvmsg(s, &msg, 0);
    621 
    622 	s_info = NULL;
    623 	len = sz;
    624 	*msg_flags = msg.msg_flags;
    625 	*fromlen = msg.msg_namelen;
    626 	if ((msg.msg_controllen) && sinfo) {
    627 		/* parse through and see if we find
    628 		 * the sctp_sndrcvinfo (if the user wants it).
    629 		 */
    630 		cmsg = (struct cmsghdr *)controlVector;
    631 		while (cmsg) {
    632 			if (cmsg->cmsg_level == IPPROTO_SCTP) {
    633 				if (cmsg->cmsg_type == SCTP_SNDRCV) {
    634 					/* Got it */
    635 					s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
    636 					/* Copy it to the user */
    637 					*sinfo = *s_info;
    638 					break;
    639 				}
    640 			}
    641 			cmsg = CMSG_NXTHDR(&msg, cmsg);
    642 		}
    643 	}
    644 	return(sz);
    645 }
    646 
    647 ssize_t
    648 sctp_recvv(int sd,
    649     const struct iovec *iov,
    650     int iovlen,
    651     struct sockaddr *from,
    652     socklen_t * fromlen,
    653     void *info,
    654     socklen_t * infolen,
    655     unsigned int *infotype,
    656     int *flags)
    657 {
    658 	char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV];
    659 	struct msghdr msg;
    660 	struct cmsghdr *cmsg;
    661 	ssize_t ret;
    662 	struct sctp_rcvinfo *rcvinfo;
    663 	struct sctp_nxtinfo *nxtinfo;
    664 
    665 	if (((info != NULL) && (infolen == NULL)) ||
    666 	    ((info == NULL) && (infolen != NULL) && (*infolen != 0)) ||
    667 	    ((info != NULL) && (infotype == NULL))) {
    668 		errno = EINVAL;
    669 		return (-1);
    670 	}
    671 	if (infotype) {
    672 		*infotype = SCTP_RECVV_NOINFO;
    673 	}
    674 	msg.msg_name = from;
    675 	if (fromlen == NULL) {
    676 		msg.msg_namelen = 0;
    677 	} else {
    678 		msg.msg_namelen = *fromlen;
    679 	}
    680 	msg.msg_iov = __UNCONST(iov);
    681 	msg.msg_iovlen = iovlen;
    682 	msg.msg_control = cmsgbuf;
    683 	msg.msg_controllen = sizeof(cmsgbuf);
    684 	msg.msg_flags = 0;
    685 	ret = recvmsg(sd, &msg, *flags);
    686 	*flags = msg.msg_flags;
    687 	if ((ret > 0) &&
    688 	    (msg.msg_controllen > 0) &&
    689 	    (infotype != NULL) &&
    690 	    (infolen != NULL) &&
    691 	    (*infolen > 0)) {
    692 		rcvinfo = NULL;
    693 		nxtinfo = NULL;
    694 		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
    695 			if (cmsg->cmsg_level != IPPROTO_SCTP) {
    696 				continue;
    697 			}
    698 			if (cmsg->cmsg_type == SCTP_RCVINFO) {
    699 				rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg);
    700 				if (nxtinfo != NULL) {
    701 					break;
    702 				} else {
    703 					continue;
    704 				}
    705 			}
    706 			if (cmsg->cmsg_type == SCTP_NXTINFO) {
    707 				nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg);
    708 				if (rcvinfo != NULL) {
    709 					break;
    710 				} else {
    711 					continue;
    712 				}
    713 			}
    714 		}
    715 		if (rcvinfo != NULL) {
    716 			if ((nxtinfo != NULL) && (*infolen >= sizeof(struct sctp_recvv_rn))) {
    717 				struct sctp_recvv_rn *rn_info;
    718 
    719 				rn_info = (struct sctp_recvv_rn *)info;
    720 				rn_info->recvv_rcvinfo = *rcvinfo;
    721 				rn_info->recvv_nxtinfo = *nxtinfo;
    722 				*infolen = (socklen_t) sizeof(struct sctp_recvv_rn);
    723 				*infotype = SCTP_RECVV_RN;
    724 			} else if (*infolen >= sizeof(struct sctp_rcvinfo)) {
    725 				memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo));
    726 				*infolen = (socklen_t) sizeof(struct sctp_rcvinfo);
    727 				*infotype = SCTP_RECVV_RCVINFO;
    728 			}
    729 		} else if (nxtinfo != NULL) {
    730 			if (*infolen >= sizeof(struct sctp_nxtinfo)) {
    731 				memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo));
    732 				*infolen = (socklen_t) sizeof(struct sctp_nxtinfo);
    733 				*infotype = SCTP_RECVV_NXTINFO;
    734 			}
    735 		}
    736 	}
    737 	return (ret);
    738 }
    739 
    740 ssize_t
    741 sctp_sendv(int sd,
    742     const struct iovec *iov, int iovcnt,
    743     struct sockaddr *addrs, int addrcnt,
    744     void *info, socklen_t infolen, unsigned int infotype,
    745     int flags)
    746 {
    747 	ssize_t ret;
    748 	int i;
    749 	socklen_t addr_len;
    750 	struct msghdr msg;
    751 	in_port_t port;
    752 	struct sctp_sendv_spa *spa_info;
    753 	struct cmsghdr *cmsg;
    754 	char *cmsgbuf;
    755 	struct sockaddr *addr;
    756 	struct sockaddr_in *addr_in;
    757 	struct sockaddr_in6 *addr_in6;
    758 	void *assoc_id_ptr;
    759 	sctp_assoc_t assoc_id;
    760 
    761 	if ((addrcnt < 0) ||
    762 	    (iovcnt < 0) ||
    763 	    ((addrs == NULL) && (addrcnt > 0)) ||
    764 	    ((addrs != NULL) && (addrcnt == 0)) ||
    765 	    ((iov == NULL) && (iovcnt > 0)) ||
    766 	    ((iov != NULL) && (iovcnt == 0))) {
    767 		errno = EINVAL;
    768 		return (-1);
    769 	}
    770 	cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) +
    771 	    CMSG_SPACE(sizeof(struct sctp_prinfo)) +
    772 	    CMSG_SPACE(sizeof(struct sctp_authinfo)) +
    773 	    (size_t)addrcnt * CMSG_SPACE(sizeof(struct in6_addr)));
    774 	if (cmsgbuf == NULL) {
    775 		errno = ENOMEM;
    776 		return (-1);
    777 	}
    778 	assoc_id_ptr = NULL;
    779 	msg.msg_control = cmsgbuf;
    780 	msg.msg_controllen = 0;
    781 	cmsg = (struct cmsghdr *)cmsgbuf;
    782 	switch (infotype) {
    783 	case SCTP_SENDV_NOINFO:
    784 		if ((infolen != 0) || (info != NULL)) {
    785 			free(cmsgbuf);
    786 			errno = EINVAL;
    787 			return (-1);
    788 		}
    789 		break;
    790 	case SCTP_SENDV_SNDINFO:
    791 		if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) {
    792 			free(cmsgbuf);
    793 			errno = EINVAL;
    794 			return (-1);
    795 		}
    796 		cmsg->cmsg_level = IPPROTO_SCTP;
    797 		cmsg->cmsg_type = SCTP_SNDINFO;
    798 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
    799 		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo));
    800 		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
    801 		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
    802 		assoc_id_ptr = &(((struct sctp_sndinfo *)info)->snd_assoc_id);
    803 		break;
    804 	case SCTP_SENDV_PRINFO:
    805 		if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) {
    806 			free(cmsgbuf);
    807 			errno = EINVAL;
    808 			return (-1);
    809 		}
    810 		cmsg->cmsg_level = IPPROTO_SCTP;
    811 		cmsg->cmsg_type = SCTP_PRINFO;
    812 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
    813 		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo));
    814 		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
    815 		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
    816 		break;
    817 	case SCTP_SENDV_AUTHINFO:
    818 		if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) {
    819 			free(cmsgbuf);
    820 			errno = EINVAL;
    821 			return (-1);
    822 		}
    823 		cmsg->cmsg_level = IPPROTO_SCTP;
    824 		cmsg->cmsg_type = SCTP_AUTHINFO;
    825 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
    826 		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo));
    827 		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
    828 		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
    829 		break;
    830 	case SCTP_SENDV_SPA:
    831 		if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) {
    832 			free(cmsgbuf);
    833 			errno = EINVAL;
    834 			return (-1);
    835 		}
    836 		spa_info = (struct sctp_sendv_spa *)info;
    837 		if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) {
    838 			cmsg->cmsg_level = IPPROTO_SCTP;
    839 			cmsg->cmsg_type = SCTP_SNDINFO;
    840 			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
    841 			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo));
    842 			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
    843 			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
    844 			assoc_id_ptr = &(spa_info->sendv_sndinfo.snd_assoc_id);
    845 		}
    846 		if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) {
    847 			cmsg->cmsg_level = IPPROTO_SCTP;
    848 			cmsg->cmsg_type = SCTP_PRINFO;
    849 			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
    850 			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo));
    851 			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
    852 			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
    853 		}
    854 		if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) {
    855 			cmsg->cmsg_level = IPPROTO_SCTP;
    856 			cmsg->cmsg_type = SCTP_AUTHINFO;
    857 			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
    858 			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo));
    859 			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
    860 			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
    861 		}
    862 		break;
    863 	default:
    864 		free(cmsgbuf);
    865 		errno = EINVAL;
    866 		return (-1);
    867 	}
    868 	addr = addrs;
    869 	msg.msg_name = NULL;
    870 	msg.msg_namelen = 0;
    871 
    872 	for (i = 0; i < addrcnt; i++) {
    873 		switch (addr->sa_family) {
    874 		case AF_INET:
    875 			addr_len = (socklen_t) sizeof(struct sockaddr_in);
    876 			addr_in = (struct sockaddr_in *)addr;
    877 			if (addr_in->sin_len != addr_len) {
    878 				free(cmsgbuf);
    879 				errno = EINVAL;
    880 				return (-1);
    881 			}
    882 			if (i == 0) {
    883 				port = addr_in->sin_port;
    884 			} else {
    885 				if (port == addr_in->sin_port) {
    886 					cmsg->cmsg_level = IPPROTO_SCTP;
    887 					cmsg->cmsg_type = SCTP_DSTADDRV4;
    888 					cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
    889 					memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr));
    890 					msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr));
    891 					cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr)));
    892 				} else {
    893 					free(cmsgbuf);
    894 					errno = EINVAL;
    895 					return (-1);
    896 				}
    897 			}
    898 			break;
    899 		case AF_INET6:
    900 			addr_len = (socklen_t) sizeof(struct sockaddr_in6);
    901 			addr_in6 = (struct sockaddr_in6 *)addr;
    902 			if (addr_in6->sin6_len != addr_len) {
    903 				free(cmsgbuf);
    904 				errno = EINVAL;
    905 				return (-1);
    906 			}
    907 			if (i == 0) {
    908 				port = addr_in6->sin6_port;
    909 			} else {
    910 				if (port == addr_in6->sin6_port) {
    911 					cmsg->cmsg_level = IPPROTO_SCTP;
    912 					cmsg->cmsg_type = SCTP_DSTADDRV6;
    913 					cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr));
    914 					memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr));
    915 					msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr));
    916 					cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr)));
    917 				} else {
    918 					free(cmsgbuf);
    919 					errno = EINVAL;
    920 					return (-1);
    921 				}
    922 			}
    923 			break;
    924 		default:
    925 			free(cmsgbuf);
    926 			errno = EINVAL;
    927 			return (-1);
    928 		}
    929 		if (i == 0) {
    930 			msg.msg_name = addr;
    931 			msg.msg_namelen = addr_len;
    932 		}
    933 		addr = (struct sockaddr *)((caddr_t)addr + addr_len);
    934 	}
    935 	if (msg.msg_controllen == 0) {
    936 		msg.msg_control = NULL;
    937 	}
    938 	msg.msg_iov = __UNCONST(iov);
    939 	msg.msg_iovlen = iovcnt;
    940 	msg.msg_flags = 0;
    941 	ret = sendmsg(sd, &msg, flags);
    942 	free(cmsgbuf);
    943 	if ((ret >= 0) && (addrs != NULL) && (assoc_id_ptr != NULL)) {
    944 		assoc_id = sctp_getassocid(sd, addrs);
    945 		memcpy(assoc_id_ptr, &assoc_id, sizeof(assoc_id));
    946 	}
    947 	return (ret);
    948 }
    949 
    950 int
    951 sctp_peeloff(int sd, sctp_assoc_t assoc_id)
    952 {
    953 	int ret;
    954 	uint32_t val;
    955 
    956 	val = assoc_id;
    957 	ret = ioctl(sd, SIOCPEELOFF, &val);
    958 	if (ret == -1)
    959 		return ret;
    960 	else
    961 		return (int) val;
    962 }
    963 
    964