sctp_sys_calls.c revision 231036
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 231036 2012-02-05 19:33:53Z 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;
249	size_t argsz;
250	uint16_t sport = 0;
251
252	/* validate the flags */
253	if ((flags != SCTP_BINDX_ADD_ADDR) &&
254	    (flags != SCTP_BINDX_REM_ADDR)) {
255		errno = EFAULT;
256		return (-1);
257	}
258	/* validate the address count and list */
259	if ((addrcnt <= 0) || (addrs == NULL)) {
260		errno = EINVAL;
261		return (-1);
262	}
263	argsz = (sizeof(struct sockaddr_storage) +
264	    sizeof(struct sctp_getaddresses));
265	gaddrs = (struct sctp_getaddresses *)calloc(1, argsz);
266	if (gaddrs == NULL) {
267		errno = ENOMEM;
268		return (-1);
269	}
270	/* First pre-screen the addresses */
271	sa = addrs;
272	for (i = 0; i < addrcnt; i++) {
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 + sa->sa_len);
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		if (sa->sa_family == AF_INET) {
323			if (sa->sa_len != sizeof(struct sockaddr_in))
324				goto out_error;
325		} else if (sa->sa_family == AF_INET6) {
326			if (sa->sa_len != sizeof(struct sockaddr_in6))
327				goto out_error;
328		} else {
329			/* invalid address family specified */
330	out_error:
331			free(gaddrs);
332			errno = EINVAL;
333			return (-1);
334		}
335		memset(gaddrs, 0, argsz);
336		gaddrs->sget_assoc_id = 0;
337		memcpy(gaddrs->addr, sa, sa->sa_len);
338		if (setsockopt(sd, IPPROTO_SCTP, flags, gaddrs,
339		    (socklen_t) argsz) != 0) {
340			free(gaddrs);
341			return (-1);
342		}
343		sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
344	}
345	free(gaddrs);
346	return (0);
347}
348
349
350int
351sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t * size)
352{
353	if (arg == NULL) {
354		errno = EINVAL;
355		return (-1);
356	}
357	switch (opt) {
358	case SCTP_RTOINFO:
359		((struct sctp_rtoinfo *)arg)->srto_assoc_id = id;
360		break;
361	case SCTP_ASSOCINFO:
362		((struct sctp_assocparams *)arg)->sasoc_assoc_id = id;
363		break;
364	case SCTP_DEFAULT_SEND_PARAM:
365		((struct sctp_assocparams *)arg)->sasoc_assoc_id = id;
366		break;
367	case SCTP_PRIMARY_ADDR:
368		((struct sctp_setprim *)arg)->ssp_assoc_id = id;
369		break;
370	case SCTP_PEER_ADDR_PARAMS:
371		((struct sctp_paddrparams *)arg)->spp_assoc_id = id;
372		break;
373	case SCTP_MAXSEG:
374		((struct sctp_assoc_value *)arg)->assoc_id = id;
375		break;
376	case SCTP_AUTH_KEY:
377		((struct sctp_authkey *)arg)->sca_assoc_id = id;
378		break;
379	case SCTP_AUTH_ACTIVE_KEY:
380		((struct sctp_authkeyid *)arg)->scact_assoc_id = id;
381		break;
382	case SCTP_DELAYED_SACK:
383		((struct sctp_sack_info *)arg)->sack_assoc_id = id;
384		break;
385	case SCTP_CONTEXT:
386		((struct sctp_assoc_value *)arg)->assoc_id = id;
387		break;
388	case SCTP_STATUS:
389		((struct sctp_status *)arg)->sstat_assoc_id = id;
390		break;
391	case SCTP_GET_PEER_ADDR_INFO:
392		((struct sctp_paddrinfo *)arg)->spinfo_assoc_id = id;
393		break;
394	case SCTP_PEER_AUTH_CHUNKS:
395		((struct sctp_authchunks *)arg)->gauth_assoc_id = id;
396		break;
397	case SCTP_LOCAL_AUTH_CHUNKS:
398		((struct sctp_authchunks *)arg)->gauth_assoc_id = id;
399		break;
400	case SCTP_TIMEOUTS:
401		((struct sctp_timeouts *)arg)->stimo_assoc_id = id;
402		break;
403	case SCTP_EVENT:
404		((struct sctp_event *)arg)->se_assoc_id = id;
405		break;
406	case SCTP_DEFAULT_SNDINFO:
407		((struct sctp_sndinfo *)arg)->snd_assoc_id = id;
408		break;
409	case SCTP_DEFAULT_PRINFO:
410		((struct sctp_default_prinfo *)arg)->pr_assoc_id = id;
411		break;
412	case SCTP_PEER_ADDR_THLDS:
413		((struct sctp_paddrthlds *)arg)->spt_assoc_id = id;
414		break;
415	case SCTP_MAX_BURST:
416		((struct sctp_assoc_value *)arg)->assoc_id = id;
417		break;
418	default:
419		break;
420	}
421	return (getsockopt(sd, IPPROTO_SCTP, opt, arg, size));
422}
423
424int
425sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs)
426{
427	struct sctp_getaddresses *addrs;
428	struct sockaddr *sa;
429	sctp_assoc_t asoc;
430	caddr_t lim;
431	socklen_t opt_len;
432	int cnt;
433
434	if (raddrs == NULL) {
435		errno = EFAULT;
436		return (-1);
437	}
438	asoc = id;
439	opt_len = (socklen_t) sizeof(sctp_assoc_t);
440	if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE,
441	    &asoc, &opt_len) != 0) {
442		return (-1);
443	}
444	/* size required is returned in 'asoc' */
445	opt_len = (socklen_t) ((size_t)asoc + sizeof(struct sctp_getaddresses));
446	addrs = calloc(1, (size_t)opt_len);
447	if (addrs == NULL) {
448		return (-1);
449	}
450	addrs->sget_assoc_id = id;
451	/* Now lets get the array of addresses */
452	if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES,
453	    addrs, &opt_len) != 0) {
454		free(addrs);
455		return (-1);
456	}
457	*raddrs = (struct sockaddr *)&addrs->addr[0];
458	cnt = 0;
459	sa = (struct sockaddr *)&addrs->addr[0];
460	lim = (caddr_t)addrs + opt_len;
461	while (((caddr_t)sa < lim) && (sa->sa_len > 0)) {
462		sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
463		cnt++;
464	}
465	return (cnt);
466}
467
468void
469sctp_freepaddrs(struct sockaddr *addrs)
470{
471	/* Take away the hidden association id */
472	void *fr_addr;
473
474	fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
475	/* Now free it */
476	free(fr_addr);
477}
478
479int
480sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs)
481{
482	struct sctp_getaddresses *addrs;
483	caddr_t lim;
484	struct sockaddr *sa;
485	size_t size_of_addresses;
486	socklen_t opt_len;
487	int cnt;
488
489	if (raddrs == NULL) {
490		errno = EFAULT;
491		return (-1);
492	}
493	size_of_addresses = 0;
494	opt_len = (socklen_t) sizeof(int);
495	if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE,
496	    &size_of_addresses, &opt_len) != 0) {
497		errno = ENOMEM;
498		return (-1);
499	}
500	if (size_of_addresses == 0) {
501		errno = ENOTCONN;
502		return (-1);
503	}
504	opt_len = (socklen_t) (size_of_addresses +
505	    sizeof(struct sockaddr_storage) +
506	    sizeof(struct sctp_getaddresses));
507	addrs = calloc(1, (size_t)opt_len);
508	if (addrs == NULL) {
509		errno = ENOMEM;
510		return (-1);
511	}
512	addrs->sget_assoc_id = id;
513	/* Now lets get the array of addresses */
514	if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs,
515	    &opt_len) != 0) {
516		free(addrs);
517		errno = ENOMEM;
518		return (-1);
519	}
520	*raddrs = (struct sockaddr *)&addrs->addr[0];
521	cnt = 0;
522	sa = (struct sockaddr *)&addrs->addr[0];
523	lim = (caddr_t)addrs + opt_len;
524	while (((caddr_t)sa < lim) && (sa->sa_len > 0)) {
525		sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
526		cnt++;
527	}
528	return (cnt);
529}
530
531void
532sctp_freeladdrs(struct sockaddr *addrs)
533{
534	/* Take away the hidden association id */
535	void *fr_addr;
536
537	fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
538	/* Now free it */
539	free(fr_addr);
540}
541
542
543ssize_t
544sctp_sendmsg(int s,
545    const void *data,
546    size_t len,
547    const struct sockaddr *to,
548    socklen_t tolen,
549    uint32_t ppid,
550    uint32_t flags,
551    uint16_t stream_no,
552    uint32_t timetolive,
553    uint32_t context)
554{
555#ifdef SYS_sctp_generic_sendmsg
556	struct sctp_sndrcvinfo sinfo;
557
558	memset(&sinfo, 0, sizeof(struct sctp_sndrcvinfo));
559	sinfo.sinfo_ppid = ppid;
560	sinfo.sinfo_flags = flags;
561	sinfo.sinfo_stream = stream_no;
562	sinfo.sinfo_timetolive = timetolive;
563	sinfo.sinfo_context = context;
564	sinfo.sinfo_assoc_id = 0;
565	return (syscall(SYS_sctp_generic_sendmsg, s,
566	    data, len, to, tolen, &sinfo, 0));
567#else
568	ssize_t sz;
569	struct msghdr msg;
570	struct sctp_sndrcvinfo *s_info;
571	struct iovec iov;
572	char controlVector[SCTP_CONTROL_VEC_SIZE_RCV];
573	struct cmsghdr *cmsg;
574	struct sockaddr *who = NULL;
575	union {
576		struct sockaddr_in in;
577		struct sockaddr_in6 in6;
578	}     addr;
579
580	if ((tolen > 0) &&
581	    ((to == NULL) || (tolen < sizeof(struct sockaddr)))) {
582		errno = EINVAL;
583		return -1;
584	}
585	if (to && (tolen > 0)) {
586		if (to->sa_family == AF_INET) {
587			if (tolen != sizeof(struct sockaddr_in)) {
588				errno = EINVAL;
589				return -1;
590			}
591			if ((to->sa_len > 0) &&
592			    (to->sa_len != sizeof(struct sockaddr_in))) {
593				errno = EINVAL;
594				return -1;
595			}
596			memcpy(&addr, to, sizeof(struct sockaddr_in));
597			addr.in.sin_len = sizeof(struct sockaddr_in);
598		} else if (to->sa_family == AF_INET6) {
599			if (tolen != sizeof(struct sockaddr_in6)) {
600				errno = EINVAL;
601				return -1;
602			}
603			if ((to->sa_len > 0) &&
604			    (to->sa_len != sizeof(struct sockaddr_in6))) {
605				errno = EINVAL;
606				return -1;
607			}
608			memcpy(&addr, to, sizeof(struct sockaddr_in6));
609			addr.in6.sin6_len = sizeof(struct sockaddr_in6);
610		} else {
611			errno = EAFNOSUPPORT;
612			return -1;
613		}
614		who = (struct sockaddr *)&addr;
615	}
616	iov.iov_base = (char *)data;
617	iov.iov_len = len;
618
619	if (who) {
620		msg.msg_name = (caddr_t)who;
621		msg.msg_namelen = who->sa_len;
622	} else {
623		msg.msg_name = (caddr_t)NULL;
624		msg.msg_namelen = 0;
625	}
626	msg.msg_iov = &iov;
627	msg.msg_iovlen = 1;
628	msg.msg_control = (caddr_t)controlVector;
629
630	cmsg = (struct cmsghdr *)controlVector;
631
632	cmsg->cmsg_level = IPPROTO_SCTP;
633	cmsg->cmsg_type = SCTP_SNDRCV;
634	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
635	s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
636
637	s_info->sinfo_stream = stream_no;
638	s_info->sinfo_ssn = 0;
639	s_info->sinfo_flags = flags;
640	s_info->sinfo_ppid = ppid;
641	s_info->sinfo_context = context;
642	s_info->sinfo_assoc_id = 0;
643	s_info->sinfo_timetolive = timetolive;
644	errno = 0;
645	msg.msg_controllen = cmsg->cmsg_len;
646	sz = sendmsg(s, &msg, 0);
647	return (sz);
648#endif
649}
650
651
652sctp_assoc_t
653sctp_getassocid(int sd, struct sockaddr *sa)
654{
655	struct sctp_paddrinfo sp;
656	socklen_t siz;
657
658	/* First get the assoc id */
659	siz = sizeof(sp);
660	memset(&sp, 0, sizeof(sp));
661	memcpy((caddr_t)&sp.spinfo_address, sa, sa->sa_len);
662	errno = 0;
663	if (getsockopt(sd, IPPROTO_SCTP,
664	    SCTP_GET_PEER_ADDR_INFO, &sp, &siz) != 0) {
665		return ((sctp_assoc_t) 0);
666	}
667	/* We depend on the fact that 0 can never be returned */
668	return (sp.spinfo_assoc_id);
669}
670
671ssize_t
672sctp_send(int sd, const void *data, size_t len,
673    const struct sctp_sndrcvinfo *sinfo,
674    int flags)
675{
676
677#ifdef SYS_sctp_generic_sendmsg
678	struct sockaddr *to = NULL;
679
680	return (syscall(SYS_sctp_generic_sendmsg, sd,
681	    data, len, to, 0, sinfo, flags));
682#else
683	ssize_t sz;
684	struct msghdr msg;
685	struct iovec iov;
686	struct sctp_sndrcvinfo *s_info;
687	char controlVector[SCTP_CONTROL_VEC_SIZE_SND];
688	struct cmsghdr *cmsg;
689
690	if (sinfo == NULL) {
691		errno = EINVAL;
692		return (-1);
693	}
694	iov.iov_base = (char *)data;
695	iov.iov_len = len;
696
697	msg.msg_name = 0;
698	msg.msg_namelen = 0;
699	msg.msg_iov = &iov;
700	msg.msg_iovlen = 1;
701	msg.msg_control = (caddr_t)controlVector;
702
703	cmsg = (struct cmsghdr *)controlVector;
704
705	cmsg->cmsg_level = IPPROTO_SCTP;
706	cmsg->cmsg_type = SCTP_SNDRCV;
707	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
708	s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
709	/* copy in the data */
710	*s_info = *sinfo;
711	errno = 0;
712	msg.msg_controllen = cmsg->cmsg_len;
713	sz = sendmsg(sd, &msg, flags);
714	return (sz);
715#endif
716}
717
718
719
720ssize_t
721sctp_sendx(int sd, const void *msg, size_t msg_len,
722    struct sockaddr *addrs, int addrcnt,
723    struct sctp_sndrcvinfo *sinfo,
724    int flags)
725{
726	struct sctp_sndrcvinfo __sinfo;
727	ssize_t ret;
728	int i, cnt, *aa, saved_errno;
729	char *buf;
730	int no_end_cx = 0;
731	size_t len, add_len;
732	struct sockaddr *at;
733
734	if (addrs == NULL) {
735		errno = EINVAL;
736		return (-1);
737	}
738#ifdef SYS_sctp_generic_sendmsg
739	if (addrcnt == 1) {
740		socklen_t l;
741
742		/*
743		 * Quick way, we don't need to do a connectx so lets use the
744		 * syscall directly.
745		 */
746		l = addrs->sa_len;
747		return (syscall(SYS_sctp_generic_sendmsg, sd,
748		    msg, msg_len, addrs, l, sinfo, flags));
749	}
750#endif
751
752	len = sizeof(int);
753	at = addrs;
754	cnt = 0;
755	/* validate all the addresses and get the size */
756	for (i = 0; i < addrcnt; i++) {
757		if (at->sa_family == AF_INET) {
758			add_len = sizeof(struct sockaddr_in);
759		} else if (at->sa_family == AF_INET6) {
760			add_len = sizeof(struct sockaddr_in6);
761		} else {
762			errno = EINVAL;
763			return (-1);
764		}
765		len += add_len;
766		at = (struct sockaddr *)((caddr_t)at + add_len);
767		cnt++;
768	}
769	/* do we have any? */
770	if (cnt == 0) {
771		errno = EINVAL;
772		return (-1);
773	}
774	buf = malloc(len);
775	if (buf == NULL) {
776		return (-1);
777	}
778	aa = (int *)buf;
779	*aa = cnt;
780	aa++;
781	memcpy((caddr_t)aa, addrs, (size_t)(len - sizeof(int)));
782	ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_DELAYED, (void *)buf,
783	    (socklen_t) len);
784
785	free(buf);
786	if (ret != 0) {
787		if (errno == EALREADY) {
788			no_end_cx = 1;
789			goto continue_send;
790		}
791		return (ret);
792	}
793continue_send:
794	if (sinfo == NULL) {
795		sinfo = &__sinfo;
796		memset(&__sinfo, 0, sizeof(__sinfo));
797	}
798	sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs);
799	if (sinfo->sinfo_assoc_id == 0) {
800		printf("Huh, can't get associd? TSNH!\n");
801		(void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
802		    (socklen_t) addrs->sa_len);
803		errno = ENOENT;
804		return (-1);
805	}
806	ret = sctp_send(sd, msg, msg_len, sinfo, flags);
807	saved_errno = errno;
808	if (no_end_cx == 0)
809		(void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
810		    (socklen_t) addrs->sa_len);
811
812	errno = saved_errno;
813	return (ret);
814}
815
816ssize_t
817sctp_sendmsgx(int sd,
818    const void *msg,
819    size_t len,
820    struct sockaddr *addrs,
821    int addrcnt,
822    uint32_t ppid,
823    uint32_t flags,
824    uint16_t stream_no,
825    uint32_t timetolive,
826    uint32_t context)
827{
828	struct sctp_sndrcvinfo sinfo;
829
830	memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo));
831	sinfo.sinfo_ppid = ppid;
832	sinfo.sinfo_flags = flags;
833	sinfo.sinfo_ssn = stream_no;
834	sinfo.sinfo_timetolive = timetolive;
835	sinfo.sinfo_context = context;
836	return sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0);
837}
838
839ssize_t
840sctp_recvmsg(int s,
841    void *dbuf,
842    size_t len,
843    struct sockaddr *from,
844    socklen_t * fromlen,
845    struct sctp_sndrcvinfo *sinfo,
846    int *msg_flags)
847{
848#ifdef SYS_sctp_generic_recvmsg
849	struct iovec iov;
850
851	iov.iov_base = dbuf;
852	iov.iov_len = len;
853	return (syscall(SYS_sctp_generic_recvmsg, s,
854	    &iov, 1, from, fromlen, sinfo, msg_flags));
855#else
856	struct sctp_sndrcvinfo *s_info;
857	ssize_t sz;
858	struct msghdr msg;
859	struct iovec iov;
860	char controlVector[SCTP_CONTROL_VEC_SIZE_RCV];
861	struct cmsghdr *cmsg;
862
863	if (msg_flags == NULL) {
864		errno = EINVAL;
865		return (-1);
866	}
867	msg.msg_flags = 0;
868	iov.iov_base = dbuf;
869	iov.iov_len = len;
870	msg.msg_name = (caddr_t)from;
871	if (fromlen == NULL)
872		msg.msg_namelen = 0;
873	else
874		msg.msg_namelen = *fromlen;
875	msg.msg_iov = &iov;
876	msg.msg_iovlen = 1;
877	msg.msg_control = (caddr_t)controlVector;
878	msg.msg_controllen = sizeof(controlVector);
879	errno = 0;
880	sz = recvmsg(s, &msg, *msg_flags);
881	*msg_flags = msg.msg_flags;
882	if (sz <= 0) {
883		return (sz);
884	}
885	s_info = NULL;
886	if (sinfo) {
887		sinfo->sinfo_assoc_id = 0;
888	}
889	if ((msg.msg_controllen) && sinfo) {
890		/*
891		 * parse through and see if we find the sctp_sndrcvinfo (if
892		 * the user wants it).
893		 */
894		cmsg = (struct cmsghdr *)controlVector;
895		while (cmsg) {
896			if ((cmsg->cmsg_len == 0) || (cmsg->cmsg_len > msg.msg_controllen)) {
897				break;
898			}
899			if (cmsg->cmsg_level == IPPROTO_SCTP) {
900				if (cmsg->cmsg_type == SCTP_SNDRCV) {
901					/* Got it */
902					s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
903					/* Copy it to the user */
904					if (sinfo)
905						*sinfo = *s_info;
906					break;
907				} else if (cmsg->cmsg_type == SCTP_EXTRCV) {
908					/*
909					 * Got it, presumably the user has
910					 * asked for this extra info, so the
911					 * structure holds more room :-D
912					 */
913					s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
914					/* Copy it to the user */
915					if (sinfo) {
916						memcpy(sinfo, s_info, sizeof(struct sctp_extrcvinfo));
917					}
918					break;
919
920				}
921			}
922			cmsg = CMSG_NXTHDR(&msg, cmsg);
923		}
924	}
925	return (sz);
926#endif
927}
928
929ssize_t
930sctp_recvv(int sd,
931    const struct iovec *iov,
932    int iovlen,
933    struct sockaddr *from,
934    socklen_t * fromlen,
935    void *info,
936    socklen_t * infolen,
937    unsigned int *infotype,
938    int *flags)
939{
940	char ctlbuf[SCTP_CONTROL_VEC_SIZE_RCV];
941	struct msghdr msg;
942	struct cmsghdr *cmsg;
943	ssize_t n;
944	struct sctp_rcvinfo *rcvinfo;
945	struct sctp_nxtinfo *nxtinfo;
946
947	if (((info != NULL) && (infolen == NULL)) |
948	    ((info == NULL) && (infolen != NULL) && (*infolen != 0)) ||
949	    ((info != NULL) && (infotype == NULL))) {
950		errno = EINVAL;
951		return (-1);
952	}
953	if (infotype) {
954		*infotype = SCTP_RECVV_NOINFO;
955	}
956	msg.msg_name = from;
957	if (fromlen == NULL) {
958		msg.msg_namelen = 0;
959	} else {
960		msg.msg_namelen = *fromlen;
961	}
962	msg.msg_iov = (struct iovec *)iov;
963	msg.msg_iovlen = iovlen;
964	msg.msg_control = ctlbuf;
965	msg.msg_controllen = sizeof(ctlbuf);
966	errno = 0;
967	n = recvmsg(sd, &msg, *flags);
968	*flags = msg.msg_flags;
969	if ((n > 0) &&
970	    (msg.msg_controllen > 0) &&
971	    (infotype != NULL) &&
972	    (infolen != NULL) &&
973	    (*infolen > 0)) {
974		rcvinfo = NULL;
975		nxtinfo = NULL;
976		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
977			if (cmsg->cmsg_level != IPPROTO_SCTP) {
978				continue;
979			}
980			if (cmsg->cmsg_type == SCTP_RCVINFO) {
981				rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg);
982			}
983			if (cmsg->cmsg_type == SCTP_NXTINFO) {
984				nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg);
985			}
986			if (rcvinfo && nxtinfo) {
987				break;
988			}
989		}
990		if (rcvinfo) {
991			if (nxtinfo) {
992				if (*infolen >= sizeof(struct sctp_recvv_rn)) {
993					struct sctp_recvv_rn *rn_info;
994
995					rn_info = (struct sctp_recvv_rn *)info;
996					rn_info->recvv_rcvinfo = *rcvinfo;
997					rn_info->recvv_nxtinfo = *nxtinfo;
998					*infolen = (socklen_t) sizeof(struct sctp_recvv_rn);
999					*infotype = SCTP_RECVV_RN;
1000				}
1001			} else {
1002				if (*infolen >= sizeof(struct sctp_rcvinfo)) {
1003					memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo));
1004					*infolen = (socklen_t) sizeof(struct sctp_rcvinfo);
1005					*infotype = SCTP_RECVV_RCVINFO;
1006				}
1007			}
1008		} else if (nxtinfo) {
1009			if (*infolen >= sizeof(struct sctp_rcvinfo)) {
1010				memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo));
1011				*infolen = (socklen_t) sizeof(struct sctp_nxtinfo);
1012				*infotype = SCTP_RECVV_NXTINFO;
1013			}
1014		}
1015	}
1016	return (n);
1017}
1018
1019ssize_t
1020sctp_sendv(int sd,
1021    const struct iovec *iov, int iovcnt,
1022    struct sockaddr *addrs, int addrcnt,
1023    void *info, socklen_t infolen, unsigned int infotype,
1024    int flags)
1025{
1026	ssize_t ret;
1027	int i;
1028	socklen_t addr_len;
1029	struct msghdr msg;
1030	in_port_t port;
1031	struct sctp_sendv_spa *spa_info;
1032	struct cmsghdr *cmsg;
1033	char *cmsgbuf;
1034	struct sockaddr *addr;
1035	struct sockaddr_in *addr_in;
1036	struct sockaddr_in6 *addr_in6;
1037
1038	if ((addrcnt < 0) ||
1039	    (iovcnt < 0) ||
1040	    ((addrs == NULL) && (addrcnt > 0)) ||
1041	    ((addrs != NULL) && (addrcnt == 0)) ||
1042	    ((iov == NULL) && (iovcnt > 0)) ||
1043	    ((iov != NULL) && (iovcnt == 0))) {
1044		errno = EINVAL;
1045		return (-1);
1046	}
1047	cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) +
1048	    CMSG_SPACE(sizeof(struct sctp_prinfo)) +
1049	    CMSG_SPACE(sizeof(struct sctp_authinfo)) +
1050	    (size_t)addrcnt * CMSG_SPACE(sizeof(struct in6_addr)));
1051	if (cmsgbuf == NULL) {
1052		errno = ENOBUFS;
1053		return (-1);
1054	}
1055	msg.msg_control = cmsgbuf;
1056	msg.msg_controllen = 0;
1057	cmsg = (struct cmsghdr *)cmsgbuf;
1058	switch (infotype) {
1059	case SCTP_SENDV_NOINFO:
1060		if ((infolen != 0) || (info != NULL)) {
1061			free(cmsgbuf);
1062			errno = EINVAL;
1063			return (-1);
1064		}
1065		break;
1066	case SCTP_SENDV_SNDINFO:
1067		if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) {
1068			free(cmsgbuf);
1069			errno = EINVAL;
1070			return (-1);
1071		}
1072		cmsg->cmsg_level = IPPROTO_SCTP;
1073		cmsg->cmsg_type = SCTP_SNDINFO;
1074		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
1075		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo));
1076		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
1077		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
1078		break;
1079	case SCTP_SENDV_PRINFO:
1080		if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) {
1081			free(cmsgbuf);
1082			errno = EINVAL;
1083			return (-1);
1084		}
1085		cmsg->cmsg_level = IPPROTO_SCTP;
1086		cmsg->cmsg_type = SCTP_PRINFO;
1087		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
1088		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo));
1089		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
1090		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
1091		break;
1092	case SCTP_SENDV_AUTHINFO:
1093		if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) {
1094			free(cmsgbuf);
1095			errno = EINVAL;
1096			return (-1);
1097		}
1098		cmsg->cmsg_level = IPPROTO_SCTP;
1099		cmsg->cmsg_type = SCTP_AUTHINFO;
1100		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
1101		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo));
1102		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
1103		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
1104		break;
1105	case SCTP_SENDV_SPA:
1106		if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) {
1107			free(cmsgbuf);
1108			errno = EINVAL;
1109			return (-1);
1110		}
1111		spa_info = (struct sctp_sendv_spa *)info;
1112		if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) {
1113			cmsg->cmsg_level = IPPROTO_SCTP;
1114			cmsg->cmsg_type = SCTP_SNDINFO;
1115			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
1116			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo));
1117			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
1118			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
1119		}
1120		if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) {
1121			cmsg->cmsg_level = IPPROTO_SCTP;
1122			cmsg->cmsg_type = SCTP_PRINFO;
1123			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
1124			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo));
1125			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
1126			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
1127		}
1128		if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) {
1129			cmsg->cmsg_level = IPPROTO_SCTP;
1130			cmsg->cmsg_type = SCTP_AUTHINFO;
1131			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
1132			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo));
1133			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
1134			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
1135		}
1136		break;
1137	default:
1138		free(cmsgbuf);
1139		errno = EINVAL;
1140		return (-1);
1141	}
1142	addr = addrs;
1143	msg.msg_name = NULL;
1144	msg.msg_namelen = 0;
1145
1146	for (i = 0; i < addrcnt; i++) {
1147		switch (addr->sa_family) {
1148		case AF_INET:
1149			addr_len = (socklen_t) sizeof(struct sockaddr_in);
1150			addr_in = (struct sockaddr_in *)addr;
1151			if (addr_in->sin_len != addr_len) {
1152				free(cmsgbuf);
1153				errno = EINVAL;
1154				return (-1);
1155			}
1156			if (i == 0) {
1157				port = addr_in->sin_port;
1158			} else {
1159				if (port == addr_in->sin_port) {
1160					cmsg->cmsg_level = IPPROTO_SCTP;
1161					cmsg->cmsg_type = SCTP_DSTADDRV4;
1162					cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
1163					memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr));
1164					msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr));
1165					cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr)));
1166				} else {
1167					free(cmsgbuf);
1168					errno = EINVAL;
1169					return (-1);
1170				}
1171			}
1172			break;
1173		case AF_INET6:
1174			addr_len = (socklen_t) sizeof(struct sockaddr_in6);
1175			addr_in6 = (struct sockaddr_in6 *)addr;
1176			if (addr_in6->sin6_len != addr_len) {
1177				free(cmsgbuf);
1178				errno = EINVAL;
1179				return (-1);
1180			}
1181			if (i == 0) {
1182				port = addr_in6->sin6_port;
1183			} else {
1184				if (port == addr_in6->sin6_port) {
1185					cmsg->cmsg_level = IPPROTO_SCTP;
1186					cmsg->cmsg_type = SCTP_DSTADDRV6;
1187					cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr));
1188					memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr));
1189					msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr));
1190					cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr)));
1191				} else {
1192					free(cmsgbuf);
1193					errno = EINVAL;
1194					return (-1);
1195				}
1196			}
1197			break;
1198		default:
1199			free(cmsgbuf);
1200			errno = EINVAL;
1201			return (-1);
1202		}
1203		if (i == 0) {
1204			msg.msg_name = addr;
1205			msg.msg_namelen = addr_len;
1206		}
1207		addr = (struct sockaddr *)((caddr_t)addr + addr_len);
1208	}
1209	if (msg.msg_controllen == 0) {
1210		msg.msg_control = NULL;
1211	}
1212	msg.msg_iov = (struct iovec *)iov;
1213	msg.msg_iovlen = iovcnt;
1214	msg.msg_flags = 0;
1215	ret = sendmsg(sd, &msg, flags);
1216	free(cmsgbuf);
1217	return (ret);
1218}
1219
1220
1221#if !defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT)
1222
1223int
1224sctp_peeloff(int sd, sctp_assoc_t assoc_id)
1225{
1226	/* NOT supported, return invalid sd */
1227	errno = ENOTSUP;
1228	return (-1);
1229}
1230
1231#endif
1232#if defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT)
1233int
1234sctp_peeloff(int sd, sctp_assoc_t assoc_id)
1235{
1236	return (syscall(SYS_sctp_peeloff, sd, assoc_id));
1237}
1238
1239#endif
1240
1241
1242#undef SCTP_CONTROL_VEC_SIZE_SND
1243#undef SCTP_CONTROL_VEC_SIZE_RCV
1244#undef SCTP_STACK_BUF_SIZE
1245