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.2 2024/01/20 14:52:48 christos 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 *)(void *)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 = (int)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 *)(void *)&addrs[i])->sin_port = ((struct sockaddr_in *)(void *)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           socklen_t 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 = (socklen_t)(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           ssize_t 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 *)(void *)&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           ssize_t 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, cnt, saved_errno;
520           ssize_t ret;
521           int add_len;
522           struct sockaddr *at;
523           struct sctp_connectx_addrs sca;
524 
525           len = 0;
526           at = addrs;
527           cnt = 0;
528           /* validate all the addresses and get the size */
529           for (i = 0; i < addrcnt; i++) {
530                     if (at->sa_family == AF_INET) {
531                               add_len = sizeof(struct sockaddr_in);
532                     } else if (at->sa_family == AF_INET6) {
533                               add_len = sizeof(struct sockaddr_in6);
534                     } else {
535                               errno = EINVAL;
536                               return (-1);
537                     }
538                     len += add_len;
539                     at = (struct sockaddr *)((caddr_t)at + add_len);
540                     cnt++;
541           }
542           /* do we have any? */
543           if (cnt == 0) {
544                     errno = EINVAL;
545                     return(-1);
546           }
547 
548           sca.cx_num = cnt;
549           sca.cx_len = (int)len;
550           sca.cx_addrs = addrs;
551           ret = ioctl(sd, SIOCCONNECTXDEL, (void *)&sca);
552           if (ret != 0) {
553                     return(ret);
554           }
555           sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs);
556           if (sinfo->sinfo_assoc_id == 0) {
557                     printf("Huh, can't get associd? TSNH!\n");
558                     (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
559                                          (unsigned int)addrs->sa_len);
560                     errno = ENOENT;
561                     return (-1);
562           }
563           ret = sctp_send(sd, msg, len, sinfo, flags);
564           saved_errno = errno;
565           (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
566                                (unsigned int)addrs->sa_len);
567 
568           errno = saved_errno;
569           return (ret);
570 }
571 
572 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)573 sctp_sendmsgx(int sd,
574                 const void *msg,
575                 size_t len,
576                 struct sockaddr *addrs,
577                 int addrcnt,
578                 u_int32_t ppid,
579                 u_int32_t flags,
580                 u_int16_t stream_no,
581                 u_int32_t timetolive,
582                 u_int32_t context)
583 {
584           struct sctp_sndrcvinfo sinfo;
585 
586           memset((void *) &sinfo, 0, sizeof(struct sctp_sndrcvinfo));
587           sinfo.sinfo_ppid       = ppid;
588           sinfo.sinfo_flags      = flags;
589           sinfo.sinfo_ssn        = stream_no;
590           sinfo.sinfo_timetolive = timetolive;
591           sinfo.sinfo_context    = context;
592           return sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0);
593 }
594 
595 ssize_t
sctp_recvmsg(int s,void * dbuf,size_t len,struct sockaddr * from,socklen_t * fromlen,struct sctp_sndrcvinfo * sinfo,int * msg_flags)596 sctp_recvmsg (int s,
597                 void *dbuf,
598                 size_t len,
599                 struct sockaddr *from,
600                 socklen_t *fromlen,
601                 struct sctp_sndrcvinfo *sinfo,
602                 int *msg_flags)
603 {
604           struct sctp_sndrcvinfo *s_info;
605           ssize_t sz;
606           struct msghdr msg;
607           struct iovec iov[2];
608           char controlVector[2048];
609           struct cmsghdr *cmsg;
610           iov[0].iov_base = dbuf;
611           iov[0].iov_len = len;
612           iov[1].iov_base = NULL;
613           iov[1].iov_len = 0;
614           msg.msg_name = (caddr_t)from;
615           msg.msg_namelen = *fromlen;
616           msg.msg_iov = iov;
617           msg.msg_iovlen = 1;
618           msg.msg_control = (caddr_t)controlVector;
619           msg.msg_controllen = sizeof(controlVector);
620           errno = 0;
621           sz = recvmsg(s, &msg, 0);
622 
623           s_info = NULL;
624           len = sz;
625           *msg_flags = msg.msg_flags;
626           *fromlen = msg.msg_namelen;
627           if ((msg.msg_controllen) && sinfo) {
628                     /* parse through and see if we find
629                      * the sctp_sndrcvinfo (if the user wants it).
630                      */
631                     cmsg = (struct cmsghdr *)controlVector;
632                     while (cmsg) {
633                               if (cmsg->cmsg_level == IPPROTO_SCTP) {
634                                         if (cmsg->cmsg_type == SCTP_SNDRCV) {
635                                                   /* Got it */
636                                                   s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
637                                                   /* Copy it to the user */
638                                                   *sinfo = *s_info;
639                                                   break;
640                                         }
641                               }
642                               cmsg = CMSG_NXTHDR(&msg, cmsg);
643                     }
644           }
645           return(sz);
646 }
647 
648 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)649 sctp_recvv(int sd,
650     const struct iovec *iov,
651     int iovlen,
652     struct sockaddr *from,
653     socklen_t * fromlen,
654     void *info,
655     socklen_t * infolen,
656     unsigned int *infotype,
657     int *flags)
658 {
659           char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV];
660           struct msghdr msg;
661           struct cmsghdr *cmsg;
662           ssize_t ret;
663           struct sctp_rcvinfo *rcvinfo;
664           struct sctp_nxtinfo *nxtinfo;
665 
666           if (((info != NULL) && (infolen == NULL)) ||
667               ((info == NULL) && (infolen != NULL) && (*infolen != 0)) ||
668               ((info != NULL) && (infotype == NULL))) {
669                     errno = EINVAL;
670                     return (-1);
671           }
672           if (infotype) {
673                     *infotype = SCTP_RECVV_NOINFO;
674           }
675           msg.msg_name = from;
676           if (fromlen == NULL) {
677                     msg.msg_namelen = 0;
678           } else {
679                     msg.msg_namelen = *fromlen;
680           }
681           msg.msg_iov = __UNCONST(iov);
682           msg.msg_iovlen = iovlen;
683           msg.msg_control = cmsgbuf;
684           msg.msg_controllen = sizeof(cmsgbuf);
685           msg.msg_flags = 0;
686           ret = recvmsg(sd, &msg, *flags);
687           *flags = msg.msg_flags;
688           if ((ret > 0) &&
689               (msg.msg_controllen > 0) &&
690               (infotype != NULL) &&
691               (infolen != NULL) &&
692               (*infolen > 0)) {
693                     rcvinfo = NULL;
694                     nxtinfo = NULL;
695                     for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
696                               if (cmsg->cmsg_level != IPPROTO_SCTP) {
697                                         continue;
698                               }
699                               if (cmsg->cmsg_type == SCTP_RCVINFO) {
700                                         rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg);
701                                         if (nxtinfo != NULL) {
702                                                   break;
703                                         } else {
704                                                   continue;
705                                         }
706                               }
707                               if (cmsg->cmsg_type == SCTP_NXTINFO) {
708                                         nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg);
709                                         if (rcvinfo != NULL) {
710                                                   break;
711                                         } else {
712                                                   continue;
713                                         }
714                               }
715                     }
716                     if (rcvinfo != NULL) {
717                               if ((nxtinfo != NULL) && (*infolen >= sizeof(struct sctp_recvv_rn))) {
718                                         struct sctp_recvv_rn *rn_info;
719 
720                                         rn_info = (struct sctp_recvv_rn *)info;
721                                         rn_info->recvv_rcvinfo = *rcvinfo;
722                                         rn_info->recvv_nxtinfo = *nxtinfo;
723                                         *infolen = (socklen_t) sizeof(struct sctp_recvv_rn);
724                                         *infotype = SCTP_RECVV_RN;
725                               } else if (*infolen >= sizeof(struct sctp_rcvinfo)) {
726                                         memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo));
727                                         *infolen = (socklen_t) sizeof(struct sctp_rcvinfo);
728                                         *infotype = SCTP_RECVV_RCVINFO;
729                               }
730                     } else if (nxtinfo != NULL) {
731                               if (*infolen >= sizeof(struct sctp_nxtinfo)) {
732                                         memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo));
733                                         *infolen = (socklen_t) sizeof(struct sctp_nxtinfo);
734                                         *infotype = SCTP_RECVV_NXTINFO;
735                               }
736                     }
737           }
738           return (ret);
739 }
740 
741 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)742 sctp_sendv(int sd,
743     const struct iovec *iov, int iovcnt,
744     struct sockaddr *addrs, int addrcnt,
745     void *info, socklen_t infolen, unsigned int infotype,
746     int flags)
747 {
748           ssize_t ret;
749           int i;
750           socklen_t addr_len;
751           struct msghdr msg;
752           in_port_t port;
753           struct sctp_sendv_spa *spa_info;
754           struct cmsghdr *cmsg;
755           char *cmsgbuf;
756           struct sockaddr *addr;
757           struct sockaddr_in *addr_in;
758           struct sockaddr_in6 *addr_in6;
759           void *assoc_id_ptr;
760           sctp_assoc_t assoc_id;
761 
762           if ((addrcnt < 0) ||
763               (iovcnt < 0) ||
764               ((addrs == NULL) && (addrcnt > 0)) ||
765               ((addrs != NULL) && (addrcnt == 0)) ||
766               ((iov == NULL) && (iovcnt > 0)) ||
767               ((iov != NULL) && (iovcnt == 0))) {
768                     errno = EINVAL;
769                     return (-1);
770           }
771           cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) +
772               CMSG_SPACE(sizeof(struct sctp_prinfo)) +
773               CMSG_SPACE(sizeof(struct sctp_authinfo)) +
774               (size_t)addrcnt * CMSG_SPACE(sizeof(struct in6_addr)));
775           if (cmsgbuf == NULL) {
776                     errno = ENOMEM;
777                     return (-1);
778           }
779           assoc_id_ptr = NULL;
780           msg.msg_control = cmsgbuf;
781           msg.msg_controllen = 0;
782           cmsg = (struct cmsghdr *)cmsgbuf;
783           switch (infotype) {
784           case SCTP_SENDV_NOINFO:
785                     if ((infolen != 0) || (info != NULL)) {
786                               free(cmsgbuf);
787                               errno = EINVAL;
788                               return (-1);
789                     }
790                     break;
791           case SCTP_SENDV_SNDINFO:
792                     if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) {
793                               free(cmsgbuf);
794                               errno = EINVAL;
795                               return (-1);
796                     }
797                     cmsg->cmsg_level = IPPROTO_SCTP;
798                     cmsg->cmsg_type = SCTP_SNDINFO;
799                     cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
800                     memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo));
801                     msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
802                     cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
803                     assoc_id_ptr = &(((struct sctp_sndinfo *)info)->snd_assoc_id);
804                     break;
805           case SCTP_SENDV_PRINFO:
806                     if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) {
807                               free(cmsgbuf);
808                               errno = EINVAL;
809                               return (-1);
810                     }
811                     cmsg->cmsg_level = IPPROTO_SCTP;
812                     cmsg->cmsg_type = SCTP_PRINFO;
813                     cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
814                     memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo));
815                     msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
816                     cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
817                     break;
818           case SCTP_SENDV_AUTHINFO:
819                     if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) {
820                               free(cmsgbuf);
821                               errno = EINVAL;
822                               return (-1);
823                     }
824                     cmsg->cmsg_level = IPPROTO_SCTP;
825                     cmsg->cmsg_type = SCTP_AUTHINFO;
826                     cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
827                     memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo));
828                     msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
829                     cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
830                     break;
831           case SCTP_SENDV_SPA:
832                     if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) {
833                               free(cmsgbuf);
834                               errno = EINVAL;
835                               return (-1);
836                     }
837                     spa_info = (struct sctp_sendv_spa *)info;
838                     if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) {
839                               cmsg->cmsg_level = IPPROTO_SCTP;
840                               cmsg->cmsg_type = SCTP_SNDINFO;
841                               cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
842                               memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo));
843                               msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
844                               cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
845                               assoc_id_ptr = &(spa_info->sendv_sndinfo.snd_assoc_id);
846                     }
847                     if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) {
848                               cmsg->cmsg_level = IPPROTO_SCTP;
849                               cmsg->cmsg_type = SCTP_PRINFO;
850                               cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
851                               memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo));
852                               msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
853                               cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
854                     }
855                     if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) {
856                               cmsg->cmsg_level = IPPROTO_SCTP;
857                               cmsg->cmsg_type = SCTP_AUTHINFO;
858                               cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
859                               memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo));
860                               msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
861                               cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
862                     }
863                     break;
864           default:
865                     free(cmsgbuf);
866                     errno = EINVAL;
867                     return (-1);
868           }
869           addr = addrs;
870           msg.msg_name = NULL;
871           msg.msg_namelen = 0;
872 
873           for (i = 0; i < addrcnt; i++) {
874                     switch (addr->sa_family) {
875                     case AF_INET:
876                               addr_len = (socklen_t) sizeof(struct sockaddr_in);
877                               addr_in = (struct sockaddr_in *)(void *)addr;
878                               if (addr_in->sin_len != addr_len) {
879                                         free(cmsgbuf);
880                                         errno = EINVAL;
881                                         return (-1);
882                               }
883                               if (i == 0) {
884                                         port = addr_in->sin_port;
885                               } else {
886                                         if (port == addr_in->sin_port) {
887                                                   cmsg->cmsg_level = IPPROTO_SCTP;
888                                                   cmsg->cmsg_type = SCTP_DSTADDRV4;
889                                                   cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
890                                                   memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr));
891                                                   msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr));
892                                                   cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr)));
893                                         } else {
894                                                   free(cmsgbuf);
895                                                   errno = EINVAL;
896                                                   return (-1);
897                                         }
898                               }
899                               break;
900                     case AF_INET6:
901                               addr_len = (socklen_t) sizeof(struct sockaddr_in6);
902                               addr_in6 = (struct sockaddr_in6 *)(void *)addr;
903                               if (addr_in6->sin6_len != addr_len) {
904                                         free(cmsgbuf);
905                                         errno = EINVAL;
906                                         return (-1);
907                               }
908                               if (i == 0) {
909                                         port = addr_in6->sin6_port;
910                               } else {
911                                         if (port == addr_in6->sin6_port) {
912                                                   cmsg->cmsg_level = IPPROTO_SCTP;
913                                                   cmsg->cmsg_type = SCTP_DSTADDRV6;
914                                                   cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr));
915                                                   memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr));
916                                                   msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr));
917                                                   cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr)));
918                                         } else {
919                                                   free(cmsgbuf);
920                                                   errno = EINVAL;
921                                                   return (-1);
922                                         }
923                               }
924                               break;
925                     default:
926                               free(cmsgbuf);
927                               errno = EINVAL;
928                               return (-1);
929                     }
930                     if (i == 0) {
931                               msg.msg_name = addr;
932                               msg.msg_namelen = addr_len;
933                     }
934                     addr = (struct sockaddr *)((caddr_t)addr + addr_len);
935           }
936           if (msg.msg_controllen == 0) {
937                     msg.msg_control = NULL;
938           }
939           msg.msg_iov = __UNCONST(iov);
940           msg.msg_iovlen = iovcnt;
941           msg.msg_flags = 0;
942           ret = sendmsg(sd, &msg, flags);
943           free(cmsgbuf);
944           if ((ret >= 0) && (addrs != NULL) && (assoc_id_ptr != NULL)) {
945                     assoc_id = sctp_getassocid(sd, addrs);
946                     memcpy(assoc_id_ptr, &assoc_id, sizeof(assoc_id));
947           }
948           return (ret);
949 }
950 
951 int
sctp_peeloff(int sd,sctp_assoc_t assoc_id)952 sctp_peeloff(int sd, sctp_assoc_t assoc_id)
953 {
954           int ret;
955           uint32_t val;
956 
957           val = assoc_id;
958           ret = ioctl(sd, SIOCPEELOFF, &val);
959           if (ret == -1)
960                     return ret;
961           else
962                     return (int) val;
963 }
964 
965