1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
5 * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
6 * Copyright (c) 2008-2012, by Michael Tuexen. 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 are met:
10 *
11 * a) Redistributions of source code must retain the above copyright notice,
12 *    this list of conditions and the following disclaimer.
13 *
14 * b) Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in
16 *    the documentation and/or other materials provided with the distribution.
17 *
18 * c) Neither the name of Cisco Systems, Inc. nor the names of its
19 *    contributors may be used to endorse or promote products derived
20 *    from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD$");
37
38#include <stdbool.h>
39#include <stddef.h>
40#include <stdio.h>
41#include <string.h>
42#include <errno.h>
43#include <stdlib.h>
44#include <unistd.h>
45#include <sys/types.h>
46#include <sys/socket.h>
47#include <sys/errno.h>
48#include <sys/syscall.h>
49#include <sys/uio.h>
50#include <netinet/in.h>
51#include <arpa/inet.h>
52#include <netinet/sctp_uio.h>
53#include <netinet/sctp.h>
54
55#ifndef IN6_IS_ADDR_V4MAPPED
56#define IN6_IS_ADDR_V4MAPPED(a)		      \
57	((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == 0) &&	\
58	 (*(const uint32_t *)(const void *)(&(a)->s6_addr[4]) == 0) &&	\
59	 (*(const uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff)))
60#endif
61
62#define SCTP_CONTROL_VEC_SIZE_RCV  16384
63
64
65static void
66in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
67{
68	bzero(sin, sizeof(*sin));
69	sin->sin_len = sizeof(struct sockaddr_in);
70	sin->sin_family = AF_INET;
71	sin->sin_port = sin6->sin6_port;
72	sin->sin_addr.s_addr = sin6->sin6_addr.__u6_addr.__u6_addr32[3];
73}
74
75int
76sctp_getaddrlen(sa_family_t family)
77{
78	int ret, sd;
79	socklen_t siz;
80	struct sctp_assoc_value av;
81
82	av.assoc_value = family;
83	siz = sizeof(av);
84#if defined(AF_INET)
85	sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
86#elif defined(AF_INET6)
87	sd = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP);
88#else
89	sd = -1;
90#endif
91	if (sd == -1) {
92		return (-1);
93	}
94	ret = getsockopt(sd, IPPROTO_SCTP, SCTP_GET_ADDR_LEN, &av, &siz);
95	close(sd);
96	if (ret == 0) {
97		return ((int)av.assoc_value);
98	} else {
99		return (-1);
100	}
101}
102
103int
104sctp_connectx(int sd, const struct sockaddr *addrs, int addrcnt,
105    sctp_assoc_t *id)
106{
107	char *buf;
108	int i, ret, *aa;
109	char *cpto;
110	const struct sockaddr *at;
111	size_t len;
112
113	/* validate the address count and list */
114	if ((addrs == NULL) || (addrcnt <= 0)) {
115		errno = EINVAL;
116		return (-1);
117	}
118	if ((buf = malloc(sizeof(int) + (size_t)addrcnt * sizeof(struct sockaddr_in6))) == NULL) {
119		errno = E2BIG;
120		return (-1);
121	}
122	len = sizeof(int);
123	at = addrs;
124	cpto = buf + sizeof(int);
125	/* validate all the addresses and get the size */
126	for (i = 0; i < addrcnt; i++) {
127		switch (at->sa_family) {
128		case AF_INET:
129			if (at->sa_len != sizeof(struct sockaddr_in)) {
130				free(buf);
131				errno = EINVAL;
132				return (-1);
133			}
134			memcpy(cpto, at, sizeof(struct sockaddr_in));
135			cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in));
136			len += sizeof(struct sockaddr_in);
137			break;
138		case AF_INET6:
139			if (at->sa_len != sizeof(struct sockaddr_in6)) {
140				free(buf);
141				errno = EINVAL;
142				return (-1);
143			}
144			if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)at)->sin6_addr)) {
145				in6_sin6_2_sin((struct sockaddr_in *)cpto, (struct sockaddr_in6 *)at);
146				cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in));
147				len += sizeof(struct sockaddr_in);
148			} else {
149				memcpy(cpto, at, sizeof(struct sockaddr_in6));
150				cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in6));
151				len += sizeof(struct sockaddr_in6);
152			}
153			break;
154		default:
155			free(buf);
156			errno = EINVAL;
157			return (-1);
158		}
159		at = (struct sockaddr *)((caddr_t)at + at->sa_len);
160	}
161	aa = (int *)buf;
162	*aa = addrcnt;
163	ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X, (void *)buf,
164	    (socklen_t)len);
165	if ((ret == 0) && (id != NULL)) {
166		*id = *(sctp_assoc_t *)buf;
167	}
168	free(buf);
169	return (ret);
170}
171
172int
173sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags)
174{
175	struct sockaddr *sa;
176	struct sockaddr_in *sin;
177	struct sockaddr_in6 *sin6;
178	int i;
179	uint16_t sport;
180	bool fix_port;
181
182	/* validate the flags */
183	if ((flags != SCTP_BINDX_ADD_ADDR) &&
184	    (flags != SCTP_BINDX_REM_ADDR)) {
185		errno = EFAULT;
186		return (-1);
187	}
188	/* validate the address count and list */
189	if ((addrcnt <= 0) || (addrs == NULL)) {
190		errno = EINVAL;
191		return (-1);
192	}
193	sport = 0;
194	fix_port = false;
195	/* First pre-screen the addresses */
196	sa = addrs;
197	for (i = 0; i < addrcnt; i++) {
198		switch (sa->sa_family) {
199		case AF_INET:
200			if (sa->sa_len != sizeof(struct sockaddr_in)) {
201				errno = EINVAL;
202				return (-1);
203			}
204			sin = (struct sockaddr_in *)sa;
205			if (sin->sin_port) {
206				/* non-zero port, check or save */
207				if (sport) {
208					/* Check against our port */
209					if (sport != sin->sin_port) {
210						errno = EINVAL;
211						return (-1);
212					}
213				} else {
214					/* save off the port */
215					sport = sin->sin_port;
216					fix_port = (i > 0);
217				}
218			}
219			break;
220		case AF_INET6:
221			if (sa->sa_len != sizeof(struct sockaddr_in6)) {
222				errno = EINVAL;
223				return (-1);
224			}
225			sin6 = (struct sockaddr_in6 *)sa;
226			if (sin6->sin6_port) {
227				/* non-zero port, check or save */
228				if (sport) {
229					/* Check against our port */
230					if (sport != sin6->sin6_port) {
231						errno = EINVAL;
232						return (-1);
233					}
234				} else {
235					/* save off the port */
236					sport = sin6->sin6_port;
237					fix_port = (i > 0);
238				}
239			}
240			break;
241		default:
242			/* Invalid address family specified. */
243			errno = EAFNOSUPPORT;
244			return (-1);
245		}
246		sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
247	}
248	sa = addrs;
249	for (i = 0; i < addrcnt; i++) {
250		/*
251		 * Now, if there was a port mentioned, assure that the first
252		 * address has that port to make sure it fails or succeeds
253		 * correctly.
254		 */
255		if (fix_port) {
256			switch (sa->sa_family) {
257			case AF_INET:
258				((struct sockaddr_in *)sa)->sin_port = sport;
259				break;
260			case AF_INET6:
261				((struct sockaddr_in6 *)sa)->sin6_port = sport;
262				break;
263			}
264			fix_port = false;
265		}
266		if (setsockopt(sd, IPPROTO_SCTP, flags, sa, sa->sa_len) != 0) {
267			return (-1);
268		}
269		sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
270	}
271	return (0);
272}
273
274int
275sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t *size)
276{
277	if (arg == NULL) {
278		errno = EINVAL;
279		return (-1);
280	}
281	if ((id == SCTP_CURRENT_ASSOC) ||
282	    (id == SCTP_ALL_ASSOC)) {
283		errno = EINVAL;
284		return (-1);
285	}
286	switch (opt) {
287	case SCTP_RTOINFO:
288		((struct sctp_rtoinfo *)arg)->srto_assoc_id = id;
289		break;
290	case SCTP_ASSOCINFO:
291		((struct sctp_assocparams *)arg)->sasoc_assoc_id = id;
292		break;
293	case SCTP_DEFAULT_SEND_PARAM:
294		((struct sctp_assocparams *)arg)->sasoc_assoc_id = id;
295		break;
296	case SCTP_PRIMARY_ADDR:
297		((struct sctp_setprim *)arg)->ssp_assoc_id = id;
298		break;
299	case SCTP_PEER_ADDR_PARAMS:
300		((struct sctp_paddrparams *)arg)->spp_assoc_id = id;
301		break;
302	case SCTP_MAXSEG:
303		((struct sctp_assoc_value *)arg)->assoc_id = id;
304		break;
305	case SCTP_AUTH_KEY:
306		((struct sctp_authkey *)arg)->sca_assoc_id = id;
307		break;
308	case SCTP_AUTH_ACTIVE_KEY:
309		((struct sctp_authkeyid *)arg)->scact_assoc_id = id;
310		break;
311	case SCTP_DELAYED_SACK:
312		((struct sctp_sack_info *)arg)->sack_assoc_id = id;
313		break;
314	case SCTP_CONTEXT:
315		((struct sctp_assoc_value *)arg)->assoc_id = id;
316		break;
317	case SCTP_STATUS:
318		((struct sctp_status *)arg)->sstat_assoc_id = id;
319		break;
320	case SCTP_GET_PEER_ADDR_INFO:
321		((struct sctp_paddrinfo *)arg)->spinfo_assoc_id = id;
322		break;
323	case SCTP_PEER_AUTH_CHUNKS:
324		((struct sctp_authchunks *)arg)->gauth_assoc_id = id;
325		break;
326	case SCTP_LOCAL_AUTH_CHUNKS:
327		((struct sctp_authchunks *)arg)->gauth_assoc_id = id;
328		break;
329	case SCTP_TIMEOUTS:
330		((struct sctp_timeouts *)arg)->stimo_assoc_id = id;
331		break;
332	case SCTP_EVENT:
333		((struct sctp_event *)arg)->se_assoc_id = id;
334		break;
335	case SCTP_DEFAULT_SNDINFO:
336		((struct sctp_sndinfo *)arg)->snd_assoc_id = id;
337		break;
338	case SCTP_DEFAULT_PRINFO:
339		((struct sctp_default_prinfo *)arg)->pr_assoc_id = id;
340		break;
341	case SCTP_PEER_ADDR_THLDS:
342		((struct sctp_paddrthlds *)arg)->spt_assoc_id = id;
343		break;
344	case SCTP_REMOTE_UDP_ENCAPS_PORT:
345		((struct sctp_udpencaps *)arg)->sue_assoc_id = id;
346		break;
347	case SCTP_ECN_SUPPORTED:
348		((struct sctp_assoc_value *)arg)->assoc_id = id;
349		break;
350	case SCTP_PR_SUPPORTED:
351		((struct sctp_assoc_value *)arg)->assoc_id = id;
352		break;
353	case SCTP_AUTH_SUPPORTED:
354		((struct sctp_assoc_value *)arg)->assoc_id = id;
355		break;
356	case SCTP_ASCONF_SUPPORTED:
357		((struct sctp_assoc_value *)arg)->assoc_id = id;
358		break;
359	case SCTP_RECONFIG_SUPPORTED:
360		((struct sctp_assoc_value *)arg)->assoc_id = id;
361		break;
362	case SCTP_NRSACK_SUPPORTED:
363		((struct sctp_assoc_value *)arg)->assoc_id = id;
364		break;
365	case SCTP_PKTDROP_SUPPORTED:
366		((struct sctp_assoc_value *)arg)->assoc_id = id;
367		break;
368	case SCTP_MAX_BURST:
369		((struct sctp_assoc_value *)arg)->assoc_id = id;
370		break;
371	case SCTP_ENABLE_STREAM_RESET:
372		((struct sctp_assoc_value *)arg)->assoc_id = id;
373		break;
374	case SCTP_PR_STREAM_STATUS:
375		((struct sctp_prstatus *)arg)->sprstat_assoc_id = id;
376		break;
377	case SCTP_PR_ASSOC_STATUS:
378		((struct sctp_prstatus *)arg)->sprstat_assoc_id = id;
379		break;
380	case SCTP_MAX_CWND:
381		((struct sctp_assoc_value *)arg)->assoc_id = id;
382		break;
383	default:
384		break;
385	}
386	return (getsockopt(sd, IPPROTO_SCTP, opt, arg, size));
387}
388
389int
390sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs)
391{
392	struct sctp_getaddresses *addrs;
393	struct sockaddr *sa;
394	sctp_assoc_t asoc;
395	caddr_t lim;
396	socklen_t opt_len;
397	int cnt;
398
399	if (raddrs == NULL) {
400		errno = EFAULT;
401		return (-1);
402	}
403	asoc = id;
404	opt_len = (socklen_t)sizeof(sctp_assoc_t);
405	if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE,
406	    &asoc, &opt_len) != 0) {
407		return (-1);
408	}
409	/* size required is returned in 'asoc' */
410	opt_len = (socklen_t)((size_t)asoc + sizeof(struct sctp_getaddresses));
411	addrs = calloc(1, (size_t)opt_len);
412	if (addrs == NULL) {
413		errno = ENOMEM;
414		return (-1);
415	}
416	addrs->sget_assoc_id = id;
417	/* Now lets get the array of addresses */
418	if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES,
419	    addrs, &opt_len) != 0) {
420		free(addrs);
421		return (-1);
422	}
423	*raddrs = &addrs->addr[0].sa;
424	cnt = 0;
425	sa = &addrs->addr[0].sa;
426	lim = (caddr_t)addrs + opt_len;
427	while (((caddr_t)sa < lim) && (sa->sa_len > 0)) {
428		sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
429		cnt++;
430	}
431	return (cnt);
432}
433
434void
435sctp_freepaddrs(struct sockaddr *addrs)
436{
437	void *fr_addr;
438
439	/* Take away the hidden association id */
440	fr_addr = (void *)((caddr_t)addrs - offsetof(struct sctp_getaddresses, addr));
441	/* Now free it */
442	free(fr_addr);
443}
444
445int
446sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs)
447{
448	struct sctp_getaddresses *addrs;
449	caddr_t lim;
450	struct sockaddr *sa;
451	size_t size_of_addresses;
452	socklen_t opt_len;
453	int cnt;
454
455	if (raddrs == NULL) {
456		errno = EFAULT;
457		return (-1);
458	}
459	size_of_addresses = 0;
460	opt_len = (socklen_t)sizeof(int);
461	if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE,
462	    &size_of_addresses, &opt_len) != 0) {
463		errno = ENOMEM;
464		return (-1);
465	}
466	if (size_of_addresses == 0) {
467		errno = ENOTCONN;
468		return (-1);
469	}
470	opt_len = (socklen_t)(size_of_addresses + sizeof(struct sctp_getaddresses));
471	addrs = calloc(1, (size_t)opt_len);
472	if (addrs == NULL) {
473		errno = ENOMEM;
474		return (-1);
475	}
476	addrs->sget_assoc_id = id;
477	/* Now lets get the array of addresses */
478	if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs,
479	    &opt_len) != 0) {
480		free(addrs);
481		errno = ENOMEM;
482		return (-1);
483	}
484	*raddrs = &addrs->addr[0].sa;
485	cnt = 0;
486	sa = &addrs->addr[0].sa;
487	lim = (caddr_t)addrs + opt_len;
488	while (((caddr_t)sa < lim) && (sa->sa_len > 0)) {
489		sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
490		cnt++;
491	}
492	return (cnt);
493}
494
495void
496sctp_freeladdrs(struct sockaddr *addrs)
497{
498	void *fr_addr;
499
500	/* Take away the hidden association id */
501	fr_addr = (void *)((caddr_t)addrs - offsetof(struct sctp_getaddresses, addr));
502	/* Now free it */
503	free(fr_addr);
504}
505
506ssize_t
507sctp_sendmsg(int s,
508    const void *data,
509    size_t len,
510    const struct sockaddr *to,
511    socklen_t tolen,
512    uint32_t ppid,
513    uint32_t flags,
514    uint16_t stream_no,
515    uint32_t timetolive,
516    uint32_t context)
517{
518#ifdef SYS_sctp_generic_sendmsg
519	struct sctp_sndrcvinfo sinfo;
520
521	memset(&sinfo, 0, sizeof(struct sctp_sndrcvinfo));
522	sinfo.sinfo_ppid = ppid;
523	sinfo.sinfo_flags = flags;
524	sinfo.sinfo_stream = stream_no;
525	sinfo.sinfo_timetolive = timetolive;
526	sinfo.sinfo_context = context;
527	sinfo.sinfo_assoc_id = 0;
528	return (syscall(SYS_sctp_generic_sendmsg, s,
529	    data, len, to, tolen, &sinfo, 0));
530#else
531	struct msghdr msg;
532	struct sctp_sndrcvinfo *sinfo;
533	struct iovec iov;
534	char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
535	struct cmsghdr *cmsg;
536	struct sockaddr *who = NULL;
537	union {
538		struct sockaddr_in in;
539		struct sockaddr_in6 in6;
540	}     addr;
541
542	if ((tolen > 0) &&
543	    ((to == NULL) || (tolen < sizeof(struct sockaddr)))) {
544		errno = EINVAL;
545		return (-1);
546	}
547	if ((to != NULL) && (tolen > 0)) {
548		switch (to->sa_family) {
549		case AF_INET:
550			if (tolen != sizeof(struct sockaddr_in)) {
551				errno = EINVAL;
552				return (-1);
553			}
554			if ((to->sa_len > 0) &&
555			    (to->sa_len != sizeof(struct sockaddr_in))) {
556				errno = EINVAL;
557				return (-1);
558			}
559			memcpy(&addr, to, sizeof(struct sockaddr_in));
560			addr.in.sin_len = sizeof(struct sockaddr_in);
561			break;
562		case AF_INET6:
563			if (tolen != sizeof(struct sockaddr_in6)) {
564				errno = EINVAL;
565				return (-1);
566			}
567			if ((to->sa_len > 0) &&
568			    (to->sa_len != sizeof(struct sockaddr_in6))) {
569				errno = EINVAL;
570				return (-1);
571			}
572			memcpy(&addr, to, sizeof(struct sockaddr_in6));
573			addr.in6.sin6_len = sizeof(struct sockaddr_in6);
574			break;
575		default:
576			errno = EAFNOSUPPORT;
577			return (-1);
578		}
579		who = (struct sockaddr *)&addr;
580	}
581
582	iov.iov_base = (char *)data;
583	iov.iov_len = len;
584
585	if (who) {
586		msg.msg_name = (caddr_t)who;
587		msg.msg_namelen = who->sa_len;
588	} else {
589		msg.msg_name = (caddr_t)NULL;
590		msg.msg_namelen = 0;
591	}
592	msg.msg_iov = &iov;
593	msg.msg_iovlen = 1;
594	msg.msg_control = cmsgbuf;
595	msg.msg_controllen = CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
596	msg.msg_flags = 0;
597	cmsg = (struct cmsghdr *)cmsgbuf;
598	cmsg->cmsg_level = IPPROTO_SCTP;
599	cmsg->cmsg_type = SCTP_SNDRCV;
600	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
601	sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
602	memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo));
603	sinfo->sinfo_stream = stream_no;
604	sinfo->sinfo_ssn = 0;
605	sinfo->sinfo_flags = flags;
606	sinfo->sinfo_ppid = ppid;
607	sinfo->sinfo_context = context;
608	sinfo->sinfo_assoc_id = 0;
609	sinfo->sinfo_timetolive = timetolive;
610	return (sendmsg(s, &msg, 0));
611#endif
612}
613
614
615sctp_assoc_t
616sctp_getassocid(int sd, struct sockaddr *sa)
617{
618	struct sctp_paddrinfo sp;
619	socklen_t siz;
620
621	/* First get the assoc id */
622	siz = sizeof(sp);
623	memset(&sp, 0, sizeof(sp));
624	memcpy((caddr_t)&sp.spinfo_address, sa, sa->sa_len);
625	if (getsockopt(sd, IPPROTO_SCTP,
626	    SCTP_GET_PEER_ADDR_INFO, &sp, &siz) != 0) {
627		/* We depend on the fact that 0 can never be returned */
628		return ((sctp_assoc_t)0);
629	}
630	return (sp.spinfo_assoc_id);
631}
632
633ssize_t
634sctp_send(int sd, const void *data, size_t len,
635    const struct sctp_sndrcvinfo *sinfo,
636    int flags)
637{
638
639#ifdef SYS_sctp_generic_sendmsg
640	struct sockaddr *to = NULL;
641
642	return (syscall(SYS_sctp_generic_sendmsg, sd,
643	    data, len, to, 0, sinfo, flags));
644#else
645	struct msghdr msg;
646	struct iovec iov;
647	char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
648	struct cmsghdr *cmsg;
649
650	if (sinfo == NULL) {
651		errno = EINVAL;
652		return (-1);
653	}
654	iov.iov_base = (char *)data;
655	iov.iov_len = len;
656
657	msg.msg_name = NULL;
658	msg.msg_namelen = 0;
659	msg.msg_iov = &iov;
660	msg.msg_iovlen = 1;
661	msg.msg_control = cmsgbuf;
662	msg.msg_controllen = CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
663	msg.msg_flags = 0;
664	cmsg = (struct cmsghdr *)cmsgbuf;
665	cmsg->cmsg_level = IPPROTO_SCTP;
666	cmsg->cmsg_type = SCTP_SNDRCV;
667	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
668	memcpy(CMSG_DATA(cmsg), sinfo, sizeof(struct sctp_sndrcvinfo));
669	return (sendmsg(sd, &msg, flags));
670#endif
671}
672
673
674
675ssize_t
676sctp_sendx(int sd, const void *msg, size_t msg_len,
677    struct sockaddr *addrs, int addrcnt,
678    struct sctp_sndrcvinfo *sinfo,
679    int flags)
680{
681	struct sctp_sndrcvinfo __sinfo;
682	ssize_t ret;
683	int i, cnt, *aa, saved_errno;
684	char *buf;
685	int no_end_cx = 0;
686	size_t len, add_len;
687	struct sockaddr *at;
688
689	if (addrs == NULL) {
690		errno = EINVAL;
691		return (-1);
692	}
693#ifdef SYS_sctp_generic_sendmsg
694	if (addrcnt == 1) {
695		socklen_t l;
696		ssize_t ret;
697
698		/*
699		 * Quick way, we don't need to do a connectx so lets use the
700		 * syscall directly.
701		 */
702		l = addrs->sa_len;
703		ret = syscall(SYS_sctp_generic_sendmsg, sd,
704		    msg, msg_len, addrs, l, sinfo, flags);
705		if ((ret >= 0) && (sinfo != NULL)) {
706			sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs);
707		}
708		return (ret);
709	}
710#endif
711
712	len = sizeof(int);
713	at = addrs;
714	cnt = 0;
715	/* validate all the addresses and get the size */
716	for (i = 0; i < addrcnt; i++) {
717		if (at->sa_family == AF_INET) {
718			add_len = sizeof(struct sockaddr_in);
719		} else if (at->sa_family == AF_INET6) {
720			add_len = sizeof(struct sockaddr_in6);
721		} else {
722			errno = EINVAL;
723			return (-1);
724		}
725		len += add_len;
726		at = (struct sockaddr *)((caddr_t)at + add_len);
727		cnt++;
728	}
729	/* do we have any? */
730	if (cnt == 0) {
731		errno = EINVAL;
732		return (-1);
733	}
734	buf = malloc(len);
735	if (buf == NULL) {
736		errno = ENOMEM;
737		return (-1);
738	}
739	aa = (int *)buf;
740	*aa = cnt;
741	aa++;
742	memcpy((caddr_t)aa, addrs, (size_t)(len - sizeof(int)));
743	ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_DELAYED, (void *)buf,
744	    (socklen_t)len);
745
746	free(buf);
747	if (ret != 0) {
748		if (errno == EALREADY) {
749			no_end_cx = 1;
750			goto continue_send;
751		}
752		return (ret);
753	}
754continue_send:
755	if (sinfo == NULL) {
756		sinfo = &__sinfo;
757		memset(&__sinfo, 0, sizeof(__sinfo));
758	}
759	sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs);
760	if (sinfo->sinfo_assoc_id == 0) {
761		(void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
762		    (socklen_t)addrs->sa_len);
763		errno = ENOENT;
764		return (-1);
765	}
766	ret = sctp_send(sd, msg, msg_len, sinfo, flags);
767	saved_errno = errno;
768	if (no_end_cx == 0)
769		(void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
770		    (socklen_t)addrs->sa_len);
771
772	errno = saved_errno;
773	return (ret);
774}
775
776ssize_t
777sctp_sendmsgx(int sd,
778    const void *msg,
779    size_t len,
780    struct sockaddr *addrs,
781    int addrcnt,
782    uint32_t ppid,
783    uint32_t flags,
784    uint16_t stream_no,
785    uint32_t timetolive,
786    uint32_t context)
787{
788	struct sctp_sndrcvinfo sinfo;
789
790	memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo));
791	sinfo.sinfo_ppid = ppid;
792	sinfo.sinfo_flags = flags;
793	sinfo.sinfo_stream = stream_no;
794	sinfo.sinfo_timetolive = timetolive;
795	sinfo.sinfo_context = context;
796	return (sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0));
797}
798
799ssize_t
800sctp_recvmsg(int s,
801    void *dbuf,
802    size_t len,
803    struct sockaddr *from,
804    socklen_t *fromlen,
805    struct sctp_sndrcvinfo *sinfo,
806    int *msg_flags)
807{
808#ifdef SYS_sctp_generic_recvmsg
809	struct iovec iov;
810
811	iov.iov_base = dbuf;
812	iov.iov_len = len;
813	return (syscall(SYS_sctp_generic_recvmsg, s,
814	    &iov, 1, from, fromlen, sinfo, msg_flags));
815#else
816	ssize_t sz;
817	struct msghdr msg;
818	struct iovec iov;
819	char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV];
820	struct cmsghdr *cmsg;
821
822	if (msg_flags == NULL) {
823		errno = EINVAL;
824		return (-1);
825	}
826	iov.iov_base = dbuf;
827	iov.iov_len = len;
828	msg.msg_name = (caddr_t)from;
829	if (fromlen == NULL)
830		msg.msg_namelen = 0;
831	else
832		msg.msg_namelen = *fromlen;
833	msg.msg_iov = &iov;
834	msg.msg_iovlen = 1;
835	msg.msg_control = cmsgbuf;
836	msg.msg_controllen = sizeof(cmsgbuf);
837	msg.msg_flags = 0;
838	sz = recvmsg(s, &msg, *msg_flags);
839	*msg_flags = msg.msg_flags;
840	if (sz <= 0) {
841		return (sz);
842	}
843	if (sinfo) {
844		sinfo->sinfo_assoc_id = 0;
845	}
846	if ((msg.msg_controllen > 0) && (sinfo != NULL)) {
847		/*
848		 * parse through and see if we find the sctp_sndrcvinfo (if
849		 * the user wants it).
850		 */
851		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
852			if (cmsg->cmsg_level != IPPROTO_SCTP) {
853				continue;
854			}
855			if (cmsg->cmsg_type == SCTP_SNDRCV) {
856				memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_sndrcvinfo));
857				break;
858			}
859			if (cmsg->cmsg_type == SCTP_EXTRCV) {
860				/*
861				 * Let's hope that the user provided enough
862				 * enough memory. At least he asked for more
863				 * information.
864				 */
865				memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_extrcvinfo));
866				break;
867			}
868		}
869	}
870	return (sz);
871#endif
872}
873
874ssize_t
875sctp_recvv(int sd,
876    const struct iovec *iov,
877    int iovlen,
878    struct sockaddr *from,
879    socklen_t *fromlen,
880    void *info,
881    socklen_t *infolen,
882    unsigned int *infotype,
883    int *flags)
884{
885	char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV];
886	struct msghdr msg;
887	struct cmsghdr *cmsg;
888	ssize_t ret;
889	struct sctp_rcvinfo *rcvinfo;
890	struct sctp_nxtinfo *nxtinfo;
891
892	if (((info != NULL) && (infolen == NULL)) ||
893	    ((info == NULL) && (infolen != NULL) && (*infolen != 0)) ||
894	    ((info != NULL) && (infotype == NULL))) {
895		errno = EINVAL;
896		return (-1);
897	}
898	if (infotype) {
899		*infotype = SCTP_RECVV_NOINFO;
900	}
901	msg.msg_name = from;
902	if (fromlen == NULL) {
903		msg.msg_namelen = 0;
904	} else {
905		msg.msg_namelen = *fromlen;
906	}
907	msg.msg_iov = (struct iovec *)iov;
908	msg.msg_iovlen = iovlen;
909	msg.msg_control = cmsgbuf;
910	msg.msg_controllen = sizeof(cmsgbuf);
911	msg.msg_flags = 0;
912	ret = recvmsg(sd, &msg, *flags);
913	*flags = msg.msg_flags;
914	if ((ret > 0) &&
915	    (msg.msg_controllen > 0) &&
916	    (infotype != NULL) &&
917	    (infolen != NULL) &&
918	    (*infolen > 0)) {
919		rcvinfo = NULL;
920		nxtinfo = NULL;
921		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
922			if (cmsg->cmsg_level != IPPROTO_SCTP) {
923				continue;
924			}
925			if (cmsg->cmsg_type == SCTP_RCVINFO) {
926				rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg);
927				if (nxtinfo != NULL) {
928					break;
929				} else {
930					continue;
931				}
932			}
933			if (cmsg->cmsg_type == SCTP_NXTINFO) {
934				nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg);
935				if (rcvinfo != NULL) {
936					break;
937				} else {
938					continue;
939				}
940			}
941		}
942		if (rcvinfo != NULL) {
943			if ((nxtinfo != NULL) && (*infolen >= sizeof(struct sctp_recvv_rn))) {
944				struct sctp_recvv_rn *rn_info;
945
946				rn_info = (struct sctp_recvv_rn *)info;
947				rn_info->recvv_rcvinfo = *rcvinfo;
948				rn_info->recvv_nxtinfo = *nxtinfo;
949				*infolen = (socklen_t)sizeof(struct sctp_recvv_rn);
950				*infotype = SCTP_RECVV_RN;
951			} else if (*infolen >= sizeof(struct sctp_rcvinfo)) {
952				memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo));
953				*infolen = (socklen_t)sizeof(struct sctp_rcvinfo);
954				*infotype = SCTP_RECVV_RCVINFO;
955			}
956		} else if (nxtinfo != NULL) {
957			if (*infolen >= sizeof(struct sctp_nxtinfo)) {
958				memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo));
959				*infolen = (socklen_t)sizeof(struct sctp_nxtinfo);
960				*infotype = SCTP_RECVV_NXTINFO;
961			}
962		}
963	}
964	return (ret);
965}
966
967ssize_t
968sctp_sendv(int sd,
969    const struct iovec *iov, int iovcnt,
970    struct sockaddr *addrs, int addrcnt,
971    void *info, socklen_t infolen, unsigned int infotype,
972    int flags)
973{
974	ssize_t ret;
975	int i;
976	socklen_t addr_len;
977	struct msghdr msg;
978	in_port_t port;
979	struct sctp_sendv_spa *spa_info;
980	struct cmsghdr *cmsg;
981	char *cmsgbuf;
982	struct sockaddr *addr;
983	struct sockaddr_in *addr_in;
984	struct sockaddr_in6 *addr_in6;
985	sctp_assoc_t *assoc_id;
986
987	if ((addrcnt < 0) ||
988	    (iovcnt < 0) ||
989	    ((addrs == NULL) && (addrcnt > 0)) ||
990	    ((addrs != NULL) && (addrcnt == 0)) ||
991	    ((iov == NULL) && (iovcnt > 0)) ||
992	    ((iov != NULL) && (iovcnt == 0))) {
993		errno = EINVAL;
994		return (-1);
995	}
996	cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) +
997	    CMSG_SPACE(sizeof(struct sctp_prinfo)) +
998	    CMSG_SPACE(sizeof(struct sctp_authinfo)) +
999	    (size_t)addrcnt * CMSG_SPACE(sizeof(struct in6_addr)));
1000	if (cmsgbuf == NULL) {
1001		errno = ENOMEM;
1002		return (-1);
1003	}
1004	assoc_id = NULL;
1005	msg.msg_control = cmsgbuf;
1006	msg.msg_controllen = 0;
1007	cmsg = (struct cmsghdr *)cmsgbuf;
1008	switch (infotype) {
1009	case SCTP_SENDV_NOINFO:
1010		if ((infolen != 0) || (info != NULL)) {
1011			free(cmsgbuf);
1012			errno = EINVAL;
1013			return (-1);
1014		}
1015		break;
1016	case SCTP_SENDV_SNDINFO:
1017		if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) {
1018			free(cmsgbuf);
1019			errno = EINVAL;
1020			return (-1);
1021		}
1022		cmsg->cmsg_level = IPPROTO_SCTP;
1023		cmsg->cmsg_type = SCTP_SNDINFO;
1024		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
1025		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo));
1026		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
1027		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
1028		assoc_id = &(((struct sctp_sndinfo *)info)->snd_assoc_id);
1029		break;
1030	case SCTP_SENDV_PRINFO:
1031		if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) {
1032			free(cmsgbuf);
1033			errno = EINVAL;
1034			return (-1);
1035		}
1036		cmsg->cmsg_level = IPPROTO_SCTP;
1037		cmsg->cmsg_type = SCTP_PRINFO;
1038		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
1039		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo));
1040		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
1041		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
1042		break;
1043	case SCTP_SENDV_AUTHINFO:
1044		if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) {
1045			free(cmsgbuf);
1046			errno = EINVAL;
1047			return (-1);
1048		}
1049		cmsg->cmsg_level = IPPROTO_SCTP;
1050		cmsg->cmsg_type = SCTP_AUTHINFO;
1051		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
1052		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo));
1053		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
1054		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
1055		break;
1056	case SCTP_SENDV_SPA:
1057		if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) {
1058			free(cmsgbuf);
1059			errno = EINVAL;
1060			return (-1);
1061		}
1062		spa_info = (struct sctp_sendv_spa *)info;
1063		if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) {
1064			cmsg->cmsg_level = IPPROTO_SCTP;
1065			cmsg->cmsg_type = SCTP_SNDINFO;
1066			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
1067			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo));
1068			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
1069			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
1070			assoc_id = &(spa_info->sendv_sndinfo.snd_assoc_id);
1071		}
1072		if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) {
1073			cmsg->cmsg_level = IPPROTO_SCTP;
1074			cmsg->cmsg_type = SCTP_PRINFO;
1075			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
1076			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo));
1077			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
1078			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
1079		}
1080		if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) {
1081			cmsg->cmsg_level = IPPROTO_SCTP;
1082			cmsg->cmsg_type = SCTP_AUTHINFO;
1083			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
1084			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo));
1085			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
1086			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
1087		}
1088		break;
1089	default:
1090		free(cmsgbuf);
1091		errno = EINVAL;
1092		return (-1);
1093	}
1094	addr = addrs;
1095	msg.msg_name = NULL;
1096	msg.msg_namelen = 0;
1097
1098	for (i = 0; i < addrcnt; i++) {
1099		switch (addr->sa_family) {
1100		case AF_INET:
1101			addr_len = (socklen_t)sizeof(struct sockaddr_in);
1102			addr_in = (struct sockaddr_in *)addr;
1103			if (addr_in->sin_len != addr_len) {
1104				free(cmsgbuf);
1105				errno = EINVAL;
1106				return (-1);
1107			}
1108			if (i == 0) {
1109				port = addr_in->sin_port;
1110			} else {
1111				if (port == addr_in->sin_port) {
1112					cmsg->cmsg_level = IPPROTO_SCTP;
1113					cmsg->cmsg_type = SCTP_DSTADDRV4;
1114					cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
1115					memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr));
1116					msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr));
1117					cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr)));
1118				} else {
1119					free(cmsgbuf);
1120					errno = EINVAL;
1121					return (-1);
1122				}
1123			}
1124			break;
1125		case AF_INET6:
1126			addr_len = (socklen_t)sizeof(struct sockaddr_in6);
1127			addr_in6 = (struct sockaddr_in6 *)addr;
1128			if (addr_in6->sin6_len != addr_len) {
1129				free(cmsgbuf);
1130				errno = EINVAL;
1131				return (-1);
1132			}
1133			if (i == 0) {
1134				port = addr_in6->sin6_port;
1135			} else {
1136				if (port == addr_in6->sin6_port) {
1137					cmsg->cmsg_level = IPPROTO_SCTP;
1138					cmsg->cmsg_type = SCTP_DSTADDRV6;
1139					cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr));
1140					memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr));
1141					msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr));
1142					cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr)));
1143				} else {
1144					free(cmsgbuf);
1145					errno = EINVAL;
1146					return (-1);
1147				}
1148			}
1149			break;
1150		default:
1151			free(cmsgbuf);
1152			errno = EINVAL;
1153			return (-1);
1154		}
1155		if (i == 0) {
1156			msg.msg_name = addr;
1157			msg.msg_namelen = addr_len;
1158		}
1159		addr = (struct sockaddr *)((caddr_t)addr + addr_len);
1160	}
1161	if (msg.msg_controllen == 0) {
1162		msg.msg_control = NULL;
1163	}
1164	msg.msg_iov = (struct iovec *)iov;
1165	msg.msg_iovlen = iovcnt;
1166	msg.msg_flags = 0;
1167	ret = sendmsg(sd, &msg, flags);
1168	free(cmsgbuf);
1169	if ((ret >= 0) && (addrs != NULL) && (assoc_id != NULL)) {
1170		*assoc_id = sctp_getassocid(sd, addrs);
1171	}
1172	return (ret);
1173}
1174
1175
1176#if !defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT)
1177
1178int
1179sctp_peeloff(int sd, sctp_assoc_t assoc_id)
1180{
1181	/* NOT supported, return invalid sd */
1182	errno = ENOTSUP;
1183	return (-1);
1184}
1185
1186#endif
1187#if defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT)
1188int
1189sctp_peeloff(int sd, sctp_assoc_t assoc_id)
1190{
1191	return (syscall(SYS_sctp_peeloff, sd, assoc_id));
1192}
1193
1194#endif
1195
1196#undef SCTP_CONTROL_VEC_SIZE_RCV
1197