4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 #define __EXTENSIONS__
33 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/stropts.h>
37 #include <sys/stream.h>
38 #include <sys/socketvar.h>
39 #include <sys/sockio.h>
47 #include <netinet/in.h>
48 #include <netinet/sctp.h>
50 /* This will hold either a v4 or a v6 sockaddr */
51 union sockaddr_storage_v6
{
52 struct sockaddr_in in
;
53 struct sockaddr_in6 in6
;
57 * This file implements all the libsctp calls.
61 * To bind a list of addresses to a socket. If the socket is
62 * v4, the type of the list of addresses is (struct in_addr).
63 * If the socket is v6, the type is (struct in6_addr).
66 sctp_bindx(int sock
, void *addrs
, int addrcnt
, int flags
)
70 if (addrs
== NULL
|| addrcnt
== 0) {
75 /* Assume the caller uses the correct family type. */
76 switch (((struct sockaddr
*)addrs
)->sa_family
) {
78 sz
= sizeof (struct sockaddr_in
);
81 sz
= sizeof (struct sockaddr_in6
);
89 case SCTP_BINDX_ADD_ADDR
:
90 return (setsockopt(sock
, IPPROTO_SCTP
, SCTP_ADD_ADDR
, addrs
,
92 case SCTP_BINDX_REM_ADDR
:
93 return (setsockopt(sock
, IPPROTO_SCTP
, SCTP_REM_ADDR
, addrs
,
102 * XXX currently not atomic -- need a better way to do this.
105 sctp_getpaddrs(int sock
, sctp_assoc_t id
, void **addrs
)
116 /* First, find out how many peer addresses there are. */
120 opt
.sopt_name
= SCTP_GET_NPADDRS
;
121 opt
.sopt_val
= (caddr_t
)&naddrs
;
122 opt
.sopt_len
= sizeof (naddrs
);
123 if (ioctl(sock
, SIOCSCTPGOPT
, &opt
) == -1) {
130 * Now we can get all the peer addresses. This will over allocate
131 * space for v4 socket. But it should be OK and save us
132 * the job to find out if it is a v4 or v6 socket.
134 bufsz
= sizeof (union sockaddr_storage_v6
) * naddrs
;
135 if ((*addrs
= malloc(bufsz
)) == NULL
) {
138 opt
.sopt_name
= SCTP_GET_PADDRS
;
139 opt
.sopt_val
= *addrs
;
140 opt
.sopt_len
= bufsz
;
141 if (ioctl(sock
, SIOCSCTPGOPT
, &opt
) == -1) {
147 /* Calculate the number of addresses returned. */
148 switch (((struct sockaddr
*)*addrs
)->sa_family
) {
150 naddrs
= opt
.sopt_len
/ sizeof (struct sockaddr_in
);
153 naddrs
= opt
.sopt_len
/ sizeof (struct sockaddr_in6
);
160 sctp_freepaddrs(void *addrs
)
166 sctp_getladdrs(int sock
, sctp_assoc_t id
, void **addrs
)
177 /* First, try to find out how many bound addresses there are. */
181 opt
.sopt_name
= SCTP_GET_NLADDRS
;
182 opt
.sopt_val
= (caddr_t
)&naddrs
;
183 opt
.sopt_len
= sizeof (naddrs
);
184 if (ioctl(sock
, SIOCSCTPGOPT
, &opt
) == -1) {
191 * Now we can get all the bound addresses. This will over allocate
192 * space for v4 socket. But it should be OK and save us
193 * the job to find out if it is a v4 or v6 socket.
195 bufsz
= sizeof (union sockaddr_storage_v6
) * naddrs
;
196 if ((*addrs
= malloc(bufsz
)) == NULL
) {
199 opt
.sopt_name
= SCTP_GET_LADDRS
;
200 opt
.sopt_val
= *addrs
;
201 opt
.sopt_len
= bufsz
;
202 if (ioctl(sock
, SIOCSCTPGOPT
, &opt
) == -1) {
208 /* Calculate the number of addresses returned. */
209 switch (((struct sockaddr
*)*addrs
)->sa_family
) {
211 naddrs
= opt
.sopt_len
/ sizeof (struct sockaddr_in
);
214 naddrs
= opt
.sopt_len
/ sizeof (struct sockaddr_in6
);
221 sctp_freeladdrs(void *addrs
)
227 sctp_opt_info(int sock
, sctp_assoc_t id
, int opt
, void *arg
, socklen_t
*len
)
232 sopt
.sopt_name
= opt
;
234 sopt
.sopt_len
= *len
;
236 if (ioctl(sock
, SIOCSCTPGOPT
, &sopt
) == -1) {
239 *len
= sopt
.sopt_len
;
244 * Branch off an association to its own socket. ioctl() allocates and
248 sctp_peeloff(int sock
, sctp_assoc_t id
)
253 if (ioctl(sock
, SIOCSCTPPEELOFF
, &fd
) == -1) {
261 sctp_recvmsg(int s
, void *msg
, size_t len
, struct sockaddr
*from
,
262 socklen_t
*fromlen
, struct sctp_sndrcvinfo
*sinfo
, int *msg_flags
)
266 struct cmsghdr
*cmsg
;
267 char cinmsg
[sizeof (*sinfo
) + sizeof (*cmsg
) + _CMSG_HDR_ALIGNMENT
];
271 hdr
.msg_namelen
= (fromlen
!= NULL
) ? *fromlen
: 0;
275 hdr
.msg_control
= (void *)_CMSG_HDR_ALIGN(cinmsg
);
276 hdr
.msg_controllen
= sizeof (cinmsg
) -
277 (_CMSG_HDR_ALIGN(cinmsg
) - (uintptr_t)cinmsg
);
279 hdr
.msg_control
= NULL
;
280 hdr
.msg_controllen
= 0;
285 err
= recvmsg(s
, &hdr
, msg_flags
== NULL
? 0 : *msg_flags
);
289 if (fromlen
!= NULL
) {
290 *fromlen
= hdr
.msg_namelen
;
292 if (msg_flags
!= NULL
) {
293 *msg_flags
= hdr
.msg_flags
;
296 for (cmsg
= CMSG_FIRSTHDR(&hdr
); cmsg
!= NULL
;
297 cmsg
= CMSG_NXTHDR(&hdr
, cmsg
)) {
298 if (cmsg
->cmsg_level
== IPPROTO_SCTP
&&
299 cmsg
->cmsg_type
== SCTP_SNDRCV
) {
300 bcopy(CMSG_DATA(cmsg
), sinfo
, sizeof (*sinfo
));
309 sctp_send_common(int s
, const void *msg
, size_t len
, const struct sockaddr
*to
,
310 socklen_t tolen
, uint32_t ppid
, uint32_t sinfo_flags
, uint16_t stream_no
,
311 uint32_t timetolive
, uint32_t context
, sctp_assoc_t aid
, int flags
)
315 struct sctp_sndrcvinfo
*sinfo
;
316 struct cmsghdr
*cmsg
;
317 char coutmsg
[sizeof (*sinfo
) + sizeof (*cmsg
) + _CMSG_HDR_ALIGNMENT
];
319 hdr
.msg_name
= (caddr_t
)to
;
320 hdr
.msg_namelen
= tolen
;
323 hdr
.msg_control
= (void *)_CMSG_HDR_ALIGN(coutmsg
);
324 hdr
.msg_controllen
= sizeof (*cmsg
) + sizeof (*sinfo
);
327 iov
.iov_base
= (caddr_t
)msg
;
329 cmsg
= CMSG_FIRSTHDR(&hdr
);
330 cmsg
->cmsg_level
= IPPROTO_SCTP
;
331 cmsg
->cmsg_type
= SCTP_SNDRCV
;
332 cmsg
->cmsg_len
= sizeof (*cmsg
) + sizeof (*sinfo
);
334 sinfo
= (struct sctp_sndrcvinfo
*)CMSG_DATA(cmsg
);
335 sinfo
->sinfo_stream
= stream_no
;
336 sinfo
->sinfo_ssn
= 0;
337 sinfo
->sinfo_flags
= sinfo_flags
;
338 sinfo
->sinfo_ppid
= ppid
;
339 sinfo
->sinfo_context
= context
;
340 sinfo
->sinfo_timetolive
= timetolive
;
341 sinfo
->sinfo_tsn
= 0;
342 sinfo
->sinfo_cumtsn
= 0;
343 sinfo
->sinfo_assoc_id
= aid
;
345 return (sendmsg(s
, &hdr
, flags
));
349 sctp_send(int s
, const void *msg
, size_t len
,
350 const struct sctp_sndrcvinfo
*sinfo
, int flags
)
352 /* Note that msg can be NULL for pure control message. */
357 return (sctp_send_common(s
, msg
, len
, NULL
, 0, sinfo
->sinfo_ppid
,
358 sinfo
->sinfo_flags
, sinfo
->sinfo_stream
, sinfo
->sinfo_timetolive
,
359 sinfo
->sinfo_context
, sinfo
->sinfo_assoc_id
, flags
));
363 sctp_sendmsg(int s
, const void *msg
, size_t len
, const struct sockaddr
*to
,
364 socklen_t tolen
, uint32_t ppid
, uint32_t flags
, uint16_t stream_no
,
365 uint32_t timetolive
, uint32_t context
)
367 return (sctp_send_common(s
, msg
, len
, to
, tolen
, ppid
, flags
,
368 stream_no
, timetolive
, context
, 0, 0));