]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/net/tcpip/v2_0/src/sys/kern/sockio.c
Initial revision
[karo-tx-redboot.git] / packages / net / tcpip / v2_0 / src / sys / kern / sockio.c
1 //==========================================================================
2 //
3 //      sys/kern/sockio.c
4 //
5 //     Socket interface to Fileio subsystem
6 //
7 //==========================================================================
8 //####BSDCOPYRIGHTBEGIN####
9 //
10 // -------------------------------------------
11 //
12 // Portions of this software may have been derived from OpenBSD or other sources,
13 // and are covered by the appropriate copyright disclaimers included herein.
14 //
15 // -------------------------------------------
16 //
17 //####BSDCOPYRIGHTEND####
18 //==========================================================================
19 //#####DESCRIPTIONBEGIN####
20 //
21 // Author(s):    nickg
22 // Contributors: nickg
23 // Date:         2000-06-06
24 // Purpose:      
25 // Description:  
26 //              
27 //
28 //####DESCRIPTIONEND####
29 //
30 //==========================================================================
31
32 /*
33  * Copyright (c) 1982, 1986, 1991, 1993
34  *      The Regents of the University of California.  All rights reserved.
35  * (c) UNIX System Laboratories, Inc.
36  * All or some portions of this file are derived from material licensed
37  * to the University of California by American Telephone and Telegraph
38  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
39  * the permission of UNIX System Laboratories, Inc.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. All advertising materials mentioning features or use of this software
50  *    must display the following acknowledgement:
51  *      This product includes software developed by the University of
52  *      California, Berkeley and its contributors.
53  * 4. Neither the name of the University nor the names of its contributors
54  *    may be used to endorse or promote products derived from this software
55  *    without specific prior written permission.
56  *
57  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67  * SUCH DAMAGE.
68  *
69  */
70 //==========================================================================
71
72 #include <pkgconf/net.h>
73 #include <pkgconf/io_fileio.h>
74
75 #include <sys/types.h>
76
77 #include <cyg/io/file.h>
78
79 #include <cyg/fileio/fileio.h>
80 #include <cyg/fileio/sockio.h>
81
82 #include <sys/param.h>
83 #include <sys/mbuf.h>
84 #include <sys/protosw.h>
85 #include <sys/socket.h>
86 #include <sys/socketvar.h>
87 #include <sys/ioctl.h>
88
89 #include <net/if.h>
90 #include <net/route.h>
91
92 //==========================================================================
93 // Forward definitions
94
95 static int     bsd_init( cyg_nstab_entry *nste );
96 static int     bsd_socket( cyg_nstab_entry *nste, int domain, int type,
97                        int protocol, cyg_file *file );
98
99 static int bsd_bind      ( cyg_file *fp, const sockaddr *sa, socklen_t len );
100 static int bsd_connect   ( cyg_file *fp, const sockaddr *sa, socklen_t len );
101 static int bsd_accept    ( cyg_file *fp, cyg_file *new_fp,
102                            struct sockaddr *name, socklen_t *anamelen );
103 static int bsd_listen    ( cyg_file *fp, int len );
104 static int bsd_getname   ( cyg_file *fp, sockaddr *sa, socklen_t *len, int peer );
105 static int bsd_shutdown  ( cyg_file *fp, int flags );
106 static int bsd_getsockopt( cyg_file *fp, int level, int optname,
107                            void *optval, socklen_t *optlen);
108 static int bsd_setsockopt( cyg_file *fp, int level, int optname,
109                            const void *optval, socklen_t optlen);
110 static int bsd_sendmsg   ( cyg_file *fp, const struct msghdr *m,
111                                int flags, ssize_t *retsize );
112 static int bsd_recvmsg   ( cyg_file *fp, struct msghdr *m,
113                                socklen_t *namelen, ssize_t *retsize );
114
115
116 // File operations
117 static int bsd_read      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
118 static int bsd_write     (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
119 static int bsd_lseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
120 static int bsd_ioctl     (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
121                                 CYG_ADDRWORD data);
122 static int bsd_select    (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info);
123 static int bsd_fsync     (struct CYG_FILE_TAG *fp, int mode );        
124 static int bsd_close     (struct CYG_FILE_TAG *fp);
125 static int bsd_fstat     (struct CYG_FILE_TAG *fp, struct stat *buf );
126 static int bsd_getinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
127 static int bsd_setinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
128
129 static int
130 bsd_recvit(cyg_file *fp, struct msghdr *mp, socklen_t *namelenp, ssize_t *retsize);
131 static int
132 bsd_sendit(cyg_file *fp, const struct msghdr *mp, int flags, ssize_t *retsize);
133
134
135 //==========================================================================
136 // Table entrys
137
138 NSTAB_ENTRY( bsd_nste, 0,
139              "bsd_tcpip",
140              "",
141              0,
142              bsd_init,
143              bsd_socket);
144
145 struct cyg_sock_ops bsd_sockops =
146 {
147     bsd_bind,
148     bsd_connect,
149     bsd_accept,
150     bsd_listen,
151     bsd_getname,
152     bsd_shutdown,
153     bsd_getsockopt,
154     bsd_setsockopt,
155     bsd_sendmsg,
156     bsd_recvmsg
157 };
158
159 cyg_fileops bsd_sock_fileops =
160 {
161     bsd_read,
162     bsd_write,
163     bsd_lseek,
164     bsd_ioctl,
165     bsd_select,
166     bsd_fsync,
167     bsd_close,
168     bsd_fstat,
169     bsd_getinfo,
170     bsd_setinfo    
171 };
172
173 //==========================================================================
174 // NStab functions
175
176
177
178 // -------------------------------------------------------------------------
179
180 static int     bsd_init( cyg_nstab_entry *nste )
181 {
182     // Initialization already handled via constructor
183     
184     return ENOERR;
185 }
186
187 // -------------------------------------------------------------------------
188
189 static int     bsd_socket( cyg_nstab_entry *nste, int domain, int type,
190                        int protocol, cyg_file *file )
191 {
192     int error = 0;
193     struct socket *so;
194
195     error = socreate( domain, &so, type, protocol );
196
197     if( error == ENOERR )
198     {
199
200         cyg_selinit(&so->so_rcv.sb_sel);
201         cyg_selinit(&so->so_snd.sb_sel);
202         
203         file->f_flag   |= CYG_FREAD|CYG_FWRITE;
204         file->f_type    = CYG_FILE_TYPE_SOCKET;
205         file->f_ops     = &bsd_sock_fileops;
206         file->f_offset  = 0;
207         file->f_data    = (CYG_ADDRWORD)so;
208         file->f_xops    = (CYG_ADDRWORD)&bsd_sockops;
209     }
210     
211     return error;
212 }
213
214
215 //==========================================================================
216 // Sockops functions
217
218 // -------------------------------------------------------------------------
219
220 static int bsd_bind      ( cyg_file *fp, const sockaddr *sa, socklen_t len )
221 {
222     struct mbuf *nam;
223     int error;
224
225     error = sockargs(&nam, (caddr_t)sa, len, MT_SONAME);
226
227     if (error)
228         return (error);
229
230     error = sobind((struct socket *)fp->f_data, nam);
231
232     m_freem(nam);
233     
234     return error;
235 }
236
237 // -------------------------------------------------------------------------
238
239 static int bsd_connect   ( cyg_file *fp, const sockaddr *sa, socklen_t len )
240 {
241     register struct socket *so;
242     struct mbuf *nam;
243     int error, s;
244
245     so = (struct socket *)fp->f_data;
246
247     if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING))
248         return (EALREADY);
249
250     error = sockargs(&nam, (caddr_t)sa, len, MT_SONAME);
251
252     if (error)
253         return (error);
254
255     error = soconnect(so, nam);
256     if (error)
257         goto bad;
258
259     if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
260         m_freem(nam);
261         return (EINPROGRESS);
262     }
263
264     s = splsoftnet();
265     while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
266         error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
267                        netcon, 0);
268         if (error)
269             break;
270     }
271
272     if (error == 0) {
273         error = so->so_error;
274         so->so_error = 0;
275     }
276
277     splx(s);
278
279 bad:
280     so->so_state &= ~SS_ISCONNECTING;
281     m_freem(nam);
282
283     return error;
284 }
285
286 // -------------------------------------------------------------------------
287
288 static int bsd_accept    ( cyg_file *fp, cyg_file *new_fp,
289                            struct sockaddr *name, socklen_t *anamelen )
290 {
291     struct mbuf *nam;
292     socklen_t namelen = 0;
293     int error = 0, s;
294     register struct socket *so;
295
296     if( anamelen != NULL )
297         namelen = *anamelen;
298
299     s = splsoftnet();
300     so = (struct socket *)fp->f_data;
301
302     if ((so->so_options & SO_ACCEPTCONN) == 0) {
303         splx(s);
304         return (EINVAL);
305     }
306
307     if ((so->so_state & SS_NBIO) && so->so_qlen == 0) {
308         splx(s);
309         return (EWOULDBLOCK);
310     }
311
312     while (so->so_qlen == 0 && so->so_error == 0) {
313         if (so->so_state & SS_CANTRCVMORE) {
314             so->so_error = ECONNABORTED;
315             break;
316         }
317         error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
318                        netcon, 0);
319         if (error) {
320             splx(s);
321             return (error);
322         }
323     }
324
325     if (so->so_error) {
326         error = so->so_error;
327         so->so_error = 0;
328         splx(s);
329         return (error);
330     }
331
332     {
333         struct socket *aso = so->so_q;
334         if (soqremque(aso, 1) == 0)
335             panic("accept");
336         so = aso;
337     }
338
339     cyg_selinit(&so->so_rcv.sb_sel);
340     cyg_selinit(&so->so_snd.sb_sel);
341     
342     new_fp->f_type      = DTYPE_SOCKET;
343     new_fp->f_flag     |= FREAD|FWRITE;
344     new_fp->f_offset    = 0;
345     new_fp->f_ops       = &bsd_sock_fileops;
346     new_fp->f_data      = (CYG_ADDRWORD)so;
347     new_fp->f_xops      = (CYG_ADDRWORD)&bsd_sockops;
348     
349     nam = m_get(M_WAIT, MT_SONAME);
350     (void) soaccept(so, nam);
351     if (name) {
352         if (namelen > nam->m_len)
353             namelen = nam->m_len;
354         /* SHOULD COPY OUT A CHAIN HERE */
355         if ((error = copyout(mtod(nam, caddr_t),
356                              (caddr_t)name, namelen)) == 0)
357             *anamelen = namelen;
358     }
359     m_freem(nam);
360     splx(s);
361     
362     return (error);
363 }
364
365 // -------------------------------------------------------------------------
366
367 static int bsd_listen    ( cyg_file *fp, int backlog )
368 {
369     return (solisten((struct socket *)fp->f_data, backlog));
370 }
371
372 // -------------------------------------------------------------------------
373
374 static int bsd_getname   ( cyg_file *fp, sockaddr *asa, socklen_t *alen, int peer )
375 {
376     register struct socket *so;
377     struct mbuf *m;
378     socklen_t len = 0;
379     int error;
380     int type = peer ? PRU_PEERADDR : PRU_SOCKADDR;
381     
382     if( alen != NULL )
383         len = *alen;
384         
385     so = (struct socket *)fp->f_data;
386
387     if ( peer && (so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
388         return (ENOTCONN);
389
390     m = m_getclr(M_WAIT, MT_SONAME);
391     if (m == NULL)
392         return (ENOBUFS);
393     
394     error = (*so->so_proto->pr_usrreq)(so, type, 0, m, 0);
395     if (error)
396         goto bad;
397
398     if (len > m->m_len)
399         len = m->m_len;
400
401     error = copyout(mtod(m, caddr_t), (caddr_t)asa, len);
402     
403     if (error == 0)
404         *alen = len;
405
406 bad:
407     m_freem(m);
408
409     return (error);
410 }
411
412 // -------------------------------------------------------------------------
413
414 static int bsd_shutdown  ( cyg_file *fp, int how )
415 {
416     return (soshutdown((struct socket *)fp->f_data, how));
417 }
418
419 // -------------------------------------------------------------------------
420
421 static int bsd_getsockopt( cyg_file *fp, int level, int optname,
422                            void *optval, socklen_t *optlen)
423 {
424     struct mbuf *m = NULL;
425     socklen_t valsize = 0;
426     int error;
427
428     if( optval != NULL && optlen != NULL )
429         valsize = *optlen;
430     
431     error = sogetopt((struct socket *)fp->f_data, level, optname, &m);
432
433     if( error == ENOERR && valsize != 0 && m != NULL)
434     {
435         if (valsize > m->m_len)
436             valsize = m->m_len;
437
438         error = copyout(mtod(m, caddr_t), optval, valsize);
439
440         if( error == ENOERR )
441             *optlen = valsize;
442         
443     }
444
445     if (m != NULL)
446         (void) m_free(m);
447     return (error);
448 }
449
450 // -------------------------------------------------------------------------
451
452 static int bsd_setsockopt( cyg_file *fp, int level, int optname,
453                            const void *optval, socklen_t optlen)
454 {
455     int error;
456     struct mbuf *m = NULL;
457     
458     if( optlen > MCLBYTES )
459         return EINVAL;
460
461     if (optval != NULL) {
462         m = m_get(M_WAIT, MT_SOOPTS);
463         if (optlen > MLEN) {
464             MCLGET(m, M_DONTWAIT);
465             if ((m->m_flags & M_EXT) == 0) {
466                 m_freem(m);
467                 return (ENOBUFS);
468             }
469         }
470         if (m == NULL)
471             return (ENOBUFS);
472         error = copyin(optval, mtod(m, caddr_t), optlen);
473         if (error) {
474             (void) m_free(m);
475             return (error);
476         }
477         m->m_len = optlen;
478     }
479     
480     return (sosetopt((struct socket *)fp->f_data, level, optname, m));
481 }
482
483 // -------------------------------------------------------------------------
484
485 static int bsd_sendmsg   ( cyg_file *fp, const struct msghdr *m, int flags, ssize_t *retsize )
486 {
487     return bsd_sendit( fp, m, flags, retsize);
488 }
489
490 // -------------------------------------------------------------------------
491
492 static int bsd_recvmsg   ( cyg_file *fp, struct msghdr *m, socklen_t *namelen, ssize_t *retsize )
493 {
494     return bsd_recvit( fp, m, namelen, retsize);
495 }
496
497 //==========================================================================
498 // File system call functions
499
500 // -------------------------------------------------------------------------
501
502 static int bsd_read      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
503 {
504     return (soreceive((struct socket *)fp->f_data, (struct mbuf **)0,
505                       uio, (struct mbuf **)0, (struct mbuf **)0, (int *)0));
506 }
507
508 // -------------------------------------------------------------------------
509
510 static int bsd_write     (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
511 {
512         return (sosend((struct socket *)fp->f_data, (struct mbuf *)0,
513                 uio, (struct mbuf *)0, (struct mbuf *)0, 0));
514 }
515
516 // -------------------------------------------------------------------------
517
518 static int bsd_lseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence )
519 {
520     return ESPIPE;
521 }
522
523 // -------------------------------------------------------------------------
524
525 static int bsd_ioctl     (struct CYG_FILE_TAG *fp, CYG_ADDRWORD cmd,
526                                 CYG_ADDRWORD data)
527 {
528         register struct socket *so = (struct socket *)fp->f_data;
529         void *p = 0;
530
531         switch (cmd) {
532
533         case FIONBIO:
534                 if (*(int *)data)
535                         so->so_state |= SS_NBIO;
536                 else
537                         so->so_state &= ~SS_NBIO;
538                 return (0);
539
540         case FIOASYNC:
541                 if (*(int *)data) {
542                         so->so_state |= SS_ASYNC;
543                         so->so_rcv.sb_flags |= SB_ASYNC;
544                         so->so_snd.sb_flags |= SB_ASYNC;
545                 } else {
546                         so->so_state &= ~SS_ASYNC;
547                         so->so_rcv.sb_flags &= ~SB_ASYNC;
548                         so->so_snd.sb_flags &= ~SB_ASYNC;
549                 }
550                 return (0);
551
552         case FIONREAD:
553                 *(int *)data = so->so_rcv.sb_cc;
554                 return (0);
555
556         case SIOCATMARK:
557                 *(int *)data = (so->so_state&SS_RCVATMARK) != 0;
558                 return (0);
559         }
560         /*
561          * Interface/routing/protocol specific ioctls:
562          * interface and routing ioctls should have a
563          * different entry since a socket's unnecessary
564          */
565         if (IOCGROUP(cmd) == 'i')
566                 return (ifioctl(so, (u_long)cmd, (caddr_t)data, p));
567         if (IOCGROUP(cmd) == 'r')
568                 return (rtioctl((u_long)cmd, (caddr_t)data, p));
569         return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 
570             (struct mbuf *)cmd, (struct mbuf *)data, (struct mbuf *)0));
571
572 }
573
574 // -------------------------------------------------------------------------
575
576 static int bsd_select    (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info)
577 {
578     register struct socket *so = (struct socket *)fp->f_data;
579     register int s = splsoftnet();
580
581     switch (which) {
582
583     case FREAD:
584         if (soreadable(so)) {
585             splx(s);
586             return (1);
587         }
588         cyg_selrecord(info, &so->so_rcv.sb_sel);
589         so->so_rcv.sb_flags |= SB_SEL;
590         break;
591
592     case FWRITE:
593         if (sowriteable(so)) {
594             splx(s);
595             return (1);
596         }
597         cyg_selrecord(info, &so->so_snd.sb_sel);
598         so->so_snd.sb_flags |= SB_SEL;
599         break;
600
601     case 0:
602         if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) {
603             splx(s);
604             return (1);
605         }
606         cyg_selrecord(info, &so->so_rcv.sb_sel);
607         so->so_rcv.sb_flags |= SB_SEL;
608         break;
609     }
610     splx(s);
611     
612     return ENOERR;
613 }
614
615 // -------------------------------------------------------------------------
616
617 static int bsd_fsync     (struct CYG_FILE_TAG *fp, int mode )
618 {
619     // FIXME: call some sort of flush IOCTL?
620     return 0;
621 }
622
623 // -------------------------------------------------------------------------
624
625 static int bsd_close     (struct CYG_FILE_TAG *fp)
626 {
627     int error = 0;
628
629     if (fp->f_data)
630         error = soclose((struct socket *)fp->f_data);
631     fp->f_data = 0;
632     return (error);
633 }
634
635 // -------------------------------------------------------------------------
636
637 static int bsd_fstat     (struct CYG_FILE_TAG *fp, struct stat *buf )
638 {
639     register struct socket *so = (struct socket *)fp->f_data;
640
641     bzero((caddr_t)buf, sizeof (*buf));
642
643     // Mark socket as a fifo for now. We need to add socket types to
644     // sys/stat.h.
645     buf->st_mode = __stat_mode_FIFO;
646     
647     return ((*so->so_proto->pr_usrreq)(so, PRU_SENSE,
648                                        (struct mbuf *)buf,
649                                        (struct mbuf *)0, 
650                                        (struct mbuf *)0));
651 }
652
653 // -------------------------------------------------------------------------
654
655 static int bsd_getinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
656 {
657     return ENOSYS;
658 }
659
660 // -------------------------------------------------------------------------
661
662 static int bsd_setinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
663 {
664     return ENOSYS;
665 }
666
667
668
669 //==========================================================================
670 // Select support
671
672 // -------------------------------------------------------------------------
673 // This function is called by the lower layers to record the
674 // fact that a particular 'select' event is being requested.
675 //
676
677 void        
678 selrecord(void *selector, struct selinfo *info)
679 {
680     // Unused by this implementation
681 }
682
683 // -------------------------------------------------------------------------
684 // This function is called to indicate that a 'select' event
685 // may have occurred.
686 //
687
688 void    
689 selwakeup(struct selinfo *info)
690 {
691     cyg_selwakeup( info );
692 }
693
694 //==========================================================================
695 // Misc support functions
696
697 int
698 sockargs(mp, buf, buflen, type)
699         struct mbuf **mp;
700         caddr_t buf;
701         socklen_t buflen;
702         int type;
703 {
704         register struct sockaddr *sa;
705         register struct mbuf *m;
706         int error;
707
708         if (buflen > MLEN) {
709 #ifdef COMPAT_OLDSOCK
710                 if (type == MT_SONAME && buflen <= 112)
711                         buflen = MLEN;          /* unix domain compat. hack */
712                 else
713 #endif
714                 return (EINVAL);
715         }
716         m = m_get(M_WAIT, type);
717         if (m == NULL)
718                 return (ENOBUFS);
719         m->m_len = buflen;
720         error = copyin(buf, mtod(m, caddr_t), buflen);
721         if (error) {
722                 (void) m_free(m);
723                 return (error);
724         }
725         *mp = m;
726         if (type == MT_SONAME) {
727                 sa = mtod(m, struct sockaddr *);
728
729 #if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
730                 if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
731                         sa->sa_family = sa->sa_len;
732 #endif
733                 sa->sa_len = buflen;
734         }
735         return (0);
736 }
737
738
739 // -------------------------------------------------------------------------
740 // bsd_recvit()
741 // Support for message reception. This is a lightly edited version of the
742 // recvit() function is uipc_syscalls.c.
743
744 static int
745 bsd_recvit(cyg_file *fp, struct msghdr *mp, socklen_t *namelenp, ssize_t *retsize)
746 {
747         struct uio auio;
748         register struct iovec *iov;
749         register int i;
750         size_t len;
751         int error;
752         struct mbuf *from = 0, *control = 0;
753
754         auio.uio_iov = mp->msg_iov;
755         auio.uio_iovcnt = mp->msg_iovlen;
756         auio.uio_segflg = UIO_USERSPACE;
757         auio.uio_rw = UIO_READ;
758         auio.uio_offset = 0;                    /* XXX */
759         auio.uio_resid = 0;
760         iov = mp->msg_iov;
761         for (i = 0; i < mp->msg_iovlen; i++, iov++) {
762                 /* Don't allow sum > SSIZE_MAX */
763                 if (iov->iov_len > SSIZE_MAX ||
764                     (auio.uio_resid += iov->iov_len) > SSIZE_MAX)
765                         return (EINVAL);
766         }
767
768         len = auio.uio_resid;
769         error = soreceive((struct socket *)fp->f_data, &from, &auio,
770                           NULL, mp->msg_control ? &control : NULL,
771                           &mp->msg_flags);
772         if (error) {
773                 if (auio.uio_resid != len && 
774                     (error == EINTR || error == EWOULDBLOCK))
775                         error = 0;
776         }
777         if (error)
778                 goto out;
779         *retsize = len - auio.uio_resid;
780         if (mp->msg_name) {
781                 len = mp->msg_namelen;
782                 if (len <= 0 || from == 0)
783                         len = 0;
784                 else {
785                         /* save sa_len before it is destroyed by MSG_COMPAT */
786                         if (len > from->m_len)
787                                 len = from->m_len;
788                         /* else if len < from->m_len ??? */
789 #ifdef COMPAT_OLDSOCK
790                         if (mp->msg_flags & MSG_COMPAT)
791                                 mtod(from, struct osockaddr *)->sa_family =
792                                     mtod(from, struct sockaddr *)->sa_family;
793 #endif
794                         error = copyout(mtod(from, caddr_t),
795                             (caddr_t)mp->msg_name, (unsigned)len);
796                         if (error)
797                                 goto out;
798                 }
799                 mp->msg_namelen = len;
800                 if (namelenp ) {
801                         *namelenp = len;
802 #ifdef COMPAT_OLDSOCK
803                         if (mp->msg_flags & MSG_COMPAT)
804                                 error = 0;      /* old recvfrom didn't check */
805                         else
806 #endif
807                         goto out;
808                 }
809         }
810         if (mp->msg_control) {
811 #ifdef COMPAT_OLDSOCK
812                 /*
813                  * We assume that old recvmsg calls won't receive access
814                  * rights and other control info, esp. as control info
815                  * is always optional and those options didn't exist in 4.3.
816                  * If we receive rights, trim the cmsghdr; anything else
817                  * is tossed.
818                  */
819                 if (control && mp->msg_flags & MSG_COMPAT) {
820                         if (mtod(control, struct cmsghdr *)->cmsg_level !=
821                             SOL_SOCKET ||
822                             mtod(control, struct cmsghdr *)->cmsg_type !=
823                             SCM_RIGHTS) {
824                                 mp->msg_controllen = 0;
825                                 goto out;
826                         }
827                         control->m_len -= sizeof (struct cmsghdr);
828                         control->m_data += sizeof (struct cmsghdr);
829                 }
830 #endif
831                 len = mp->msg_controllen;
832                 if (len <= 0 || control == 0)
833                         len = 0;
834                 else {
835                         struct mbuf *m = control;
836                         caddr_t p = (caddr_t)mp->msg_control;
837
838                         do {
839                                 i = m->m_len;
840                                 if (len < i) {
841                                         mp->msg_flags |= MSG_CTRUNC;
842                                         i = len;
843                                 }
844                                 error = copyout(mtod(m, caddr_t), p,
845                                     (unsigned)i);
846                                 if (m->m_next)
847                                         i = ALIGN(i);
848                                 p += i;
849                                 len -= i;
850                                 if (error != 0 || len <= 0)
851                                         break;
852                         } while ((m = m->m_next) != NULL);
853                         len = p - (caddr_t)mp->msg_control;
854                 }
855                 mp->msg_controllen = len;
856         }
857 out:
858         if (from)
859                 m_freem(from);
860         if (control)
861                 m_freem(control);
862         return (error);
863 }
864
865 // -------------------------------------------------------------------------
866 // sendit()
867 // Support for message transmission. This is a lightly edited version of the
868 // synonymous function is uipc_syscalls.c.
869
870 static int
871 bsd_sendit(cyg_file *fp, const struct msghdr *mp, int flags, ssize_t *retsize)
872 {
873         struct uio auio;
874         register struct iovec *iov;
875         register int i;
876         struct mbuf *to, *control;
877         int len, error;
878         
879         auio.uio_iov = mp->msg_iov;
880         auio.uio_iovcnt = mp->msg_iovlen;
881         auio.uio_segflg = UIO_USERSPACE;
882         auio.uio_rw = UIO_WRITE;
883         auio.uio_offset = 0;                    /* XXX */
884         auio.uio_resid = 0;
885         iov = mp->msg_iov;
886         for (i = 0; i < mp->msg_iovlen; i++, iov++) {
887                 /* Don't allow sum > SSIZE_MAX */
888                 if (iov->iov_len > SSIZE_MAX ||
889                     (auio.uio_resid += iov->iov_len) > SSIZE_MAX)
890                         return (EINVAL);
891         }
892         if (mp->msg_name) {
893                 error = sockargs(&to, mp->msg_name, mp->msg_namelen,
894                                  MT_SONAME);
895                 if (error)
896                         return (error);
897         } else
898                 to = 0;
899         if (mp->msg_control) {
900                 if (mp->msg_controllen < sizeof(struct cmsghdr)
901 #ifdef COMPAT_OLDSOCK
902                     && mp->msg_flags != MSG_COMPAT
903 #endif
904                 ) {
905                         error = EINVAL;
906                         goto bad;
907                 }
908                 error = sockargs(&control, mp->msg_control,
909                                  mp->msg_controllen, MT_CONTROL);
910                 if (error)
911                         goto bad;
912 #ifdef COMPAT_OLDSOCK
913                 if (mp->msg_flags == MSG_COMPAT) {
914                         register struct cmsghdr *cm;
915
916                         M_PREPEND(control, sizeof(*cm), M_WAIT);
917                         if (control == 0) {
918                                 error = ENOBUFS;
919                                 goto bad;
920                         } else {
921                                 cm = mtod(control, struct cmsghdr *);
922                                 cm->cmsg_len = control->m_len;
923                                 cm->cmsg_level = SOL_SOCKET;
924                                 cm->cmsg_type = SCM_RIGHTS;
925                         }
926                 }
927 #endif
928         } else
929                 control = 0;
930
931         len = auio.uio_resid;
932         error = sosend((struct socket *)fp->f_data, to, &auio,
933                        NULL, control, flags);
934         if (error) {
935                 if (auio.uio_resid != len && 
936                     (error == EINTR || error == EWOULDBLOCK))
937                         error = 0;
938 #ifndef __ECOS
939                 if (error == EPIPE)
940                         psignal(p, SIGPIPE);
941 #endif
942         }
943         if (error == 0)
944                 *retsize = len - auio.uio_resid;
945 bad:
946         if (to)
947                 m_freem(to);
948         return (error);
949 }
950
951
952 //==========================================================================
953 // End of sockio.c