2 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
3 * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
4 * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * a) Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
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.
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.
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.
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <sys/errno.h>
44 #include <sys/syscall.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <netinet/sctp_uio.h>
49 #include <netinet/sctp.h>
51 #ifndef IN6_IS_ADDR_V4MAPPED
52 #define IN6_IS_ADDR_V4MAPPED(a) \
53 ((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
54 (*(const uint32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
55 (*(const uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff)))
58 #define SCTP_CONTROL_VEC_SIZE_RCV 16384
62 in6_sin6_2_sin(struct sockaddr_in
*sin
, struct sockaddr_in6
*sin6
)
64 bzero(sin
, sizeof(*sin
));
65 sin
->sin_len
= sizeof(struct sockaddr_in
);
66 sin
->sin_family
= AF_INET
;
67 sin
->sin_port
= sin6
->sin6_port
;
68 sin
->sin_addr
.s_addr
= sin6
->sin6_addr
.__u6_addr
.__u6_addr32
[3];
72 sctp_getaddrlen(sa_family_t family
)
76 struct sctp_assoc_value av
;
78 av
.assoc_value
= family
;
81 sd
= socket(AF_INET
, SOCK_SEQPACKET
, IPPROTO_SCTP
);
82 #elif defined(AF_INET6)
83 sd
= socket(AF_INET6
, SOCK_SEQPACKET
, IPPROTO_SCTP
);
90 ret
= getsockopt(sd
, IPPROTO_SCTP
, SCTP_GET_ADDR_LEN
, &av
, &siz
);
93 return ((int)av
.assoc_value
);
100 sctp_connectx(int sd
, const struct sockaddr
*addrs
, int addrcnt
,
106 const struct sockaddr
*at
;
109 /* validate the address count and list */
110 if ((addrs
== NULL
) || (addrcnt
<= 0)) {
114 if ((buf
= malloc(sizeof(int) + (size_t)addrcnt
* sizeof(struct sockaddr_in6
))) == NULL
) {
120 cpto
= buf
+ sizeof(int);
121 /* validate all the addresses and get the size */
122 for (i
= 0; i
< addrcnt
; i
++) {
123 switch (at
->sa_family
) {
125 if (at
->sa_len
!= sizeof(struct sockaddr_in
)) {
130 memcpy(cpto
, at
, sizeof(struct sockaddr_in
));
131 cpto
= ((caddr_t
)cpto
+ sizeof(struct sockaddr_in
));
132 len
+= sizeof(struct sockaddr_in
);
135 if (at
->sa_len
!= sizeof(struct sockaddr_in6
)) {
140 if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6
*)at
)->sin6_addr
)) {
141 in6_sin6_2_sin((struct sockaddr_in
*)cpto
, (struct sockaddr_in6
*)at
);
142 cpto
= ((caddr_t
)cpto
+ sizeof(struct sockaddr_in
));
143 len
+= sizeof(struct sockaddr_in
);
145 memcpy(cpto
, at
, sizeof(struct sockaddr_in6
));
146 cpto
= ((caddr_t
)cpto
+ sizeof(struct sockaddr_in6
));
147 len
+= sizeof(struct sockaddr_in6
);
155 at
= (struct sockaddr
*)((caddr_t
)at
+ at
->sa_len
);
159 ret
= setsockopt(sd
, IPPROTO_SCTP
, SCTP_CONNECT_X
, (void *)buf
,
161 if ((ret
== 0) && (id
!= NULL
)) {
162 *id
= *(sctp_assoc_t
*) buf
;
169 sctp_bindx(int sd
, struct sockaddr
*addrs
, int addrcnt
, int flags
)
171 struct sctp_getaddresses
*gaddrs
;
173 struct sockaddr_in
*sin
;
174 struct sockaddr_in6
*sin6
;
179 /* validate the flags */
180 if ((flags
!= SCTP_BINDX_ADD_ADDR
) &&
181 (flags
!= SCTP_BINDX_REM_ADDR
)) {
185 /* validate the address count and list */
186 if ((addrcnt
<= 0) || (addrs
== NULL
)) {
190 /* First pre-screen the addresses */
192 for (i
= 0; i
< addrcnt
; i
++) {
193 switch (sa
->sa_family
) {
195 if (sa
->sa_len
!= sizeof(struct sockaddr_in
)) {
199 sin
= (struct sockaddr_in
*)sa
;
201 /* non-zero port, check or save */
203 /* Check against our port */
204 if (sport
!= sin
->sin_port
) {
209 /* save off the port */
210 sport
= sin
->sin_port
;
215 if (sa
->sa_len
!= sizeof(struct sockaddr_in6
)) {
219 sin6
= (struct sockaddr_in6
*)sa
;
220 if (sin6
->sin6_port
) {
221 /* non-zero port, check or save */
223 /* Check against our port */
224 if (sport
!= sin6
->sin6_port
) {
229 /* save off the port */
230 sport
= sin6
->sin6_port
;
235 /* Invalid address family specified. */
236 errno
= EAFNOSUPPORT
;
239 sa
= (struct sockaddr
*)((caddr_t
)sa
+ sa
->sa_len
);
241 argsz
= sizeof(struct sctp_getaddresses
) +
242 sizeof(struct sockaddr_storage
);
243 if ((gaddrs
= (struct sctp_getaddresses
*)malloc(argsz
)) == NULL
) {
248 for (i
= 0; i
< addrcnt
; i
++) {
249 memset(gaddrs
, 0, argsz
);
250 gaddrs
->sget_assoc_id
= 0;
251 memcpy(gaddrs
->addr
, sa
, sa
->sa_len
);
253 * Now, if there was a port mentioned, assure that the first
254 * address has that port to make sure it fails or succeeds
257 if ((i
== 0) && (sport
!= 0)) {
258 switch (gaddrs
->addr
->sa_family
) {
260 sin
= (struct sockaddr_in
*)gaddrs
->addr
;
261 sin
->sin_port
= sport
;
264 sin6
= (struct sockaddr_in6
*)gaddrs
->addr
;
265 sin6
->sin6_port
= sport
;
269 if (setsockopt(sd
, IPPROTO_SCTP
, flags
, gaddrs
,
270 (socklen_t
) argsz
) != 0) {
274 sa
= (struct sockaddr
*)((caddr_t
)sa
+ sa
->sa_len
);
281 sctp_opt_info(int sd
, sctp_assoc_t id
, int opt
, void *arg
, socklen_t
* size
)
287 if ((id
== SCTP_CURRENT_ASSOC
) ||
288 (id
== SCTP_ALL_ASSOC
)) {
294 ((struct sctp_rtoinfo
*)arg
)->srto_assoc_id
= id
;
297 ((struct sctp_assocparams
*)arg
)->sasoc_assoc_id
= id
;
299 case SCTP_DEFAULT_SEND_PARAM
:
300 ((struct sctp_assocparams
*)arg
)->sasoc_assoc_id
= id
;
302 case SCTP_PRIMARY_ADDR
:
303 ((struct sctp_setprim
*)arg
)->ssp_assoc_id
= id
;
305 case SCTP_PEER_ADDR_PARAMS
:
306 ((struct sctp_paddrparams
*)arg
)->spp_assoc_id
= id
;
309 ((struct sctp_assoc_value
*)arg
)->assoc_id
= id
;
312 ((struct sctp_authkey
*)arg
)->sca_assoc_id
= id
;
314 case SCTP_AUTH_ACTIVE_KEY
:
315 ((struct sctp_authkeyid
*)arg
)->scact_assoc_id
= id
;
317 case SCTP_DELAYED_SACK
:
318 ((struct sctp_sack_info
*)arg
)->sack_assoc_id
= id
;
321 ((struct sctp_assoc_value
*)arg
)->assoc_id
= id
;
324 ((struct sctp_status
*)arg
)->sstat_assoc_id
= id
;
326 case SCTP_GET_PEER_ADDR_INFO
:
327 ((struct sctp_paddrinfo
*)arg
)->spinfo_assoc_id
= id
;
329 case SCTP_PEER_AUTH_CHUNKS
:
330 ((struct sctp_authchunks
*)arg
)->gauth_assoc_id
= id
;
332 case SCTP_LOCAL_AUTH_CHUNKS
:
333 ((struct sctp_authchunks
*)arg
)->gauth_assoc_id
= id
;
336 ((struct sctp_timeouts
*)arg
)->stimo_assoc_id
= id
;
339 ((struct sctp_event
*)arg
)->se_assoc_id
= id
;
341 case SCTP_DEFAULT_SNDINFO
:
342 ((struct sctp_sndinfo
*)arg
)->snd_assoc_id
= id
;
344 case SCTP_DEFAULT_PRINFO
:
345 ((struct sctp_default_prinfo
*)arg
)->pr_assoc_id
= id
;
347 case SCTP_PEER_ADDR_THLDS
:
348 ((struct sctp_paddrthlds
*)arg
)->spt_assoc_id
= id
;
350 case SCTP_REMOTE_UDP_ENCAPS_PORT
:
351 ((struct sctp_udpencaps
*)arg
)->sue_assoc_id
= id
;
353 case SCTP_ECN_SUPPORTED
:
354 ((struct sctp_assoc_value
*)arg
)->assoc_id
= id
;
356 case SCTP_PR_SUPPORTED
:
357 ((struct sctp_assoc_value
*)arg
)->assoc_id
= id
;
359 case SCTP_AUTH_SUPPORTED
:
360 ((struct sctp_assoc_value
*)arg
)->assoc_id
= id
;
362 case SCTP_ASCONF_SUPPORTED
:
363 ((struct sctp_assoc_value
*)arg
)->assoc_id
= id
;
365 case SCTP_RECONFIG_SUPPORTED
:
366 ((struct sctp_assoc_value
*)arg
)->assoc_id
= id
;
368 case SCTP_NRSACK_SUPPORTED
:
369 ((struct sctp_assoc_value
*)arg
)->assoc_id
= id
;
371 case SCTP_PKTDROP_SUPPORTED
:
372 ((struct sctp_assoc_value
*)arg
)->assoc_id
= id
;
375 ((struct sctp_assoc_value
*)arg
)->assoc_id
= id
;
377 case SCTP_ENABLE_STREAM_RESET
:
378 ((struct sctp_assoc_value
*)arg
)->assoc_id
= id
;
380 case SCTP_PR_STREAM_STATUS
:
381 ((struct sctp_prstatus
*)arg
)->sprstat_assoc_id
= id
;
383 case SCTP_PR_ASSOC_STATUS
:
384 ((struct sctp_prstatus
*)arg
)->sprstat_assoc_id
= id
;
387 ((struct sctp_assoc_value
*)arg
)->assoc_id
= id
;
392 return (getsockopt(sd
, IPPROTO_SCTP
, opt
, arg
, size
));
396 sctp_getpaddrs(int sd
, sctp_assoc_t id
, struct sockaddr
**raddrs
)
398 struct sctp_getaddresses
*addrs
;
405 if (raddrs
== NULL
) {
410 opt_len
= (socklen_t
) sizeof(sctp_assoc_t
);
411 if (getsockopt(sd
, IPPROTO_SCTP
, SCTP_GET_REMOTE_ADDR_SIZE
,
412 &asoc
, &opt_len
) != 0) {
415 /* size required is returned in 'asoc' */
416 opt_len
= (socklen_t
) ((size_t)asoc
+ sizeof(struct sctp_getaddresses
));
417 addrs
= calloc(1, (size_t)opt_len
);
422 addrs
->sget_assoc_id
= id
;
423 /* Now lets get the array of addresses */
424 if (getsockopt(sd
, IPPROTO_SCTP
, SCTP_GET_PEER_ADDRESSES
,
425 addrs
, &opt_len
) != 0) {
429 *raddrs
= (struct sockaddr
*)&addrs
->addr
[0];
431 sa
= (struct sockaddr
*)&addrs
->addr
[0];
432 lim
= (caddr_t
)addrs
+ opt_len
;
433 while (((caddr_t
)sa
< lim
) && (sa
->sa_len
> 0)) {
434 sa
= (struct sockaddr
*)((caddr_t
)sa
+ sa
->sa_len
);
441 sctp_freepaddrs(struct sockaddr
*addrs
)
445 /* Take away the hidden association id */
446 fr_addr
= (void *)((caddr_t
)addrs
- sizeof(sctp_assoc_t
));
452 sctp_getladdrs(int sd
, sctp_assoc_t id
, struct sockaddr
**raddrs
)
454 struct sctp_getaddresses
*addrs
;
457 size_t size_of_addresses
;
461 if (raddrs
== NULL
) {
465 size_of_addresses
= 0;
466 opt_len
= (socklen_t
) sizeof(int);
467 if (getsockopt(sd
, IPPROTO_SCTP
, SCTP_GET_LOCAL_ADDR_SIZE
,
468 &size_of_addresses
, &opt_len
) != 0) {
472 if (size_of_addresses
== 0) {
476 opt_len
= (socklen_t
) (size_of_addresses
+
477 sizeof(struct sockaddr_storage
) +
478 sizeof(struct sctp_getaddresses
));
479 addrs
= calloc(1, (size_t)opt_len
);
484 addrs
->sget_assoc_id
= id
;
485 /* Now lets get the array of addresses */
486 if (getsockopt(sd
, IPPROTO_SCTP
, SCTP_GET_LOCAL_ADDRESSES
, addrs
,
492 *raddrs
= (struct sockaddr
*)&addrs
->addr
[0];
494 sa
= (struct sockaddr
*)&addrs
->addr
[0];
495 lim
= (caddr_t
)addrs
+ opt_len
;
496 while (((caddr_t
)sa
< lim
) && (sa
->sa_len
> 0)) {
497 sa
= (struct sockaddr
*)((caddr_t
)sa
+ sa
->sa_len
);
504 sctp_freeladdrs(struct sockaddr
*addrs
)
508 /* Take away the hidden association id */
509 fr_addr
= (void *)((caddr_t
)addrs
- sizeof(sctp_assoc_t
));
518 const struct sockaddr
*to
,
526 #ifdef SYS_sctp_generic_sendmsg
527 struct sctp_sndrcvinfo sinfo
;
529 memset(&sinfo
, 0, sizeof(struct sctp_sndrcvinfo
));
530 sinfo
.sinfo_ppid
= ppid
;
531 sinfo
.sinfo_flags
= flags
;
532 sinfo
.sinfo_stream
= stream_no
;
533 sinfo
.sinfo_timetolive
= timetolive
;
534 sinfo
.sinfo_context
= context
;
535 sinfo
.sinfo_assoc_id
= 0;
536 return (syscall(SYS_sctp_generic_sendmsg
, s
,
537 data
, len
, to
, tolen
, &sinfo
, 0));
540 struct sctp_sndrcvinfo
*sinfo
;
542 char cmsgbuf
[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo
))];
543 struct cmsghdr
*cmsg
;
544 struct sockaddr
*who
= NULL
;
546 struct sockaddr_in in
;
547 struct sockaddr_in6 in6
;
551 ((to
== NULL
) || (tolen
< sizeof(struct sockaddr
)))) {
555 if ((to
!= NULL
) && (tolen
> 0)) {
556 switch (to
->sa_family
) {
558 if (tolen
!= sizeof(struct sockaddr_in
)) {
562 if ((to
->sa_len
> 0) &&
563 (to
->sa_len
!= sizeof(struct sockaddr_in
))) {
567 memcpy(&addr
, to
, sizeof(struct sockaddr_in
));
568 addr
.in
.sin_len
= sizeof(struct sockaddr_in
);
571 if (tolen
!= sizeof(struct sockaddr_in6
)) {
575 if ((to
->sa_len
> 0) &&
576 (to
->sa_len
!= sizeof(struct sockaddr_in6
))) {
580 memcpy(&addr
, to
, sizeof(struct sockaddr_in6
));
581 addr
.in6
.sin6_len
= sizeof(struct sockaddr_in6
);
584 errno
= EAFNOSUPPORT
;
587 who
= (struct sockaddr
*)&addr
;
589 iov
.iov_base
= (char *)data
;
593 msg
.msg_name
= (caddr_t
)who
;
594 msg
.msg_namelen
= who
->sa_len
;
596 msg
.msg_name
= (caddr_t
)NULL
;
601 msg
.msg_control
= cmsgbuf
;
602 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct sctp_sndrcvinfo
));
604 cmsg
= (struct cmsghdr
*)cmsgbuf
;
605 cmsg
->cmsg_level
= IPPROTO_SCTP
;
606 cmsg
->cmsg_type
= SCTP_SNDRCV
;
607 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct sctp_sndrcvinfo
));
608 sinfo
= (struct sctp_sndrcvinfo
*)CMSG_DATA(cmsg
);
609 memset(sinfo
, 0, sizeof(struct sctp_sndrcvinfo
));
610 sinfo
->sinfo_stream
= stream_no
;
611 sinfo
->sinfo_ssn
= 0;
612 sinfo
->sinfo_flags
= flags
;
613 sinfo
->sinfo_ppid
= ppid
;
614 sinfo
->sinfo_context
= context
;
615 sinfo
->sinfo_assoc_id
= 0;
616 sinfo
->sinfo_timetolive
= timetolive
;
617 return (sendmsg(s
, &msg
, 0));
623 sctp_getassocid(int sd
, struct sockaddr
*sa
)
625 struct sctp_paddrinfo sp
;
628 /* First get the assoc id */
630 memset(&sp
, 0, sizeof(sp
));
631 memcpy((caddr_t
)&sp
.spinfo_address
, sa
, sa
->sa_len
);
632 if (getsockopt(sd
, IPPROTO_SCTP
,
633 SCTP_GET_PEER_ADDR_INFO
, &sp
, &siz
) != 0) {
634 /* We depend on the fact that 0 can never be returned */
635 return ((sctp_assoc_t
) 0);
637 return (sp
.spinfo_assoc_id
);
641 sctp_send(int sd
, const void *data
, size_t len
,
642 const struct sctp_sndrcvinfo
*sinfo
,
646 #ifdef SYS_sctp_generic_sendmsg
647 struct sockaddr
*to
= NULL
;
649 return (syscall(SYS_sctp_generic_sendmsg
, sd
,
650 data
, len
, to
, 0, sinfo
, flags
));
654 char cmsgbuf
[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo
))];
655 struct cmsghdr
*cmsg
;
661 iov
.iov_base
= (char *)data
;
668 msg
.msg_control
= cmsgbuf
;
669 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct sctp_sndrcvinfo
));
671 cmsg
= (struct cmsghdr
*)cmsgbuf
;
672 cmsg
->cmsg_level
= IPPROTO_SCTP
;
673 cmsg
->cmsg_type
= SCTP_SNDRCV
;
674 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct sctp_sndrcvinfo
));
675 memcpy(CMSG_DATA(cmsg
), sinfo
, sizeof(struct sctp_sndrcvinfo
));
676 return (sendmsg(sd
, &msg
, flags
));
683 sctp_sendx(int sd
, const void *msg
, size_t msg_len
,
684 struct sockaddr
*addrs
, int addrcnt
,
685 struct sctp_sndrcvinfo
*sinfo
,
688 struct sctp_sndrcvinfo __sinfo
;
690 int i
, cnt
, *aa
, saved_errno
;
700 #ifdef SYS_sctp_generic_sendmsg
706 * Quick way, we don't need to do a connectx so lets use the
710 ret
= syscall(SYS_sctp_generic_sendmsg
, sd
,
711 msg
, msg_len
, addrs
, l
, sinfo
, flags
);
712 if ((ret
>= 0) && (sinfo
!= NULL
)) {
713 sinfo
->sinfo_assoc_id
= sctp_getassocid(sd
, addrs
);
722 /* validate all the addresses and get the size */
723 for (i
= 0; i
< addrcnt
; i
++) {
724 if (at
->sa_family
== AF_INET
) {
725 add_len
= sizeof(struct sockaddr_in
);
726 } else if (at
->sa_family
== AF_INET6
) {
727 add_len
= sizeof(struct sockaddr_in6
);
733 at
= (struct sockaddr
*)((caddr_t
)at
+ add_len
);
736 /* do we have any? */
749 memcpy((caddr_t
)aa
, addrs
, (size_t)(len
- sizeof(int)));
750 ret
= setsockopt(sd
, IPPROTO_SCTP
, SCTP_CONNECT_X_DELAYED
, (void *)buf
,
755 if (errno
== EALREADY
) {
764 memset(&__sinfo
, 0, sizeof(__sinfo
));
766 sinfo
->sinfo_assoc_id
= sctp_getassocid(sd
, addrs
);
767 if (sinfo
->sinfo_assoc_id
== 0) {
768 (void)setsockopt(sd
, IPPROTO_SCTP
, SCTP_CONNECT_X_COMPLETE
, (void *)addrs
,
769 (socklen_t
) addrs
->sa_len
);
773 ret
= sctp_send(sd
, msg
, msg_len
, sinfo
, flags
);
776 (void)setsockopt(sd
, IPPROTO_SCTP
, SCTP_CONNECT_X_COMPLETE
, (void *)addrs
,
777 (socklen_t
) addrs
->sa_len
);
784 sctp_sendmsgx(int sd
,
787 struct sockaddr
*addrs
,
795 struct sctp_sndrcvinfo sinfo
;
797 memset((void *)&sinfo
, 0, sizeof(struct sctp_sndrcvinfo
));
798 sinfo
.sinfo_ppid
= ppid
;
799 sinfo
.sinfo_flags
= flags
;
800 sinfo
.sinfo_ssn
= stream_no
;
801 sinfo
.sinfo_timetolive
= timetolive
;
802 sinfo
.sinfo_context
= context
;
803 return (sctp_sendx(sd
, msg
, len
, addrs
, addrcnt
, &sinfo
, 0));
810 struct sockaddr
*from
,
812 struct sctp_sndrcvinfo
*sinfo
,
815 #ifdef SYS_sctp_generic_recvmsg
820 return (syscall(SYS_sctp_generic_recvmsg
, s
,
821 &iov
, 1, from
, fromlen
, sinfo
, msg_flags
));
826 char cmsgbuf
[SCTP_CONTROL_VEC_SIZE_RCV
];
827 struct cmsghdr
*cmsg
;
829 if (msg_flags
== NULL
) {
835 msg
.msg_name
= (caddr_t
)from
;
839 msg
.msg_namelen
= *fromlen
;
842 msg
.msg_control
= cmsgbuf
;
843 msg
.msg_controllen
= sizeof(cmsgbuf
);
845 sz
= recvmsg(s
, &msg
, *msg_flags
);
846 *msg_flags
= msg
.msg_flags
;
851 sinfo
->sinfo_assoc_id
= 0;
853 if ((msg
.msg_controllen
> 0) && (sinfo
!= NULL
)) {
855 * parse through and see if we find the sctp_sndrcvinfo (if
856 * the user wants it).
858 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
; cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
859 if (cmsg
->cmsg_level
!= IPPROTO_SCTP
) {
862 if (cmsg
->cmsg_type
== SCTP_SNDRCV
) {
863 memcpy(sinfo
, CMSG_DATA(cmsg
), sizeof(struct sctp_sndrcvinfo
));
866 if (cmsg
->cmsg_type
== SCTP_EXTRCV
) {
868 * Let's hope that the user provided enough
869 * enough memory. At least he asked for more
872 memcpy(sinfo
, CMSG_DATA(cmsg
), sizeof(struct sctp_extrcvinfo
));
883 const struct iovec
*iov
,
885 struct sockaddr
*from
,
889 unsigned int *infotype
,
892 char cmsgbuf
[SCTP_CONTROL_VEC_SIZE_RCV
];
894 struct cmsghdr
*cmsg
;
896 struct sctp_rcvinfo
*rcvinfo
;
897 struct sctp_nxtinfo
*nxtinfo
;
899 if (((info
!= NULL
) && (infolen
== NULL
)) ||
900 ((info
== NULL
) && (infolen
!= NULL
) && (*infolen
!= 0)) ||
901 ((info
!= NULL
) && (infotype
== NULL
))) {
906 *infotype
= SCTP_RECVV_NOINFO
;
909 if (fromlen
== NULL
) {
912 msg
.msg_namelen
= *fromlen
;
914 msg
.msg_iov
= (struct iovec
*)iov
;
915 msg
.msg_iovlen
= iovlen
;
916 msg
.msg_control
= cmsgbuf
;
917 msg
.msg_controllen
= sizeof(cmsgbuf
);
919 ret
= recvmsg(sd
, &msg
, *flags
);
920 *flags
= msg
.msg_flags
;
922 (msg
.msg_controllen
> 0) &&
923 (infotype
!= NULL
) &&
928 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
; cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
929 if (cmsg
->cmsg_level
!= IPPROTO_SCTP
) {
932 if (cmsg
->cmsg_type
== SCTP_RCVINFO
) {
933 rcvinfo
= (struct sctp_rcvinfo
*)CMSG_DATA(cmsg
);
934 if (nxtinfo
!= NULL
) {
940 if (cmsg
->cmsg_type
== SCTP_NXTINFO
) {
941 nxtinfo
= (struct sctp_nxtinfo
*)CMSG_DATA(cmsg
);
942 if (rcvinfo
!= NULL
) {
949 if (rcvinfo
!= NULL
) {
950 if ((nxtinfo
!= NULL
) && (*infolen
>= sizeof(struct sctp_recvv_rn
))) {
951 struct sctp_recvv_rn
*rn_info
;
953 rn_info
= (struct sctp_recvv_rn
*)info
;
954 rn_info
->recvv_rcvinfo
= *rcvinfo
;
955 rn_info
->recvv_nxtinfo
= *nxtinfo
;
956 *infolen
= (socklen_t
) sizeof(struct sctp_recvv_rn
);
957 *infotype
= SCTP_RECVV_RN
;
958 } else if (*infolen
>= sizeof(struct sctp_rcvinfo
)) {
959 memcpy(info
, rcvinfo
, sizeof(struct sctp_rcvinfo
));
960 *infolen
= (socklen_t
) sizeof(struct sctp_rcvinfo
);
961 *infotype
= SCTP_RECVV_RCVINFO
;
963 } else if (nxtinfo
!= NULL
) {
964 if (*infolen
>= sizeof(struct sctp_nxtinfo
)) {
965 memcpy(info
, nxtinfo
, sizeof(struct sctp_nxtinfo
));
966 *infolen
= (socklen_t
) sizeof(struct sctp_nxtinfo
);
967 *infotype
= SCTP_RECVV_NXTINFO
;
976 const struct iovec
*iov
, int iovcnt
,
977 struct sockaddr
*addrs
, int addrcnt
,
978 void *info
, socklen_t infolen
, unsigned int infotype
,
986 struct sctp_sendv_spa
*spa_info
;
987 struct cmsghdr
*cmsg
;
989 struct sockaddr
*addr
;
990 struct sockaddr_in
*addr_in
;
991 struct sockaddr_in6
*addr_in6
;
992 sctp_assoc_t
*assoc_id
;
996 ((addrs
== NULL
) && (addrcnt
> 0)) ||
997 ((addrs
!= NULL
) && (addrcnt
== 0)) ||
998 ((iov
== NULL
) && (iovcnt
> 0)) ||
999 ((iov
!= NULL
) && (iovcnt
== 0))) {
1003 cmsgbuf
= malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo
)) +
1004 CMSG_SPACE(sizeof(struct sctp_prinfo
)) +
1005 CMSG_SPACE(sizeof(struct sctp_authinfo
)) +
1006 (size_t)addrcnt
* CMSG_SPACE(sizeof(struct in6_addr
)));
1007 if (cmsgbuf
== NULL
) {
1012 msg
.msg_control
= cmsgbuf
;
1013 msg
.msg_controllen
= 0;
1014 cmsg
= (struct cmsghdr
*)cmsgbuf
;
1016 case SCTP_SENDV_NOINFO
:
1017 if ((infolen
!= 0) || (info
!= NULL
)) {
1023 case SCTP_SENDV_SNDINFO
:
1024 if ((info
== NULL
) || (infolen
< sizeof(struct sctp_sndinfo
))) {
1029 cmsg
->cmsg_level
= IPPROTO_SCTP
;
1030 cmsg
->cmsg_type
= SCTP_SNDINFO
;
1031 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct sctp_sndinfo
));
1032 memcpy(CMSG_DATA(cmsg
), info
, sizeof(struct sctp_sndinfo
));
1033 msg
.msg_controllen
+= CMSG_SPACE(sizeof(struct sctp_sndinfo
));
1034 cmsg
= (struct cmsghdr
*)((caddr_t
)cmsg
+ CMSG_SPACE(sizeof(struct sctp_sndinfo
)));
1035 assoc_id
= &(((struct sctp_sndinfo
*)info
)->snd_assoc_id
);
1037 case SCTP_SENDV_PRINFO
:
1038 if ((info
== NULL
) || (infolen
< sizeof(struct sctp_prinfo
))) {
1043 cmsg
->cmsg_level
= IPPROTO_SCTP
;
1044 cmsg
->cmsg_type
= SCTP_PRINFO
;
1045 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct sctp_prinfo
));
1046 memcpy(CMSG_DATA(cmsg
), info
, sizeof(struct sctp_prinfo
));
1047 msg
.msg_controllen
+= CMSG_SPACE(sizeof(struct sctp_prinfo
));
1048 cmsg
= (struct cmsghdr
*)((caddr_t
)cmsg
+ CMSG_SPACE(sizeof(struct sctp_prinfo
)));
1050 case SCTP_SENDV_AUTHINFO
:
1051 if ((info
== NULL
) || (infolen
< sizeof(struct sctp_authinfo
))) {
1056 cmsg
->cmsg_level
= IPPROTO_SCTP
;
1057 cmsg
->cmsg_type
= SCTP_AUTHINFO
;
1058 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct sctp_authinfo
));
1059 memcpy(CMSG_DATA(cmsg
), info
, sizeof(struct sctp_authinfo
));
1060 msg
.msg_controllen
+= CMSG_SPACE(sizeof(struct sctp_authinfo
));
1061 cmsg
= (struct cmsghdr
*)((caddr_t
)cmsg
+ CMSG_SPACE(sizeof(struct sctp_authinfo
)));
1063 case SCTP_SENDV_SPA
:
1064 if ((info
== NULL
) || (infolen
< sizeof(struct sctp_sendv_spa
))) {
1069 spa_info
= (struct sctp_sendv_spa
*)info
;
1070 if (spa_info
->sendv_flags
& SCTP_SEND_SNDINFO_VALID
) {
1071 cmsg
->cmsg_level
= IPPROTO_SCTP
;
1072 cmsg
->cmsg_type
= SCTP_SNDINFO
;
1073 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct sctp_sndinfo
));
1074 memcpy(CMSG_DATA(cmsg
), &spa_info
->sendv_sndinfo
, sizeof(struct sctp_sndinfo
));
1075 msg
.msg_controllen
+= CMSG_SPACE(sizeof(struct sctp_sndinfo
));
1076 cmsg
= (struct cmsghdr
*)((caddr_t
)cmsg
+ CMSG_SPACE(sizeof(struct sctp_sndinfo
)));
1077 assoc_id
= &(spa_info
->sendv_sndinfo
.snd_assoc_id
);
1079 if (spa_info
->sendv_flags
& SCTP_SEND_PRINFO_VALID
) {
1080 cmsg
->cmsg_level
= IPPROTO_SCTP
;
1081 cmsg
->cmsg_type
= SCTP_PRINFO
;
1082 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct sctp_prinfo
));
1083 memcpy(CMSG_DATA(cmsg
), &spa_info
->sendv_prinfo
, sizeof(struct sctp_prinfo
));
1084 msg
.msg_controllen
+= CMSG_SPACE(sizeof(struct sctp_prinfo
));
1085 cmsg
= (struct cmsghdr
*)((caddr_t
)cmsg
+ CMSG_SPACE(sizeof(struct sctp_prinfo
)));
1087 if (spa_info
->sendv_flags
& SCTP_SEND_AUTHINFO_VALID
) {
1088 cmsg
->cmsg_level
= IPPROTO_SCTP
;
1089 cmsg
->cmsg_type
= SCTP_AUTHINFO
;
1090 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct sctp_authinfo
));
1091 memcpy(CMSG_DATA(cmsg
), &spa_info
->sendv_authinfo
, sizeof(struct sctp_authinfo
));
1092 msg
.msg_controllen
+= CMSG_SPACE(sizeof(struct sctp_authinfo
));
1093 cmsg
= (struct cmsghdr
*)((caddr_t
)cmsg
+ CMSG_SPACE(sizeof(struct sctp_authinfo
)));
1102 msg
.msg_name
= NULL
;
1103 msg
.msg_namelen
= 0;
1105 for (i
= 0; i
< addrcnt
; i
++) {
1106 switch (addr
->sa_family
) {
1108 addr_len
= (socklen_t
) sizeof(struct sockaddr_in
);
1109 addr_in
= (struct sockaddr_in
*)addr
;
1110 if (addr_in
->sin_len
!= addr_len
) {
1116 port
= addr_in
->sin_port
;
1118 if (port
== addr_in
->sin_port
) {
1119 cmsg
->cmsg_level
= IPPROTO_SCTP
;
1120 cmsg
->cmsg_type
= SCTP_DSTADDRV4
;
1121 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct in_addr
));
1122 memcpy(CMSG_DATA(cmsg
), &addr_in
->sin_addr
, sizeof(struct in_addr
));
1123 msg
.msg_controllen
+= CMSG_SPACE(sizeof(struct in_addr
));
1124 cmsg
= (struct cmsghdr
*)((caddr_t
)cmsg
+ CMSG_SPACE(sizeof(struct in_addr
)));
1133 addr_len
= (socklen_t
) sizeof(struct sockaddr_in6
);
1134 addr_in6
= (struct sockaddr_in6
*)addr
;
1135 if (addr_in6
->sin6_len
!= addr_len
) {
1141 port
= addr_in6
->sin6_port
;
1143 if (port
== addr_in6
->sin6_port
) {
1144 cmsg
->cmsg_level
= IPPROTO_SCTP
;
1145 cmsg
->cmsg_type
= SCTP_DSTADDRV6
;
1146 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct in6_addr
));
1147 memcpy(CMSG_DATA(cmsg
), &addr_in6
->sin6_addr
, sizeof(struct in6_addr
));
1148 msg
.msg_controllen
+= CMSG_SPACE(sizeof(struct in6_addr
));
1149 cmsg
= (struct cmsghdr
*)((caddr_t
)cmsg
+ CMSG_SPACE(sizeof(struct in6_addr
)));
1163 msg
.msg_name
= addr
;
1164 msg
.msg_namelen
= addr_len
;
1166 addr
= (struct sockaddr
*)((caddr_t
)addr
+ addr_len
);
1168 if (msg
.msg_controllen
== 0) {
1169 msg
.msg_control
= NULL
;
1171 msg
.msg_iov
= (struct iovec
*)iov
;
1172 msg
.msg_iovlen
= iovcnt
;
1174 ret
= sendmsg(sd
, &msg
, flags
);
1176 if ((ret
>= 0) && (addrs
!= NULL
) && (assoc_id
!= NULL
)) {
1177 *assoc_id
= sctp_getassocid(sd
, addrs
);
1183 #if !defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT)
1186 sctp_peeloff(int sd
, sctp_assoc_t assoc_id
)
1188 /* NOT supported, return invalid sd */
1194 #if defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT)
1196 sctp_peeloff(int sd
, sctp_assoc_t assoc_id
)
1198 return (syscall(SYS_sctp_peeloff
, sd
, assoc_id
));
1203 #undef SCTP_CONTROL_VEC_SIZE_RCV