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