1 //==========================================================================
5 // Socket interface to Fileio subsystem
7 //==========================================================================
8 //####BSDCOPYRIGHTBEGIN####
10 // -------------------------------------------
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.
15 // -------------------------------------------
17 //####BSDCOPYRIGHTEND####
18 //==========================================================================
19 //#####DESCRIPTIONBEGIN####
22 // Contributors: nickg
28 //####DESCRIPTIONEND####
30 //==========================================================================
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.
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
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.
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
70 //==========================================================================
72 #include <pkgconf/net.h>
73 #include <pkgconf/io_fileio.h>
75 #include <sys/types.h>
77 #include <cyg/io/file.h>
79 #include <cyg/fileio/fileio.h>
80 #include <cyg/fileio/sockio.h>
82 #include <sys/param.h>
84 #include <sys/protosw.h>
85 #include <sys/socket.h>
86 #include <sys/socketvar.h>
87 #include <sys/ioctl.h>
90 #include <net/route.h>
92 //==========================================================================
93 // Forward definitions
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 );
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 );
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,
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 );
130 bsd_recvit(cyg_file *fp, struct msghdr *mp, socklen_t *namelenp, ssize_t *retsize);
132 bsd_sendit(cyg_file *fp, const struct msghdr *mp, int flags, ssize_t *retsize);
135 //==========================================================================
138 NSTAB_ENTRY( bsd_nste, 0,
145 struct cyg_sock_ops bsd_sockops =
159 cyg_fileops bsd_sock_fileops =
173 //==========================================================================
178 // -------------------------------------------------------------------------
180 static int bsd_init( cyg_nstab_entry *nste )
182 // Initialization already handled via constructor
187 // -------------------------------------------------------------------------
189 static int bsd_socket( cyg_nstab_entry *nste, int domain, int type,
190 int protocol, cyg_file *file )
195 error = socreate( domain, &so, type, protocol );
197 if( error == ENOERR )
200 cyg_selinit(&so->so_rcv.sb_sel);
201 cyg_selinit(&so->so_snd.sb_sel);
203 file->f_flag |= CYG_FREAD|CYG_FWRITE;
204 file->f_type = CYG_FILE_TYPE_SOCKET;
205 file->f_ops = &bsd_sock_fileops;
207 file->f_data = (CYG_ADDRWORD)so;
208 file->f_xops = (CYG_ADDRWORD)&bsd_sockops;
215 //==========================================================================
218 // -------------------------------------------------------------------------
220 static int bsd_bind ( cyg_file *fp, const sockaddr *sa, socklen_t len )
225 error = sockargs(&nam, (caddr_t)sa, len, MT_SONAME);
230 error = sobind((struct socket *)fp->f_data, nam);
237 // -------------------------------------------------------------------------
239 static int bsd_connect ( cyg_file *fp, const sockaddr *sa, socklen_t len )
241 register struct socket *so;
245 so = (struct socket *)fp->f_data;
247 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING))
250 error = sockargs(&nam, (caddr_t)sa, len, MT_SONAME);
255 error = soconnect(so, nam);
259 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
261 return (EINPROGRESS);
265 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
266 error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
273 error = so->so_error;
280 so->so_state &= ~SS_ISCONNECTING;
286 // -------------------------------------------------------------------------
288 static int bsd_accept ( cyg_file *fp, cyg_file *new_fp,
289 struct sockaddr *name, socklen_t *anamelen )
292 socklen_t namelen = 0;
294 register struct socket *so;
296 if( anamelen != NULL )
300 so = (struct socket *)fp->f_data;
302 if ((so->so_options & SO_ACCEPTCONN) == 0) {
307 if ((so->so_state & SS_NBIO) && so->so_qlen == 0) {
309 return (EWOULDBLOCK);
312 while (so->so_qlen == 0 && so->so_error == 0) {
313 if (so->so_state & SS_CANTRCVMORE) {
314 so->so_error = ECONNABORTED;
317 error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
326 error = so->so_error;
333 struct socket *aso = so->so_q;
334 if (soqremque(aso, 1) == 0)
339 cyg_selinit(&so->so_rcv.sb_sel);
340 cyg_selinit(&so->so_snd.sb_sel);
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;
349 nam = m_get(M_WAIT, MT_SONAME);
350 (void) soaccept(so, nam);
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)
365 // -------------------------------------------------------------------------
367 static int bsd_listen ( cyg_file *fp, int backlog )
369 return (solisten((struct socket *)fp->f_data, backlog));
372 // -------------------------------------------------------------------------
374 static int bsd_getname ( cyg_file *fp, sockaddr *asa, socklen_t *alen, int peer )
376 register struct socket *so;
380 int type = peer ? PRU_PEERADDR : PRU_SOCKADDR;
385 so = (struct socket *)fp->f_data;
387 if ( peer && (so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
390 m = m_getclr(M_WAIT, MT_SONAME);
394 error = (*so->so_proto->pr_usrreq)(so, type, 0, m, 0);
401 error = copyout(mtod(m, caddr_t), (caddr_t)asa, len);
412 // -------------------------------------------------------------------------
414 static int bsd_shutdown ( cyg_file *fp, int how )
416 return (soshutdown((struct socket *)fp->f_data, how));
419 // -------------------------------------------------------------------------
421 static int bsd_getsockopt( cyg_file *fp, int level, int optname,
422 void *optval, socklen_t *optlen)
424 struct mbuf *m = NULL;
425 socklen_t valsize = 0;
428 if( optval != NULL && optlen != NULL )
431 error = sogetopt((struct socket *)fp->f_data, level, optname, &m);
433 if( error == ENOERR && valsize != 0 && m != NULL)
435 if (valsize > m->m_len)
438 error = copyout(mtod(m, caddr_t), optval, valsize);
440 if( error == ENOERR )
450 // -------------------------------------------------------------------------
452 static int bsd_setsockopt( cyg_file *fp, int level, int optname,
453 const void *optval, socklen_t optlen)
456 struct mbuf *m = NULL;
458 if( optlen > MCLBYTES )
461 if (optval != NULL) {
462 m = m_get(M_WAIT, MT_SOOPTS);
464 MCLGET(m, M_DONTWAIT);
465 if ((m->m_flags & M_EXT) == 0) {
472 error = copyin(optval, mtod(m, caddr_t), optlen);
480 return (sosetopt((struct socket *)fp->f_data, level, optname, m));
483 // -------------------------------------------------------------------------
485 static int bsd_sendmsg ( cyg_file *fp, const struct msghdr *m, int flags, ssize_t *retsize )
487 return bsd_sendit( fp, m, flags, retsize);
490 // -------------------------------------------------------------------------
492 static int bsd_recvmsg ( cyg_file *fp, struct msghdr *m, socklen_t *namelen, ssize_t *retsize )
494 return bsd_recvit( fp, m, namelen, retsize);
497 //==========================================================================
498 // File system call functions
500 // -------------------------------------------------------------------------
502 static int bsd_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
504 return (soreceive((struct socket *)fp->f_data, (struct mbuf **)0,
505 uio, (struct mbuf **)0, (struct mbuf **)0, (int *)0));
508 // -------------------------------------------------------------------------
510 static int bsd_write (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
512 return (sosend((struct socket *)fp->f_data, (struct mbuf *)0,
513 uio, (struct mbuf *)0, (struct mbuf *)0, 0));
516 // -------------------------------------------------------------------------
518 static int bsd_lseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence )
523 // -------------------------------------------------------------------------
525 static int bsd_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD cmd,
528 register struct socket *so = (struct socket *)fp->f_data;
535 so->so_state |= SS_NBIO;
537 so->so_state &= ~SS_NBIO;
542 so->so_state |= SS_ASYNC;
543 so->so_rcv.sb_flags |= SB_ASYNC;
544 so->so_snd.sb_flags |= SB_ASYNC;
546 so->so_state &= ~SS_ASYNC;
547 so->so_rcv.sb_flags &= ~SB_ASYNC;
548 so->so_snd.sb_flags &= ~SB_ASYNC;
553 *(int *)data = so->so_rcv.sb_cc;
557 *(int *)data = (so->so_state&SS_RCVATMARK) != 0;
561 * Interface/routing/protocol specific ioctls:
562 * interface and routing ioctls should have a
563 * different entry since a socket's unnecessary
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));
574 // -------------------------------------------------------------------------
576 static int bsd_select (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info)
578 register struct socket *so = (struct socket *)fp->f_data;
579 register int s = splsoftnet();
584 if (soreadable(so)) {
588 cyg_selrecord(info, &so->so_rcv.sb_sel);
589 so->so_rcv.sb_flags |= SB_SEL;
593 if (sowriteable(so)) {
597 cyg_selrecord(info, &so->so_snd.sb_sel);
598 so->so_snd.sb_flags |= SB_SEL;
602 if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) {
606 cyg_selrecord(info, &so->so_rcv.sb_sel);
607 so->so_rcv.sb_flags |= SB_SEL;
615 // -------------------------------------------------------------------------
617 static int bsd_fsync (struct CYG_FILE_TAG *fp, int mode )
619 // FIXME: call some sort of flush IOCTL?
623 // -------------------------------------------------------------------------
625 static int bsd_close (struct CYG_FILE_TAG *fp)
630 error = soclose((struct socket *)fp->f_data);
635 // -------------------------------------------------------------------------
637 static int bsd_fstat (struct CYG_FILE_TAG *fp, struct stat *buf )
639 register struct socket *so = (struct socket *)fp->f_data;
641 bzero((caddr_t)buf, sizeof (*buf));
643 // Mark socket as a fifo for now. We need to add socket types to
645 buf->st_mode = __stat_mode_FIFO;
647 return ((*so->so_proto->pr_usrreq)(so, PRU_SENSE,
653 // -------------------------------------------------------------------------
655 static int bsd_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
660 // -------------------------------------------------------------------------
662 static int bsd_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
669 //==========================================================================
672 // -------------------------------------------------------------------------
673 // This function is called by the lower layers to record the
674 // fact that a particular 'select' event is being requested.
678 selrecord(void *selector, struct selinfo *info)
680 // Unused by this implementation
683 // -------------------------------------------------------------------------
684 // This function is called to indicate that a 'select' event
685 // may have occurred.
689 selwakeup(struct selinfo *info)
691 cyg_selwakeup( info );
694 //==========================================================================
695 // Misc support functions
698 sockargs(mp, buf, buflen, type)
704 register struct sockaddr *sa;
705 register struct mbuf *m;
709 #ifdef COMPAT_OLDSOCK
710 if (type == MT_SONAME && buflen <= 112)
711 buflen = MLEN; /* unix domain compat. hack */
716 m = m_get(M_WAIT, type);
720 error = copyin(buf, mtod(m, caddr_t), buflen);
726 if (type == MT_SONAME) {
727 sa = mtod(m, struct sockaddr *);
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;
739 // -------------------------------------------------------------------------
741 // Support for message reception. This is a lightly edited version of the
742 // recvit() function is uipc_syscalls.c.
745 bsd_recvit(cyg_file *fp, struct msghdr *mp, socklen_t *namelenp, ssize_t *retsize)
748 register struct iovec *iov;
752 struct mbuf *from = 0, *control = 0;
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 */
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)
768 len = auio.uio_resid;
769 error = soreceive((struct socket *)fp->f_data, &from, &auio,
770 NULL, mp->msg_control ? &control : NULL,
773 if (auio.uio_resid != len &&
774 (error == EINTR || error == EWOULDBLOCK))
779 *retsize = len - auio.uio_resid;
781 len = mp->msg_namelen;
782 if (len <= 0 || from == 0)
785 /* save sa_len before it is destroyed by MSG_COMPAT */
786 if (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;
794 error = copyout(mtod(from, caddr_t),
795 (caddr_t)mp->msg_name, (unsigned)len);
799 mp->msg_namelen = len;
802 #ifdef COMPAT_OLDSOCK
803 if (mp->msg_flags & MSG_COMPAT)
804 error = 0; /* old recvfrom didn't check */
810 if (mp->msg_control) {
811 #ifdef COMPAT_OLDSOCK
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
819 if (control && mp->msg_flags & MSG_COMPAT) {
820 if (mtod(control, struct cmsghdr *)->cmsg_level !=
822 mtod(control, struct cmsghdr *)->cmsg_type !=
824 mp->msg_controllen = 0;
827 control->m_len -= sizeof (struct cmsghdr);
828 control->m_data += sizeof (struct cmsghdr);
831 len = mp->msg_controllen;
832 if (len <= 0 || control == 0)
835 struct mbuf *m = control;
836 caddr_t p = (caddr_t)mp->msg_control;
841 mp->msg_flags |= MSG_CTRUNC;
844 error = copyout(mtod(m, caddr_t), p,
850 if (error != 0 || len <= 0)
852 } while ((m = m->m_next) != NULL);
853 len = p - (caddr_t)mp->msg_control;
855 mp->msg_controllen = len;
865 // -------------------------------------------------------------------------
867 // Support for message transmission. This is a lightly edited version of the
868 // synonymous function is uipc_syscalls.c.
871 bsd_sendit(cyg_file *fp, const struct msghdr *mp, int flags, ssize_t *retsize)
874 register struct iovec *iov;
876 struct mbuf *to, *control;
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 */
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)
893 error = sockargs(&to, mp->msg_name, mp->msg_namelen,
899 if (mp->msg_control) {
900 if (mp->msg_controllen < sizeof(struct cmsghdr)
901 #ifdef COMPAT_OLDSOCK
902 && mp->msg_flags != MSG_COMPAT
908 error = sockargs(&control, mp->msg_control,
909 mp->msg_controllen, MT_CONTROL);
912 #ifdef COMPAT_OLDSOCK
913 if (mp->msg_flags == MSG_COMPAT) {
914 register struct cmsghdr *cm;
916 M_PREPEND(control, sizeof(*cm), M_WAIT);
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;
931 len = auio.uio_resid;
932 error = sosend((struct socket *)fp->f_data, to, &auio,
933 NULL, control, flags);
935 if (auio.uio_resid != len &&
936 (error == EINTR || error == EWOULDBLOCK))
944 *retsize = len - auio.uio_resid;
952 //==========================================================================