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