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