1 /* $KAME: sctp_sys_calls.c,v 1.9 2004/08/17 06:08:53 itojun Exp $ */
2 /* $DragonFly: src/lib/libsctp/sctp_sys_calls.c,v 1.2 2006/06/28 23:14:43 corecode Exp $ */
5 * Copyright (C) 2002, 2003, 2004 Cisco Systems Inc,
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <sys/errno.h>
41 #include <sys/syscall.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <netinet/sctp_uio.h>
46 #include <netinet/sctp.h>
47 #include <netinet/sctp_constants.h>
49 #include <net/if_dl.h>
51 #ifndef IN6_IS_ADDR_V4MAPPED
52 #define IN6_IS_ADDR_V4MAPPED(a) \
53 ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
54 (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
55 (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff)))
59 #ifdef SCTP_DEBUG_PRINT_ADDRESS
61 SCTPPrintAnAddress(struct sockaddr
*a
)
63 char stringToPrint
[256];
71 if (a
->sa_family
== AF_INET
) {
72 srcaddr
= (char *)&((struct sockaddr_in
*)a
)->sin_addr
;
73 txt
= "IPv4 Address: ";
74 prt
= ntohs(((struct sockaddr_in
*)a
)->sin_port
);
75 } else if (a
->sa_family
== AF_INET6
) {
76 srcaddr
= (char *)&((struct sockaddr_in6
*)a
)->sin6_addr
;
77 prt
= ntohs(((struct sockaddr_in6
*)a
)->sin6_port
);
78 txt
= "IPv6 Address: ";
79 } else if (a
->sa_family
== AF_LINK
) {
83 struct sockaddr_dl
*dl
;
85 dl
= (struct sockaddr_dl
*)a
;
86 strncpy(tbuf
, dl
->sdl_data
, dl
->sdl_nlen
);
87 tbuf
[dl
->sdl_nlen
] = 0;
88 printf("Intf:%s (len:%d)Interface index:%d type:%x(%d) ll-len:%d ",
89 tbuf
, dl
->sdl_nlen
, dl
->sdl_index
, dl
->sdl_type
,
90 dl
->sdl_type
, dl
->sdl_alen
);
91 memcpy(adbuf
, LLADDR(dl
), dl
->sdl_alen
);
92 for (i
= 0; i
< dl
->sdl_alen
; i
++){
93 printf("%2.2x", adbuf
[i
]);
94 if (i
< (dl
->sdl_alen
- 1))
98 /* u_short sdl_route[16];*/ /* source routing information */
103 if (inet_ntop(a
->sa_family
, srcaddr
, stringToPrint
,
104 sizeof(stringToPrint
))) {
105 if (a
->sa_family
== AF_INET6
) {
106 printf("%s%s:%d scope:%d\n", txt
, stringToPrint
, prt
,
107 ((struct sockaddr_in6
*)a
)->sin6_scope_id
);
109 printf("%s%s:%d\n", txt
, stringToPrint
, prt
);
113 printf("%s unprintable?\n", txt
);
116 #endif /* SCTP_DEBUG_PRINT_ADDRESS */
119 in6_sin6_2_sin(struct sockaddr_in
*sin
, struct sockaddr_in6
*sin6
)
121 bzero(sin
, sizeof(*sin
));
122 sin
->sin_len
= sizeof(struct sockaddr_in
);
123 sin
->sin_family
= AF_INET
;
124 sin
->sin_port
= sin6
->sin6_port
;
125 sin
->sin_addr
.s_addr
= sin6
->sin6_addr
.__u6_addr
.__u6_addr32
[3];
129 sctp_connectx(int sd
, struct sockaddr
*addrs
, int addrcnt
)
132 int i
, ret
, cnt
, *aa
;
135 size_t len
= sizeof(int);
139 cpto
= ((caddr_t
)buf
+ sizeof(int));
140 /* validate all the addresses and get the size */
141 for (i
= 0; i
< addrcnt
; i
++) {
142 if (at
->sa_family
== AF_INET
) {
143 memcpy(cpto
, at
, at
->sa_len
);
144 cpto
= ((caddr_t
)cpto
+ at
->sa_len
);
146 } else if (at
->sa_family
== AF_INET6
){
147 if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6
*)at
)->sin6_addr
)){
148 len
+= sizeof(struct sockaddr_in
);
149 in6_sin6_2_sin((struct sockaddr_in
*)cpto
,
150 (struct sockaddr_in6
*)at
);
151 cpto
= ((caddr_t
)cpto
+ sizeof(struct sockaddr_in
));
152 len
+= sizeof(struct sockaddr_in
);
154 memcpy(cpto
, at
, at
->sa_len
);
155 cpto
= ((caddr_t
)cpto
+ at
->sa_len
);
162 if (len
> (sizeof(buf
)-sizeof(int))) {
163 /* Never enough memory */
166 at
= (struct sockaddr
*)((caddr_t
)at
+ at
->sa_len
);
169 /* do we have any? */
176 ret
= setsockopt(sd
, IPPROTO_SCTP
, SCTP_CONNECT_X
, (void *)buf
,
182 sctp_bindx(int sd
, struct sockaddr
*addrs
, int addrcnt
, int flags
)
184 struct sctp_getaddresses
*gaddrs
;
186 int i
, sz
, fam
, argsz
;
188 if ((flags
!= SCTP_BINDX_ADD_ADDR
) &&
189 (flags
!= SCTP_BINDX_REM_ADDR
)) {
193 argsz
= (sizeof(struct sockaddr_storage
) +
194 sizeof(struct sctp_getaddresses
));
195 gaddrs
= (struct sctp_getaddresses
*)calloc(1, argsz
);
196 if (gaddrs
== NULL
) {
200 gaddrs
->sget_assoc_id
= 0;
202 for (i
= 0; i
< addrcnt
; i
++) {
205 ((struct sockaddr_in
*)&addrs
[i
])->sin_port
= ((struct sockaddr_in
*)sa
)->sin_port
;
206 if ((fam
!= AF_INET
) && (fam
!= AF_INET6
)) {
210 memcpy(gaddrs
->addr
, sa
, sz
);
211 if (setsockopt(sd
, IPPROTO_SCTP
, flags
, gaddrs
,
212 (unsigned int)argsz
) != 0) {
216 memset(gaddrs
, 0, argsz
);
217 sa
= (struct sockaddr
*)((caddr_t
)sa
+ sz
);
225 sctp_opt_info(int sd
, sctp_assoc_t id
, int opt
, void *arg
, size_t *size
)
227 if ((opt
== SCTP_RTOINFO
) ||
228 (opt
== SCTP_ASSOCINFO
) ||
229 (opt
== SCTP_PRIMARY_ADDR
) ||
230 (opt
== SCTP_SET_PEER_PRIMARY_ADDR
) ||
231 (opt
== SCTP_PEER_ADDR_PARAMS
) ||
232 (opt
== SCTP_STATUS
) ||
233 (opt
== SCTP_GET_PEER_ADDR_INFO
)) {
234 *(sctp_assoc_t
*)arg
= id
;
235 return(getsockopt(sd
, IPPROTO_SCTP
, opt
, arg
, (int *)size
));
243 sctp_getpaddrs(int sd
, sctp_assoc_t id
, struct sockaddr
**raddrs
)
245 struct sctp_getaddresses
*addrs
;
253 if (raddrs
== NULL
) {
258 siz
= sizeof(sctp_assoc_t
);
259 if (getsockopt(sd
, IPPROTO_SCTP
, SCTP_GET_REMOTE_ADDR_SIZE
,
263 siz
= (unsigned int)asoc
;
264 siz
+= sizeof(struct sctp_getaddresses
);
265 addrs
= calloc((unsigned long)1, (unsigned long)siz
);
270 memset(addrs
, 0, (size_t)siz
);
271 addrs
->sget_assoc_id
= id
;
272 /* Now lets get the array of addresses */
273 if (getsockopt(sd
, IPPROTO_SCTP
, SCTP_GET_PEER_ADDRESSES
,
278 re
= (struct sockaddr
*)&addrs
->addr
[0];
281 sa
= (struct sockaddr
*)&addrs
->addr
[0];
282 lim
= (caddr_t
)addrs
+ siz
;
283 while ((caddr_t
)sa
< lim
) {
285 sa
= (struct sockaddr
*)((caddr_t
)sa
+ sa
->sa_len
);
292 void sctp_freepaddrs(struct sockaddr
*addrs
)
294 /* Take away the hidden association id */
296 fr_addr
= (void *)((caddr_t
)addrs
- sizeof(sctp_assoc_t
));
302 sctp_getladdrs (int sd
, sctp_assoc_t id
, struct sockaddr
**raddrs
)
304 struct sctp_getaddresses
*addrs
;
308 int size_of_addresses
;
312 if (raddrs
== NULL
) {
316 size_of_addresses
= 0;
318 if (getsockopt(sd
, IPPROTO_SCTP
, SCTP_GET_LOCAL_ADDR_SIZE
,
319 &size_of_addresses
, &siz
) != 0) {
322 if (size_of_addresses
== 0) {
326 siz
= size_of_addresses
+ sizeof(struct sockaddr_storage
);
327 siz
+= sizeof(struct sctp_getaddresses
);
328 addrs
= calloc((unsigned long)1, (unsigned long)siz
);
333 memset(addrs
, 0, (size_t)siz
);
334 addrs
->sget_assoc_id
= id
;
335 /* Now lets get the array of addresses */
336 if (getsockopt(sd
, IPPROTO_SCTP
, SCTP_GET_LOCAL_ADDRESSES
, addrs
,
341 re
= (struct sockaddr
*)&addrs
->addr
[0];
344 sa
= (struct sockaddr
*)&addrs
->addr
[0];
345 lim
= (caddr_t
)addrs
+ siz
;
346 while ((caddr_t
)sa
< lim
) {
348 sa
= (struct sockaddr
*)((caddr_t
)sa
+ sa
->sa_len
);
355 void sctp_freeladdrs(struct sockaddr
*addrs
)
357 /* Take away the hidden association id */
359 fr_addr
= (void *)((caddr_t
)addrs
- sizeof(sctp_assoc_t
));
369 const struct sockaddr
*to
,
370 socklen_t tolen
__attribute__((unused
)),
374 u_int32_t timetolive
,
380 char controlVector
[256];
381 struct sctp_sndrcvinfo
*s_info
;
382 struct cmsghdr
*cmsg
;
383 struct sockaddr
*who
=NULL
;
385 struct sockaddr_in in
;
386 struct sockaddr_in6 in6
;
390 fprintf(io
, "sctp_sendmsg(sd:%d, data:%x, len:%d, to:%x, tolen:%d, ppid:%x, flags:%x str:%d ttl:%d ctx:%x\n",
391 s
, (u_int
)data
, (int)len
, (u_int
)to
, (int)tolen
, ppid
, flags
,
392 (int)stream_no
, (int)timetolive
, (u_int
)context
);
396 if (to
->sa_len
== 0) {
398 * For the lazy app, that did not
399 * set sa_len, we attempt to set for them.
401 if (to
->sa_family
== AF_INET
){
402 memcpy(&addr
, to
, sizeof(struct sockaddr_in
));
403 addr
.in
.sin_len
= sizeof(struct sockaddr_in
);
404 } else if (to
->sa_family
== AF_INET6
){
405 memcpy(&addr
, to
, sizeof(struct sockaddr_in6
));
406 addr
.in6
.sin6_len
= sizeof(struct sockaddr_in6
);
409 memcpy (&addr
, to
, to
->sa_len
);
411 who
= (struct sockaddr
*)&addr
;
413 iov
[0].iov_base
= (char *)data
;
414 iov
[0].iov_len
= len
;
415 iov
[1].iov_base
= NULL
;
419 msg
.msg_name
= (caddr_t
)who
;
420 msg
.msg_namelen
= who
->sa_len
;
422 msg
.msg_name
= (caddr_t
)NULL
;
427 msg
.msg_control
= (caddr_t
)controlVector
;
429 cmsg
= (struct cmsghdr
*)controlVector
;
431 cmsg
->cmsg_level
= IPPROTO_SCTP
;
432 cmsg
->cmsg_type
= SCTP_SNDRCV
;
433 cmsg
->cmsg_len
= CMSG_LEN (sizeof(struct sctp_sndrcvinfo
) );
434 s_info
= (struct sctp_sndrcvinfo
*)CMSG_DATA(cmsg
);
436 s_info
->sinfo_stream
= stream_no
;
437 s_info
->sinfo_ssn
= 0;
438 s_info
->sinfo_flags
= flags
;
439 s_info
->sinfo_ppid
= ppid
;
440 s_info
->sinfo_context
= context
;
441 s_info
->sinfo_assoc_id
= 0;
442 s_info
->sinfo_timetolive
= timetolive
;
444 msg
.msg_controllen
= cmsg
->cmsg_len
;
445 sz
= sendmsg(s
, &msg
, 0);
450 sctp_getassocid(int sd
, struct sockaddr
*sa
)
452 struct sctp_paddrparams sp
;
455 /* First get the assoc id */
456 siz
= sizeof(struct sctp_paddrparams
);
457 memset(&sp
, 0, sizeof(sp
));
458 memcpy((caddr_t
)&sp
.spp_address
, sa
, sa
->sa_len
);
460 if (getsockopt(sd
, IPPROTO_SCTP
, SCTP_PEER_ADDR_PARAMS
, &sp
, &siz
) != 0)
461 return((sctp_assoc_t
)0);
462 /* We depend on the fact that 0 can never be returned */
463 return(sp
.spp_assoc_id
);
469 sctp_send(int sd
, const void *data
, size_t len
,
470 const struct sctp_sndrcvinfo
*sinfo
,
476 struct sctp_sndrcvinfo
*s_info
;
477 char controlVector
[256];
478 struct cmsghdr
*cmsg
;
480 iov
[0].iov_base
= (char *)data
;
481 iov
[0].iov_len
= len
;
482 iov
[1].iov_base
= NULL
;
489 msg
.msg_control
= (caddr_t
)controlVector
;
491 cmsg
= (struct cmsghdr
*)controlVector
;
493 cmsg
->cmsg_level
= IPPROTO_SCTP
;
494 cmsg
->cmsg_type
= SCTP_SNDRCV
;
495 cmsg
->cmsg_len
= CMSG_LEN (sizeof(struct sctp_sndrcvinfo
) );
496 s_info
= (struct sctp_sndrcvinfo
*)CMSG_DATA(cmsg
);
497 /* copy in the data */
500 msg
.msg_controllen
= cmsg
->cmsg_len
;
501 sz
= sendmsg(sd
, &msg
, flags
);
507 sctp_sendx(int sd
, const void *msg
, size_t len
,
508 struct sockaddr
*addrs
, int addrcnt
,
509 struct sctp_sndrcvinfo
*sinfo
,
512 int i
, cnt
, *aa
, saved_errno
;
520 /* validate all the addresses and get the size */
521 for (i
= 0; i
< addrcnt
; i
++) {
522 if (at
->sa_family
== AF_INET
) {
523 add_len
= sizeof(struct sockaddr_in
);
524 } else if (at
->sa_family
== AF_INET6
) {
525 add_len
= sizeof(struct sockaddr_in6
);
531 at
= (struct sockaddr
*)((caddr_t
)at
+ add_len
);
534 /* do we have any? */
540 /* Never enough memory */
552 memcpy((caddr_t
)aa
, addrs
, (len
- sizeof(int)));
553 ret
= setsockopt(sd
, IPPROTO_SCTP
, SCTP_CONNECT_X_DELAYED
, (void *)buf
,
560 sinfo
->sinfo_assoc_id
= sctp_getassocid(sd
, addrs
);
561 if (sinfo
->sinfo_assoc_id
== 0) {
562 printf("Huh, can't get associd? TSNH!\n");
563 (void)setsockopt(sd
, IPPROTO_SCTP
, SCTP_CONNECT_X_COMPLETE
, (void *)addrs
,
564 (unsigned int)addrs
->sa_len
);
568 ret
= sctp_send(sd
, msg
, len
, sinfo
, flags
);
570 (void)setsockopt(sd
, IPPROTO_SCTP
, SCTP_CONNECT_X_COMPLETE
, (void *)addrs
,
571 (unsigned int)addrs
->sa_len
);
578 sctp_sendmsgx(int sd
,
581 struct sockaddr
*addrs
,
586 u_int32_t timetolive
,
589 struct sctp_sndrcvinfo sinfo
;
591 memset((void *) &sinfo
, 0, sizeof(struct sctp_sndrcvinfo
));
592 sinfo
.sinfo_ppid
= ppid
;
593 sinfo
.sinfo_flags
= flags
;
594 sinfo
.sinfo_ssn
= stream_no
;
595 sinfo
.sinfo_timetolive
= timetolive
;
596 sinfo
.sinfo_context
= context
;
597 return sctp_sendx(sd
, msg
, len
, addrs
, addrcnt
, &sinfo
, 0);
604 struct sockaddr
*from
,
606 struct sctp_sndrcvinfo
*sinfo
,
609 struct sctp_sndrcvinfo
*s_info
;
613 char controlVector
[2048];
614 struct cmsghdr
*cmsg
;
615 iov
[0].iov_base
= dbuf
;
616 iov
[0].iov_len
= len
;
617 iov
[1].iov_base
= NULL
;
619 msg
.msg_name
= (caddr_t
)from
;
620 msg
.msg_namelen
= *fromlen
;
623 msg
.msg_control
= (caddr_t
)controlVector
;
624 msg
.msg_controllen
= sizeof(controlVector
);
626 sz
= recvmsg(s
, &msg
, 0);
630 *msg_flags
= msg
.msg_flags
;
631 *fromlen
= msg
.msg_namelen
;
632 if ((msg
.msg_controllen
) && sinfo
) {
633 /* parse through and see if we find
634 * the sctp_sndrcvinfo (if the user wants it).
636 cmsg
= (struct cmsghdr
*)controlVector
;
638 if (cmsg
->cmsg_level
== IPPROTO_SCTP
) {
639 if (cmsg
->cmsg_type
== SCTP_SNDRCV
) {
641 s_info
= (struct sctp_sndrcvinfo
*)CMSG_DATA(cmsg
);
642 /* Copy it to the user */
647 cmsg
= CMSG_NXTHDR(&msg
, cmsg
);
653 #ifdef SYS_sctp_peeloff
655 sctp_peeloff(sd
, assoc_id
)
657 sctp_assoc_t assoc_id
;
659 return (syscall(SYS_sctp_peeloff
, sd
, assoc_id
));