2b5a94bb5a79b53e402d3065c0708a86c694e00b
[dragonfly.git] / lib / libsctp / sctp_sys_calls.c
1 /*      $KAME: sctp_sys_calls.c,v 1.9 2004/08/17 06:08:53 itojun Exp $ */
2 /*      $DragonFly: src/lib/libsctp/sctp_sys_calls.c,v 1.3 2008/09/30 16:57:05 swildner Exp $   */
3
4 /*
5  * Copyright (C) 2002, 2003, 2004 Cisco Systems Inc,
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the project nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <sys/errno.h>
41 #include <sys/syscall.h>
42 #include <sys/uio.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <netinet/sctp_uio.h>
46 #include <netinet/sctp.h>
47 #include <netinet/sctp_constants.h>
48
49 #include <net/if_dl.h>
50
51 #ifndef IN6_IS_ADDR_V4MAPPED
52 #define IN6_IS_ADDR_V4MAPPED(a)              \
53         ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
54          (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
55          (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff)))
56 #endif
57
58
59 #ifdef SCTP_DEBUG_PRINT_ADDRESS
60 static void
61 SCTPPrintAnAddress(struct sockaddr *a)
62 {
63         char stringToPrint[256];
64         u_short prt;
65         char *srcaddr, *txt;
66
67         if (a == NULL) {
68                 printf("NULL\n");
69                 return;
70         }
71         if (a->sa_family == AF_INET) {
72                 srcaddr = (char *)&((struct sockaddr_in *)a)->sin_addr;
73                 txt = "IPv4 Address: ";
74                 prt = ntohs(((struct sockaddr_in *)a)->sin_port);
75         } else if (a->sa_family == AF_INET6) {
76                 srcaddr = (char *)&((struct sockaddr_in6 *)a)->sin6_addr;
77                 prt = ntohs(((struct sockaddr_in6 *)a)->sin6_port);
78                 txt = "IPv6 Address: ";
79         } else if (a->sa_family == AF_LINK) {
80                 int i;
81                 char tbuf[200];
82                 u_char adbuf[200];
83                 struct sockaddr_dl *dl;
84
85                 dl = (struct sockaddr_dl *)a;
86                 strncpy(tbuf, dl->sdl_data, dl->sdl_nlen);
87                 tbuf[dl->sdl_nlen] = 0;
88                 printf("Intf:%s (len:%d)Interface index:%d type:%x(%d) ll-len:%d ",
89                     tbuf, dl->sdl_nlen, dl->sdl_index, dl->sdl_type,
90                     dl->sdl_type, dl->sdl_alen);
91                 memcpy(adbuf, LLADDR(dl), dl->sdl_alen);
92                 for (i = 0; i < dl->sdl_alen; i++){
93                         printf("%2.2x", adbuf[i]);
94                         if (i < (dl->sdl_alen - 1))
95                                 printf(":");
96                 }
97                 printf("\n");
98         /*      u_short sdl_route[16];*/        /* source routing information */
99                 return;
100         } else {
101                 return;
102         }
103         if (inet_ntop(a->sa_family, srcaddr, stringToPrint,
104             sizeof(stringToPrint))) {
105                 if (a->sa_family == AF_INET6) {
106                         printf("%s%s:%d scope:%d\n", txt, stringToPrint, prt,
107                             ((struct sockaddr_in6 *)a)->sin6_scope_id);
108                 } else {
109                         printf("%s%s:%d\n", txt, stringToPrint, prt);
110                 }
111
112         } else {
113                 printf("%s unprintable?\n", txt);
114         }
115 }
116 #endif /* SCTP_DEBUG_PRINT_ADDRESS */
117
118 static void
119 in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
120 {
121         bzero(sin, sizeof(*sin));
122         sin->sin_len = sizeof(struct sockaddr_in);
123         sin->sin_family = AF_INET;
124         sin->sin_port = sin6->sin6_port;
125         sin->sin_addr.s_addr = sin6->sin6_addr.__u6_addr.__u6_addr32[3];
126 }
127
128 int
129 sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt)
130 {
131         char buf[2048];
132         int i, ret, cnt, *aa;
133         char *cpto;
134         struct sockaddr *at;
135         size_t len = sizeof(int);
136         
137         at = addrs;
138         cnt = 0;
139         cpto = ((caddr_t)buf + sizeof(int));
140         /* validate all the addresses and get the size */
141         for (i = 0; i < addrcnt; i++) {
142                 if (at->sa_family == AF_INET) {
143                         memcpy(cpto, at, at->sa_len);
144                         cpto = ((caddr_t)cpto + at->sa_len);
145                         len += at->sa_len;
146                 } else if (at->sa_family == AF_INET6){
147                         if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)at)->sin6_addr)){
148                                 len += sizeof(struct sockaddr_in);
149                                 in6_sin6_2_sin((struct sockaddr_in *)cpto,
150                                     (struct sockaddr_in6 *)at);
151                                 cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in));
152                                 len += sizeof(struct sockaddr_in);
153                         } else {
154                                 memcpy(cpto, at, at->sa_len);
155                                 cpto = ((caddr_t)cpto + at->sa_len);
156                                 len += at->sa_len;
157                         }
158                 } else {
159                         errno = EINVAL;
160                         return (-1);
161                 }
162                 if (len > (sizeof(buf)-sizeof(int))) {
163                         /* Never enough memory */
164                         return(E2BIG);
165                 }
166                 at = (struct sockaddr *)((caddr_t)at + at->sa_len);
167                 cnt++;
168         }
169         /* do we have any? */
170         if (cnt == 0) {
171                 errno = EINVAL;
172                 return(-1);
173         }
174         aa = (int *)buf;
175         *aa = cnt;
176         ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X, (void *)buf,
177             (unsigned int)len);
178         return (ret);
179 }
180
181 int
182 sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags)
183 {
184         struct sctp_getaddresses *gaddrs;
185         struct sockaddr *sa;
186         int i, sz, fam, argsz;
187
188         if ((flags != SCTP_BINDX_ADD_ADDR) && 
189             (flags != SCTP_BINDX_REM_ADDR)) {
190                 errno = EFAULT;
191                 return(-1);
192         }
193         argsz = (sizeof(struct sockaddr_storage) +
194             sizeof(struct sctp_getaddresses));
195         gaddrs = (struct sctp_getaddresses *)calloc(1, argsz);
196         if (gaddrs == NULL) {
197                 errno = ENOMEM;
198                 return(-1);
199         }
200         gaddrs->sget_assoc_id = 0;
201         sa = addrs;
202         for (i = 0; i < addrcnt; i++) {
203                 sz = sa->sa_len;
204                 fam = sa->sa_family;
205                 ((struct sockaddr_in *)&addrs[i])->sin_port = ((struct sockaddr_in *)sa)->sin_port;
206                 if ((fam != AF_INET) && (fam != AF_INET6)) {
207                         errno = EINVAL;
208                         return(-1);
209                 }
210                 memcpy(gaddrs->addr, sa, sz);
211                 if (setsockopt(sd, IPPROTO_SCTP, flags, gaddrs,
212                     (unsigned int)argsz) != 0) {
213                         free(gaddrs);
214                         return(-1);
215                 }
216                 memset(gaddrs, 0, argsz);
217                 sa = (struct sockaddr *)((caddr_t)sa + sz);
218         }
219         free(gaddrs);
220         return(0);
221 }
222
223
224 int
225 sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, size_t *size)
226 {
227         if ((opt == SCTP_RTOINFO) || 
228             (opt == SCTP_ASSOCINFO) || 
229             (opt == SCTP_PRIMARY_ADDR) || 
230             (opt == SCTP_SET_PEER_PRIMARY_ADDR) || 
231             (opt == SCTP_PEER_ADDR_PARAMS) || 
232             (opt == SCTP_STATUS) || 
233             (opt == SCTP_GET_PEER_ADDR_INFO)) { 
234                 *(sctp_assoc_t *)arg = id;
235                 return(getsockopt(sd, IPPROTO_SCTP, opt, arg, (int *)size));
236         } else {
237                 errno = EOPNOTSUPP;
238                 return(-1);
239         }
240 }
241
242 int
243 sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs)
244 {
245         struct sctp_getaddresses *addrs;
246         struct sockaddr *sa;
247         struct sockaddr *re;
248         sctp_assoc_t asoc;
249         caddr_t lim;
250         unsigned int siz;
251         int cnt;
252
253         if (raddrs == NULL) {
254                 errno = EFAULT;
255                 return(-1);
256         }
257         asoc = id;
258         siz = sizeof(sctp_assoc_t);  
259         if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE,
260             &asoc, &siz) != 0) {
261                 return(-1);
262         }
263         siz = (unsigned int)(uintptr_t)asoc;
264         siz += sizeof(struct sctp_getaddresses);
265         addrs = calloc((unsigned long)1, (unsigned long)siz);
266         if (addrs == NULL) {
267                 errno = ENOMEM;
268                 return(-1);
269         }
270         memset(addrs, 0, (size_t)siz);
271         addrs->sget_assoc_id = id;
272         /* Now lets get the array of addresses */
273         if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES,
274             addrs, &siz) != 0) {
275                 free(addrs);
276                 return(-1);
277         }
278         re = (struct sockaddr *)&addrs->addr[0];
279         *raddrs = re;
280         cnt = 0;
281         sa = (struct sockaddr *)&addrs->addr[0];
282         lim = (caddr_t)addrs + siz;
283         while ((caddr_t)sa < lim) {
284                 cnt++;
285                 sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
286                 if (sa->sa_len == 0)
287                         break;
288         }
289         return(cnt);
290 }
291
292 void sctp_freepaddrs(struct sockaddr *addrs)
293 {
294         /* Take away the hidden association id */
295         void *fr_addr;
296         fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
297         /* Now free it */
298         free(fr_addr);
299 }
300
301 int
302 sctp_getladdrs (int sd, sctp_assoc_t id, struct sockaddr **raddrs)
303 {
304         struct sctp_getaddresses *addrs;
305         struct sockaddr *re;
306         caddr_t lim;
307         struct sockaddr *sa;
308         int size_of_addresses;
309         unsigned int siz;
310         int cnt;
311
312         if (raddrs == NULL) {
313                 errno = EFAULT;
314                 return(-1);
315         }
316         size_of_addresses = 0;
317         siz = sizeof(int);  
318         if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE,
319             &size_of_addresses, &siz) != 0) {
320                 return(-1);
321         }
322         if (size_of_addresses == 0) {
323                 errno = ENOTCONN;
324                 return(-1);
325         }
326         siz = size_of_addresses + sizeof(struct sockaddr_storage);
327         siz += sizeof(struct sctp_getaddresses);
328         addrs = calloc((unsigned long)1, (unsigned long)siz);
329         if (addrs == NULL) {
330                 errno = ENOMEM;
331                 return(-1);
332         }
333         memset(addrs, 0, (size_t)siz);
334         addrs->sget_assoc_id = id;
335         /* Now lets get the array of addresses */
336         if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs,
337             &siz) != 0) {
338                 free(addrs);
339                 return(-1);
340         }
341         re = (struct sockaddr *)&addrs->addr[0];
342         *raddrs = re;
343         cnt = 0;
344         sa = (struct sockaddr *)&addrs->addr[0];
345         lim = (caddr_t)addrs + siz;
346         while ((caddr_t)sa < lim) {
347                 cnt++;
348                 sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
349                 if (sa->sa_len == 0)
350                         break;
351         }
352         return(cnt);
353 }
354
355 void sctp_freeladdrs(struct sockaddr *addrs)
356 {
357         /* Take away the hidden association id */
358         void *fr_addr;
359         fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
360         /* Now free it */
361         free(fr_addr);
362 }
363
364
365 ssize_t
366 sctp_sendmsg(int s, 
367              const void *data, 
368              size_t len,
369              const struct sockaddr *to,
370              socklen_t tolen __attribute__((unused)),
371              u_int32_t ppid,
372              u_int32_t flags,
373              u_int16_t stream_no,
374              u_int32_t timetolive,
375              u_int32_t context)
376 {
377         ssize_t sz;
378         struct msghdr msg;
379         struct iovec iov[2];
380         char controlVector[256];
381         struct sctp_sndrcvinfo *s_info;
382         struct cmsghdr *cmsg;
383         struct sockaddr *who=NULL;
384         union {
385                 struct sockaddr_in in;
386                 struct sockaddr_in6 in6;
387         } addr;
388
389 #if 0
390         fprintf(io, "sctp_sendmsg(sd:%d, data:%x, len:%d, to:%x, tolen:%d, ppid:%x, flags:%x str:%d ttl:%d ctx:%x\n",
391             s, (u_int)data, (int)len, (u_int)to, (int)tolen, ppid, flags,
392             (int)stream_no, (int)timetolive, (u_int)context);
393         fflush(io);
394 #endif
395         if (to) {
396                 if (to->sa_len == 0) {
397                         /*
398                          * For the lazy app, that did not
399                          * set sa_len, we attempt to set for them.
400                          */
401                         if (to->sa_family == AF_INET){
402                                 memcpy(&addr, to, sizeof(struct sockaddr_in));
403                                 addr.in.sin_len = sizeof(struct sockaddr_in);
404                         } else if (to->sa_family == AF_INET6){
405                                 memcpy(&addr, to, sizeof(struct sockaddr_in6));
406                                 addr.in6.sin6_len = sizeof(struct sockaddr_in6);
407                         }
408                 } else {
409                         memcpy (&addr, to, to->sa_len);
410                 }
411                 who = (struct sockaddr *)&addr;
412         }
413         iov[0].iov_base = (char *)data;
414         iov[0].iov_len = len;
415         iov[1].iov_base = NULL;
416         iov[1].iov_len = 0;
417
418         if (to) {
419                 msg.msg_name = (caddr_t)who;
420                 msg.msg_namelen = who->sa_len;
421         } else {
422                 msg.msg_name = (caddr_t)NULL;
423                 msg.msg_namelen = 0;
424         }
425         msg.msg_iov = iov;
426         msg.msg_iovlen = 1;
427         msg.msg_control = (caddr_t)controlVector;
428
429         cmsg = (struct cmsghdr *)controlVector;
430
431         cmsg->cmsg_level = IPPROTO_SCTP;
432         cmsg->cmsg_type = SCTP_SNDRCV;
433         cmsg->cmsg_len = CMSG_LEN (sizeof(struct sctp_sndrcvinfo) );
434         s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
435
436         s_info->sinfo_stream = stream_no;
437         s_info->sinfo_ssn = 0;
438         s_info->sinfo_flags = flags;
439         s_info->sinfo_ppid = ppid;
440         s_info->sinfo_context = context;
441         s_info->sinfo_assoc_id = 0;
442         s_info->sinfo_timetolive = timetolive;
443         errno = 0;
444         msg.msg_controllen = cmsg->cmsg_len;
445         sz = sendmsg(s, &msg, 0);
446         return(sz);
447 }
448
449 sctp_assoc_t
450 sctp_getassocid(int sd, struct sockaddr *sa)
451 {
452         struct sctp_paddrparams sp;
453         int siz;
454
455         /* First get the assoc id */
456         siz = sizeof(struct sctp_paddrparams);
457         memset(&sp, 0, sizeof(sp));
458         memcpy((caddr_t)&sp.spp_address, sa, sa->sa_len);
459         errno = 0;
460         if (getsockopt(sd, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &sp, &siz) != 0)
461                 return((sctp_assoc_t)0);
462         /* We depend on the fact that 0 can never be returned */
463         return(sp.spp_assoc_id);
464 }
465
466
467
468 ssize_t
469 sctp_send(int sd, const void *data, size_t len,
470           const struct sctp_sndrcvinfo *sinfo,
471           int flags)
472 {
473         ssize_t sz;
474         struct msghdr msg;
475         struct iovec iov[2];
476         struct sctp_sndrcvinfo *s_info;
477         char controlVector[256];
478         struct cmsghdr *cmsg;
479
480         iov[0].iov_base = (char *)data;
481         iov[0].iov_len = len;
482         iov[1].iov_base = NULL;
483         iov[1].iov_len = 0;
484
485         msg.msg_name = 0;
486         msg.msg_namelen = 0;
487         msg.msg_iov = iov;
488         msg.msg_iovlen = 1;
489         msg.msg_control = (caddr_t)controlVector;
490   
491         cmsg = (struct cmsghdr *)controlVector;
492
493         cmsg->cmsg_level = IPPROTO_SCTP;
494         cmsg->cmsg_type = SCTP_SNDRCV;
495         cmsg->cmsg_len = CMSG_LEN (sizeof(struct sctp_sndrcvinfo) );
496         s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
497         /* copy in the data */
498         *s_info = *sinfo;
499         errno = 0;
500         msg.msg_controllen = cmsg->cmsg_len;
501         sz = sendmsg(sd, &msg, flags);
502         return(sz);
503 }
504
505
506 ssize_t
507 sctp_sendx(int sd, const void *msg, size_t len, 
508            struct sockaddr *addrs, int addrcnt,
509            struct sctp_sndrcvinfo *sinfo,
510            int flags)
511 {
512         int i, cnt, *aa, saved_errno;
513         ssize_t ret;
514         char *buf;
515         int add_len;
516         struct sockaddr *at;
517         len = sizeof(int);
518         at = addrs;
519         cnt = 0;
520         /* validate all the addresses and get the size */
521         for (i = 0; i < addrcnt; i++) {
522                 if (at->sa_family == AF_INET) {
523                         add_len = sizeof(struct sockaddr_in);
524                 } else if (at->sa_family == AF_INET6) {
525                         add_len = sizeof(struct sockaddr_in6);
526                 } else {
527                         errno = EINVAL;
528                         return (-1);
529                 }
530                 len += add_len;
531                 at = (struct sockaddr *)((caddr_t)at + add_len);
532                 cnt++;
533         }
534         /* do we have any? */
535         if (cnt == 0) {
536                 errno = EINVAL;
537                 return(-1);
538         }
539         if (len > 2048) {
540                 /* Never enough memory */
541                 errno = E2BIG;
542                 return(-1);
543         }
544         buf = malloc(len);
545         if (buf == NULL) {
546                 errno = ENOMEM;
547                 return(-1);
548         }
549         aa = (int *)buf;
550         *aa = cnt;
551         aa++;
552         memcpy((caddr_t)aa, addrs, (len - sizeof(int)));
553         ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_DELAYED, (void *)buf,
554             (unsigned int)len);
555
556         free(buf);
557         if (ret != 0) {
558                 return(ret);
559         }
560         sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs);
561         if (sinfo->sinfo_assoc_id == 0) {
562                 printf("Huh, can't get associd? TSNH!\n");
563                 (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
564                                  (unsigned int)addrs->sa_len);
565                 errno = ENOENT;
566                 return (-1);
567         }
568         ret = sctp_send(sd, msg, len, sinfo, flags);
569         saved_errno = errno;
570         (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
571                          (unsigned int)addrs->sa_len);
572
573         errno = saved_errno;
574         return (ret);
575 }
576
577 ssize_t
578 sctp_sendmsgx(int sd, 
579               const void *msg, 
580               size_t len,
581               struct sockaddr *addrs,
582               int addrcnt,
583               u_int32_t ppid,
584               u_int32_t flags,
585               u_int16_t stream_no,
586               u_int32_t timetolive,
587               u_int32_t context)
588 {
589         struct sctp_sndrcvinfo sinfo;
590     
591         memset((void *) &sinfo, 0, sizeof(struct sctp_sndrcvinfo));
592         sinfo.sinfo_ppid       = ppid;
593         sinfo.sinfo_flags      = flags;
594         sinfo.sinfo_ssn        = stream_no;
595         sinfo.sinfo_timetolive = timetolive;
596         sinfo.sinfo_context    = context;
597         return sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0);
598 }
599
600 ssize_t
601 sctp_recvmsg (int s, 
602               void *dbuf, 
603               size_t len,
604               struct sockaddr *from,
605               socklen_t *fromlen,
606               struct sctp_sndrcvinfo *sinfo,
607               int *msg_flags)
608 {
609         struct sctp_sndrcvinfo *s_info;
610         ssize_t sz;
611         struct msghdr msg;
612         struct iovec iov[2];
613         char controlVector[2048];
614         struct cmsghdr *cmsg;
615         iov[0].iov_base = dbuf;
616         iov[0].iov_len = len;
617         iov[1].iov_base = NULL;
618         iov[1].iov_len = 0;
619         msg.msg_name = (caddr_t)from;
620         msg.msg_namelen = *fromlen;
621         msg.msg_iov = iov;
622         msg.msg_iovlen = 1;
623         msg.msg_control = (caddr_t)controlVector;
624         msg.msg_controllen = sizeof(controlVector);
625         errno = 0;
626         sz = recvmsg(s, &msg, 0);
627
628         s_info = NULL;
629         len = sz;
630         *msg_flags = msg.msg_flags;
631         *fromlen = msg.msg_namelen;
632         if ((msg.msg_controllen) && sinfo) {
633                 /* parse through and see if we find
634                  * the sctp_sndrcvinfo (if the user wants it).
635                  */
636                 cmsg = (struct cmsghdr *)controlVector;
637                 while (cmsg) {
638                         if (cmsg->cmsg_level == IPPROTO_SCTP) {
639                                 if (cmsg->cmsg_type == SCTP_SNDRCV) {
640                                         /* Got it */
641                                         s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
642                                         /* Copy it to the user */
643                                         *sinfo = *s_info;
644                                         break;
645                                 }
646                         }
647                         cmsg = CMSG_NXTHDR(&msg, cmsg);
648                 }
649         }
650         return(sz);
651 }
652
653 #ifdef SYS_sctp_peeloff
654 int
655 sctp_peeloff(int sd, sctp_assoc_t assoc_id)
656 {
657         return (syscall(SYS_sctp_peeloff, sd, assoc_id));
658 }
659 #endif