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