1 | /* $KAME: sctp_sys_calls.c,v 1.10 2005/03/06 16:04:16 itojun Exp $ */ |
2 | /* $NetBSD: sctp_sys_calls.c,v 1.1 2018/08/02 08:40:48 rjs Exp $ */ |
3 | |
4 | /* |
5 | * Copyright (C) 2002, 2003, 2004 Cisco Systems Inc, |
6 | * All rights reserved. |
7 | * |
8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions |
10 | * are met: |
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. |
19 | * |
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 |
30 | * SUCH DAMAGE. |
31 | */ |
32 | |
33 | #include <stdio.h> |
34 | #include <string.h> |
35 | #include <errno.h> |
36 | #include <stdlib.h> |
37 | #include <unistd.h> |
38 | #include <sys/types.h> |
39 | #include <sys/socket.h> |
40 | #include <sys/errno.h> |
41 | #include <sys/syscall.h> |
42 | #include <sys/ioctl.h> |
43 | #include <sys/uio.h> |
44 | #include <netinet/in.h> |
45 | #include <arpa/inet.h> |
46 | #include <netinet/sctp_uio.h> |
47 | #include <netinet/sctp.h> |
48 | |
49 | #include <net/if_dl.h> |
50 | |
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))) |
56 | #endif |
57 | |
58 | #define SCTP_CONTROL_VEC_SIZE_RCV 16384 |
59 | |
60 | #ifdef SCTP_DEBUG_PRINT_ADDRESS |
61 | static void |
62 | SCTPPrintAnAddress(struct sockaddr *a) |
63 | { |
64 | char stringToPrint[256]; |
65 | u_short prt; |
66 | char *srcaddr, *txt; |
67 | |
68 | if (a == NULL) { |
69 | printf("NULL\n" ); |
70 | return; |
71 | } |
72 | if (a->sa_family == AF_INET) { |
73 | srcaddr = (char *)&((struct sockaddr_in *)a)->sin_addr; |
74 | txt = "IPv4 Address: " ; |
75 | prt = ntohs(((struct sockaddr_in *)a)->sin_port); |
76 | } else if (a->sa_family == AF_INET6) { |
77 | srcaddr = (char *)&((struct sockaddr_in6 *)a)->sin6_addr; |
78 | prt = ntohs(((struct sockaddr_in6 *)a)->sin6_port); |
79 | txt = "IPv6 Address: " ; |
80 | } else if (a->sa_family == AF_LINK) { |
81 | int i; |
82 | char tbuf[200]; |
83 | u_char adbuf[200]; |
84 | struct sockaddr_dl *dl; |
85 | |
86 | dl = (struct sockaddr_dl *)a; |
87 | strncpy(tbuf, dl->sdl_data, dl->sdl_nlen); |
88 | tbuf[dl->sdl_nlen] = 0; |
89 | printf("Intf:%s (len:%d)Interface index:%d type:%x(%d) ll-len:%d " , |
90 | tbuf, dl->sdl_nlen, dl->sdl_index, dl->sdl_type, |
91 | dl->sdl_type, dl->sdl_alen); |
92 | memcpy(adbuf, LLADDR(dl), dl->sdl_alen); |
93 | for (i = 0; i < dl->sdl_alen; i++){ |
94 | printf("%2.2x" , adbuf[i]); |
95 | if (i < (dl->sdl_alen - 1)) |
96 | printf(":" ); |
97 | } |
98 | printf("\n" ); |
99 | /* u_short sdl_route[16];*/ /* source routing information */ |
100 | return; |
101 | } else { |
102 | return; |
103 | } |
104 | if (inet_ntop(a->sa_family, srcaddr, stringToPrint, |
105 | sizeof(stringToPrint))) { |
106 | if (a->sa_family == AF_INET6) { |
107 | printf("%s%s:%d scope:%d\n" , txt, stringToPrint, prt, |
108 | ((struct sockaddr_in6 *)a)->sin6_scope_id); |
109 | } else { |
110 | printf("%s%s:%d\n" , txt, stringToPrint, prt); |
111 | } |
112 | |
113 | } else { |
114 | printf("%s unprintable?\n" , txt); |
115 | } |
116 | } |
117 | #endif /* SCTP_DEBUG_PRINT_ADDRESS */ |
118 | |
119 | void |
120 | in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) |
121 | { |
122 | memset(sin, 0, sizeof(*sin)); |
123 | sin->sin_len = sizeof(struct sockaddr_in); |
124 | sin->sin_family = AF_INET; |
125 | sin->sin_port = sin6->sin6_port; |
126 | sin->sin_addr.s_addr = sin6->sin6_addr.__u6_addr.__u6_addr32[3]; |
127 | } |
128 | |
129 | int |
130 | sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt, |
131 | sctp_assoc_t *id) |
132 | { |
133 | int i, ret, cnt; |
134 | struct sockaddr *at; |
135 | struct sctp_connectx_addrs sca; |
136 | #if 0 |
137 | char *cpto; |
138 | #endif |
139 | size_t len; |
140 | |
141 | at = addrs; |
142 | cnt = 0; |
143 | len = 0; |
144 | /* validate all the addresses and get the size */ |
145 | for (i = 0; i < addrcnt; i++) { |
146 | if (at->sa_family == AF_INET) { |
147 | len += at->sa_len; |
148 | } else if (at->sa_family == AF_INET6){ |
149 | if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)at)->sin6_addr)){ |
150 | len += sizeof(struct sockaddr_in); |
151 | #if 0 |
152 | in6_sin6_2_sin((struct sockaddr_in *)cpto, |
153 | (struct sockaddr_in6 *)at); |
154 | cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in)); |
155 | len += sizeof(struct sockaddr_in); |
156 | #endif |
157 | } else { |
158 | len += at->sa_len; |
159 | } |
160 | } else { |
161 | errno = EINVAL; |
162 | return (-1); |
163 | } |
164 | at = (struct sockaddr *)((caddr_t)at + at->sa_len); |
165 | cnt++; |
166 | } |
167 | /* do we have any? */ |
168 | if (cnt == 0) { |
169 | errno = EINVAL; |
170 | return(-1); |
171 | } |
172 | |
173 | sca.cx_num = cnt; |
174 | sca.cx_len = len; |
175 | sca.cx_addrs = addrs; |
176 | ret = ioctl(sd, SIOCCONNECTX, (void *)&sca); |
177 | if ((ret == 0) && (id != NULL)) { |
178 | memcpy(id, &sca.cx_num, sizeof(sctp_assoc_t)); |
179 | } |
180 | return (ret); |
181 | } |
182 | |
183 | int |
184 | sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags) |
185 | { |
186 | struct sctp_getaddresses *gaddrs; |
187 | struct sockaddr *sa; |
188 | int i, sz, fam, argsz; |
189 | |
190 | if ((flags != SCTP_BINDX_ADD_ADDR) && |
191 | (flags != SCTP_BINDX_REM_ADDR)) { |
192 | errno = EFAULT; |
193 | return(-1); |
194 | } |
195 | argsz = (sizeof(struct sockaddr_storage) + |
196 | sizeof(struct sctp_getaddresses)); |
197 | gaddrs = (struct sctp_getaddresses *)calloc(1, argsz); |
198 | if (gaddrs == NULL) { |
199 | errno = ENOMEM; |
200 | return(-1); |
201 | } |
202 | gaddrs->sget_assoc_id = 0; |
203 | sa = addrs; |
204 | for (i = 0; i < addrcnt; i++) { |
205 | sz = sa->sa_len; |
206 | fam = sa->sa_family; |
207 | ((struct sockaddr_in *)&addrs[i])->sin_port = ((struct sockaddr_in *)sa)->sin_port; |
208 | if ((fam != AF_INET) && (fam != AF_INET6)) { |
209 | errno = EINVAL; |
210 | return(-1); |
211 | } |
212 | memcpy(gaddrs->addr, sa, sz); |
213 | if (setsockopt(sd, IPPROTO_SCTP, flags, gaddrs, |
214 | (unsigned int)argsz) != 0) { |
215 | free(gaddrs); |
216 | return(-1); |
217 | } |
218 | memset(gaddrs, 0, argsz); |
219 | sa = (struct sockaddr *)((caddr_t)sa + sz); |
220 | } |
221 | free(gaddrs); |
222 | return(0); |
223 | } |
224 | |
225 | |
226 | int |
227 | sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t *size) |
228 | { |
229 | if ((opt == SCTP_RTOINFO) || |
230 | (opt == SCTP_ASSOCINFO) || |
231 | (opt == SCTP_PRIMARY_ADDR) || |
232 | (opt == SCTP_SET_PEER_PRIMARY_ADDR) || |
233 | (opt == SCTP_PEER_ADDR_PARAMS) || |
234 | (opt == SCTP_STATUS) || |
235 | (opt == SCTP_GET_PEER_ADDR_INFO)) { |
236 | *(sctp_assoc_t *)arg = id; |
237 | return(getsockopt2(sd, IPPROTO_SCTP, opt, arg, size)); |
238 | } else { |
239 | errno = EOPNOTSUPP; |
240 | return(-1); |
241 | } |
242 | } |
243 | |
244 | int |
245 | sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs) |
246 | { |
247 | struct sctp_getaddresses *addrs; |
248 | struct sockaddr *sa; |
249 | struct sockaddr *re; |
250 | sctp_assoc_t asoc; |
251 | caddr_t lim; |
252 | unsigned int siz; |
253 | int cnt; |
254 | |
255 | if (raddrs == NULL) { |
256 | errno = EFAULT; |
257 | return(-1); |
258 | } |
259 | asoc = id; |
260 | siz = sizeof(sctp_assoc_t); |
261 | if (getsockopt2(sd, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE, |
262 | &asoc, &siz) != 0) { |
263 | return(-1); |
264 | } |
265 | siz = (unsigned int)asoc; |
266 | siz += sizeof(struct sctp_getaddresses); |
267 | addrs = calloc((unsigned long)1, (unsigned long)siz); |
268 | if (addrs == NULL) { |
269 | errno = ENOMEM; |
270 | return(-1); |
271 | } |
272 | memset(addrs, 0, (size_t)siz); |
273 | addrs->sget_assoc_id = id; |
274 | /* Now lets get the array of addresses */ |
275 | if (getsockopt2(sd, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES, |
276 | addrs, &siz) != 0) { |
277 | free(addrs); |
278 | return(-1); |
279 | } |
280 | re = (struct sockaddr *)&addrs->addr[0]; |
281 | *raddrs = re; |
282 | cnt = 0; |
283 | sa = (struct sockaddr *)&addrs->addr[0]; |
284 | lim = (caddr_t)addrs + siz; |
285 | while ((caddr_t)sa < lim) { |
286 | cnt++; |
287 | sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); |
288 | if (sa->sa_len == 0) |
289 | break; |
290 | } |
291 | return(cnt); |
292 | } |
293 | |
294 | void sctp_freepaddrs(struct sockaddr *addrs) |
295 | { |
296 | /* Take away the hidden association id */ |
297 | void *fr_addr; |
298 | fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t)); |
299 | /* Now free it */ |
300 | free(fr_addr); |
301 | } |
302 | |
303 | int |
304 | sctp_getladdrs (int sd, sctp_assoc_t id, struct sockaddr **raddrs) |
305 | { |
306 | struct sctp_getaddresses *addrs; |
307 | struct sockaddr *re; |
308 | caddr_t lim; |
309 | struct sockaddr *sa; |
310 | int size_of_addresses; |
311 | unsigned int siz; |
312 | int cnt; |
313 | |
314 | if (raddrs == NULL) { |
315 | errno = EFAULT; |
316 | return(-1); |
317 | } |
318 | size_of_addresses = 0; |
319 | siz = sizeof(int); |
320 | if (getsockopt2(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE, |
321 | &size_of_addresses, &siz) != 0) { |
322 | return(-1); |
323 | } |
324 | if (size_of_addresses == 0) { |
325 | errno = ENOTCONN; |
326 | return(-1); |
327 | } |
328 | siz = size_of_addresses + sizeof(struct sockaddr_storage); |
329 | siz += sizeof(struct sctp_getaddresses); |
330 | addrs = calloc((unsigned long)1, (unsigned long)siz); |
331 | if (addrs == NULL) { |
332 | errno = ENOMEM; |
333 | return(-1); |
334 | } |
335 | memset(addrs, 0, (size_t)siz); |
336 | addrs->sget_assoc_id = id; |
337 | /* Now lets get the array of addresses */ |
338 | if (getsockopt2(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs, |
339 | &siz) != 0) { |
340 | free(addrs); |
341 | return(-1); |
342 | } |
343 | re = (struct sockaddr *)&addrs->addr[0]; |
344 | *raddrs = re; |
345 | cnt = 0; |
346 | sa = (struct sockaddr *)&addrs->addr[0]; |
347 | lim = (caddr_t)addrs + siz; |
348 | while ((caddr_t)sa < lim) { |
349 | cnt++; |
350 | sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); |
351 | if (sa->sa_len == 0) |
352 | break; |
353 | } |
354 | return(cnt); |
355 | } |
356 | |
357 | void sctp_freeladdrs(struct sockaddr *addrs) |
358 | { |
359 | /* Take away the hidden association id */ |
360 | void *fr_addr; |
361 | fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t)); |
362 | /* Now free it */ |
363 | free(fr_addr); |
364 | } |
365 | |
366 | ssize_t |
367 | sctp_sendmsg(int s, |
368 | const void *data, |
369 | size_t len, |
370 | const struct sockaddr *to, |
371 | socklen_t tolen __attribute__((unused)), |
372 | u_int32_t ppid, |
373 | u_int32_t flags, |
374 | u_int16_t stream_no, |
375 | u_int32_t timetolive, |
376 | u_int32_t context) |
377 | { |
378 | int sz; |
379 | struct msghdr msg; |
380 | struct iovec iov[2]; |
381 | char controlVector[256]; |
382 | struct sctp_sndrcvinfo *s_info; |
383 | struct cmsghdr *cmsg; |
384 | struct sockaddr *who=NULL; |
385 | union { |
386 | struct sockaddr_in in; |
387 | struct sockaddr_in6 in6; |
388 | } addr; |
389 | |
390 | #if 0 |
391 | 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" , |
392 | s, (u_int)data, (int)len, (u_int)to, (int)tolen, ppid, flags, |
393 | (int)stream_no, (int)timetolive, (u_int)context); |
394 | fflush(io); |
395 | #endif |
396 | if (to) { |
397 | if (to->sa_len == 0) { |
398 | /* |
399 | * For the lazy app, that did not |
400 | * set sa_len, we attempt to set for them. |
401 | */ |
402 | switch (to->sa_family) { |
403 | case AF_INET: |
404 | memcpy(&addr, to, sizeof(struct sockaddr_in)); |
405 | addr.in.sin_len = sizeof(struct sockaddr_in); |
406 | break; |
407 | case AF_INET6: |
408 | memcpy(&addr, to, sizeof(struct sockaddr_in6)); |
409 | addr.in6.sin6_len = sizeof(struct sockaddr_in6); |
410 | break; |
411 | default: |
412 | errno = EAFNOSUPPORT; |
413 | return -1; |
414 | } |
415 | } else { |
416 | memcpy (&addr, to, to->sa_len); |
417 | } |
418 | who = (struct sockaddr *)&addr; |
419 | } |
420 | iov[0].iov_base = (void *)(unsigned long)data; |
421 | iov[0].iov_len = len; |
422 | iov[1].iov_base = NULL; |
423 | iov[1].iov_len = 0; |
424 | |
425 | if (to) { |
426 | msg.msg_name = (caddr_t)who; |
427 | msg.msg_namelen = who->sa_len; |
428 | } else { |
429 | msg.msg_name = (caddr_t)NULL; |
430 | msg.msg_namelen = 0; |
431 | } |
432 | msg.msg_iov = iov; |
433 | msg.msg_iovlen = 1; |
434 | msg.msg_control = (caddr_t)controlVector; |
435 | |
436 | cmsg = (struct cmsghdr *)controlVector; |
437 | |
438 | cmsg->cmsg_level = IPPROTO_SCTP; |
439 | cmsg->cmsg_type = SCTP_SNDRCV; |
440 | cmsg->cmsg_len = CMSG_LEN (sizeof(struct sctp_sndrcvinfo) ); |
441 | s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); |
442 | |
443 | s_info->sinfo_stream = stream_no; |
444 | s_info->sinfo_ssn = 0; |
445 | s_info->sinfo_flags = flags; |
446 | s_info->sinfo_ppid = ppid; |
447 | s_info->sinfo_context = context; |
448 | s_info->sinfo_assoc_id = 0; |
449 | s_info->sinfo_timetolive = timetolive; |
450 | errno = 0; |
451 | msg.msg_controllen = cmsg->cmsg_len; |
452 | sz = sendmsg(s, &msg, 0); |
453 | return(sz); |
454 | } |
455 | |
456 | sctp_assoc_t |
457 | sctp_getassocid(int sd, struct sockaddr *sa) |
458 | { |
459 | struct sctp_paddrparams sp; |
460 | socklen_t siz; |
461 | |
462 | /* First get the assoc id */ |
463 | siz = sizeof(struct sctp_paddrparams); |
464 | memset(&sp, 0, sizeof(sp)); |
465 | memcpy((caddr_t)&sp.spp_address, sa, sa->sa_len); |
466 | errno = 0; |
467 | if (getsockopt2(sd, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &sp, &siz) != 0) |
468 | return((sctp_assoc_t)0); |
469 | /* We depend on the fact that 0 can never be returned */ |
470 | return(sp.spp_assoc_id); |
471 | } |
472 | |
473 | |
474 | |
475 | ssize_t |
476 | sctp_send(int sd, const void *data, size_t len, |
477 | const struct sctp_sndrcvinfo *sinfo, |
478 | int flags) |
479 | { |
480 | int sz; |
481 | struct msghdr msg; |
482 | struct iovec iov[2]; |
483 | struct sctp_sndrcvinfo *s_info; |
484 | char controlVector[256]; |
485 | struct cmsghdr *cmsg; |
486 | |
487 | iov[0].iov_base = (void *)(unsigned long)data; |
488 | iov[0].iov_len = len; |
489 | iov[1].iov_base = NULL; |
490 | iov[1].iov_len = 0; |
491 | |
492 | msg.msg_name = 0; |
493 | msg.msg_namelen = 0; |
494 | msg.msg_iov = iov; |
495 | msg.msg_iovlen = 1; |
496 | msg.msg_control = (caddr_t)controlVector; |
497 | |
498 | cmsg = (struct cmsghdr *)controlVector; |
499 | |
500 | cmsg->cmsg_level = IPPROTO_SCTP; |
501 | cmsg->cmsg_type = SCTP_SNDRCV; |
502 | cmsg->cmsg_len = CMSG_LEN (sizeof(struct sctp_sndrcvinfo) ); |
503 | s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); |
504 | /* copy in the data */ |
505 | *s_info = *sinfo; |
506 | errno = 0; |
507 | msg.msg_controllen = cmsg->cmsg_len; |
508 | sz = sendmsg(sd, &msg, flags); |
509 | return(sz); |
510 | } |
511 | |
512 | |
513 | ssize_t |
514 | sctp_sendx(int sd, const void *msg, size_t len, |
515 | struct sockaddr *addrs, int addrcnt, |
516 | struct sctp_sndrcvinfo *sinfo, |
517 | int flags) |
518 | { |
519 | int i, ret, cnt, saved_errno; |
520 | int add_len; |
521 | struct sockaddr *at; |
522 | struct sctp_connectx_addrs sca; |
523 | |
524 | len = 0; |
525 | at = addrs; |
526 | cnt = 0; |
527 | /* validate all the addresses and get the size */ |
528 | for (i = 0; i < addrcnt; i++) { |
529 | if (at->sa_family == AF_INET) { |
530 | add_len = sizeof(struct sockaddr_in); |
531 | } else if (at->sa_family == AF_INET6) { |
532 | add_len = sizeof(struct sockaddr_in6); |
533 | } else { |
534 | errno = EINVAL; |
535 | return (-1); |
536 | } |
537 | len += add_len; |
538 | at = (struct sockaddr *)((caddr_t)at + add_len); |
539 | cnt++; |
540 | } |
541 | /* do we have any? */ |
542 | if (cnt == 0) { |
543 | errno = EINVAL; |
544 | return(-1); |
545 | } |
546 | |
547 | sca.cx_num = cnt; |
548 | sca.cx_len = len; |
549 | sca.cx_addrs = addrs; |
550 | ret = ioctl(sd, SIOCCONNECTXDEL, (void *)&sca); |
551 | if (ret != 0) { |
552 | return(ret); |
553 | } |
554 | sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs); |
555 | if (sinfo->sinfo_assoc_id == 0) { |
556 | printf("Huh, can't get associd? TSNH!\n" ); |
557 | (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs, |
558 | (unsigned int)addrs->sa_len); |
559 | errno = ENOENT; |
560 | return (-1); |
561 | } |
562 | ret = sctp_send(sd, msg, len, sinfo, flags); |
563 | saved_errno = errno; |
564 | (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs, |
565 | (unsigned int)addrs->sa_len); |
566 | |
567 | errno = saved_errno; |
568 | return (ret); |
569 | } |
570 | |
571 | ssize_t |
572 | sctp_sendmsgx(int sd, |
573 | const void *msg, |
574 | size_t len, |
575 | struct sockaddr *addrs, |
576 | int addrcnt, |
577 | u_int32_t ppid, |
578 | u_int32_t flags, |
579 | u_int16_t stream_no, |
580 | u_int32_t timetolive, |
581 | u_int32_t context) |
582 | { |
583 | struct sctp_sndrcvinfo sinfo; |
584 | |
585 | memset((void *) &sinfo, 0, sizeof(struct sctp_sndrcvinfo)); |
586 | sinfo.sinfo_ppid = ppid; |
587 | sinfo.sinfo_flags = flags; |
588 | sinfo.sinfo_ssn = stream_no; |
589 | sinfo.sinfo_timetolive = timetolive; |
590 | sinfo.sinfo_context = context; |
591 | return sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0); |
592 | } |
593 | |
594 | ssize_t |
595 | sctp_recvmsg (int s, |
596 | void *dbuf, |
597 | size_t len, |
598 | struct sockaddr *from, |
599 | socklen_t *fromlen, |
600 | struct sctp_sndrcvinfo *sinfo, |
601 | int *msg_flags) |
602 | { |
603 | struct sctp_sndrcvinfo *s_info; |
604 | ssize_t sz; |
605 | struct msghdr msg; |
606 | struct iovec iov[2]; |
607 | char controlVector[2048]; |
608 | struct cmsghdr *cmsg; |
609 | iov[0].iov_base = dbuf; |
610 | iov[0].iov_len = len; |
611 | iov[1].iov_base = NULL; |
612 | iov[1].iov_len = 0; |
613 | msg.msg_name = (caddr_t)from; |
614 | msg.msg_namelen = *fromlen; |
615 | msg.msg_iov = iov; |
616 | msg.msg_iovlen = 1; |
617 | msg.msg_control = (caddr_t)controlVector; |
618 | msg.msg_controllen = sizeof(controlVector); |
619 | errno = 0; |
620 | sz = recvmsg(s, &msg, 0); |
621 | |
622 | s_info = NULL; |
623 | len = sz; |
624 | *msg_flags = msg.msg_flags; |
625 | *fromlen = msg.msg_namelen; |
626 | if ((msg.msg_controllen) && sinfo) { |
627 | /* parse through and see if we find |
628 | * the sctp_sndrcvinfo (if the user wants it). |
629 | */ |
630 | cmsg = (struct cmsghdr *)controlVector; |
631 | while (cmsg) { |
632 | if (cmsg->cmsg_level == IPPROTO_SCTP) { |
633 | if (cmsg->cmsg_type == SCTP_SNDRCV) { |
634 | /* Got it */ |
635 | s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); |
636 | /* Copy it to the user */ |
637 | *sinfo = *s_info; |
638 | break; |
639 | } |
640 | } |
641 | cmsg = CMSG_NXTHDR(&msg, cmsg); |
642 | } |
643 | } |
644 | return(sz); |
645 | } |
646 | |
647 | ssize_t |
648 | sctp_recvv(int sd, |
649 | const struct iovec *iov, |
650 | int iovlen, |
651 | struct sockaddr *from, |
652 | socklen_t * fromlen, |
653 | void *info, |
654 | socklen_t * infolen, |
655 | unsigned int *infotype, |
656 | int *flags) |
657 | { |
658 | char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV]; |
659 | struct msghdr msg; |
660 | struct cmsghdr *cmsg; |
661 | ssize_t ret; |
662 | struct sctp_rcvinfo *rcvinfo; |
663 | struct sctp_nxtinfo *nxtinfo; |
664 | |
665 | if (((info != NULL) && (infolen == NULL)) || |
666 | ((info == NULL) && (infolen != NULL) && (*infolen != 0)) || |
667 | ((info != NULL) && (infotype == NULL))) { |
668 | errno = EINVAL; |
669 | return (-1); |
670 | } |
671 | if (infotype) { |
672 | *infotype = SCTP_RECVV_NOINFO; |
673 | } |
674 | msg.msg_name = from; |
675 | if (fromlen == NULL) { |
676 | msg.msg_namelen = 0; |
677 | } else { |
678 | msg.msg_namelen = *fromlen; |
679 | } |
680 | msg.msg_iov = __UNCONST(iov); |
681 | msg.msg_iovlen = iovlen; |
682 | msg.msg_control = cmsgbuf; |
683 | msg.msg_controllen = sizeof(cmsgbuf); |
684 | msg.msg_flags = 0; |
685 | ret = recvmsg(sd, &msg, *flags); |
686 | *flags = msg.msg_flags; |
687 | if ((ret > 0) && |
688 | (msg.msg_controllen > 0) && |
689 | (infotype != NULL) && |
690 | (infolen != NULL) && |
691 | (*infolen > 0)) { |
692 | rcvinfo = NULL; |
693 | nxtinfo = NULL; |
694 | for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { |
695 | if (cmsg->cmsg_level != IPPROTO_SCTP) { |
696 | continue; |
697 | } |
698 | if (cmsg->cmsg_type == SCTP_RCVINFO) { |
699 | rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg); |
700 | if (nxtinfo != NULL) { |
701 | break; |
702 | } else { |
703 | continue; |
704 | } |
705 | } |
706 | if (cmsg->cmsg_type == SCTP_NXTINFO) { |
707 | nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg); |
708 | if (rcvinfo != NULL) { |
709 | break; |
710 | } else { |
711 | continue; |
712 | } |
713 | } |
714 | } |
715 | if (rcvinfo != NULL) { |
716 | if ((nxtinfo != NULL) && (*infolen >= sizeof(struct sctp_recvv_rn))) { |
717 | struct sctp_recvv_rn *rn_info; |
718 | |
719 | rn_info = (struct sctp_recvv_rn *)info; |
720 | rn_info->recvv_rcvinfo = *rcvinfo; |
721 | rn_info->recvv_nxtinfo = *nxtinfo; |
722 | *infolen = (socklen_t) sizeof(struct sctp_recvv_rn); |
723 | *infotype = SCTP_RECVV_RN; |
724 | } else if (*infolen >= sizeof(struct sctp_rcvinfo)) { |
725 | memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo)); |
726 | *infolen = (socklen_t) sizeof(struct sctp_rcvinfo); |
727 | *infotype = SCTP_RECVV_RCVINFO; |
728 | } |
729 | } else if (nxtinfo != NULL) { |
730 | if (*infolen >= sizeof(struct sctp_nxtinfo)) { |
731 | memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo)); |
732 | *infolen = (socklen_t) sizeof(struct sctp_nxtinfo); |
733 | *infotype = SCTP_RECVV_NXTINFO; |
734 | } |
735 | } |
736 | } |
737 | return (ret); |
738 | } |
739 | |
740 | ssize_t |
741 | sctp_sendv(int sd, |
742 | const struct iovec *iov, int iovcnt, |
743 | struct sockaddr *addrs, int addrcnt, |
744 | void *info, socklen_t infolen, unsigned int infotype, |
745 | int flags) |
746 | { |
747 | ssize_t ret; |
748 | int i; |
749 | socklen_t addr_len; |
750 | struct msghdr msg; |
751 | in_port_t port; |
752 | struct sctp_sendv_spa *spa_info; |
753 | struct cmsghdr *cmsg; |
754 | char *cmsgbuf; |
755 | struct sockaddr *addr; |
756 | struct sockaddr_in *addr_in; |
757 | struct sockaddr_in6 *addr_in6; |
758 | void *assoc_id_ptr; |
759 | sctp_assoc_t assoc_id; |
760 | |
761 | if ((addrcnt < 0) || |
762 | (iovcnt < 0) || |
763 | ((addrs == NULL) && (addrcnt > 0)) || |
764 | ((addrs != NULL) && (addrcnt == 0)) || |
765 | ((iov == NULL) && (iovcnt > 0)) || |
766 | ((iov != NULL) && (iovcnt == 0))) { |
767 | errno = EINVAL; |
768 | return (-1); |
769 | } |
770 | cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) + |
771 | CMSG_SPACE(sizeof(struct sctp_prinfo)) + |
772 | CMSG_SPACE(sizeof(struct sctp_authinfo)) + |
773 | (size_t)addrcnt * CMSG_SPACE(sizeof(struct in6_addr))); |
774 | if (cmsgbuf == NULL) { |
775 | errno = ENOMEM; |
776 | return (-1); |
777 | } |
778 | assoc_id_ptr = NULL; |
779 | msg.msg_control = cmsgbuf; |
780 | msg.msg_controllen = 0; |
781 | cmsg = (struct cmsghdr *)cmsgbuf; |
782 | switch (infotype) { |
783 | case SCTP_SENDV_NOINFO: |
784 | if ((infolen != 0) || (info != NULL)) { |
785 | free(cmsgbuf); |
786 | errno = EINVAL; |
787 | return (-1); |
788 | } |
789 | break; |
790 | case SCTP_SENDV_SNDINFO: |
791 | if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) { |
792 | free(cmsgbuf); |
793 | errno = EINVAL; |
794 | return (-1); |
795 | } |
796 | cmsg->cmsg_level = IPPROTO_SCTP; |
797 | cmsg->cmsg_type = SCTP_SNDINFO; |
798 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); |
799 | memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo)); |
800 | msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); |
801 | cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); |
802 | assoc_id_ptr = &(((struct sctp_sndinfo *)info)->snd_assoc_id); |
803 | break; |
804 | case SCTP_SENDV_PRINFO: |
805 | if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) { |
806 | free(cmsgbuf); |
807 | errno = EINVAL; |
808 | return (-1); |
809 | } |
810 | cmsg->cmsg_level = IPPROTO_SCTP; |
811 | cmsg->cmsg_type = SCTP_PRINFO; |
812 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); |
813 | memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo)); |
814 | msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); |
815 | cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo))); |
816 | break; |
817 | case SCTP_SENDV_AUTHINFO: |
818 | if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) { |
819 | free(cmsgbuf); |
820 | errno = EINVAL; |
821 | return (-1); |
822 | } |
823 | cmsg->cmsg_level = IPPROTO_SCTP; |
824 | cmsg->cmsg_type = SCTP_AUTHINFO; |
825 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo)); |
826 | memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo)); |
827 | msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo)); |
828 | cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo))); |
829 | break; |
830 | case SCTP_SENDV_SPA: |
831 | if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) { |
832 | free(cmsgbuf); |
833 | errno = EINVAL; |
834 | return (-1); |
835 | } |
836 | spa_info = (struct sctp_sendv_spa *)info; |
837 | if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) { |
838 | cmsg->cmsg_level = IPPROTO_SCTP; |
839 | cmsg->cmsg_type = SCTP_SNDINFO; |
840 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); |
841 | memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo)); |
842 | msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); |
843 | cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); |
844 | assoc_id_ptr = &(spa_info->sendv_sndinfo.snd_assoc_id); |
845 | } |
846 | if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) { |
847 | cmsg->cmsg_level = IPPROTO_SCTP; |
848 | cmsg->cmsg_type = SCTP_PRINFO; |
849 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); |
850 | memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo)); |
851 | msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); |
852 | cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo))); |
853 | } |
854 | if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) { |
855 | cmsg->cmsg_level = IPPROTO_SCTP; |
856 | cmsg->cmsg_type = SCTP_AUTHINFO; |
857 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo)); |
858 | memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo)); |
859 | msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo)); |
860 | cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo))); |
861 | } |
862 | break; |
863 | default: |
864 | free(cmsgbuf); |
865 | errno = EINVAL; |
866 | return (-1); |
867 | } |
868 | addr = addrs; |
869 | msg.msg_name = NULL; |
870 | msg.msg_namelen = 0; |
871 | |
872 | for (i = 0; i < addrcnt; i++) { |
873 | switch (addr->sa_family) { |
874 | case AF_INET: |
875 | addr_len = (socklen_t) sizeof(struct sockaddr_in); |
876 | addr_in = (struct sockaddr_in *)addr; |
877 | if (addr_in->sin_len != addr_len) { |
878 | free(cmsgbuf); |
879 | errno = EINVAL; |
880 | return (-1); |
881 | } |
882 | if (i == 0) { |
883 | port = addr_in->sin_port; |
884 | } else { |
885 | if (port == addr_in->sin_port) { |
886 | cmsg->cmsg_level = IPPROTO_SCTP; |
887 | cmsg->cmsg_type = SCTP_DSTADDRV4; |
888 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); |
889 | memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr)); |
890 | msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr)); |
891 | cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr))); |
892 | } else { |
893 | free(cmsgbuf); |
894 | errno = EINVAL; |
895 | return (-1); |
896 | } |
897 | } |
898 | break; |
899 | case AF_INET6: |
900 | addr_len = (socklen_t) sizeof(struct sockaddr_in6); |
901 | addr_in6 = (struct sockaddr_in6 *)addr; |
902 | if (addr_in6->sin6_len != addr_len) { |
903 | free(cmsgbuf); |
904 | errno = EINVAL; |
905 | return (-1); |
906 | } |
907 | if (i == 0) { |
908 | port = addr_in6->sin6_port; |
909 | } else { |
910 | if (port == addr_in6->sin6_port) { |
911 | cmsg->cmsg_level = IPPROTO_SCTP; |
912 | cmsg->cmsg_type = SCTP_DSTADDRV6; |
913 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr)); |
914 | memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr)); |
915 | msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr)); |
916 | cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr))); |
917 | } else { |
918 | free(cmsgbuf); |
919 | errno = EINVAL; |
920 | return (-1); |
921 | } |
922 | } |
923 | break; |
924 | default: |
925 | free(cmsgbuf); |
926 | errno = EINVAL; |
927 | return (-1); |
928 | } |
929 | if (i == 0) { |
930 | msg.msg_name = addr; |
931 | msg.msg_namelen = addr_len; |
932 | } |
933 | addr = (struct sockaddr *)((caddr_t)addr + addr_len); |
934 | } |
935 | if (msg.msg_controllen == 0) { |
936 | msg.msg_control = NULL; |
937 | } |
938 | msg.msg_iov = __UNCONST(iov); |
939 | msg.msg_iovlen = iovcnt; |
940 | msg.msg_flags = 0; |
941 | ret = sendmsg(sd, &msg, flags); |
942 | free(cmsgbuf); |
943 | if ((ret >= 0) && (addrs != NULL) && (assoc_id_ptr != NULL)) { |
944 | assoc_id = sctp_getassocid(sd, addrs); |
945 | memcpy(assoc_id_ptr, &assoc_id, sizeof(assoc_id)); |
946 | } |
947 | return (ret); |
948 | } |
949 | |
950 | int |
951 | sctp_peeloff(int sd, sctp_assoc_t assoc_id) |
952 | { |
953 | int ret; |
954 | uint32_t val; |
955 | |
956 | val = assoc_id; |
957 | ret = ioctl(sd, SIOCPEELOFF, &val); |
958 | if (ret == -1) |
959 | return ret; |
960 | else |
961 | return (int) val; |
962 | } |
963 | |
964 | |