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