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
61static void
62SCTPPrintAnAddress(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
119void
120in6_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
129int
130sctp_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
183int
184sctp_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
226int
227sctp_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
244int
245sctp_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
294void 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
303int
304sctp_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
357void 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
366ssize_t
367sctp_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
456sctp_assoc_t
457sctp_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
475ssize_t
476sctp_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
513ssize_t
514sctp_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
572ssize_t
573sctp_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
595ssize_t
596sctp_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
648ssize_t
649sctp_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
741ssize_t
742sctp_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
951int
952sctp_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