]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - lib/libc/net/sctp_sys_calls.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / lib / libc / net / sctp_sys_calls.c
1 /*-
2  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
3  * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved.
4  * Copyright (c) 2008-2011, by Michael Tuexen. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * a) Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  *
12  * b) Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in
14  *    the documentation and/or other materials provided with the distribution.
15  *
16  * c) Neither the name of Cisco Systems, Inc. nor the names of its
17  *    contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30  * THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35 #include <stdio.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/errno.h>
43 #include <sys/syscall.h>
44 #include <sys/uio.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <netinet/sctp_uio.h>
48 #include <netinet/sctp.h>
49
50 #include <net/if_dl.h>
51
52 #ifndef IN6_IS_ADDR_V4MAPPED
53 #define IN6_IS_ADDR_V4MAPPED(a)               \
54         ((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == 0) &&  \
55          (*(const uint32_t *)(const void *)(&(a)->s6_addr[4]) == 0) &&  \
56          (*(const uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff)))
57 #endif
58
59
60 #define SCTP_CONTROL_VEC_SIZE_SND   8192
61 #define SCTP_CONTROL_VEC_SIZE_RCV  16384
62 #define SCTP_STACK_BUF_SIZE         2048
63
64 #ifdef SCTP_DEBUG_PRINT_ADDRESS
65
66 #define SCTP_STRING_BUF_SZ 256
67
68 static void
69 SCTPPrintAnAddress(struct sockaddr *a)
70 {
71         char stringToPrint[SCTP_STRING_BUF_SZ];
72         u_short prt;
73         char *srcaddr, *txt;
74
75         if (a == NULL) {
76                 printf("NULL\n");
77                 return;
78         }
79         if (a->sa_family == AF_INET) {
80                 srcaddr = (char *)&((struct sockaddr_in *)a)->sin_addr;
81                 txt = "IPv4 Address: ";
82                 prt = ntohs(((struct sockaddr_in *)a)->sin_port);
83         } else if (a->sa_family == AF_INET6) {
84                 srcaddr = (char *)&((struct sockaddr_in6 *)a)->sin6_addr;
85                 prt = ntohs(((struct sockaddr_in6 *)a)->sin6_port);
86                 txt = "IPv6 Address: ";
87         } else if (a->sa_family == AF_LINK) {
88                 int i;
89                 char tbuf[SCTP_STRING_BUF_SZ];
90                 u_char adbuf[SCTP_STRING_BUF_SZ];
91                 struct sockaddr_dl *dl;
92
93                 dl = (struct sockaddr_dl *)a;
94                 strncpy(tbuf, dl->sdl_data, dl->sdl_nlen);
95                 tbuf[dl->sdl_nlen] = 0;
96                 printf("Intf:%s (len:%d)Interface index:%d type:%x(%d) ll-len:%d ",
97                     tbuf,
98                     dl->sdl_nlen,
99                     dl->sdl_index,
100                     dl->sdl_type,
101                     dl->sdl_type,
102                     dl->sdl_alen
103                     );
104                 memcpy(adbuf, LLADDR(dl), dl->sdl_alen);
105                 for (i = 0; i < dl->sdl_alen; i++) {
106                         printf("%2.2x", adbuf[i]);
107                         if (i < (dl->sdl_alen - 1))
108                                 printf(":");
109                 }
110                 printf("\n");
111                 return;
112         } else {
113                 return;
114         }
115         if (inet_ntop(a->sa_family, srcaddr, stringToPrint, sizeof(stringToPrint))) {
116                 if (a->sa_family == AF_INET6) {
117                         printf("%s%s:%d scope:%d\n",
118                             txt, stringToPrint, prt,
119                             ((struct sockaddr_in6 *)a)->sin6_scope_id);
120                 } else {
121                         printf("%s%s:%d\n", txt, stringToPrint, prt);
122                 }
123
124         } else {
125                 printf("%s unprintable?\n", txt);
126         }
127 }
128
129 #endif                          /* SCTP_DEBUG_PRINT_ADDRESS */
130
131 static void
132 in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
133 {
134         bzero(sin, sizeof(*sin));
135         sin->sin_len = sizeof(struct sockaddr_in);
136         sin->sin_family = AF_INET;
137         sin->sin_port = sin6->sin6_port;
138         sin->sin_addr.s_addr = sin6->sin6_addr.__u6_addr.__u6_addr32[3];
139 }
140
141 int
142 sctp_getaddrlen(sa_family_t family)
143 {
144         int ret, sd;
145         socklen_t siz;
146         struct sctp_assoc_value av;
147
148         av.assoc_value = family;
149         siz = sizeof(av);
150 #if defined(AF_INET)
151         sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
152 #elif defined(AF_INET6)
153         sd = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP);
154 #else
155         sd = -1;
156 #endif
157         if (sd == -1) {
158                 return (-1);
159         }
160         ret = getsockopt(sd, IPPROTO_SCTP, SCTP_GET_ADDR_LEN, &av, &siz);
161         close(sd);
162         if (ret == 0) {
163                 return ((int)av.assoc_value);
164         } else {
165                 return (-1);
166         }
167 }
168
169 int
170 sctp_connectx(int sd, const struct sockaddr *addrs, int addrcnt,
171     sctp_assoc_t * id)
172 {
173         char buf[SCTP_STACK_BUF_SIZE];
174         int i, ret, cnt, *aa;
175         char *cpto;
176         const struct sockaddr *at;
177         sctp_assoc_t *p_id;
178         size_t len = sizeof(int);
179
180         /* validate the address count and list */
181         if ((addrs == NULL) || (addrcnt <= 0)) {
182                 errno = EINVAL;
183                 return (-1);
184         }
185         at = addrs;
186         cnt = 0;
187         cpto = ((caddr_t)buf + sizeof(int));
188         /* validate all the addresses and get the size */
189         for (i = 0; i < addrcnt; i++) {
190                 if (at->sa_family == AF_INET) {
191                         if (at->sa_len != sizeof(struct sockaddr_in)) {
192                                 errno = EINVAL;
193                                 return (-1);
194                         }
195                         memcpy(cpto, at, at->sa_len);
196                         cpto = ((caddr_t)cpto + at->sa_len);
197                         len += at->sa_len;
198                 } else if (at->sa_family == AF_INET6) {
199                         if (at->sa_len != sizeof(struct sockaddr_in6)) {
200                                 errno = EINVAL;
201                                 return (-1);
202                         }
203                         if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)at)->sin6_addr)) {
204                                 len += sizeof(struct sockaddr_in);
205                                 in6_sin6_2_sin((struct sockaddr_in *)cpto, (struct sockaddr_in6 *)at);
206                                 cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in));
207                                 len += sizeof(struct sockaddr_in);
208                         } else {
209                                 memcpy(cpto, at, at->sa_len);
210                                 cpto = ((caddr_t)cpto + at->sa_len);
211                                 len += at->sa_len;
212                         }
213                 } else {
214                         errno = EINVAL;
215                         return (-1);
216                 }
217                 if (len > (sizeof(buf) - sizeof(int))) {
218                         /* Never enough memory */
219                         errno = E2BIG;
220                         return (-1);
221                 }
222                 at = (struct sockaddr *)((caddr_t)at + at->sa_len);
223                 cnt++;
224         }
225         /* do we have any? */
226         if (cnt == 0) {
227                 errno = EINVAL;
228                 return (-1);
229         }
230         aa = (int *)buf;
231         *aa = cnt;
232         ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X, (void *)buf,
233             (socklen_t) len);
234         if ((ret == 0) && id) {
235                 p_id = (sctp_assoc_t *) buf;
236                 *id = *p_id;
237         }
238         return (ret);
239 }
240
241 int
242 sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags)
243 {
244         struct sctp_getaddresses *gaddrs;
245         struct sockaddr *sa;
246         struct sockaddr_in *sin;
247         struct sockaddr_in6 *sin6;
248         int i, sz, argsz;
249         uint16_t sport = 0;
250
251         /* validate the flags */
252         if ((flags != SCTP_BINDX_ADD_ADDR) &&
253             (flags != SCTP_BINDX_REM_ADDR)) {
254                 errno = EFAULT;
255                 return (-1);
256         }
257         /* validate the address count and list */
258         if ((addrcnt <= 0) || (addrs == NULL)) {
259                 errno = EINVAL;
260                 return (-1);
261         }
262         argsz = (sizeof(struct sockaddr_storage) +
263             sizeof(struct sctp_getaddresses));
264         gaddrs = (struct sctp_getaddresses *)calloc(1, argsz);
265         if (gaddrs == NULL) {
266                 errno = ENOMEM;
267                 return (-1);
268         }
269         /* First pre-screen the addresses */
270         sa = addrs;
271         for (i = 0; i < addrcnt; i++) {
272                 sz = sa->sa_len;
273                 if (sa->sa_family == AF_INET) {
274                         if (sa->sa_len != sizeof(struct sockaddr_in))
275                                 goto out_error;
276                         sin = (struct sockaddr_in *)sa;
277                         if (sin->sin_port) {
278                                 /* non-zero port, check or save */
279                                 if (sport) {
280                                         /* Check against our port */
281                                         if (sport != sin->sin_port) {
282                                                 goto out_error;
283                                         }
284                                 } else {
285                                         /* save off the port */
286                                         sport = sin->sin_port;
287                                 }
288                         }
289                 } else if (sa->sa_family == AF_INET6) {
290                         if (sa->sa_len != sizeof(struct sockaddr_in6))
291                                 goto out_error;
292                         sin6 = (struct sockaddr_in6 *)sa;
293                         if (sin6->sin6_port) {
294                                 /* non-zero port, check or save */
295                                 if (sport) {
296                                         /* Check against our port */
297                                         if (sport != sin6->sin6_port) {
298                                                 goto out_error;
299                                         }
300                                 } else {
301                                         /* save off the port */
302                                         sport = sin6->sin6_port;
303                                 }
304                         }
305                 } else {
306                         /* invalid address family specified */
307                         goto out_error;
308                 }
309
310                 sa = (struct sockaddr *)((caddr_t)sa + sz);
311         }
312         sa = addrs;
313         /*
314          * Now if there was a port mentioned, assure that the first address
315          * has that port to make sure it fails or succeeds correctly.
316          */
317         if (sport) {
318                 sin = (struct sockaddr_in *)sa;
319                 sin->sin_port = sport;
320         }
321         for (i = 0; i < addrcnt; i++) {
322                 sz = sa->sa_len;
323                 if (sa->sa_family == AF_INET) {
324                         if (sa->sa_len != sizeof(struct sockaddr_in))
325                                 goto out_error;
326                 } else if (sa->sa_family == AF_INET6) {
327                         if (sa->sa_len != sizeof(struct sockaddr_in6))
328                                 goto out_error;
329                 } else {
330                         /* invalid address family specified */
331         out_error:
332                         free(gaddrs);
333                         errno = EINVAL;
334                         return (-1);
335                 }
336                 memset(gaddrs, 0, argsz);
337                 gaddrs->sget_assoc_id = 0;
338                 memcpy(gaddrs->addr, sa, sz);
339                 if (setsockopt(sd, IPPROTO_SCTP, flags, gaddrs,
340                     (socklen_t) argsz) != 0) {
341                         free(gaddrs);
342                         return (-1);
343                 }
344                 sa = (struct sockaddr *)((caddr_t)sa + sz);
345         }
346         free(gaddrs);
347         return (0);
348 }
349
350
351 int
352 sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t * size)
353 {
354         if (arg == NULL) {
355                 errno = EINVAL;
356                 return (-1);
357         }
358         switch (opt) {
359         case SCTP_RTOINFO:
360                 ((struct sctp_rtoinfo *)arg)->srto_assoc_id = id;
361                 break;
362         case SCTP_ASSOCINFO:
363                 ((struct sctp_assocparams *)arg)->sasoc_assoc_id = id;
364                 break;
365         case SCTP_DEFAULT_SEND_PARAM:
366                 ((struct sctp_assocparams *)arg)->sasoc_assoc_id = id;
367                 break;
368         case SCTP_PRIMARY_ADDR:
369                 ((struct sctp_setprim *)arg)->ssp_assoc_id = id;
370                 break;
371         case SCTP_PEER_ADDR_PARAMS:
372                 ((struct sctp_paddrparams *)arg)->spp_assoc_id = id;
373                 break;
374         case SCTP_MAXSEG:
375                 ((struct sctp_assoc_value *)arg)->assoc_id = id;
376                 break;
377         case SCTP_AUTH_KEY:
378                 ((struct sctp_authkey *)arg)->sca_assoc_id = id;
379                 break;
380         case SCTP_AUTH_ACTIVE_KEY:
381                 ((struct sctp_authkeyid *)arg)->scact_assoc_id = id;
382                 break;
383         case SCTP_DELAYED_SACK:
384                 ((struct sctp_sack_info *)arg)->sack_assoc_id = id;
385                 break;
386         case SCTP_CONTEXT:
387                 ((struct sctp_assoc_value *)arg)->assoc_id = id;
388                 break;
389         case SCTP_STATUS:
390                 ((struct sctp_status *)arg)->sstat_assoc_id = id;
391                 break;
392         case SCTP_GET_PEER_ADDR_INFO:
393                 ((struct sctp_paddrinfo *)arg)->spinfo_assoc_id = id;
394                 break;
395         case SCTP_PEER_AUTH_CHUNKS:
396                 ((struct sctp_authchunks *)arg)->gauth_assoc_id = id;
397                 break;
398         case SCTP_LOCAL_AUTH_CHUNKS:
399                 ((struct sctp_authchunks *)arg)->gauth_assoc_id = id;
400                 break;
401         case SCTP_TIMEOUTS:
402                 ((struct sctp_timeouts *)arg)->stimo_assoc_id = id;
403                 break;
404         case SCTP_EVENT:
405                 ((struct sctp_event *)arg)->se_assoc_id = id;
406                 break;
407         case SCTP_DEFAULT_SNDINFO:
408                 ((struct sctp_sndinfo *)arg)->snd_assoc_id = id;
409                 break;
410         case SCTP_DEFAULT_PRINFO:
411                 ((struct sctp_default_prinfo *)arg)->pr_assoc_id = id;
412                 break;
413         case SCTP_PEER_ADDR_THLDS:
414                 ((struct sctp_paddrthlds *)arg)->spt_assoc_id = id;
415                 break;
416         case SCTP_MAX_BURST:
417                 ((struct sctp_assoc_value *)arg)->assoc_id = id;
418                 break;
419         default:
420                 break;
421         }
422         return (getsockopt(sd, IPPROTO_SCTP, opt, arg, size));
423 }
424
425 int
426 sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs)
427 {
428         struct sctp_getaddresses *addrs;
429         struct sockaddr *sa;
430         struct sockaddr *re;
431         sctp_assoc_t asoc;
432         caddr_t lim;
433         socklen_t siz;
434         int cnt;
435
436         if (raddrs == NULL) {
437                 errno = EFAULT;
438                 return (-1);
439         }
440         asoc = id;
441         siz = sizeof(sctp_assoc_t);
442         if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE,
443             &asoc, &siz) != 0) {
444                 return (-1);
445         }
446         /* size required is returned in 'asoc' */
447         siz = (size_t)asoc;
448         siz += sizeof(struct sctp_getaddresses);
449         addrs = calloc(1, siz);
450         if (addrs == NULL) {
451                 return (-1);
452         }
453         addrs->sget_assoc_id = id;
454         /* Now lets get the array of addresses */
455         if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES,
456             addrs, &siz) != 0) {
457                 free(addrs);
458                 return (-1);
459         }
460         re = (struct sockaddr *)&addrs->addr[0];
461         *raddrs = re;
462         cnt = 0;
463         sa = (struct sockaddr *)&addrs->addr[0];
464         lim = (caddr_t)addrs + siz;
465         while (((caddr_t)sa < lim) && (sa->sa_len > 0)) {
466                 sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
467                 cnt++;
468         }
469         return (cnt);
470 }
471
472 void
473 sctp_freepaddrs(struct sockaddr *addrs)
474 {
475         /* Take away the hidden association id */
476         void *fr_addr;
477
478         fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
479         /* Now free it */
480         free(fr_addr);
481 }
482
483 int
484 sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs)
485 {
486         struct sctp_getaddresses *addrs;
487         struct sockaddr *re;
488         caddr_t lim;
489         struct sockaddr *sa;
490         int size_of_addresses;
491         socklen_t siz;
492         int cnt;
493
494         if (raddrs == NULL) {
495                 errno = EFAULT;
496                 return (-1);
497         }
498         size_of_addresses = 0;
499         siz = sizeof(int);
500         if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE,
501             &size_of_addresses, &siz) != 0) {
502                 errno = ENOMEM;
503                 return (-1);
504         }
505         if (size_of_addresses == 0) {
506                 errno = ENOTCONN;
507                 return (-1);
508         }
509         siz = size_of_addresses + sizeof(struct sockaddr_storage);
510         siz += sizeof(struct sctp_getaddresses);
511         addrs = calloc(1, siz);
512         if (addrs == NULL) {
513                 errno = ENOMEM;
514                 return (-1);
515         }
516         addrs->sget_assoc_id = id;
517         /* Now lets get the array of addresses */
518         if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs,
519             &siz) != 0) {
520                 free(addrs);
521                 errno = ENOMEM;
522                 return (-1);
523         }
524         re = (struct sockaddr *)&addrs->addr[0];
525         *raddrs = re;
526         cnt = 0;
527         sa = (struct sockaddr *)&addrs->addr[0];
528         lim = (caddr_t)addrs + siz;
529         while (((caddr_t)sa < lim) && (sa->sa_len > 0)) {
530                 sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
531                 cnt++;
532         }
533         return (cnt);
534 }
535
536 void
537 sctp_freeladdrs(struct sockaddr *addrs)
538 {
539         /* Take away the hidden association id */
540         void *fr_addr;
541
542         fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
543         /* Now free it */
544         free(fr_addr);
545 }
546
547
548 ssize_t
549 sctp_sendmsg(int s,
550     const void *data,
551     size_t len,
552     const struct sockaddr *to,
553     socklen_t tolen,
554     uint32_t ppid,
555     uint32_t flags,
556     uint16_t stream_no,
557     uint32_t timetolive,
558     uint32_t context)
559 {
560 #ifdef SYS_sctp_generic_sendmsg
561         struct sctp_sndrcvinfo sinfo;
562
563         sinfo.sinfo_ppid = ppid;
564         sinfo.sinfo_flags = flags;
565         sinfo.sinfo_stream = stream_no;
566         sinfo.sinfo_timetolive = timetolive;
567         sinfo.sinfo_context = context;
568         sinfo.sinfo_assoc_id = 0;
569         return (syscall(SYS_sctp_generic_sendmsg, s,
570             data, len, to, tolen, &sinfo, 0));
571 #else
572         ssize_t sz;
573         struct msghdr msg;
574         struct sctp_sndrcvinfo *s_info;
575         struct iovec iov;
576         char controlVector[SCTP_CONTROL_VEC_SIZE_RCV];
577         struct cmsghdr *cmsg;
578         struct sockaddr *who = NULL;
579         union {
580                 struct sockaddr_in in;
581                 struct sockaddr_in6 in6;
582         }     addr;
583
584         if ((tolen > 0) &&
585             ((to == NULL) || (tolen < sizeof(struct sockaddr)))) {
586                 errno = EINVAL;
587                 return -1;
588         }
589         if (to && (tolen > 0)) {
590                 if (to->sa_family == AF_INET) {
591                         if (tolen != sizeof(struct sockaddr_in)) {
592                                 errno = EINVAL;
593                                 return -1;
594                         }
595                         if ((to->sa_len > 0) &&
596                             (to->sa_len != sizeof(struct sockaddr_in))) {
597                                 errno = EINVAL;
598                                 return -1;
599                         }
600                         memcpy(&addr, to, sizeof(struct sockaddr_in));
601                         addr.in.sin_len = sizeof(struct sockaddr_in);
602                 } else if (to->sa_family == AF_INET6) {
603                         if (tolen != sizeof(struct sockaddr_in6)) {
604                                 errno = EINVAL;
605                                 return -1;
606                         }
607                         if ((to->sa_len > 0) &&
608                             (to->sa_len != sizeof(struct sockaddr_in6))) {
609                                 errno = EINVAL;
610                                 return -1;
611                         }
612                         memcpy(&addr, to, sizeof(struct sockaddr_in6));
613                         addr.in6.sin6_len = sizeof(struct sockaddr_in6);
614                 } else {
615                         errno = EAFNOSUPPORT;
616                         return -1;
617                 }
618                 who = (struct sockaddr *)&addr;
619         }
620         iov.iov_base = (char *)data;
621         iov.iov_len = len;
622
623         if (who) {
624                 msg.msg_name = (caddr_t)who;
625                 msg.msg_namelen = who->sa_len;
626         } else {
627                 msg.msg_name = (caddr_t)NULL;
628                 msg.msg_namelen = 0;
629         }
630         msg.msg_iov = &iov;
631         msg.msg_iovlen = 1;
632         msg.msg_control = (caddr_t)controlVector;
633
634         cmsg = (struct cmsghdr *)controlVector;
635
636         cmsg->cmsg_level = IPPROTO_SCTP;
637         cmsg->cmsg_type = SCTP_SNDRCV;
638         cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
639         s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
640
641         s_info->sinfo_stream = stream_no;
642         s_info->sinfo_ssn = 0;
643         s_info->sinfo_flags = flags;
644         s_info->sinfo_ppid = ppid;
645         s_info->sinfo_context = context;
646         s_info->sinfo_assoc_id = 0;
647         s_info->sinfo_timetolive = timetolive;
648         errno = 0;
649         msg.msg_controllen = cmsg->cmsg_len;
650         sz = sendmsg(s, &msg, 0);
651         return (sz);
652 #endif
653 }
654
655
656 sctp_assoc_t
657 sctp_getassocid(int sd, struct sockaddr *sa)
658 {
659         struct sctp_paddrinfo sp;
660         socklen_t siz;
661
662         /* First get the assoc id */
663         siz = sizeof(sp);
664         memset(&sp, 0, sizeof(sp));
665         memcpy((caddr_t)&sp.spinfo_address, sa, sa->sa_len);
666         errno = 0;
667         if (getsockopt(sd, IPPROTO_SCTP,
668             SCTP_GET_PEER_ADDR_INFO, &sp, &siz) != 0) {
669                 return ((sctp_assoc_t) 0);
670         }
671         /* We depend on the fact that 0 can never be returned */
672         return (sp.spinfo_assoc_id);
673 }
674
675 ssize_t
676 sctp_send(int sd, const void *data, size_t len,
677     const struct sctp_sndrcvinfo *sinfo,
678     int flags)
679 {
680
681 #ifdef SYS_sctp_generic_sendmsg
682         struct sockaddr *to = NULL;
683
684         return (syscall(SYS_sctp_generic_sendmsg, sd,
685             data, len, to, 0, sinfo, flags));
686 #else
687         ssize_t sz;
688         struct msghdr msg;
689         struct iovec iov;
690         struct sctp_sndrcvinfo *s_info;
691         char controlVector[SCTP_CONTROL_VEC_SIZE_SND];
692         struct cmsghdr *cmsg;
693
694         if (sinfo == NULL) {
695                 errno = EINVAL;
696                 return (-1);
697         }
698         iov.iov_base = (char *)data;
699         iov.iov_len = len;
700
701         msg.msg_name = 0;
702         msg.msg_namelen = 0;
703         msg.msg_iov = &iov;
704         msg.msg_iovlen = 1;
705         msg.msg_control = (caddr_t)controlVector;
706
707         cmsg = (struct cmsghdr *)controlVector;
708
709         cmsg->cmsg_level = IPPROTO_SCTP;
710         cmsg->cmsg_type = SCTP_SNDRCV;
711         cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
712         s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
713         /* copy in the data */
714         *s_info = *sinfo;
715         errno = 0;
716         msg.msg_controllen = cmsg->cmsg_len;
717         sz = sendmsg(sd, &msg, flags);
718         return (sz);
719 #endif
720 }
721
722
723
724 ssize_t
725 sctp_sendx(int sd, const void *msg, size_t msg_len,
726     struct sockaddr *addrs, int addrcnt,
727     struct sctp_sndrcvinfo *sinfo,
728     int flags)
729 {
730         struct sctp_sndrcvinfo __sinfo;
731         ssize_t ret;
732         int i, cnt, *aa, saved_errno;
733         char *buf;
734         int add_len, len, no_end_cx = 0;
735         struct sockaddr *at;
736
737         if (addrs == NULL) {
738                 errno = EINVAL;
739                 return (-1);
740         }
741 #ifdef SYS_sctp_generic_sendmsg
742         if (addrcnt == 1) {
743                 socklen_t l;
744
745                 /*
746                  * Quick way, we don't need to do a connectx so lets use the
747                  * syscall directly.
748                  */
749                 l = addrs->sa_len;
750                 return (syscall(SYS_sctp_generic_sendmsg, sd,
751                     msg, msg_len, addrs, l, sinfo, flags));
752         }
753 #endif
754
755         len = sizeof(int);
756         at = addrs;
757         cnt = 0;
758         /* validate all the addresses and get the size */
759         for (i = 0; i < addrcnt; i++) {
760                 if (at->sa_family == AF_INET) {
761                         add_len = sizeof(struct sockaddr_in);
762                 } else if (at->sa_family == AF_INET6) {
763                         add_len = sizeof(struct sockaddr_in6);
764                 } else {
765                         errno = EINVAL;
766                         return (-1);
767                 }
768                 len += add_len;
769                 at = (struct sockaddr *)((caddr_t)at + add_len);
770                 cnt++;
771         }
772         /* do we have any? */
773         if (cnt == 0) {
774                 errno = EINVAL;
775                 return (-1);
776         }
777         buf = malloc(len);
778         if (buf == NULL) {
779                 return (-1);
780         }
781         aa = (int *)buf;
782         *aa = cnt;
783         aa++;
784         memcpy((caddr_t)aa, addrs, (len - sizeof(int)));
785         ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_DELAYED, (void *)buf,
786             (socklen_t) len);
787
788         free(buf);
789         if (ret != 0) {
790                 if (errno == EALREADY) {
791                         no_end_cx = 1;
792                         goto continue_send;
793                 }
794                 return (ret);
795         }
796 continue_send:
797         if (sinfo == NULL) {
798                 sinfo = &__sinfo;
799                 memset(&__sinfo, 0, sizeof(__sinfo));
800         }
801         sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs);
802         if (sinfo->sinfo_assoc_id == 0) {
803                 printf("Huh, can't get associd? TSNH!\n");
804                 (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
805                     (socklen_t) addrs->sa_len);
806                 errno = ENOENT;
807                 return (-1);
808         }
809         ret = sctp_send(sd, msg, msg_len, sinfo, flags);
810         saved_errno = errno;
811         if (no_end_cx == 0)
812                 (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
813                     (socklen_t) addrs->sa_len);
814
815         errno = saved_errno;
816         return (ret);
817 }
818
819 ssize_t
820 sctp_sendmsgx(int sd,
821     const void *msg,
822     size_t len,
823     struct sockaddr *addrs,
824     int addrcnt,
825     uint32_t ppid,
826     uint32_t flags,
827     uint16_t stream_no,
828     uint32_t timetolive,
829     uint32_t context)
830 {
831         struct sctp_sndrcvinfo sinfo;
832
833         memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo));
834         sinfo.sinfo_ppid = ppid;
835         sinfo.sinfo_flags = flags;
836         sinfo.sinfo_ssn = stream_no;
837         sinfo.sinfo_timetolive = timetolive;
838         sinfo.sinfo_context = context;
839         return sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0);
840 }
841
842 ssize_t
843 sctp_recvmsg(int s,
844     void *dbuf,
845     size_t len,
846     struct sockaddr *from,
847     socklen_t * fromlen,
848     struct sctp_sndrcvinfo *sinfo,
849     int *msg_flags)
850 {
851 #ifdef SYS_sctp_generic_recvmsg
852         struct iovec iov;
853
854         iov.iov_base = dbuf;
855         iov.iov_len = len;
856         return (syscall(SYS_sctp_generic_recvmsg, s,
857             &iov, 1, from, fromlen, sinfo, msg_flags));
858 #else
859         struct sctp_sndrcvinfo *s_info;
860         ssize_t sz;
861         int sinfo_found = 0;
862         struct msghdr msg;
863         struct iovec iov;
864         char controlVector[SCTP_CONTROL_VEC_SIZE_RCV];
865         struct cmsghdr *cmsg;
866
867         if (msg_flags == NULL) {
868                 errno = EINVAL;
869                 return (-1);
870         }
871         msg.msg_flags = 0;
872         iov.iov_base = dbuf;
873         iov.iov_len = len;
874         msg.msg_name = (caddr_t)from;
875         if (fromlen == NULL)
876                 msg.msg_namelen = 0;
877         else
878                 msg.msg_namelen = *fromlen;
879         msg.msg_iov = &iov;
880         msg.msg_iovlen = 1;
881         msg.msg_control = (caddr_t)controlVector;
882         msg.msg_controllen = sizeof(controlVector);
883         errno = 0;
884         sz = recvmsg(s, &msg, *msg_flags);
885         *msg_flags = msg.msg_flags;
886         if (sz <= 0) {
887                 return (sz);
888         }
889         s_info = NULL;
890         len = sz;
891         if (sinfo) {
892                 sinfo->sinfo_assoc_id = 0;
893         }
894         if ((msg.msg_controllen) && sinfo) {
895                 /*
896                  * parse through and see if we find the sctp_sndrcvinfo (if
897                  * the user wants it).
898                  */
899                 cmsg = (struct cmsghdr *)controlVector;
900                 while (cmsg) {
901                         if ((cmsg->cmsg_len == 0) || (cmsg->cmsg_len > msg.msg_controllen)) {
902                                 break;
903                         }
904                         if (cmsg->cmsg_level == IPPROTO_SCTP) {
905                                 if (cmsg->cmsg_type == SCTP_SNDRCV) {
906                                         /* Got it */
907                                         s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
908                                         /* Copy it to the user */
909                                         if (sinfo)
910                                                 *sinfo = *s_info;
911                                         sinfo_found = 1;
912                                         break;
913                                 } else if (cmsg->cmsg_type == SCTP_EXTRCV) {
914                                         /*
915                                          * Got it, presumably the user has
916                                          * asked for this extra info, so the
917                                          * structure holds more room :-D
918                                          */
919                                         s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
920                                         /* Copy it to the user */
921                                         if (sinfo) {
922                                                 memcpy(sinfo, s_info, sizeof(struct sctp_extrcvinfo));
923                                         }
924                                         sinfo_found = 1;
925                                         break;
926
927                                 }
928                         }
929                         cmsg = CMSG_NXTHDR(&msg, cmsg);
930                 }
931         }
932         return (sz);
933 #endif
934 }
935
936 ssize_t 
937 sctp_recvv(int sd,
938     const struct iovec *iov,
939     int iovlen,
940     struct sockaddr *from,
941     socklen_t * fromlen,
942     void *info,
943     socklen_t * infolen,
944     unsigned int *infotype,
945     int *flags)
946 {
947         char ctlbuf[SCTP_CONTROL_VEC_SIZE_RCV];
948         struct msghdr msg;
949         struct cmsghdr *cmsg;
950         ssize_t n;
951         struct sctp_rcvinfo *rcvinfo;
952         struct sctp_nxtinfo *nxtinfo;
953
954         if (((info != NULL) && (infolen == NULL)) |
955             ((info == NULL) && (infolen != NULL) && (*infolen != 0)) ||
956             ((info != NULL) && (infotype == NULL))) {
957                 errno = EINVAL;
958                 return (-1);
959         }
960         if (infotype) {
961                 *infotype = SCTP_RECVV_NOINFO;
962         }
963         msg.msg_name = from;
964         if (fromlen == NULL) {
965                 msg.msg_namelen = 0;
966         } else {
967                 msg.msg_namelen = *fromlen;
968         }
969         msg.msg_iov = (struct iovec *)iov;
970         msg.msg_iovlen = iovlen;
971         msg.msg_control = ctlbuf;
972         msg.msg_controllen = sizeof(ctlbuf);
973         errno = 0;
974         n = recvmsg(sd, &msg, *flags);
975         *flags = msg.msg_flags;
976         if ((n > 0) &&
977             (msg.msg_controllen > 0) &&
978             (infotype != NULL) &&
979             (infolen != NULL) &&
980             (*infolen > 0)) {
981                 rcvinfo = NULL;
982                 nxtinfo = NULL;
983                 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
984                         if (cmsg->cmsg_level != IPPROTO_SCTP) {
985                                 continue;
986                         }
987                         if (cmsg->cmsg_type == SCTP_RCVINFO) {
988                                 rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg);
989                         }
990                         if (cmsg->cmsg_type == SCTP_NXTINFO) {
991                                 nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg);
992                         }
993                         if (rcvinfo && nxtinfo) {
994                                 break;
995                         }
996                 }
997                 if (rcvinfo) {
998                         if (nxtinfo) {
999                                 if (*infolen >= sizeof(struct sctp_recvv_rn)) {
1000                                         struct sctp_recvv_rn *rn_info;
1001
1002                                         rn_info = (struct sctp_recvv_rn *)info;
1003                                         rn_info->recvv_rcvinfo = *rcvinfo;
1004                                         rn_info->recvv_nxtinfo = *nxtinfo;
1005                                         *infolen = (socklen_t) sizeof(struct sctp_recvv_rn);
1006                                         *infotype = SCTP_RECVV_RN;
1007                                 }
1008                         } else {
1009                                 if (*infolen >= sizeof(struct sctp_rcvinfo)) {
1010                                         memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo));
1011                                         *infolen = (socklen_t) sizeof(struct sctp_rcvinfo);
1012                                         *infotype = SCTP_RECVV_RCVINFO;
1013                                 }
1014                         }
1015                 } else if (nxtinfo) {
1016                         if (*infolen >= sizeof(struct sctp_rcvinfo)) {
1017                                 memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo));
1018                                 *infolen = (socklen_t) sizeof(struct sctp_nxtinfo);
1019                                 *infotype = SCTP_RECVV_NXTINFO;
1020                         }
1021                 }
1022         }
1023         return (n);
1024 }
1025
1026 ssize_t
1027 sctp_sendv(int sd,
1028     const struct iovec *iov, int iovcnt,
1029     struct sockaddr *addrs, int addrcnt,
1030     void *info, socklen_t infolen, unsigned int infotype,
1031     int flags)
1032 {
1033         ssize_t ret;
1034         int i;
1035         socklen_t addr_len;
1036         struct msghdr msg;
1037         in_port_t port;
1038         struct sctp_sendv_spa *spa_info;
1039         struct cmsghdr *cmsg;
1040         char *cmsgbuf;
1041         struct sockaddr *addr;
1042         struct sockaddr_in *addr_in;
1043         struct sockaddr_in6 *addr_in6;
1044
1045         if ((addrcnt < 0) ||
1046             (iovcnt < 0) ||
1047             ((addrs == NULL) && (addrcnt > 0)) ||
1048             ((addrs != NULL) && (addrcnt == 0)) ||
1049             ((iov == NULL) && (iovcnt > 0)) ||
1050             ((iov != NULL) && (iovcnt == 0))) {
1051                 errno = EINVAL;
1052                 return (-1);
1053         }
1054         cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) +
1055             CMSG_SPACE(sizeof(struct sctp_prinfo)) +
1056             CMSG_SPACE(sizeof(struct sctp_authinfo)) +
1057             addrcnt * CMSG_SPACE(sizeof(struct in6_addr)));
1058         if (cmsgbuf == NULL) {
1059                 errno = ENOBUFS;
1060                 return (-1);
1061         }
1062         msg.msg_control = cmsgbuf;
1063         msg.msg_controllen = 0;
1064         cmsg = (struct cmsghdr *)cmsgbuf;
1065         switch (infotype) {
1066         case SCTP_SENDV_NOINFO:
1067                 if ((infolen != 0) || (info != NULL)) {
1068                         free(cmsgbuf);
1069                         errno = EINVAL;
1070                         return (-1);
1071                 }
1072                 break;
1073         case SCTP_SENDV_SNDINFO:
1074                 if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) {
1075                         free(cmsgbuf);
1076                         errno = EINVAL;
1077                         return (-1);
1078                 }
1079                 cmsg->cmsg_level = IPPROTO_SCTP;
1080                 cmsg->cmsg_type = SCTP_SNDINFO;
1081                 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
1082                 memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo));
1083                 msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
1084                 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
1085                 break;
1086         case SCTP_SENDV_PRINFO:
1087                 if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) {
1088                         free(cmsgbuf);
1089                         errno = EINVAL;
1090                         return (-1);
1091                 }
1092                 cmsg->cmsg_level = IPPROTO_SCTP;
1093                 cmsg->cmsg_type = SCTP_PRINFO;
1094                 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
1095                 memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo));
1096                 msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
1097                 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
1098                 break;
1099         case SCTP_SENDV_AUTHINFO:
1100                 if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) {
1101                         free(cmsgbuf);
1102                         errno = EINVAL;
1103                         return (-1);
1104                 }
1105                 cmsg->cmsg_level = IPPROTO_SCTP;
1106                 cmsg->cmsg_type = SCTP_AUTHINFO;
1107                 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
1108                 memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo));
1109                 msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
1110                 cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
1111                 break;
1112         case SCTP_SENDV_SPA:
1113                 if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) {
1114                         free(cmsgbuf);
1115                         errno = EINVAL;
1116                         return (-1);
1117                 }
1118                 spa_info = (struct sctp_sendv_spa *)info;
1119                 if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) {
1120                         cmsg->cmsg_level = IPPROTO_SCTP;
1121                         cmsg->cmsg_type = SCTP_SNDINFO;
1122                         cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
1123                         memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo));
1124                         msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
1125                         cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
1126                 }
1127                 if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) {
1128                         cmsg->cmsg_level = IPPROTO_SCTP;
1129                         cmsg->cmsg_type = SCTP_PRINFO;
1130                         cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
1131                         memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo));
1132                         msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
1133                         cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
1134                 }
1135                 if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) {
1136                         cmsg->cmsg_level = IPPROTO_SCTP;
1137                         cmsg->cmsg_type = SCTP_AUTHINFO;
1138                         cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
1139                         memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo));
1140                         msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
1141                         cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
1142                 }
1143                 break;
1144         default:
1145                 free(cmsgbuf);
1146                 errno = EINVAL;
1147                 return (-1);
1148         }
1149         addr = addrs;
1150         msg.msg_name = NULL;
1151         msg.msg_namelen = 0;
1152
1153         for (i = 0; i < addrcnt; i++) {
1154                 switch (addr->sa_family) {
1155                 case AF_INET:
1156                         addr_len = (socklen_t) sizeof(struct sockaddr_in);
1157                         addr_in = (struct sockaddr_in *)addr;
1158                         if (addr_in->sin_len != addr_len) {
1159                                 free(cmsgbuf);
1160                                 errno = EINVAL;
1161                                 return (-1);
1162                         }
1163                         if (i == 0) {
1164                                 port = addr_in->sin_port;
1165                         } else {
1166                                 if (port == addr_in->sin_port) {
1167                                         cmsg->cmsg_level = IPPROTO_SCTP;
1168                                         cmsg->cmsg_type = SCTP_DSTADDRV4;
1169                                         cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
1170                                         memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr));
1171                                         msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr));
1172                                         cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr)));
1173                                 } else {
1174                                         free(cmsgbuf);
1175                                         errno = EINVAL;
1176                                         return (-1);
1177                                 }
1178                         }
1179                         break;
1180                 case AF_INET6:
1181                         addr_len = (socklen_t) sizeof(struct sockaddr_in6);
1182                         addr_in6 = (struct sockaddr_in6 *)addr;
1183                         if (addr_in6->sin6_len != addr_len) {
1184                                 free(cmsgbuf);
1185                                 errno = EINVAL;
1186                                 return (-1);
1187                         }
1188                         if (i == 0) {
1189                                 port = addr_in6->sin6_port;
1190                         } else {
1191                                 if (port == addr_in6->sin6_port) {
1192                                         cmsg->cmsg_level = IPPROTO_SCTP;
1193                                         cmsg->cmsg_type = SCTP_DSTADDRV6;
1194                                         cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr));
1195                                         memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr));
1196                                         msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr));
1197                                         cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr)));
1198                                 } else {
1199                                         free(cmsgbuf);
1200                                         errno = EINVAL;
1201                                         return (-1);
1202                                 }
1203                         }
1204                         break;
1205                 default:
1206                         free(cmsgbuf);
1207                         errno = EINVAL;
1208                         return (-1);
1209                 }
1210                 if (i == 0) {
1211                         msg.msg_name = addr;
1212                         msg.msg_namelen = addr_len;
1213                 }
1214                 addr = (struct sockaddr *)((caddr_t)addr + addr_len);
1215         }
1216         if (msg.msg_controllen == 0) {
1217                 msg.msg_control = NULL;
1218         }
1219         msg.msg_iov = (struct iovec *)iov;
1220         msg.msg_iovlen = iovcnt;
1221         msg.msg_flags = 0;
1222         ret = sendmsg(sd, &msg, flags);
1223         free(cmsgbuf);
1224         return (ret);
1225 }
1226
1227
1228 #if !defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT)
1229
1230 int
1231 sctp_peeloff(int sd, sctp_assoc_t assoc_id)
1232 {
1233         /* NOT supported, return invalid sd */
1234         errno = ENOTSUP;
1235         return (-1);
1236 }
1237
1238 #endif
1239 #if defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT)
1240 int
1241 sctp_peeloff(int sd, sctp_assoc_t assoc_id)
1242 {
1243         return (syscall(SYS_sctp_peeloff, sd, assoc_id));
1244 }
1245
1246 #endif
1247
1248
1249 #undef SCTP_CONTROL_VEC_SIZE_SND
1250 #undef SCTP_CONTROL_VEC_SIZE_RCV
1251 #undef SCTP_STACK_BUF_SIZE