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
SCTPPrintAnAddress(struct sockaddr * a)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
in6_sin6_2_sin(struct sockaddr_in * sin,struct sockaddr_in6 * sin6)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
sctp_connectx(int sd,struct sockaddr * addrs,int addrcnt,sctp_assoc_t * id)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
sctp_bindx(int sd,struct sockaddr * addrs,int addrcnt,int flags)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
sctp_opt_info(int sd,sctp_assoc_t id,int opt,void * arg,socklen_t * size)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
sctp_getpaddrs(int sd,sctp_assoc_t id,struct sockaddr ** raddrs)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
sctp_freepaddrs(struct sockaddr * addrs)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
sctp_getladdrs(int sd,sctp_assoc_t id,struct sockaddr ** raddrs)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
sctp_freeladdrs(struct sockaddr * addrs)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
sctp_sendmsg(int s,const void * data,size_t len,const struct sockaddr * to,socklen_t tolen,u_int32_t ppid,u_int32_t flags,u_int16_t stream_no,u_int32_t timetolive,u_int32_t context)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
sctp_getassocid(int sd,struct sockaddr * sa)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
sctp_send(int sd,const void * data,size_t len,const struct sctp_sndrcvinfo * sinfo,int flags)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
sctp_sendx(int sd,const void * msg,size_t len,struct sockaddr * addrs,int addrcnt,struct sctp_sndrcvinfo * sinfo,int flags)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
sctp_sendmsgx(int sd,const void * msg,size_t len,struct sockaddr * addrs,int addrcnt,u_int32_t ppid,u_int32_t flags,u_int16_t stream_no,u_int32_t timetolive,u_int32_t context)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
sctp_recvmsg(int s,void * dbuf,size_t len,struct sockaddr * from,socklen_t * fromlen,struct sctp_sndrcvinfo * sinfo,int * msg_flags)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
sctp_recvv(int sd,const struct iovec * iov,int iovlen,struct sockaddr * from,socklen_t * fromlen,void * info,socklen_t * infolen,unsigned int * infotype,int * flags)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
sctp_sendv(int sd,const struct iovec * iov,int iovcnt,struct sockaddr * addrs,int addrcnt,void * info,socklen_t infolen,unsigned int infotype,int flags)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
sctp_peeloff(int sd,sctp_assoc_t assoc_id)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