xref: /onnv-gate/usr/src/lib/libsctp/common/sctp.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #define	_XPG4_2
30*0Sstevel@tonic-gate #define	__EXTENSIONS__
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate #include <assert.h>
33*0Sstevel@tonic-gate #include <sys/types.h>
34*0Sstevel@tonic-gate #include <sys/uio.h>
35*0Sstevel@tonic-gate #include <sys/socket.h>
36*0Sstevel@tonic-gate #include <sys/stropts.h>
37*0Sstevel@tonic-gate #include <sys/stream.h>
38*0Sstevel@tonic-gate #include <sys/socketvar.h>
39*0Sstevel@tonic-gate #include <sys/sockio.h>
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #include <errno.h>
42*0Sstevel@tonic-gate #include <stdlib.h>
43*0Sstevel@tonic-gate #include <unistd.h>
44*0Sstevel@tonic-gate #include <stropts.h>
45*0Sstevel@tonic-gate #include <stdio.h>
46*0Sstevel@tonic-gate #include <strings.h>
47*0Sstevel@tonic-gate #include <netinet/in.h>
48*0Sstevel@tonic-gate #include <netinet/sctp.h>
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate /* This will hold either a v4 or a v6 sockaddr */
51*0Sstevel@tonic-gate union sockaddr_storage_v6 {
52*0Sstevel@tonic-gate 	struct sockaddr_in in;
53*0Sstevel@tonic-gate 	struct sockaddr_in6 in6;
54*0Sstevel@tonic-gate };
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate /*
57*0Sstevel@tonic-gate  * This file implements all the libsctp calls.
58*0Sstevel@tonic-gate  */
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate /*
61*0Sstevel@tonic-gate  * To bind a list of addresses to a socket.  If the socket is
62*0Sstevel@tonic-gate  * v4, the type of the list of addresses is (struct in_addr).
63*0Sstevel@tonic-gate  * If the socket is v6, the type is (struct in6_addr).
64*0Sstevel@tonic-gate  */
65*0Sstevel@tonic-gate int
sctp_bindx(int sock,void * addrs,int addrcnt,int flags)66*0Sstevel@tonic-gate sctp_bindx(int sock, void *addrs, int addrcnt, int flags)
67*0Sstevel@tonic-gate {
68*0Sstevel@tonic-gate 	socklen_t sz;
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate 	if (addrs == NULL || addrcnt == 0) {
71*0Sstevel@tonic-gate 		errno = EINVAL;
72*0Sstevel@tonic-gate 		return (-1);
73*0Sstevel@tonic-gate 	}
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate 	/* Assume the caller uses the correct family type. */
76*0Sstevel@tonic-gate 	switch (((struct sockaddr *)addrs)->sa_family) {
77*0Sstevel@tonic-gate 	case AF_INET:
78*0Sstevel@tonic-gate 		sz = sizeof (struct sockaddr_in);
79*0Sstevel@tonic-gate 		break;
80*0Sstevel@tonic-gate 	case AF_INET6:
81*0Sstevel@tonic-gate 		sz = sizeof (struct sockaddr_in6);
82*0Sstevel@tonic-gate 		break;
83*0Sstevel@tonic-gate 	default:
84*0Sstevel@tonic-gate 		errno = EAFNOSUPPORT;
85*0Sstevel@tonic-gate 		return (-1);
86*0Sstevel@tonic-gate 	}
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate 	switch (flags) {
89*0Sstevel@tonic-gate 	case SCTP_BINDX_ADD_ADDR:
90*0Sstevel@tonic-gate 		return (setsockopt(sock, IPPROTO_SCTP, SCTP_ADD_ADDR, addrs,
91*0Sstevel@tonic-gate 		    sz * addrcnt));
92*0Sstevel@tonic-gate 	case SCTP_BINDX_REM_ADDR:
93*0Sstevel@tonic-gate 		return (setsockopt(sock, IPPROTO_SCTP, SCTP_REM_ADDR, addrs,
94*0Sstevel@tonic-gate 		    sz * addrcnt));
95*0Sstevel@tonic-gate 	default:
96*0Sstevel@tonic-gate 		errno = EINVAL;
97*0Sstevel@tonic-gate 		return (-1);
98*0Sstevel@tonic-gate 	}
99*0Sstevel@tonic-gate }
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate /*
102*0Sstevel@tonic-gate  * XXX currently not atomic -- need a better way to do this.
103*0Sstevel@tonic-gate  */
104*0Sstevel@tonic-gate int
sctp_getpaddrs(int sock,sctp_assoc_t id,void ** addrs)105*0Sstevel@tonic-gate sctp_getpaddrs(int sock, sctp_assoc_t id, void **addrs)
106*0Sstevel@tonic-gate {
107*0Sstevel@tonic-gate 	uint32_t naddrs;
108*0Sstevel@tonic-gate 	socklen_t bufsz;
109*0Sstevel@tonic-gate 	struct sctpopt opt;
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 	if (addrs == NULL) {
112*0Sstevel@tonic-gate 		errno = EINVAL;
113*0Sstevel@tonic-gate 		return (-1);
114*0Sstevel@tonic-gate 	}
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate 	/* First, find out how many peer addresses there are. */
117*0Sstevel@tonic-gate 	*addrs = NULL;
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate 	opt.sopt_aid = id;
120*0Sstevel@tonic-gate 	opt.sopt_name = SCTP_GET_NPADDRS;
121*0Sstevel@tonic-gate 	opt.sopt_val = (caddr_t)&naddrs;
122*0Sstevel@tonic-gate 	opt.sopt_len = sizeof (naddrs);
123*0Sstevel@tonic-gate 	if (ioctl(sock, SIOCSCTPGOPT, &opt) == -1) {
124*0Sstevel@tonic-gate 		return (-1);
125*0Sstevel@tonic-gate 	}
126*0Sstevel@tonic-gate 	if (naddrs == 0)
127*0Sstevel@tonic-gate 		return (0);
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 	/*
130*0Sstevel@tonic-gate 	 * Now we can get all the peer addresses.  This will over allocate
131*0Sstevel@tonic-gate 	 * space for v4 socket.  But it should be OK and save us
132*0Sstevel@tonic-gate 	 * the job to find out if it is a v4 or v6 socket.
133*0Sstevel@tonic-gate 	 */
134*0Sstevel@tonic-gate 	bufsz = sizeof (union sockaddr_storage_v6) * naddrs;
135*0Sstevel@tonic-gate 	if ((*addrs = malloc(bufsz)) == NULL) {
136*0Sstevel@tonic-gate 		return (-1);
137*0Sstevel@tonic-gate 	}
138*0Sstevel@tonic-gate 	opt.sopt_name = SCTP_GET_PADDRS;
139*0Sstevel@tonic-gate 	opt.sopt_val = *addrs;
140*0Sstevel@tonic-gate 	opt.sopt_len = bufsz;
141*0Sstevel@tonic-gate 	if (ioctl(sock, SIOCSCTPGOPT, &opt) == -1) {
142*0Sstevel@tonic-gate 		free(*addrs);
143*0Sstevel@tonic-gate 		*addrs = NULL;
144*0Sstevel@tonic-gate 		return (-1);
145*0Sstevel@tonic-gate 	}
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 	/* Calculate the number of addresses returned. */
148*0Sstevel@tonic-gate 	switch (((struct sockaddr *)*addrs)->sa_family) {
149*0Sstevel@tonic-gate 	case AF_INET:
150*0Sstevel@tonic-gate 		naddrs = opt.sopt_len / sizeof (struct sockaddr_in);
151*0Sstevel@tonic-gate 		break;
152*0Sstevel@tonic-gate 	case AF_INET6:
153*0Sstevel@tonic-gate 		naddrs = opt.sopt_len / sizeof (struct sockaddr_in6);
154*0Sstevel@tonic-gate 		break;
155*0Sstevel@tonic-gate 	}
156*0Sstevel@tonic-gate 	return (naddrs);
157*0Sstevel@tonic-gate }
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate void
sctp_freepaddrs(void * addrs)160*0Sstevel@tonic-gate sctp_freepaddrs(void *addrs)
161*0Sstevel@tonic-gate {
162*0Sstevel@tonic-gate 	free(addrs);
163*0Sstevel@tonic-gate }
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate int
sctp_getladdrs(int sock,sctp_assoc_t id,void ** addrs)166*0Sstevel@tonic-gate sctp_getladdrs(int sock, sctp_assoc_t id, void **addrs)
167*0Sstevel@tonic-gate {
168*0Sstevel@tonic-gate 	uint32_t naddrs;
169*0Sstevel@tonic-gate 	socklen_t bufsz;
170*0Sstevel@tonic-gate 	struct sctpopt opt;
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	if (addrs == NULL) {
173*0Sstevel@tonic-gate 		errno = EINVAL;
174*0Sstevel@tonic-gate 		return (-1);
175*0Sstevel@tonic-gate 	}
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	/* First, try to find out how many bound addresses there are. */
178*0Sstevel@tonic-gate 	*addrs = NULL;
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	opt.sopt_aid = id;
181*0Sstevel@tonic-gate 	opt.sopt_name = SCTP_GET_NLADDRS;
182*0Sstevel@tonic-gate 	opt.sopt_val = (caddr_t)&naddrs;
183*0Sstevel@tonic-gate 	opt.sopt_len = sizeof (naddrs);
184*0Sstevel@tonic-gate 	if (ioctl(sock, SIOCSCTPGOPT, &opt) == -1) {
185*0Sstevel@tonic-gate 		return (-1);
186*0Sstevel@tonic-gate 	}
187*0Sstevel@tonic-gate 	if (naddrs == 0)
188*0Sstevel@tonic-gate 		return (0);
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 	/*
191*0Sstevel@tonic-gate 	 * Now we can get all the bound addresses.  This will over allocate
192*0Sstevel@tonic-gate 	 * space for v4 socket.  But it should be OK and save us
193*0Sstevel@tonic-gate 	 * the job to find out if it is a v4 or v6 socket.
194*0Sstevel@tonic-gate 	 */
195*0Sstevel@tonic-gate 	bufsz = sizeof (union sockaddr_storage_v6) * naddrs;
196*0Sstevel@tonic-gate 	if ((*addrs = malloc(bufsz)) == NULL) {
197*0Sstevel@tonic-gate 		return (-1);
198*0Sstevel@tonic-gate 	}
199*0Sstevel@tonic-gate 	opt.sopt_name = SCTP_GET_LADDRS;
200*0Sstevel@tonic-gate 	opt.sopt_val = *addrs;
201*0Sstevel@tonic-gate 	opt.sopt_len = bufsz;
202*0Sstevel@tonic-gate 	if (ioctl(sock, SIOCSCTPGOPT, &opt) == -1) {
203*0Sstevel@tonic-gate 		free(*addrs);
204*0Sstevel@tonic-gate 		*addrs = NULL;
205*0Sstevel@tonic-gate 		return (-1);
206*0Sstevel@tonic-gate 	}
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	/* Calculate the number of addresses returned. */
209*0Sstevel@tonic-gate 	switch (((struct sockaddr *)*addrs)->sa_family) {
210*0Sstevel@tonic-gate 	case AF_INET:
211*0Sstevel@tonic-gate 		naddrs = opt.sopt_len / sizeof (struct sockaddr_in);
212*0Sstevel@tonic-gate 		break;
213*0Sstevel@tonic-gate 	case AF_INET6:
214*0Sstevel@tonic-gate 		naddrs = opt.sopt_len / sizeof (struct sockaddr_in6);
215*0Sstevel@tonic-gate 		break;
216*0Sstevel@tonic-gate 	}
217*0Sstevel@tonic-gate 	return (naddrs);
218*0Sstevel@tonic-gate }
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate void
sctp_freeladdrs(void * addrs)221*0Sstevel@tonic-gate sctp_freeladdrs(void *addrs)
222*0Sstevel@tonic-gate {
223*0Sstevel@tonic-gate 	free(addrs);
224*0Sstevel@tonic-gate }
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate int
sctp_opt_info(int sock,sctp_assoc_t id,int opt,void * arg,socklen_t * len)227*0Sstevel@tonic-gate sctp_opt_info(int sock, sctp_assoc_t id, int opt, void *arg, socklen_t *len)
228*0Sstevel@tonic-gate {
229*0Sstevel@tonic-gate 	struct sctpopt sopt;
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 	sopt.sopt_aid = id;
232*0Sstevel@tonic-gate 	sopt.sopt_name = opt;
233*0Sstevel@tonic-gate 	sopt.sopt_val = arg;
234*0Sstevel@tonic-gate 	sopt.sopt_len = *len;
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 	if (ioctl(sock, SIOCSCTPGOPT, &sopt) == -1) {
237*0Sstevel@tonic-gate 		return (-1);
238*0Sstevel@tonic-gate 	}
239*0Sstevel@tonic-gate 	*len = sopt.sopt_len;
240*0Sstevel@tonic-gate 	return (0);
241*0Sstevel@tonic-gate }
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate /*
244*0Sstevel@tonic-gate  * Branch off an association to its own socket. ioctl() allocates and
245*0Sstevel@tonic-gate  * returns new fd.
246*0Sstevel@tonic-gate  */
247*0Sstevel@tonic-gate int
sctp_peeloff(int sock,sctp_assoc_t id)248*0Sstevel@tonic-gate sctp_peeloff(int sock, sctp_assoc_t id)
249*0Sstevel@tonic-gate {
250*0Sstevel@tonic-gate 	int fd;
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 	fd = id;
253*0Sstevel@tonic-gate 	if (ioctl(sock, SIOCSCTPPEELOFF, &fd) == -1) {
254*0Sstevel@tonic-gate 		return (-1);
255*0Sstevel@tonic-gate 	}
256*0Sstevel@tonic-gate 	return (fd);
257*0Sstevel@tonic-gate }
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate ssize_t
sctp_recvmsg(int s,void * msg,size_t len,struct sockaddr * from,socklen_t * fromlen,struct sctp_sndrcvinfo * sinfo,int * msg_flags)261*0Sstevel@tonic-gate sctp_recvmsg(int s, void *msg, size_t len, struct sockaddr *from,
262*0Sstevel@tonic-gate     socklen_t *fromlen, struct sctp_sndrcvinfo *sinfo, int *msg_flags)
263*0Sstevel@tonic-gate {
264*0Sstevel@tonic-gate 	struct msghdr hdr;
265*0Sstevel@tonic-gate 	struct iovec iov;
266*0Sstevel@tonic-gate 	struct cmsghdr *cmsg;
267*0Sstevel@tonic-gate 	char cinmsg[sizeof (*sinfo) + sizeof (*cmsg) + _CMSG_HDR_ALIGNMENT];
268*0Sstevel@tonic-gate 	int err;
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	hdr.msg_name = from;
271*0Sstevel@tonic-gate 	hdr.msg_namelen = (fromlen != NULL) ? *fromlen : 0;
272*0Sstevel@tonic-gate 	hdr.msg_iov = &iov;
273*0Sstevel@tonic-gate 	hdr.msg_iovlen = 1;
274*0Sstevel@tonic-gate 	if (sinfo != NULL) {
275*0Sstevel@tonic-gate 		hdr.msg_control = (void *)_CMSG_HDR_ALIGN(cinmsg);
276*0Sstevel@tonic-gate 		hdr.msg_controllen = sizeof (cinmsg) -
277*0Sstevel@tonic-gate 		    (_CMSG_HDR_ALIGN(cinmsg) - (uintptr_t)cinmsg);
278*0Sstevel@tonic-gate 	} else {
279*0Sstevel@tonic-gate 		hdr.msg_control = NULL;
280*0Sstevel@tonic-gate 		hdr.msg_controllen = 0;
281*0Sstevel@tonic-gate 	}
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 	iov.iov_base = msg;
284*0Sstevel@tonic-gate 	iov.iov_len = len;
285*0Sstevel@tonic-gate 	err = recvmsg(s, &hdr, msg_flags == NULL ? 0 : *msg_flags);
286*0Sstevel@tonic-gate 	if (err == -1) {
287*0Sstevel@tonic-gate 		return (-1);
288*0Sstevel@tonic-gate 	}
289*0Sstevel@tonic-gate 	if (fromlen != NULL) {
290*0Sstevel@tonic-gate 		*fromlen = hdr.msg_namelen;
291*0Sstevel@tonic-gate 	}
292*0Sstevel@tonic-gate 	if (msg_flags != NULL) {
293*0Sstevel@tonic-gate 		*msg_flags = hdr.msg_flags;
294*0Sstevel@tonic-gate 	}
295*0Sstevel@tonic-gate 	if (sinfo != NULL) {
296*0Sstevel@tonic-gate 		for (cmsg = CMSG_FIRSTHDR(&hdr); cmsg != NULL;
297*0Sstevel@tonic-gate 			cmsg = CMSG_NXTHDR(&hdr, cmsg)) {
298*0Sstevel@tonic-gate 			if (cmsg->cmsg_level == IPPROTO_SCTP &&
299*0Sstevel@tonic-gate 			    cmsg->cmsg_type == SCTP_SNDRCV) {
300*0Sstevel@tonic-gate 				bcopy(CMSG_DATA(cmsg), sinfo, sizeof (*sinfo));
301*0Sstevel@tonic-gate 				break;
302*0Sstevel@tonic-gate 			}
303*0Sstevel@tonic-gate 		}
304*0Sstevel@tonic-gate 	}
305*0Sstevel@tonic-gate 	return (err);
306*0Sstevel@tonic-gate }
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate static ssize_t
sctp_send_common(int s,const void * msg,size_t len,const struct sockaddr * to,socklen_t tolen,uint32_t ppid,uint32_t sinfo_flags,uint16_t stream_no,uint32_t timetolive,uint32_t context,sctp_assoc_t aid,int flags)309*0Sstevel@tonic-gate sctp_send_common(int s, const void *msg, size_t len, const struct sockaddr *to,
310*0Sstevel@tonic-gate     socklen_t tolen, uint32_t ppid, uint32_t sinfo_flags, uint16_t stream_no,
311*0Sstevel@tonic-gate     uint32_t timetolive, uint32_t context, sctp_assoc_t aid, int flags)
312*0Sstevel@tonic-gate {
313*0Sstevel@tonic-gate 	struct msghdr hdr;
314*0Sstevel@tonic-gate 	struct iovec iov;
315*0Sstevel@tonic-gate 	struct sctp_sndrcvinfo *sinfo;
316*0Sstevel@tonic-gate 	struct cmsghdr *cmsg;
317*0Sstevel@tonic-gate 	char coutmsg[sizeof (*sinfo) + sizeof (*cmsg) + _CMSG_HDR_ALIGNMENT];
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate 	hdr.msg_name = (caddr_t)to;
320*0Sstevel@tonic-gate 	hdr.msg_namelen = tolen;
321*0Sstevel@tonic-gate 	hdr.msg_iov = &iov;
322*0Sstevel@tonic-gate 	hdr.msg_iovlen = 1;
323*0Sstevel@tonic-gate 	hdr.msg_control = (void *)_CMSG_HDR_ALIGN(coutmsg);
324*0Sstevel@tonic-gate 	hdr.msg_controllen = sizeof (*cmsg) + sizeof (*sinfo);
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 	iov.iov_len = len;
327*0Sstevel@tonic-gate 	iov.iov_base = (caddr_t)msg;
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	cmsg = CMSG_FIRSTHDR(&hdr);
330*0Sstevel@tonic-gate 	cmsg->cmsg_level = IPPROTO_SCTP;
331*0Sstevel@tonic-gate 	cmsg->cmsg_type = SCTP_SNDRCV;
332*0Sstevel@tonic-gate 	cmsg->cmsg_len = sizeof (*cmsg) + sizeof (*sinfo);
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 	sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
335*0Sstevel@tonic-gate 	sinfo->sinfo_stream = stream_no;
336*0Sstevel@tonic-gate 	sinfo->sinfo_ssn = 0;
337*0Sstevel@tonic-gate 	sinfo->sinfo_flags = sinfo_flags;
338*0Sstevel@tonic-gate 	sinfo->sinfo_ppid = ppid;
339*0Sstevel@tonic-gate 	sinfo->sinfo_context = context;
340*0Sstevel@tonic-gate 	sinfo->sinfo_timetolive = timetolive;
341*0Sstevel@tonic-gate 	sinfo->sinfo_tsn = 0;
342*0Sstevel@tonic-gate 	sinfo->sinfo_cumtsn = 0;
343*0Sstevel@tonic-gate 	sinfo->sinfo_assoc_id = aid;
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 	return (sendmsg(s, &hdr, flags));
346*0Sstevel@tonic-gate }
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate ssize_t
sctp_send(int s,const void * msg,size_t len,const struct sctp_sndrcvinfo * sinfo,int flags)349*0Sstevel@tonic-gate sctp_send(int s, const void *msg, size_t len,
350*0Sstevel@tonic-gate     const struct sctp_sndrcvinfo *sinfo, int flags)
351*0Sstevel@tonic-gate {
352*0Sstevel@tonic-gate 	/* Note that msg can be NULL for pure control message. */
353*0Sstevel@tonic-gate 	if (sinfo == NULL) {
354*0Sstevel@tonic-gate 		errno = EINVAL;
355*0Sstevel@tonic-gate 		return (-1);
356*0Sstevel@tonic-gate 	}
357*0Sstevel@tonic-gate 	return (sctp_send_common(s, msg, len, NULL, 0, sinfo->sinfo_ppid,
358*0Sstevel@tonic-gate 	    sinfo->sinfo_flags, sinfo->sinfo_stream, sinfo->sinfo_timetolive,
359*0Sstevel@tonic-gate 	    sinfo->sinfo_context, sinfo->sinfo_assoc_id, flags));
360*0Sstevel@tonic-gate }
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate ssize_t
sctp_sendmsg(int s,const void * msg,size_t len,const struct sockaddr * to,socklen_t tolen,uint32_t ppid,uint32_t flags,uint16_t stream_no,uint32_t timetolive,uint32_t context)363*0Sstevel@tonic-gate sctp_sendmsg(int s, const void *msg, size_t len, const struct sockaddr *to,
364*0Sstevel@tonic-gate     socklen_t tolen, uint32_t ppid, uint32_t flags, uint16_t stream_no,
365*0Sstevel@tonic-gate     uint32_t timetolive, uint32_t context)
366*0Sstevel@tonic-gate {
367*0Sstevel@tonic-gate 	return (sctp_send_common(s, msg, len, to, tolen, ppid, flags,
368*0Sstevel@tonic-gate 	    stream_no, timetolive, context, 0, 0));
369*0Sstevel@tonic-gate }
370