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