URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
Compare Revisions
- This comparison shows the changes necessary to convert path
/openrisc/trunk/rtos/ecos-2.0/packages/net/tcpip/v2_0/src/sys/kern
- from Rev 27 to Rev 174
- ↔ Reverse comparison
Rev 27 → Rev 174
/uipc_proto.c
0,0 → 1,108
//========================================================================== |
// |
// sys/kern/uipc_proto.c |
// |
// |
// |
//========================================================================== |
//####BSDCOPYRIGHTBEGIN#### |
// |
// ------------------------------------------- |
// |
// Portions of this software may have been derived from OpenBSD or other sources, |
// and are covered by the appropriate copyright disclaimers included herein. |
// |
// ------------------------------------------- |
// |
//####BSDCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): gthomas |
// Contributors: gthomas |
// Date: 2000-01-10 |
// Purpose: |
// Description: |
// |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
|
/* $OpenBSD: uipc_proto.c,v 1.3 1998/04/26 22:40:42 millert Exp $ */ |
/* $NetBSD: uipc_proto.c,v 1.8 1996/02/13 21:10:47 christos Exp $ */ |
|
/*- |
* Copyright (c) 1982, 1986, 1993 |
* The Regents of the University of California. All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
* |
* @(#)uipc_proto.c 8.1 (Berkeley) 6/10/93 |
*/ |
|
#include <sys/param.h> |
#include <sys/socket.h> |
#include <sys/protosw.h> |
#include <sys/domain.h> |
#include <sys/mbuf.h> |
#include <sys/un.h> |
#include <sys/socketvar.h> |
|
#include <net/if.h> |
#include <net/raw_cb.h> |
|
/* |
* Definitions of protocols supported in the UNIX domain. |
*/ |
|
extern struct domain unixdomain; /* or at least forward */ |
|
struct protosw unixsw[] = { |
{ SOCK_STREAM, &unixdomain, PF_LOCAL, PR_CONNREQUIRED|PR_WANTRCVD|PR_RIGHTS, |
0, 0, 0, 0, |
uipc_usrreq, |
0, 0, 0, 0, |
}, |
{ SOCK_DGRAM, &unixdomain, PF_LOCAL, PR_ATOMIC|PR_ADDR|PR_RIGHTS, |
0, 0, 0, 0, |
uipc_usrreq, |
0, 0, 0, 0, |
}, |
{ 0, 0, 0, 0, |
raw_input, 0, raw_ctlinput, 0, |
raw_usrreq, |
raw_init, 0, 0, 0, |
} |
}; |
|
struct domain unixdomain = |
{ AF_LOCAL, "unix", 0, unp_externalize, unp_dispose, |
unixsw, &unixsw[sizeof(unixsw)/sizeof(unixsw[0])] }; |
/sys_socket.c
0,0 → 1,282
//========================================================================== |
// |
// sys/kern/sys_socket.c |
// |
// |
// |
//========================================================================== |
//####BSDCOPYRIGHTBEGIN#### |
// |
// ------------------------------------------- |
// |
// Portions of this software may have been derived from OpenBSD or other sources, |
// and are covered by the appropriate copyright disclaimers included herein. |
// |
// ------------------------------------------- |
// |
//####BSDCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): gthomas |
// Contributors: gthomas |
// Date: 2000-01-10 |
// Purpose: |
// Description: |
// |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
|
/* $OpenBSD: sys_socket.c,v 1.3 1997/08/31 20:42:23 deraadt Exp $ */ |
/* $NetBSD: sys_socket.c,v 1.13 1995/08/12 23:59:09 mycroft Exp $ */ |
|
/* |
* Copyright (c) 1982, 1986, 1990, 1993 |
* The Regents of the University of California. All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
* |
* @(#)sys_socket.c 8.1 (Berkeley) 6/10/93 |
*/ |
|
#include <sys/param.h> |
#ifdef __ECOS |
#include <cyg/io/file.h> |
#else |
#include <sys/systm.h> |
#include <sys/file.h> |
#include <sys/proc.h> |
#endif |
#include <sys/mbuf.h> |
#include <sys/protosw.h> |
#include <sys/socket.h> |
#include <sys/socketvar.h> |
#include <sys/ioctl.h> |
#ifndef __ECOS |
#include <sys/stat.h> |
#endif |
|
#include <net/if.h> |
#include <net/route.h> |
|
struct fileops socketops = |
{ soo_read, soo_write, soo_ioctl, soo_select, soo_close }; |
|
#ifdef __ECOS |
/* ARGSUSED */ |
int |
soo_read(struct file *fp, struct uio *uio) |
#else |
/* ARGSUSED */ |
int |
soo_read(fp, uio, cred) |
struct file *fp; |
struct uio *uio; |
struct ucred *cred; |
#endif |
{ |
|
return (soreceive((struct socket *)fp->f_data, (struct mbuf **)0, |
uio, (struct mbuf **)0, (struct mbuf **)0, (int *)0)); |
} |
|
#ifdef __ECOS |
int |
soo_write(struct file *fp, struct uio *uio) |
#else |
/* ARGSUSED */ |
int |
soo_write(fp, uio, cred) |
struct file *fp; |
struct uio *uio; |
struct ucred *cred; |
#endif |
{ |
|
return (sosend((struct socket *)fp->f_data, (struct mbuf *)0, |
uio, (struct mbuf *)0, (struct mbuf *)0, 0)); |
} |
|
#ifdef __ECOS |
int |
soo_ioctl(struct file *fp, CYG_ADDRWORD cmd, CYG_ADDRWORD data) |
#else |
int |
soo_ioctl(fp, cmd, data, p) |
struct file *fp; |
u_long cmd; |
register caddr_t data; |
struct proc *p; |
#endif |
{ |
register struct socket *so = (struct socket *)fp->f_data; |
#ifdef __ECOS |
void *p = 0; |
#endif |
|
switch (cmd) { |
|
case FIONBIO: |
if (*(int *)data) |
so->so_state |= SS_NBIO; |
else |
so->so_state &= ~SS_NBIO; |
return (0); |
|
case FIOASYNC: |
if (*(int *)data) { |
so->so_state |= SS_ASYNC; |
so->so_rcv.sb_flags |= SB_ASYNC; |
so->so_snd.sb_flags |= SB_ASYNC; |
} else { |
so->so_state &= ~SS_ASYNC; |
so->so_rcv.sb_flags &= ~SB_ASYNC; |
so->so_snd.sb_flags &= ~SB_ASYNC; |
} |
return (0); |
|
case FIONREAD: |
*(int *)data = so->so_rcv.sb_cc; |
return (0); |
|
#ifndef __ECOS |
case SIOCSPGRP: |
so->so_pgid = *(int *)data; |
so->so_siguid = p->p_cred->p_ruid; |
so->so_sigeuid = p->p_ucred->cr_uid; |
return (0); |
|
case SIOCGPGRP: |
*(int *)data = so->so_pgid; |
return (0); |
#endif |
|
case SIOCATMARK: |
*(int *)data = (so->so_state&SS_RCVATMARK) != 0; |
return (0); |
} |
/* |
* Interface/routing/protocol specific ioctls: |
* interface and routing ioctls should have a |
* different entry since a socket's unnecessary |
*/ |
if (IOCGROUP(cmd) == 'i') |
return (ifioctl(so, (u_long)cmd, (caddr_t)data, p)); |
if (IOCGROUP(cmd) == 'r') |
return (rtioctl((u_long)cmd, (caddr_t)data, p)); |
return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, |
(struct mbuf *)cmd, (struct mbuf *)data, (struct mbuf *)0)); |
} |
|
#ifdef __ECOS |
int |
soo_select(struct file *fp, int which) |
#else |
int |
soo_select(fp, which, p) |
struct file *fp; |
int which; |
struct proc *p; |
#endif |
{ |
register struct socket *so = (struct socket *)fp->f_data; |
register int s = splsoftnet(); |
#ifdef __ECOS |
void *p = 0; |
#endif |
|
switch (which) { |
|
case FREAD: |
if (soreadable(so)) { |
splx(s); |
return (1); |
} |
selrecord(p, &so->so_rcv.sb_sel); |
so->so_rcv.sb_flags |= SB_SEL; |
break; |
|
case FWRITE: |
if (sowriteable(so)) { |
splx(s); |
return (1); |
} |
selrecord(p, &so->so_snd.sb_sel); |
so->so_snd.sb_flags |= SB_SEL; |
break; |
|
case 0: |
if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) { |
splx(s); |
return (1); |
} |
selrecord(p, &so->so_rcv.sb_sel); |
so->so_rcv.sb_flags |= SB_SEL; |
break; |
} |
splx(s); |
return (0); |
} |
|
#ifndef __ECOS |
int |
soo_stat(so, ub) |
register struct socket *so; |
register struct stat *ub; |
{ |
|
bzero((caddr_t)ub, sizeof (*ub)); |
ub->st_mode = S_IFSOCK; |
return ((*so->so_proto->pr_usrreq)(so, PRU_SENSE, |
(struct mbuf *)ub, (struct mbuf *)0, |
(struct mbuf *)0)); |
} |
#endif |
|
#ifdef __ECOS |
int |
soo_close(struct file *fp) |
#else |
/* ARGSUSED */ |
int |
soo_close(fp, p) |
struct file *fp; |
struct proc *p; |
#endif |
{ |
int error = 0; |
|
if (fp->f_data) |
error = soclose((struct socket *)fp->f_data); |
fp->f_data = 0; |
return (error); |
} |
/sockio.c
0,0 → 1,953
//========================================================================== |
// |
// sys/kern/sockio.c |
// |
// Socket interface to Fileio subsystem |
// |
//========================================================================== |
//####BSDCOPYRIGHTBEGIN#### |
// |
// ------------------------------------------- |
// |
// Portions of this software may have been derived from OpenBSD or other sources, |
// and are covered by the appropriate copyright disclaimers included herein. |
// |
// ------------------------------------------- |
// |
//####BSDCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): nickg |
// Contributors: nickg |
// Date: 2000-06-06 |
// Purpose: |
// Description: |
// |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
/* |
* Copyright (c) 1982, 1986, 1991, 1993 |
* The Regents of the University of California. All rights reserved. |
* (c) UNIX System Laboratories, Inc. |
* All or some portions of this file are derived from material licensed |
* to the University of California by American Telephone and Telegraph |
* Co. or Unix System Laboratories, Inc. and are reproduced herein with |
* the permission of UNIX System Laboratories, Inc. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
* |
*/ |
//========================================================================== |
|
#include <pkgconf/net.h> |
#include <pkgconf/io_fileio.h> |
|
#include <sys/types.h> |
|
#include <cyg/io/file.h> |
|
#include <cyg/fileio/fileio.h> |
#include <cyg/fileio/sockio.h> |
|
#include <sys/param.h> |
#include <sys/mbuf.h> |
#include <sys/protosw.h> |
#include <sys/socket.h> |
#include <sys/socketvar.h> |
#include <sys/ioctl.h> |
|
#include <net/if.h> |
#include <net/route.h> |
|
//========================================================================== |
// Forward definitions |
|
static int bsd_init( cyg_nstab_entry *nste ); |
static int bsd_socket( cyg_nstab_entry *nste, int domain, int type, |
int protocol, cyg_file *file ); |
|
static int bsd_bind ( cyg_file *fp, const sockaddr *sa, socklen_t len ); |
static int bsd_connect ( cyg_file *fp, const sockaddr *sa, socklen_t len ); |
static int bsd_accept ( cyg_file *fp, cyg_file *new_fp, |
struct sockaddr *name, socklen_t *anamelen ); |
static int bsd_listen ( cyg_file *fp, int len ); |
static int bsd_getname ( cyg_file *fp, sockaddr *sa, socklen_t *len, int peer ); |
static int bsd_shutdown ( cyg_file *fp, int flags ); |
static int bsd_getsockopt( cyg_file *fp, int level, int optname, |
void *optval, socklen_t *optlen); |
static int bsd_setsockopt( cyg_file *fp, int level, int optname, |
const void *optval, socklen_t optlen); |
static int bsd_sendmsg ( cyg_file *fp, const struct msghdr *m, |
int flags, ssize_t *retsize ); |
static int bsd_recvmsg ( cyg_file *fp, struct msghdr *m, |
socklen_t *namelen, ssize_t *retsize ); |
|
|
// File operations |
static int bsd_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio); |
static int bsd_write (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio); |
static int bsd_lseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence ); |
static int bsd_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com, |
CYG_ADDRWORD data); |
static int bsd_select (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info); |
static int bsd_fsync (struct CYG_FILE_TAG *fp, int mode ); |
static int bsd_close (struct CYG_FILE_TAG *fp); |
static int bsd_fstat (struct CYG_FILE_TAG *fp, struct stat *buf ); |
static int bsd_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len ); |
static int bsd_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len ); |
|
static int |
bsd_recvit(cyg_file *fp, struct msghdr *mp, socklen_t *namelenp, ssize_t *retsize); |
static int |
bsd_sendit(cyg_file *fp, const struct msghdr *mp, int flags, ssize_t *retsize); |
|
|
//========================================================================== |
// Table entrys |
|
NSTAB_ENTRY( bsd_nste, 0, |
"bsd_tcpip", |
"", |
0, |
bsd_init, |
bsd_socket); |
|
struct cyg_sock_ops bsd_sockops = |
{ |
bsd_bind, |
bsd_connect, |
bsd_accept, |
bsd_listen, |
bsd_getname, |
bsd_shutdown, |
bsd_getsockopt, |
bsd_setsockopt, |
bsd_sendmsg, |
bsd_recvmsg |
}; |
|
cyg_fileops bsd_sock_fileops = |
{ |
bsd_read, |
bsd_write, |
bsd_lseek, |
bsd_ioctl, |
bsd_select, |
bsd_fsync, |
bsd_close, |
bsd_fstat, |
bsd_getinfo, |
bsd_setinfo |
}; |
|
//========================================================================== |
// NStab functions |
|
|
|
// ------------------------------------------------------------------------- |
|
static int bsd_init( cyg_nstab_entry *nste ) |
{ |
// Initialization already handled via constructor |
|
return ENOERR; |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_socket( cyg_nstab_entry *nste, int domain, int type, |
int protocol, cyg_file *file ) |
{ |
int error = 0; |
struct socket *so; |
|
error = socreate( domain, &so, type, protocol ); |
|
if( error == ENOERR ) |
{ |
|
cyg_selinit(&so->so_rcv.sb_sel); |
cyg_selinit(&so->so_snd.sb_sel); |
|
file->f_flag |= CYG_FREAD|CYG_FWRITE; |
file->f_type = CYG_FILE_TYPE_SOCKET; |
file->f_ops = &bsd_sock_fileops; |
file->f_offset = 0; |
file->f_data = (CYG_ADDRWORD)so; |
file->f_xops = (CYG_ADDRWORD)&bsd_sockops; |
} |
|
return error; |
} |
|
|
//========================================================================== |
// Sockops functions |
|
// ------------------------------------------------------------------------- |
|
static int bsd_bind ( cyg_file *fp, const sockaddr *sa, socklen_t len ) |
{ |
struct mbuf *nam; |
int error; |
|
error = sockargs(&nam, (caddr_t)sa, len, MT_SONAME); |
|
if (error) |
return (error); |
|
error = sobind((struct socket *)fp->f_data, nam); |
|
m_freem(nam); |
|
return error; |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_connect ( cyg_file *fp, const sockaddr *sa, socklen_t len ) |
{ |
register struct socket *so; |
struct mbuf *nam; |
int error, s; |
|
so = (struct socket *)fp->f_data; |
|
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) |
return (EALREADY); |
|
error = sockargs(&nam, (caddr_t)sa, len, MT_SONAME); |
|
if (error) |
return (error); |
|
error = soconnect(so, nam); |
if (error) |
goto bad; |
|
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { |
m_freem(nam); |
return (EINPROGRESS); |
} |
|
s = splsoftnet(); |
while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { |
error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH, |
netcon, 0); |
if (error) |
break; |
} |
|
if (error == 0) { |
error = so->so_error; |
so->so_error = 0; |
} |
|
splx(s); |
|
bad: |
so->so_state &= ~SS_ISCONNECTING; |
m_freem(nam); |
|
return error; |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_accept ( cyg_file *fp, cyg_file *new_fp, |
struct sockaddr *name, socklen_t *anamelen ) |
{ |
struct mbuf *nam; |
socklen_t namelen = 0; |
int error = 0, s; |
register struct socket *so; |
|
if( anamelen != NULL ) |
namelen = *anamelen; |
|
s = splsoftnet(); |
so = (struct socket *)fp->f_data; |
|
if ((so->so_options & SO_ACCEPTCONN) == 0) { |
splx(s); |
return (EINVAL); |
} |
|
if ((so->so_state & SS_NBIO) && so->so_qlen == 0) { |
splx(s); |
return (EWOULDBLOCK); |
} |
|
while (so->so_qlen == 0 && so->so_error == 0) { |
if (so->so_state & SS_CANTRCVMORE) { |
so->so_error = ECONNABORTED; |
break; |
} |
error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH, |
netcon, 0); |
if (error) { |
splx(s); |
return (error); |
} |
} |
|
if (so->so_error) { |
error = so->so_error; |
so->so_error = 0; |
splx(s); |
return (error); |
} |
|
{ |
struct socket *aso = so->so_q; |
if (soqremque(aso, 1) == 0) |
panic("accept"); |
so = aso; |
} |
|
cyg_selinit(&so->so_rcv.sb_sel); |
cyg_selinit(&so->so_snd.sb_sel); |
|
new_fp->f_type = DTYPE_SOCKET; |
new_fp->f_flag |= FREAD|FWRITE; |
new_fp->f_offset = 0; |
new_fp->f_ops = &bsd_sock_fileops; |
new_fp->f_data = (CYG_ADDRWORD)so; |
new_fp->f_xops = (CYG_ADDRWORD)&bsd_sockops; |
|
nam = m_get(M_WAIT, MT_SONAME); |
(void) soaccept(so, nam); |
if (name) { |
if (namelen > nam->m_len) |
namelen = nam->m_len; |
/* SHOULD COPY OUT A CHAIN HERE */ |
if ((error = copyout(mtod(nam, caddr_t), |
(caddr_t)name, namelen)) == 0) |
*anamelen = namelen; |
} |
m_freem(nam); |
splx(s); |
|
return (error); |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_listen ( cyg_file *fp, int backlog ) |
{ |
return (solisten((struct socket *)fp->f_data, backlog)); |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_getname ( cyg_file *fp, sockaddr *asa, socklen_t *alen, int peer ) |
{ |
register struct socket *so; |
struct mbuf *m; |
socklen_t len = 0; |
int error; |
int type = peer ? PRU_PEERADDR : PRU_SOCKADDR; |
|
if( alen != NULL ) |
len = *alen; |
|
so = (struct socket *)fp->f_data; |
|
if ( peer && (so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) |
return (ENOTCONN); |
|
m = m_getclr(M_WAIT, MT_SONAME); |
if (m == NULL) |
return (ENOBUFS); |
|
error = (*so->so_proto->pr_usrreq)(so, type, 0, m, 0); |
if (error) |
goto bad; |
|
if (len > m->m_len) |
len = m->m_len; |
|
error = copyout(mtod(m, caddr_t), (caddr_t)asa, len); |
|
if (error == 0) |
*alen = len; |
|
bad: |
m_freem(m); |
|
return (error); |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_shutdown ( cyg_file *fp, int how ) |
{ |
return (soshutdown((struct socket *)fp->f_data, how)); |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_getsockopt( cyg_file *fp, int level, int optname, |
void *optval, socklen_t *optlen) |
{ |
struct mbuf *m = NULL; |
socklen_t valsize = 0; |
int error; |
|
if( optval != NULL && optlen != NULL ) |
valsize = *optlen; |
|
error = sogetopt((struct socket *)fp->f_data, level, optname, &m); |
|
if( error == ENOERR && valsize != 0 && m != NULL) |
{ |
if (valsize > m->m_len) |
valsize = m->m_len; |
|
error = copyout(mtod(m, caddr_t), optval, valsize); |
|
if( error == ENOERR ) |
*optlen = valsize; |
|
} |
|
if (m != NULL) |
(void) m_free(m); |
return (error); |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_setsockopt( cyg_file *fp, int level, int optname, |
const void *optval, socklen_t optlen) |
{ |
int error; |
struct mbuf *m = NULL; |
|
if( optlen > MCLBYTES ) |
return EINVAL; |
|
if (optval != NULL) { |
m = m_get(M_WAIT, MT_SOOPTS); |
if (optlen > MLEN) { |
MCLGET(m, M_DONTWAIT); |
if ((m->m_flags & M_EXT) == 0) { |
m_freem(m); |
return (ENOBUFS); |
} |
} |
if (m == NULL) |
return (ENOBUFS); |
error = copyin(optval, mtod(m, caddr_t), optlen); |
if (error) { |
(void) m_free(m); |
return (error); |
} |
m->m_len = optlen; |
} |
|
return (sosetopt((struct socket *)fp->f_data, level, optname, m)); |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_sendmsg ( cyg_file *fp, const struct msghdr *m, int flags, ssize_t *retsize ) |
{ |
return bsd_sendit( fp, m, flags, retsize); |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_recvmsg ( cyg_file *fp, struct msghdr *m, socklen_t *namelen, ssize_t *retsize ) |
{ |
return bsd_recvit( fp, m, namelen, retsize); |
} |
|
//========================================================================== |
// File system call functions |
|
// ------------------------------------------------------------------------- |
|
static int bsd_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) |
{ |
return (soreceive((struct socket *)fp->f_data, (struct mbuf **)0, |
uio, (struct mbuf **)0, (struct mbuf **)0, (int *)0)); |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_write (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) |
{ |
return (sosend((struct socket *)fp->f_data, (struct mbuf *)0, |
uio, (struct mbuf *)0, (struct mbuf *)0, 0)); |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_lseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence ) |
{ |
return ESPIPE; |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD cmd, |
CYG_ADDRWORD data) |
{ |
register struct socket *so = (struct socket *)fp->f_data; |
void *p = 0; |
|
switch (cmd) { |
|
case FIONBIO: |
if (*(int *)data) |
so->so_state |= SS_NBIO; |
else |
so->so_state &= ~SS_NBIO; |
return (0); |
|
case FIOASYNC: |
if (*(int *)data) { |
so->so_state |= SS_ASYNC; |
so->so_rcv.sb_flags |= SB_ASYNC; |
so->so_snd.sb_flags |= SB_ASYNC; |
} else { |
so->so_state &= ~SS_ASYNC; |
so->so_rcv.sb_flags &= ~SB_ASYNC; |
so->so_snd.sb_flags &= ~SB_ASYNC; |
} |
return (0); |
|
case FIONREAD: |
*(int *)data = so->so_rcv.sb_cc; |
return (0); |
|
case SIOCATMARK: |
*(int *)data = (so->so_state&SS_RCVATMARK) != 0; |
return (0); |
} |
/* |
* Interface/routing/protocol specific ioctls: |
* interface and routing ioctls should have a |
* different entry since a socket's unnecessary |
*/ |
if (IOCGROUP(cmd) == 'i') |
return (ifioctl(so, (u_long)cmd, (caddr_t)data, p)); |
if (IOCGROUP(cmd) == 'r') |
return (rtioctl((u_long)cmd, (caddr_t)data, p)); |
return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, |
(struct mbuf *)cmd, (struct mbuf *)data, (struct mbuf *)0)); |
|
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_select (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info) |
{ |
register struct socket *so = (struct socket *)fp->f_data; |
register int s = splsoftnet(); |
|
switch (which) { |
|
case FREAD: |
if (soreadable(so)) { |
splx(s); |
return (1); |
} |
cyg_selrecord(info, &so->so_rcv.sb_sel); |
so->so_rcv.sb_flags |= SB_SEL; |
break; |
|
case FWRITE: |
if (sowriteable(so)) { |
splx(s); |
return (1); |
} |
cyg_selrecord(info, &so->so_snd.sb_sel); |
so->so_snd.sb_flags |= SB_SEL; |
break; |
|
case 0: |
if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) { |
splx(s); |
return (1); |
} |
cyg_selrecord(info, &so->so_rcv.sb_sel); |
so->so_rcv.sb_flags |= SB_SEL; |
break; |
} |
splx(s); |
|
return ENOERR; |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_fsync (struct CYG_FILE_TAG *fp, int mode ) |
{ |
// FIXME: call some sort of flush IOCTL? |
return 0; |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_close (struct CYG_FILE_TAG *fp) |
{ |
int error = 0; |
|
if (fp->f_data) |
error = soclose((struct socket *)fp->f_data); |
fp->f_data = 0; |
return (error); |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_fstat (struct CYG_FILE_TAG *fp, struct stat *buf ) |
{ |
register struct socket *so = (struct socket *)fp->f_data; |
|
bzero((caddr_t)buf, sizeof (*buf)); |
|
// Mark socket as a fifo for now. We need to add socket types to |
// sys/stat.h. |
buf->st_mode = __stat_mode_FIFO; |
|
return ((*so->so_proto->pr_usrreq)(so, PRU_SENSE, |
(struct mbuf *)buf, |
(struct mbuf *)0, |
(struct mbuf *)0)); |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len ) |
{ |
return ENOSYS; |
} |
|
// ------------------------------------------------------------------------- |
|
static int bsd_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len ) |
{ |
return ENOSYS; |
} |
|
|
|
//========================================================================== |
// Select support |
|
// ------------------------------------------------------------------------- |
// This function is called by the lower layers to record the |
// fact that a particular 'select' event is being requested. |
// |
|
void |
selrecord(void *selector, struct selinfo *info) |
{ |
// Unused by this implementation |
} |
|
// ------------------------------------------------------------------------- |
// This function is called to indicate that a 'select' event |
// may have occurred. |
// |
|
void |
selwakeup(struct selinfo *info) |
{ |
cyg_selwakeup( info ); |
} |
|
//========================================================================== |
// Misc support functions |
|
int |
sockargs(mp, buf, buflen, type) |
struct mbuf **mp; |
caddr_t buf; |
socklen_t buflen; |
int type; |
{ |
register struct sockaddr *sa; |
register struct mbuf *m; |
int error; |
|
if (buflen > MLEN) { |
#ifdef COMPAT_OLDSOCK |
if (type == MT_SONAME && buflen <= 112) |
buflen = MLEN; /* unix domain compat. hack */ |
else |
#endif |
return (EINVAL); |
} |
m = m_get(M_WAIT, type); |
if (m == NULL) |
return (ENOBUFS); |
m->m_len = buflen; |
error = copyin(buf, mtod(m, caddr_t), buflen); |
if (error) { |
(void) m_free(m); |
return (error); |
} |
*mp = m; |
if (type == MT_SONAME) { |
sa = mtod(m, struct sockaddr *); |
|
#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN |
if (sa->sa_family == 0 && sa->sa_len < AF_MAX) |
sa->sa_family = sa->sa_len; |
#endif |
sa->sa_len = buflen; |
} |
return (0); |
} |
|
|
// ------------------------------------------------------------------------- |
// bsd_recvit() |
// Support for message reception. This is a lightly edited version of the |
// recvit() function is uipc_syscalls.c. |
|
static int |
bsd_recvit(cyg_file *fp, struct msghdr *mp, socklen_t *namelenp, ssize_t *retsize) |
{ |
struct uio auio; |
register struct iovec *iov; |
register int i; |
size_t len; |
int error; |
struct mbuf *from = 0, *control = 0; |
|
auio.uio_iov = mp->msg_iov; |
auio.uio_iovcnt = mp->msg_iovlen; |
auio.uio_segflg = UIO_USERSPACE; |
auio.uio_rw = UIO_READ; |
auio.uio_offset = 0; /* XXX */ |
auio.uio_resid = 0; |
iov = mp->msg_iov; |
for (i = 0; i < mp->msg_iovlen; i++, iov++) { |
/* Don't allow sum > SSIZE_MAX */ |
if (iov->iov_len > SSIZE_MAX || |
(auio.uio_resid += iov->iov_len) > SSIZE_MAX) |
return (EINVAL); |
} |
|
len = auio.uio_resid; |
error = soreceive((struct socket *)fp->f_data, &from, &auio, |
NULL, mp->msg_control ? &control : NULL, |
&mp->msg_flags); |
if (error) { |
if (auio.uio_resid != len && |
(error == EINTR || error == EWOULDBLOCK)) |
error = 0; |
} |
if (error) |
goto out; |
*retsize = len - auio.uio_resid; |
if (mp->msg_name) { |
len = mp->msg_namelen; |
if (len <= 0 || from == 0) |
len = 0; |
else { |
/* save sa_len before it is destroyed by MSG_COMPAT */ |
if (len > from->m_len) |
len = from->m_len; |
/* else if len < from->m_len ??? */ |
#ifdef COMPAT_OLDSOCK |
if (mp->msg_flags & MSG_COMPAT) |
mtod(from, struct osockaddr *)->sa_family = |
mtod(from, struct sockaddr *)->sa_family; |
#endif |
error = copyout(mtod(from, caddr_t), |
(caddr_t)mp->msg_name, (unsigned)len); |
if (error) |
goto out; |
} |
mp->msg_namelen = len; |
if (namelenp ) { |
*namelenp = len; |
#ifdef COMPAT_OLDSOCK |
if (mp->msg_flags & MSG_COMPAT) |
error = 0; /* old recvfrom didn't check */ |
else |
#endif |
goto out; |
} |
} |
if (mp->msg_control) { |
#ifdef COMPAT_OLDSOCK |
/* |
* We assume that old recvmsg calls won't receive access |
* rights and other control info, esp. as control info |
* is always optional and those options didn't exist in 4.3. |
* If we receive rights, trim the cmsghdr; anything else |
* is tossed. |
*/ |
if (control && mp->msg_flags & MSG_COMPAT) { |
if (mtod(control, struct cmsghdr *)->cmsg_level != |
SOL_SOCKET || |
mtod(control, struct cmsghdr *)->cmsg_type != |
SCM_RIGHTS) { |
mp->msg_controllen = 0; |
goto out; |
} |
control->m_len -= sizeof (struct cmsghdr); |
control->m_data += sizeof (struct cmsghdr); |
} |
#endif |
len = mp->msg_controllen; |
if (len <= 0 || control == 0) |
len = 0; |
else { |
struct mbuf *m = control; |
caddr_t p = (caddr_t)mp->msg_control; |
|
do { |
i = m->m_len; |
if (len < i) { |
mp->msg_flags |= MSG_CTRUNC; |
i = len; |
} |
error = copyout(mtod(m, caddr_t), p, |
(unsigned)i); |
if (m->m_next) |
i = ALIGN(i); |
p += i; |
len -= i; |
if (error != 0 || len <= 0) |
break; |
} while ((m = m->m_next) != NULL); |
len = p - (caddr_t)mp->msg_control; |
} |
mp->msg_controllen = len; |
} |
out: |
if (from) |
m_freem(from); |
if (control) |
m_freem(control); |
return (error); |
} |
|
// ------------------------------------------------------------------------- |
// sendit() |
// Support for message transmission. This is a lightly edited version of the |
// synonymous function is uipc_syscalls.c. |
|
static int |
bsd_sendit(cyg_file *fp, const struct msghdr *mp, int flags, ssize_t *retsize) |
{ |
struct uio auio; |
register struct iovec *iov; |
register int i; |
struct mbuf *to, *control; |
int len, error; |
|
auio.uio_iov = mp->msg_iov; |
auio.uio_iovcnt = mp->msg_iovlen; |
auio.uio_segflg = UIO_USERSPACE; |
auio.uio_rw = UIO_WRITE; |
auio.uio_offset = 0; /* XXX */ |
auio.uio_resid = 0; |
iov = mp->msg_iov; |
for (i = 0; i < mp->msg_iovlen; i++, iov++) { |
/* Don't allow sum > SSIZE_MAX */ |
if (iov->iov_len > SSIZE_MAX || |
(auio.uio_resid += iov->iov_len) > SSIZE_MAX) |
return (EINVAL); |
} |
if (mp->msg_name) { |
error = sockargs(&to, mp->msg_name, mp->msg_namelen, |
MT_SONAME); |
if (error) |
return (error); |
} else |
to = 0; |
if (mp->msg_control) { |
if (mp->msg_controllen < sizeof(struct cmsghdr) |
#ifdef COMPAT_OLDSOCK |
&& mp->msg_flags != MSG_COMPAT |
#endif |
) { |
error = EINVAL; |
goto bad; |
} |
error = sockargs(&control, mp->msg_control, |
mp->msg_controllen, MT_CONTROL); |
if (error) |
goto bad; |
#ifdef COMPAT_OLDSOCK |
if (mp->msg_flags == MSG_COMPAT) { |
register struct cmsghdr *cm; |
|
M_PREPEND(control, sizeof(*cm), M_WAIT); |
if (control == 0) { |
error = ENOBUFS; |
goto bad; |
} else { |
cm = mtod(control, struct cmsghdr *); |
cm->cmsg_len = control->m_len; |
cm->cmsg_level = SOL_SOCKET; |
cm->cmsg_type = SCM_RIGHTS; |
} |
} |
#endif |
} else |
control = 0; |
|
len = auio.uio_resid; |
error = sosend((struct socket *)fp->f_data, to, &auio, |
NULL, control, flags); |
if (error) { |
if (auio.uio_resid != len && |
(error == EINTR || error == EWOULDBLOCK)) |
error = 0; |
#ifndef __ECOS |
if (error == EPIPE) |
psignal(p, SIGPIPE); |
#endif |
} |
if (error == 0) |
*retsize = len - auio.uio_resid; |
bad: |
if (to) |
m_freem(to); |
return (error); |
} |
|
|
//========================================================================== |
// End of sockio.c |
/uipc_domain.c
0,0 → 1,311
//========================================================================== |
// |
// sys/kern/uipc_domain.c |
// |
// |
// |
//========================================================================== |
//####BSDCOPYRIGHTBEGIN#### |
// |
// ------------------------------------------- |
// |
// Portions of this software may have been derived from OpenBSD or other sources, |
// and are covered by the appropriate copyright disclaimers included herein. |
// |
// ------------------------------------------- |
// |
//####BSDCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): gthomas |
// Contributors: gthomas |
// Date: 2000-01-10 |
// Purpose: |
// Description: |
// |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
|
/* $OpenBSD: uipc_domain.c,v 1.9 1999/12/08 06:50:17 itojun Exp $ */ |
/* $NetBSD: uipc_domain.c,v 1.14 1996/02/09 19:00:44 christos Exp $ */ |
|
/* |
* Copyright (c) 1982, 1986, 1993 |
* The Regents of the University of California. All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
* |
* @(#)uipc_domain.c 8.2 (Berkeley) 10/18/93 |
*/ |
|
#include <sys/param.h> |
#include <sys/socket.h> |
#include <sys/protosw.h> |
#include <sys/domain.h> |
#include <sys/mbuf.h> |
#include <sys/time.h> |
#include <sys/kernel.h> |
#ifndef __ECOS |
#include <sys/systm.h> |
#include <sys/proc.h> |
|
#include <vm/vm.h> |
#include <sys/sysctl.h> |
#endif |
|
void pffasttimo __P((void *)); |
void pfslowtimo __P((void *)); |
#if defined (KEY) || defined (IPSEC) |
int pfkey_init __P((void)); |
#endif /* KEY || IPSEC */ |
|
#define ADDDOMAIN(x) { \ |
extern struct domain __CONCAT(x,domain); \ |
__CONCAT(x,domain.dom_next) = domains; \ |
domains = &__CONCAT(x,domain); \ |
} |
|
void |
domaininit() |
{ |
register struct domain *dp; |
register struct protosw *pr; |
|
#undef unix |
/* |
* KAME NOTE: ADDDOMAIN(route) is moved to the last part so that |
* it will be initialized as the *first* element. confusing! |
*/ |
#ifndef lint |
#ifndef __ECOS |
ADDDOMAIN(unix); |
#endif |
#ifdef INET |
ADDDOMAIN(inet); |
#endif |
#ifdef INET6 |
ADDDOMAIN(inet6); |
#endif /* INET6 */ |
#if defined (KEY) || defined (IPSEC) |
pfkey_init(); |
#endif /* KEY || IPSEC */ |
#ifdef IPX |
ADDDOMAIN(ipx); |
#endif |
#ifdef NETATALK |
ADDDOMAIN(atalk); |
#endif |
#ifdef NS |
ADDDOMAIN(ns); |
#endif |
#ifdef ISO |
ADDDOMAIN(iso); |
#endif |
#ifdef CCITT |
ADDDOMAIN(ccitt); |
#endif |
#ifdef notdef /* XXXX */ |
#include "imp.h" |
#if NIMP > 0 |
ADDDOMAIN(imp); |
#endif |
#endif |
#ifdef IPSEC |
#ifdef __KAME__ |
ADDDOMAIN(key); |
#endif |
#endif |
ADDDOMAIN(route); |
#endif |
|
for (dp = domains; dp; dp = dp->dom_next) { |
if (dp->dom_init) |
(*dp->dom_init)(); |
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) |
if (pr->pr_init) |
(*pr->pr_init)(); |
} |
|
if (max_linkhdr < 16) /* XXX */ |
max_linkhdr = 16; |
max_hdr = max_linkhdr + max_protohdr; |
max_datalen = MHLEN - max_hdr; |
timeout(pffasttimo, NULL, 1); |
timeout(pfslowtimo, NULL, 1); |
} |
|
struct protosw * |
pffindtype(family, type) |
int family, type; |
{ |
register struct domain *dp; |
register struct protosw *pr; |
|
for (dp = domains; dp; dp = dp->dom_next) |
if (dp->dom_family == family) |
goto found; |
return (0); |
found: |
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) |
if (pr->pr_type && pr->pr_type == type) |
return (pr); |
return (0); |
} |
|
struct protosw * |
pffindproto(family, protocol, type) |
int family, protocol, type; |
{ |
register struct domain *dp; |
register struct protosw *pr; |
struct protosw *maybe = 0; |
|
if (family == 0) |
return (0); |
for (dp = domains; dp; dp = dp->dom_next) |
if (dp->dom_family == family) |
goto found; |
return (0); |
found: |
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { |
if ((pr->pr_protocol == protocol) && (pr->pr_type == type)) |
return (pr); |
|
if (type == SOCK_RAW && pr->pr_type == SOCK_RAW && |
pr->pr_protocol == 0 && maybe == (struct protosw *)0) |
maybe = pr; |
} |
return (maybe); |
} |
|
#ifndef __ECOS |
int |
net_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) |
int *name; |
u_int namelen; |
void *oldp; |
size_t *oldlenp; |
void *newp; |
size_t newlen; |
struct proc *p; |
{ |
register struct domain *dp; |
register struct protosw *pr; |
int family, protocol; |
|
/* |
* All sysctl names at this level are nonterminal. |
* PF_KEY: next component is protocol family, and then at least one |
* additional component. |
* usually: next two components are protocol family and protocol |
* number, then at least one addition component. |
*/ |
if (namelen < 2) |
return (EISDIR); /* overloaded */ |
family = name[0]; |
|
if (family == 0) |
return (0); |
for (dp = domains; dp; dp = dp->dom_next) |
if (dp->dom_family == family) |
goto found; |
return (ENOPROTOOPT); |
found: |
switch (family) { |
#ifdef IPSEC |
#ifdef __KAME__ |
case PF_KEY: |
pr = dp->dom_protosw; |
if (pr->pr_sysctl) |
return ((*pr->pr_sysctl)(name + 1, namelen - 1, |
oldp, oldlenp, newp, newlen)); |
return (ENOPROTOOPT); |
#endif |
#endif |
default: |
break; |
} |
if (namelen < 3) |
return (EISDIR); /* overloaded */ |
protocol = name[1]; |
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) |
if (pr->pr_protocol == protocol && pr->pr_sysctl) |
return ((*pr->pr_sysctl)(name + 2, namelen - 2, |
oldp, oldlenp, newp, newlen)); |
return (ENOPROTOOPT); |
} |
#endif |
|
void |
pfctlinput(cmd, sa) |
int cmd; |
struct sockaddr *sa; |
{ |
register struct domain *dp; |
register struct protosw *pr; |
|
for (dp = domains; dp; dp = dp->dom_next) |
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) |
if (pr->pr_ctlinput) |
(*pr->pr_ctlinput)(cmd, sa, NULL); |
} |
|
void |
pfslowtimo(arg) |
void *arg; |
{ |
register struct domain *dp; |
register struct protosw *pr; |
|
for (dp = domains; dp; dp = dp->dom_next) |
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) |
if (pr->pr_slowtimo) { |
(*pr->pr_slowtimo)(); |
} |
timeout(pfslowtimo, NULL, hz/2); |
} |
|
void |
pffasttimo(arg) |
void *arg; |
{ |
register struct domain *dp; |
register struct protosw *pr; |
|
for (dp = domains; dp; dp = dp->dom_next) |
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) |
if (pr->pr_fasttimo) { |
(*pr->pr_fasttimo)(); |
} |
timeout(pffasttimo, NULL, hz/5); |
} |
/uipc_socket.c
0,0 → 1,1147
//========================================================================== |
// |
// sys/kern/uipc_socket.c |
// |
// |
// |
//========================================================================== |
//####BSDCOPYRIGHTBEGIN#### |
// |
// ------------------------------------------- |
// |
// Portions of this software may have been derived from OpenBSD or other sources, |
// and are covered by the appropriate copyright disclaimers included herein. |
// |
// ------------------------------------------- |
// |
//####BSDCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): gthomas |
// Contributors: gthomas |
// Date: 2000-01-10 |
// Purpose: |
// Description: |
// |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
|
/* $OpenBSD: uipc_socket.c,v 1.27 1999/10/14 08:18:49 cmetz Exp $ */ |
/* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */ |
|
/* |
* Copyright (c) 1982, 1986, 1988, 1990, 1993 |
* The Regents of the University of California. All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
* |
* @(#)uipc_socket.c 8.3 (Berkeley) 4/15/94 |
*/ |
|
#include <sys/param.h> |
#ifdef __ECOS |
#include <cyg/io/file.h> |
#else |
#include <sys/systm.h> |
#include <sys/proc.h> |
#include <sys/file.h> |
#endif |
#include <sys/malloc.h> |
#include <sys/mbuf.h> |
#include <sys/domain.h> |
#include <sys/kernel.h> |
#include <sys/protosw.h> |
#include <sys/socket.h> |
#include <sys/socketvar.h> |
#ifndef __ECOS |
#include <sys/signalvar.h> |
#include <sys/resourcevar.h> |
#endif |
|
#ifndef SOMINCONN |
#define SOMINCONN 80 |
#endif /* SOMINCONN */ |
|
int somaxconn = SOMAXCONN; |
int sominconn = SOMINCONN; |
|
/* |
* Socket operation routines. |
* These routines are called by the routines in |
* sys_socket.c or from a system process, and |
* implement the semantics of socket operations by |
* switching out to the protocol specific routines. |
*/ |
/*ARGSUSED*/ |
int |
socreate(dom, aso, type, proto) |
int dom; |
struct socket **aso; |
register int type; |
int proto; |
{ |
#ifndef __ECOS |
struct proc *p = curproc; /* XXX */ |
#endif |
register struct protosw *prp; |
register struct socket *so; |
register int error; |
|
if (proto) |
prp = pffindproto(dom, proto, type); |
else |
prp = pffindtype(dom, type); |
if (prp == 0 || prp->pr_usrreq == 0) |
return (EPROTONOSUPPORT); |
if (prp->pr_type != type) |
return (EPROTOTYPE); |
MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT); |
bzero((caddr_t)so, sizeof(*so)); |
so->so_type = type; |
#ifdef __ECOS |
so->so_state = SS_PRIV; |
so->so_ruid = 0; // FIXME |
so->so_euid = 0; // FIXME |
#else |
if (p->p_ucred->cr_uid == 0) |
so->so_state = SS_PRIV; |
so->so_ruid = p->p_cred->p_ruid; |
so->so_euid = p->p_ucred->cr_uid; |
#endif |
so->so_proto = prp; |
error = |
(*prp->pr_usrreq)(so, PRU_ATTACH, NULL, (struct mbuf *)(long)proto, |
NULL); |
if (error) { |
so->so_state |= SS_NOFDREF; |
sofree(so); |
return (error); |
} |
#ifdef COMPAT_SUNOS |
{ |
extern struct emul emul_sunos; |
if (p->p_emul == &emul_sunos && type == SOCK_DGRAM) |
so->so_options |= SO_BROADCAST; |
} |
#endif |
*aso = so; |
return (0); |
} |
|
int |
sobind(so, nam) |
struct socket *so; |
struct mbuf *nam; |
{ |
int s = splsoftnet(); |
int error; |
|
error = (*so->so_proto->pr_usrreq)(so, PRU_BIND, NULL, nam, NULL); |
splx(s); |
return (error); |
} |
|
int |
solisten(so, backlog) |
register struct socket *so; |
int backlog; |
{ |
int s = splsoftnet(), error; |
|
error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, NULL, NULL, NULL); |
if (error) { |
splx(s); |
return (error); |
} |
if (so->so_q == 0) |
so->so_options |= SO_ACCEPTCONN; |
if (backlog < 0 || backlog > somaxconn) |
backlog = somaxconn; |
if (backlog < sominconn) |
backlog = sominconn; |
so->so_qlimit = backlog; |
splx(s); |
return (0); |
} |
|
void |
sofree(so) |
register struct socket *so; |
{ |
|
if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) |
return; |
if (so->so_head) { |
/* |
* We must not decommission a socket that's on the accept(2) |
* queue. If we do, then accept(2) may hang after select(2) |
* indicated that the listening socket was ready. |
*/ |
if (!soqremque(so, 0)) |
return; |
} |
sbrelease(&so->so_snd); |
sorflush(so); |
FREE(so, M_SOCKET); |
} |
|
/* |
* Close a socket on last file table reference removal. |
* Initiate disconnect if connected. |
* Free socket when disconnect complete. |
*/ |
int |
soclose(so) |
register struct socket *so; |
{ |
struct socket *so2; |
int s = splsoftnet(); /* conservative */ |
int error = 0; |
|
if (so->so_options & SO_ACCEPTCONN) { |
while ((so2 = so->so_q0) != NULL) { |
(void) soqremque(so2, 0); |
(void) soabort(so2); |
} |
while ((so2 = so->so_q) != NULL) { |
(void) soqremque(so2, 1); |
(void) soabort(so2); |
} |
} |
if (so->so_pcb == 0) |
goto discard; |
if (so->so_state & SS_ISCONNECTED) { |
if ((so->so_state & SS_ISDISCONNECTING) == 0) { |
error = sodisconnect(so); |
if (error) |
goto drop; |
} |
if (so->so_options & SO_LINGER) { |
if ((so->so_state & SS_ISDISCONNECTING) && |
(so->so_state & SS_NBIO)) |
goto drop; |
while (so->so_state & SS_ISCONNECTED) { |
error = tsleep((caddr_t)&so->so_timeo, |
PSOCK | PCATCH, netcls, |
so->so_linger * hz); |
if (error) |
break; |
} |
} |
} |
drop: |
if (so->so_pcb) { |
int error2 = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, NULL, |
NULL, NULL); |
if (error == 0) |
error = error2; |
} |
discard: |
if (so->so_state & SS_NOFDREF) |
panic("soclose: NOFDREF"); |
so->so_state |= SS_NOFDREF; |
sofree(so); |
splx(s); |
return (error); |
} |
|
/* |
* Must be called at splsoftnet... |
*/ |
int |
soabort(so) |
struct socket *so; |
{ |
|
return (*so->so_proto->pr_usrreq)(so, PRU_ABORT, NULL, NULL, NULL); |
} |
|
int |
soaccept(so, nam) |
register struct socket *so; |
struct mbuf *nam; |
{ |
int s = splsoftnet(); |
int error = 0; |
|
if ((so->so_state & SS_NOFDREF) == 0) |
panic("soaccept: !NOFDREF"); |
so->so_state &= ~SS_NOFDREF; |
if ((so->so_state & SS_ISDISCONNECTED) == 0) |
error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, NULL, |
nam, NULL); |
splx(s); |
return (error); |
} |
|
int |
soconnect(so, nam) |
register struct socket *so; |
struct mbuf *nam; |
{ |
int s; |
int error; |
|
if (so->so_options & SO_ACCEPTCONN) |
return (EOPNOTSUPP); |
s = splsoftnet(); |
/* |
* If protocol is connection-based, can only connect once. |
* Otherwise, if connected, try to disconnect first. |
* This allows user to disconnect by connecting to, e.g., |
* a null address. |
*/ |
if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && |
((so->so_proto->pr_flags & PR_CONNREQUIRED) || |
(error = sodisconnect(so)))) |
error = EISCONN; |
else |
error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, |
NULL, nam, NULL); |
splx(s); |
return (error); |
} |
|
int |
soconnect2(so1, so2) |
register struct socket *so1; |
struct socket *so2; |
{ |
int s = splsoftnet(); |
int error; |
|
error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, NULL, |
(struct mbuf *)so2, NULL); |
splx(s); |
return (error); |
} |
|
int |
sodisconnect(so) |
register struct socket *so; |
{ |
int s = splsoftnet(); |
int error; |
|
if ((so->so_state & SS_ISCONNECTED) == 0) { |
error = ENOTCONN; |
goto bad; |
} |
if (so->so_state & SS_ISDISCONNECTING) { |
error = EALREADY; |
goto bad; |
} |
error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, NULL, NULL, |
NULL); |
bad: |
splx(s); |
return (error); |
} |
|
#define SBLOCKWAIT(f) (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK) |
/* |
* Send on a socket. |
* If send must go all at once and message is larger than |
* send buffering, then hard error. |
* Lock against other senders. |
* If must go all at once and not enough room now, then |
* inform user that this would block and do nothing. |
* Otherwise, if nonblocking, send as much as possible. |
* The data to be sent is described by "uio" if nonzero, |
* otherwise by the mbuf chain "top" (which must be null |
* if uio is not). Data provided in mbuf chain must be small |
* enough to send all at once. |
* |
* Returns nonzero on error, timeout or signal; callers |
* must check for short counts if EINTR/ERESTART are returned. |
* Data and control buffers are freed on return. |
*/ |
int |
sosend(so, addr, uio, top, control, flags) |
register struct socket *so; |
struct mbuf *addr; |
struct uio *uio; |
struct mbuf *top; |
struct mbuf *control; |
int flags; |
{ |
#ifndef __ECOS |
struct proc *p = curproc; /* XXX */ |
#endif |
struct mbuf **mp; |
register struct mbuf *m; |
register long space, len; |
register quad_t resid; |
int clen = 0, error, s, dontroute, mlen; |
int atomic = sosendallatonce(so) || top; |
|
if (uio) |
resid = uio->uio_resid; |
else |
resid = top->m_pkthdr.len; |
/* |
* In theory resid should be unsigned (since uio->uio_resid is). |
* However, space must be signed, as it might be less than 0 |
* if we over-committed, and we must use a signed comparison |
* of space and resid. On the other hand, a negative resid |
* causes us to loop sending 0-length segments to the protocol. |
* MSG_EOR on a SOCK_STREAM socket is also invalid. |
*/ |
if (resid < 0 || |
(so->so_type == SOCK_STREAM && (flags & MSG_EOR))) { |
error = EINVAL; |
goto out; |
} |
dontroute = |
(flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && |
(so->so_proto->pr_flags & PR_ATOMIC); |
#ifndef __ECOS |
p->p_stats->p_ru.ru_msgsnd++; |
#endif |
if (control) |
clen = control->m_len; |
#define snderr(errno) { error = errno; splx(s); goto release; } |
|
restart: |
if ((error = sblock(&so->so_snd, SBLOCKWAIT(flags))) != 0) |
goto out; |
do { |
s = splsoftnet(); |
if (so->so_state & SS_CANTSENDMORE) |
snderr(EPIPE); |
if (so->so_error) |
snderr(so->so_error); |
if ((so->so_state & SS_ISCONNECTED) == 0) { |
if (so->so_proto->pr_flags & PR_CONNREQUIRED) { |
if ((so->so_state & SS_ISCONFIRMING) == 0 && |
!(resid == 0 && clen != 0)) |
snderr(ENOTCONN); |
} else if (addr == 0) |
snderr(EDESTADDRREQ); |
} |
space = sbspace(&so->so_snd); |
if (flags & MSG_OOB) |
space += 1024; |
if ((atomic && resid > so->so_snd.sb_hiwat) || |
clen > so->so_snd.sb_hiwat) |
snderr(EMSGSIZE); |
if (space < resid + clen && uio && |
(atomic || space < so->so_snd.sb_lowat || space < clen)) { |
if (so->so_state & SS_NBIO) |
snderr(EWOULDBLOCK); |
sbunlock(&so->so_snd); |
error = sbwait(&so->so_snd); |
splx(s); |
if (error) |
goto out; |
goto restart; |
} |
splx(s); |
mp = ⊤ |
space -= clen; |
do { |
if (uio == NULL) { |
/* |
* Data is prepackaged in "top". |
*/ |
resid = 0; |
if (flags & MSG_EOR) |
top->m_flags |= M_EOR; |
} else do { |
if (top == 0) { |
MGETHDR(m, M_WAIT, MT_DATA); |
mlen = MHLEN; |
m->m_pkthdr.len = 0; |
m->m_pkthdr.rcvif = (struct ifnet *)0; |
} else { |
MGET(m, M_WAIT, MT_DATA); |
mlen = MLEN; |
} |
if (resid >= MINCLSIZE && space >= MCLBYTES) { |
MCLGET(m, M_WAIT); |
if ((m->m_flags & M_EXT) == 0) |
goto nopages; |
mlen = MCLBYTES; |
#ifdef MAPPED_MBUFS |
len = min(MCLBYTES, resid); |
#else |
if (atomic && top == 0) { |
len = min(MCLBYTES - max_hdr, resid); |
m->m_data += max_hdr; |
} else |
len = min(MCLBYTES, resid); |
#endif |
space -= len; |
} else { |
nopages: |
len = min(min(mlen, resid), space); |
space -= len; |
/* |
* For datagram protocols, leave room |
* for protocol headers in first mbuf. |
*/ |
if (atomic && top == 0 && len < mlen) |
MH_ALIGN(m, len); |
} |
error = uiomove(mtod(m, caddr_t), (int)len, uio); |
resid = uio->uio_resid; |
m->m_len = len; |
*mp = m; |
top->m_pkthdr.len += len; |
if (error) |
goto release; |
mp = &m->m_next; |
if (resid <= 0) { |
if (flags & MSG_EOR) |
top->m_flags |= M_EOR; |
break; |
} |
} while (space > 0 && atomic); |
if (dontroute) |
so->so_options |= SO_DONTROUTE; |
s = splsoftnet(); /* XXX */ |
error = (*so->so_proto->pr_usrreq)(so, (flags & MSG_OOB) ? |
PRU_SENDOOB : PRU_SEND, |
top, addr, control); |
splx(s); |
if (dontroute) |
so->so_options &= ~SO_DONTROUTE; |
clen = 0; |
control = 0; |
top = 0; |
mp = ⊤ |
if (error) |
goto release; |
} while (resid && space > 0); |
} while (resid); |
|
release: |
sbunlock(&so->so_snd); |
out: |
if (top) |
m_freem(top); |
if (control) |
m_freem(control); |
return (error); |
} |
|
/* |
* Implement receive operations on a socket. |
* We depend on the way that records are added to the sockbuf |
* by sbappend*. In particular, each record (mbufs linked through m_next) |
* must begin with an address if the protocol so specifies, |
* followed by an optional mbuf or mbufs containing ancillary data, |
* and then zero or more mbufs of data. |
* In order to avoid blocking network interrupts for the entire time here, |
* we splx() while doing the actual copy to user space. |
* Although the sockbuf is locked, new data may still be appended, |
* and thus we must maintain consistency of the sockbuf during that time. |
* |
* The caller may receive the data as a single mbuf chain by supplying |
* an mbuf **mp0 for use in returning the chain. The uio is then used |
* only for the count in uio_resid. |
*/ |
int |
soreceive(so, paddr, uio, mp0, controlp, flagsp) |
register struct socket *so; |
struct mbuf **paddr; |
struct uio *uio; |
struct mbuf **mp0; |
struct mbuf **controlp; |
int *flagsp; |
{ |
register struct mbuf *m, **mp; |
register int flags, len, error, s, offset; |
struct protosw *pr = so->so_proto; |
struct mbuf *nextrecord; |
int moff, type = 0; |
size_t orig_resid = uio->uio_resid; |
int uio_error = 0; |
int resid; |
|
mp = mp0; |
if (paddr) |
*paddr = 0; |
if (controlp) |
*controlp = 0; |
if (flagsp) |
flags = *flagsp &~ MSG_EOR; |
else |
flags = 0; |
if (so->so_state & SS_NBIO) |
flags |= MSG_DONTWAIT; |
if (flags & MSG_OOB) { |
m = m_get(M_WAIT, MT_DATA); |
error = (*pr->pr_usrreq)(so, PRU_RCVOOB, m, |
(struct mbuf *)(long)(flags & MSG_PEEK), NULL); |
if (error) |
goto bad; |
do { |
error = uiomove(mtod(m, caddr_t), |
(int) min(uio->uio_resid, m->m_len), uio); |
m = m_free(m); |
} while (uio->uio_resid && error == 0 && m); |
bad: |
if (m) |
m_freem(m); |
return (error); |
} |
if (mp) |
*mp = (struct mbuf *)0; |
if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) |
(*pr->pr_usrreq)(so, PRU_RCVD, NULL, NULL, NULL); |
|
restart: |
if ((error = sblock(&so->so_rcv, SBLOCKWAIT(flags))) != 0) |
return (error); |
s = splsoftnet(); |
|
m = so->so_rcv.sb_mb; |
/* |
* If we have less data than requested, block awaiting more |
* (subject to any timeout) if: |
* 1. the current count is less than the low water mark, |
* 2. MSG_WAITALL is set, and it is possible to do the entire |
* receive operation at once if we block (resid <= hiwat), or |
* 3. MSG_DONTWAIT is not set. |
* If MSG_WAITALL is set but resid is larger than the receive buffer, |
* we have to do the receive in sections, and thus risk returning |
* a short count if a timeout or signal occurs after we start. |
*/ |
if (m == 0 || (((flags & MSG_DONTWAIT) == 0 && |
so->so_rcv.sb_cc < uio->uio_resid) && |
(so->so_rcv.sb_cc < so->so_rcv.sb_lowat || |
((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) && |
m->m_nextpkt == 0 && (pr->pr_flags & PR_ATOMIC) == 0)) { |
#ifdef DIAGNOSTIC |
if (m == 0 && so->so_rcv.sb_cc) |
panic("receive 1"); |
#endif |
if (so->so_error) { |
if (m) |
goto dontblock; |
error = so->so_error; |
if ((flags & MSG_PEEK) == 0) |
so->so_error = 0; |
goto release; |
} |
if (so->so_state & SS_CANTRCVMORE) { |
if (m) |
goto dontblock; |
else |
goto release; |
} |
for (; m; m = m->m_next) |
if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) { |
m = so->so_rcv.sb_mb; |
goto dontblock; |
} |
if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 && |
(so->so_proto->pr_flags & PR_CONNREQUIRED)) { |
error = ENOTCONN; |
goto release; |
} |
if (uio->uio_resid == 0 && controlp == NULL) |
goto release; |
if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) { |
error = EWOULDBLOCK; |
goto release; |
} |
sbunlock(&so->so_rcv); |
error = sbwait(&so->so_rcv); |
splx(s); |
if (error) |
return (error); |
goto restart; |
} |
dontblock: |
#ifdef notyet /* XXXX */ |
if (uio->uio_procp) |
uio->uio_procp->p_stats->p_ru.ru_msgrcv++; |
#endif |
nextrecord = m->m_nextpkt; |
if (pr->pr_flags & PR_ADDR) { |
#ifdef DIAGNOSTIC |
if (m->m_type != MT_SONAME) |
panic("receive 1a"); |
#endif |
orig_resid = 0; |
if (flags & MSG_PEEK) { |
if (paddr) |
*paddr = m_copy(m, 0, m->m_len); |
m = m->m_next; |
} else { |
sbfree(&so->so_rcv, m); |
if (paddr) { |
*paddr = m; |
so->so_rcv.sb_mb = m->m_next; |
m->m_next = 0; |
m = so->so_rcv.sb_mb; |
} else { |
MFREE(m, so->so_rcv.sb_mb); |
m = so->so_rcv.sb_mb; |
} |
} |
} |
while (m && m->m_type == MT_CONTROL && error == 0) { |
if (flags & MSG_PEEK) { |
if (controlp) |
*controlp = m_copy(m, 0, m->m_len); |
m = m->m_next; |
} else { |
sbfree(&so->so_rcv, m); |
if (controlp) { |
if (pr->pr_domain->dom_externalize && |
mtod(m, struct cmsghdr *)->cmsg_type == |
SCM_RIGHTS) |
error = (*pr->pr_domain->dom_externalize)(m); |
*controlp = m; |
so->so_rcv.sb_mb = m->m_next; |
m->m_next = 0; |
m = so->so_rcv.sb_mb; |
} else { |
MFREE(m, so->so_rcv.sb_mb); |
m = so->so_rcv.sb_mb; |
} |
} |
if (controlp) { |
orig_resid = 0; |
controlp = &(*controlp)->m_next; |
} |
} |
if (m) { |
if ((flags & MSG_PEEK) == 0) |
m->m_nextpkt = nextrecord; |
type = m->m_type; |
if (type == MT_OOBDATA) |
flags |= MSG_OOB; |
if (m->m_flags & M_BCAST) |
flags |= MSG_BCAST; |
if (m->m_flags & M_MCAST) |
flags |= MSG_MCAST; |
} |
moff = 0; |
offset = 0; |
while (m && uio->uio_resid > 0 && error == 0) { |
if (m->m_type == MT_OOBDATA) { |
if (type != MT_OOBDATA) |
break; |
} else if (type == MT_OOBDATA) |
break; |
#ifdef DIAGNOSTIC |
else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) |
panic("receive 3"); |
#endif |
so->so_state &= ~SS_RCVATMARK; |
len = uio->uio_resid; |
if (so->so_oobmark && len > so->so_oobmark - offset) |
len = so->so_oobmark - offset; |
if (len > m->m_len - moff) |
len = m->m_len - moff; |
/* |
* If mp is set, just pass back the mbufs. |
* Otherwise copy them out via the uio, then free. |
* Sockbuf must be consistent here (points to current mbuf, |
* it points to next record) when we drop priority; |
* we must note any additions to the sockbuf when we |
* block interrupts again. |
*/ |
if (mp == 0 && uio_error == 0) { |
resid = uio->uio_resid; |
splx(s); |
uio_error = |
uiomove(mtod(m, caddr_t) + moff, (int)len, |
uio); |
s = splsoftnet(); |
if (uio_error) |
uio->uio_resid = resid - len; |
} else |
uio->uio_resid -= len; |
if (len == m->m_len - moff) { |
if (m->m_flags & M_EOR) |
flags |= MSG_EOR; |
if (flags & MSG_PEEK) { |
m = m->m_next; |
moff = 0; |
} else { |
nextrecord = m->m_nextpkt; |
sbfree(&so->so_rcv, m); |
if (mp) { |
*mp = m; |
mp = &m->m_next; |
so->so_rcv.sb_mb = m = m->m_next; |
*mp = (struct mbuf *)0; |
} else { |
MFREE(m, so->so_rcv.sb_mb); |
m = so->so_rcv.sb_mb; |
} |
if (m) |
m->m_nextpkt = nextrecord; |
} |
} else { |
if (flags & MSG_PEEK) |
moff += len; |
else { |
if (mp) |
*mp = m_copym(m, 0, len, M_WAIT); |
m->m_data += len; |
m->m_len -= len; |
so->so_rcv.sb_cc -= len; |
} |
} |
if (so->so_oobmark) { |
if ((flags & MSG_PEEK) == 0) { |
so->so_oobmark -= len; |
if (so->so_oobmark == 0) { |
so->so_state |= SS_RCVATMARK; |
break; |
} |
} else { |
offset += len; |
if (offset == so->so_oobmark) |
break; |
} |
} |
if (flags & MSG_EOR) |
break; |
/* |
* If the MSG_WAITALL flag is set (for non-atomic socket), |
* we must not quit until "uio->uio_resid == 0" or an error |
* termination. If a signal/timeout occurs, return |
* with a short count but without error. |
* Keep sockbuf locked against other readers. |
*/ |
while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 && |
!sosendallatonce(so) && !nextrecord) { |
if (so->so_error || so->so_state & SS_CANTRCVMORE) |
break; |
error = sbwait(&so->so_rcv); |
if (error) { |
sbunlock(&so->so_rcv); |
splx(s); |
return (0); |
} |
if ((m = so->so_rcv.sb_mb) != NULL) |
nextrecord = m->m_nextpkt; |
} |
} |
|
if (m && pr->pr_flags & PR_ATOMIC) { |
flags |= MSG_TRUNC; |
if ((flags & MSG_PEEK) == 0) |
(void) sbdroprecord(&so->so_rcv); |
} |
if ((flags & MSG_PEEK) == 0) { |
if (m == 0) |
so->so_rcv.sb_mb = nextrecord; |
if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) |
(*pr->pr_usrreq)(so, PRU_RCVD, NULL, |
(struct mbuf *)(long)flags, NULL); |
} |
if (orig_resid == uio->uio_resid && orig_resid && |
(flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) { |
sbunlock(&so->so_rcv); |
splx(s); |
goto restart; |
} |
|
if (uio_error) |
error = uio_error; |
|
if (flagsp) |
*flagsp |= flags; |
release: |
sbunlock(&so->so_rcv); |
splx(s); |
return (error); |
} |
|
int |
soshutdown(so, how) |
register struct socket *so; |
register int how; |
{ |
register struct protosw *pr = so->so_proto; |
|
how++; |
if (how & ~(FREAD|FWRITE)) |
return (EINVAL); |
if (how & FREAD) |
sorflush(so); |
if (how & FWRITE) |
return (*pr->pr_usrreq)(so, PRU_SHUTDOWN, NULL, NULL, NULL); |
return (0); |
} |
|
void |
sorflush(so) |
register struct socket *so; |
{ |
register struct sockbuf *sb = &so->so_rcv; |
register struct protosw *pr = so->so_proto; |
register int s; |
struct sockbuf asb; |
|
sb->sb_flags |= SB_NOINTR; |
(void) sblock(sb, M_WAITOK); |
s = splimp(); |
socantrcvmore(so); |
sbunlock(sb); |
asb = *sb; |
bzero((caddr_t)sb, sizeof (*sb)); |
splx(s); |
if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) |
(*pr->pr_domain->dom_dispose)(asb.sb_mb); |
sbrelease(&asb); |
} |
|
int |
sosetopt(so, level, optname, m0) |
register struct socket *so; |
int level, optname; |
struct mbuf *m0; |
{ |
int error = 0; |
register struct mbuf *m = m0; |
|
if (level != SOL_SOCKET) { |
if (so->so_proto && so->so_proto->pr_ctloutput) |
return ((*so->so_proto->pr_ctloutput) |
(PRCO_SETOPT, so, level, optname, &m0)); |
error = ENOPROTOOPT; |
} else { |
switch (optname) { |
|
case SO_LINGER: |
if (m == NULL || m->m_len != sizeof (struct linger)) { |
error = EINVAL; |
goto bad; |
} |
so->so_linger = mtod(m, struct linger *)->l_linger; |
/* fall thru... */ |
|
case SO_DEBUG: |
case SO_KEEPALIVE: |
case SO_DONTROUTE: |
case SO_USELOOPBACK: |
case SO_BROADCAST: |
case SO_REUSEADDR: |
case SO_REUSEPORT: |
case SO_OOBINLINE: |
if (m == NULL || m->m_len < sizeof (int)) { |
error = EINVAL; |
goto bad; |
} |
if (*mtod(m, int *)) |
so->so_options |= optname; |
else |
so->so_options &= ~optname; |
break; |
|
case SO_SNDBUF: |
case SO_RCVBUF: |
case SO_SNDLOWAT: |
case SO_RCVLOWAT: |
{ |
u_long cnt; |
|
if (m == NULL || m->m_len < sizeof (int)) { |
error = EINVAL; |
goto bad; |
} |
cnt = *mtod(m, int *); |
if ((long)cnt <= 0) |
cnt = 1; |
switch (optname) { |
|
case SO_SNDBUF: |
case SO_RCVBUF: |
if (sbreserve(optname == SO_SNDBUF ? |
&so->so_snd : &so->so_rcv, |
cnt) == 0) { |
error = ENOBUFS; |
goto bad; |
} |
break; |
|
case SO_SNDLOWAT: |
so->so_snd.sb_lowat = (cnt > so->so_snd.sb_hiwat) ? |
so->so_snd.sb_hiwat : cnt; |
break; |
case SO_RCVLOWAT: |
so->so_rcv.sb_lowat = (cnt > so->so_rcv.sb_hiwat) ? |
so->so_rcv.sb_hiwat : cnt; |
break; |
} |
break; |
} |
|
case SO_SNDTIMEO: |
case SO_RCVTIMEO: |
{ |
struct timeval *tv; |
short val; |
|
if (m == NULL || m->m_len < sizeof (*tv)) { |
error = EINVAL; |
goto bad; |
} |
tv = mtod(m, struct timeval *); |
if (tv->tv_sec * hz + tv->tv_usec / tick > SHRT_MAX) { |
error = EDOM; |
goto bad; |
} |
val = tv->tv_sec * hz + tv->tv_usec / tick; |
|
switch (optname) { |
|
case SO_SNDTIMEO: |
so->so_snd.sb_timeo = val; |
break; |
case SO_RCVTIMEO: |
so->so_rcv.sb_timeo = val; |
break; |
} |
break; |
} |
|
default: |
error = ENOPROTOOPT; |
break; |
} |
if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) { |
(void) ((*so->so_proto->pr_ctloutput) |
(PRCO_SETOPT, so, level, optname, &m0)); |
m = NULL; /* freed by protocol */ |
} |
} |
bad: |
if (m) |
(void) m_free(m); |
return (error); |
} |
|
int |
sogetopt(so, level, optname, mp) |
register struct socket *so; |
int level, optname; |
struct mbuf **mp; |
{ |
register struct mbuf *m; |
|
if (level != SOL_SOCKET) { |
if (so->so_proto && so->so_proto->pr_ctloutput) { |
return ((*so->so_proto->pr_ctloutput) |
(PRCO_GETOPT, so, level, optname, mp)); |
} else |
return (ENOPROTOOPT); |
} else { |
m = m_get(M_WAIT, MT_SOOPTS); |
m->m_len = sizeof (int); |
|
switch (optname) { |
|
case SO_LINGER: |
m->m_len = sizeof (struct linger); |
mtod(m, struct linger *)->l_onoff = |
so->so_options & SO_LINGER; |
mtod(m, struct linger *)->l_linger = so->so_linger; |
break; |
|
case SO_USELOOPBACK: |
case SO_DONTROUTE: |
case SO_DEBUG: |
case SO_KEEPALIVE: |
case SO_REUSEADDR: |
case SO_REUSEPORT: |
case SO_BROADCAST: |
case SO_OOBINLINE: |
*mtod(m, int *) = so->so_options & optname; |
break; |
|
case SO_TYPE: |
*mtod(m, int *) = so->so_type; |
break; |
|
case SO_ERROR: |
*mtod(m, int *) = so->so_error; |
so->so_error = 0; |
break; |
|
case SO_SNDBUF: |
*mtod(m, int *) = so->so_snd.sb_hiwat; |
break; |
|
case SO_RCVBUF: |
*mtod(m, int *) = so->so_rcv.sb_hiwat; |
break; |
|
case SO_SNDLOWAT: |
*mtod(m, int *) = so->so_snd.sb_lowat; |
break; |
|
case SO_RCVLOWAT: |
*mtod(m, int *) = so->so_rcv.sb_lowat; |
break; |
|
case SO_SNDTIMEO: |
case SO_RCVTIMEO: |
{ |
int val = (optname == SO_SNDTIMEO ? |
so->so_snd.sb_timeo : so->so_rcv.sb_timeo); |
|
m->m_len = sizeof(struct timeval); |
mtod(m, struct timeval *)->tv_sec = val / hz; |
mtod(m, struct timeval *)->tv_usec = |
(val % hz) * tick; |
break; |
} |
|
default: |
(void)m_free(m); |
return (ENOPROTOOPT); |
} |
*mp = m; |
return (0); |
} |
} |
|
void |
sohasoutofband(so) |
register struct socket *so; |
{ |
#ifndef __ECOS |
csignal(so->so_pgid, SIGURG, so->so_siguid, so->so_sigeuid); |
#endif |
selwakeup(&so->so_rcv.sb_sel); |
} |
/uipc_mbuf.c
0,0 → 1,1096
//========================================================================== |
// |
// sys/kern/uipc_mbuf.c |
// |
// |
// |
//========================================================================== |
//####BSDCOPYRIGHTBEGIN#### |
// |
// ------------------------------------------- |
// |
// Portions of this software may have been derived from OpenBSD or other sources, |
// and are covered by the appropriate copyright disclaimers included herein. |
// |
// ------------------------------------------- |
// |
//####BSDCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): gthomas |
// Contributors: gthomas |
// Date: 2000-01-10 |
// Purpose: |
// Description: |
// |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
|
/* $OpenBSD: uipc_mbuf.c,v 1.18 1999/12/05 07:30:31 angelos Exp $ */ |
/* $NetBSD: uipc_mbuf.c,v 1.15.4.1 1996/06/13 17:11:44 cgd Exp $ */ |
|
/* |
* Copyright (c) 1982, 1986, 1988, 1991, 1993 |
* The Regents of the University of California. All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
* |
* @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 |
*/ |
|
/* |
%%% portions-copyright-nrl-95 |
Portions of this software are Copyright 1995-1998 by Randall Atkinson, |
Ronald Lee, Daniel McDonald, Bao Phan, and Chris Winters. All Rights |
Reserved. All rights under this copyright have been assigned to the US |
Naval Research Laboratory (NRL). The NRL Copyright Notice and License |
Agreement Version 1.1 (January 17, 1995) applies to these portions of the |
software. |
You should have received a copy of the license with this software. If you |
didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. |
*/ |
|
#include <sys/param.h> |
#ifndef __ECOS |
#include <sys/systm.h> |
#include <sys/proc.h> |
#endif |
#include <sys/malloc.h> |
#ifndef __ECOS |
#include <sys/map.h> |
#endif |
#define MBTYPES |
#include <sys/mbuf.h> |
#include <sys/kernel.h> |
#ifndef __ECOS |
#include <sys/syslog.h> |
#endif |
#include <sys/domain.h> |
#include <sys/protosw.h> |
|
#include <machine/cpu.h> |
|
#ifndef __ECOS |
#include <vm/vm.h> |
#endif |
|
#if defined(UVM) |
#include <uvm/uvm_extern.h> |
#endif |
|
#ifndef __ECOS |
extern vm_map_t mb_map; |
#endif |
struct mbuf *mbutl; |
char *mclrefcnt; |
int needqueuedrain; |
|
#ifdef __ECOS |
extern void setsoftnet(void); |
extern void *cyg_net_cluster_alloc(void); |
#endif |
|
/* Declarations of variables move from mbuf.h to keep g++ happy */ |
#ifdef __ECOS |
struct mbstat mbstat; |
union mcluster *mclfree; |
int max_linkhdr; /* largest link-level header */ |
int max_protohdr; /* largest protocol header */ |
int max_hdr; /* largest link+protocol header */ |
int max_datalen; /* MHLEN - max_hdr */ |
#ifdef MBTYPES |
int mbtypes[] = { /* XXX */ |
M_FREE, /* MT_FREE 0 should be on free list */ |
M_MBUF, /* MT_DATA 1 dynamic (data) allocation */ |
M_MBUF, /* MT_HEADER 2 packet header */ |
M_SOCKET, /* MT_SOCKET 3 socket structure */ |
M_PCB, /* MT_PCB 4 protocol control block */ |
M_RTABLE, /* MT_RTABLE 5 routing tables */ |
M_HTABLE, /* MT_HTABLE 6 IMP host tables */ |
0, /* MT_ATABLE 7 address resolution tables */ |
M_MBUF, /* MT_SONAME 8 socket name */ |
0, /* 9 */ |
M_SOOPTS, /* MT_SOOPTS 10 socket options */ |
M_FTABLE, /* MT_FTABLE 11 fragment reassembly header */ |
M_MBUF, /* MT_RIGHTS 12 access rights */ |
M_IFADDR, /* MT_IFADDR 13 interface address */ |
M_MBUF, /* MT_CONTROL 14 extra-data protocol message */ |
M_MBUF, /* MT_OOBDATA 15 expedited data */ |
#ifdef DATAKIT |
25, 26, 27, 28, 29, 30, 31, 32 /* datakit ugliness */ |
#endif |
}; |
#endif |
#endif // __ECOS |
|
void |
mbinit() |
{ |
int s; |
|
s = splimp(); |
#ifdef __ECOS |
if (m_clalloc(1, M_DONTWAIT) == 0) |
#else |
if (m_clalloc(max(4096 / CLBYTES, 1), M_DONTWAIT) == 0) |
#endif |
goto bad; |
splx(s); |
return; |
bad: |
panic("mbinit"); |
} |
|
/* |
* Allocate some number of mbuf clusters |
* and place on cluster free list. |
* Must be called at splimp. |
*/ |
/* ARGSUSED */ |
int |
m_clalloc(ncl, nowait) |
register int ncl; |
int nowait; |
{ |
#ifdef __ECOS |
caddr_t p; |
int i; |
|
if (ncl != 1) { |
panic("Allocate multiple clusters!"); |
} |
p = (caddr_t)cyg_net_cluster_alloc(); |
if (p == NULL) { |
m_reclaim(); |
return (mclfree != NULL); |
} |
for (i = 0; i < ncl; i++) { |
((union mcluster *)p)->mcl_next = mclfree; |
mclfree = (union mcluster *)p; |
p += MCLBYTES; |
mbstat.m_clfree++; |
} |
mbstat.m_clusters += ncl; |
return (1); |
#else // __ECOS |
volatile static struct timeval lastlogged; |
struct timeval curtime, logdiff; |
register caddr_t p; |
register int i; |
int npg, s; |
|
npg = ncl * CLSIZE; |
#if defined(UVM) |
p = (caddr_t)uvm_km_kmemalloc(mb_map, uvmexp.mb_object, ctob(npg), |
nowait ? 0 : UVM_KMF_NOWAIT); |
#else |
p = (caddr_t)kmem_malloc(mb_map, ctob(npg), !nowait); |
#endif |
if (p == NULL) { |
s = splclock(); |
curtime = time; |
splx(s); |
timersub(&curtime, &lastlogged, &logdiff); |
if (logdiff.tv_sec >= 60) { |
lastlogged = curtime; |
log(LOG_ERR, "mb_map full\n"); |
} |
m_reclaim(); |
return (mclfree != NULL); |
} |
ncl = ncl * CLBYTES / MCLBYTES; |
for (i = 0; i < ncl; i++) { |
((union mcluster *)p)->mcl_next = mclfree; |
mclfree = (union mcluster *)p; |
p += MCLBYTES; |
mbstat.m_clfree++; |
} |
mbstat.m_clusters += ncl; |
return (1); |
#endif // __ECOS |
} |
|
/* |
* When MGET failes, ask protocols to free space when short of memory, |
* then re-attempt to allocate an mbuf. |
*/ |
struct mbuf * |
m_retry(i, t) |
int i, t; |
{ |
register struct mbuf *m; |
|
if (i & M_DONTWAIT) { |
needqueuedrain = 1; |
setsoftnet(); |
return (NULL); |
} |
m_reclaim(); |
#define m_retry(i, t) NULL |
MGET(m, i, t); |
#undef m_retry |
return (m); |
} |
|
/* |
* As above; retry an MGETHDR. |
*/ |
struct mbuf * |
m_retryhdr(i, t) |
int i, t; |
{ |
register struct mbuf *m; |
|
if (i & M_DONTWAIT) { |
needqueuedrain = 1; |
setsoftnet(); |
return (NULL); |
} |
m_reclaim(); |
#define m_retryhdr(i, t) NULL |
MGETHDR(m, i, t); |
#undef m_retryhdr |
return (m); |
} |
|
void |
m_reclaim() |
{ |
register struct domain *dp; |
register struct protosw *pr; |
int s = splimp(); |
|
needqueuedrain = 0; |
for (dp = domains; dp; dp = dp->dom_next) |
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) |
if (pr->pr_drain) |
(*pr->pr_drain)(); |
splx(s); |
mbstat.m_drain++; |
} |
|
/* |
* Space allocation routines. |
* These are also available as macros |
* for critical paths. |
*/ |
struct mbuf * |
m_get(nowait, type) |
int nowait, type; |
{ |
register struct mbuf *m; |
|
MGET(m, nowait, type); |
return (m); |
} |
|
struct mbuf * |
m_gethdr(nowait, type) |
int nowait, type; |
{ |
register struct mbuf *m; |
|
MGETHDR(m, nowait, type); |
return (m); |
} |
|
struct mbuf * |
m_getclr(nowait, type) |
int nowait, type; |
{ |
register struct mbuf *m; |
|
MGET(m, nowait, type); |
if (m == NULL) |
return (NULL); |
bzero(mtod(m, caddr_t), MLEN); |
return (m); |
} |
|
struct mbuf * |
m_free(m) |
struct mbuf *m; |
{ |
register struct mbuf *n; |
|
MFREE(m, n); |
return (n); |
} |
|
void |
m_freem(m) |
register struct mbuf *m; |
{ |
register struct mbuf *n; |
|
if (m == NULL) |
return; |
do { |
MFREE(m, n); |
} while ((m = n) != NULL); |
} |
|
/* |
* Mbuffer utility routines. |
*/ |
|
/* |
* Lesser-used path for M_PREPEND: |
* allocate new mbuf to prepend to chain, |
* copy junk along. |
*/ |
struct mbuf * |
m_prepend(m, len, how) |
register struct mbuf *m; |
int len, how; |
{ |
struct mbuf *mn; |
|
MGET(mn, how, m->m_type); |
if (mn == NULL) { |
m_freem(m); |
return (NULL); |
} |
if (m->m_flags & M_PKTHDR) { |
M_COPY_PKTHDR(mn, m); |
m->m_flags &= ~M_PKTHDR; |
} |
mn->m_next = m; |
m = mn; |
if (len < MHLEN) |
MH_ALIGN(m, len); |
m->m_len = len; |
return (m); |
} |
|
/* |
* Make a copy of an mbuf chain starting "off0" bytes from the beginning, |
* continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. |
* The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller. |
*/ |
int MCFail; |
|
struct mbuf * |
m_copym(m, off0, len, wait) |
register struct mbuf *m; |
int off0, wait; |
register int len; |
{ |
register struct mbuf *n, **np; |
register int off = off0; |
struct mbuf *top; |
int copyhdr = 0; |
|
if (off < 0) |
panic("m_copym: off %d < 0", off); |
if (len < 0) |
panic("m_copym: len %d < 0", len); |
if (off == 0 && m->m_flags & M_PKTHDR) |
copyhdr = 1; |
while (off > 0) { |
if (m == NULL) |
panic("m_copym: null mbuf"); |
if (off < m->m_len) |
break; |
off -= m->m_len; |
m = m->m_next; |
} |
np = ⊤ |
top = NULL; |
while (len > 0) { |
if (m == NULL) { |
if (len != M_COPYALL) |
panic("m_copym: %d not M_COPYALL", len); |
break; |
} |
MGET(n, wait, m->m_type); |
*np = n; |
if (n == NULL) |
goto nospace; |
if (copyhdr) { |
M_COPY_PKTHDR(n, m); |
if (len == M_COPYALL) |
n->m_pkthdr.len -= off0; |
else |
n->m_pkthdr.len = len; |
copyhdr = 0; |
} |
n->m_len = min(len, m->m_len - off); |
if (m->m_flags & M_EXT) { |
n->m_data = m->m_data + off; |
if (!m->m_ext.ext_ref) |
mclrefcnt[mtocl(m->m_ext.ext_buf)]++; |
else |
(*(m->m_ext.ext_ref))(m); |
n->m_ext = m->m_ext; |
n->m_flags |= M_EXT; |
} else |
bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), |
(unsigned)n->m_len); |
if (len != M_COPYALL) |
len -= n->m_len; |
off = 0; |
m = m->m_next; |
np = &n->m_next; |
} |
if (top == NULL) |
MCFail++; |
return (top); |
nospace: |
m_freem(top); |
MCFail++; |
return (NULL); |
} |
|
/* |
* m_copym2() is like m_copym(), except it COPIES cluster mbufs, instead |
* of merely bumping the reference count. |
*/ |
struct mbuf * |
m_copym2(m, off0, len, wait) |
register struct mbuf *m; |
int off0, wait; |
register int len; |
{ |
register struct mbuf *n, **np; |
register int off = off0; |
struct mbuf *top; |
int copyhdr = 0; |
|
if (len < 0) |
panic("m_copym2: len %d < 0", len); |
if (off < 0) |
panic("m_copym2: off %d < 0", off); |
if (off == 0 && m->m_flags & M_PKTHDR) |
copyhdr = 1; |
while (off > 0) { |
if (m == NULL) |
panic("m_copym2: null mbuf"); |
if (off < m->m_len) |
break; |
off -= m->m_len; |
m = m->m_next; |
} |
np = ⊤ |
top = NULL; |
while (len > 0) { |
if (m == NULL) { |
if (len != M_COPYALL) |
panic("m_copym2: %d != M_COPYALL", len); |
break; |
} |
MGET(n, wait, m->m_type); |
*np = n; |
if (n == NULL) |
goto nospace; |
if (copyhdr) { |
M_COPY_PKTHDR(n, m); |
if (len == M_COPYALL) |
n->m_pkthdr.len -= off0; |
else |
n->m_pkthdr.len = len; |
copyhdr = 0; |
} |
n->m_len = min(len, m->m_len - off); |
if ((m->m_flags & M_EXT) && (n->m_len > MHLEN)) { |
/* This is a cheesy hack. */ |
MCLGET(n, wait); |
if (n->m_flags & M_EXT) |
bcopy(mtod(m, caddr_t) + off, mtod(n, caddr_t), |
(unsigned)n->m_len); |
else |
goto nospace; |
} else |
bcopy(mtod(m, caddr_t) + off, mtod(n, caddr_t), |
(unsigned)n->m_len); |
if (len != M_COPYALL) |
len -= n->m_len; |
off = 0; |
m = m->m_next; |
np = &n->m_next; |
} |
if (top == NULL) |
MCFail++; |
return (top); |
nospace: |
m_freem(top); |
MCFail++; |
return (NULL); |
} |
|
/* |
* Copy data from an mbuf chain starting "off" bytes from the beginning, |
* continuing for "len" bytes, into the indicated buffer. |
*/ |
void |
m_copydata(m, off, len, cp) |
register struct mbuf *m; |
register int off; |
register int len; |
caddr_t cp; |
{ |
register unsigned count; |
|
if (off < 0) |
panic("m_copydata: off %d < 0", off); |
if (len < 0) |
panic("m_copydata: len %d < 0", len); |
while (off > 0) { |
if (m == NULL) |
panic("m_copydata: null mbuf in skip"); |
if (off < m->m_len) |
break; |
off -= m->m_len; |
m = m->m_next; |
} |
while (len > 0) { |
if (m == NULL) |
panic("m_copydata: null mbuf"); |
count = min(m->m_len - off, len); |
bcopy(mtod(m, caddr_t) + off, cp, count); |
len -= count; |
cp += count; |
off = 0; |
m = m->m_next; |
} |
} |
|
/* |
* Concatenate mbuf chain n to m. |
* Both chains must be of the same type (e.g. MT_DATA). |
* Any m_pkthdr is not updated. |
*/ |
void |
m_cat(m, n) |
register struct mbuf *m, *n; |
{ |
while (m->m_next) |
m = m->m_next; |
while (n) { |
if (m->m_flags & M_EXT || |
m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) { |
/* just join the two chains */ |
m->m_next = n; |
return; |
} |
/* splat the data from one into the other */ |
bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, |
(u_int)n->m_len); |
m->m_len += n->m_len; |
n = m_free(n); |
} |
} |
|
void |
m_adj(mp, req_len) |
struct mbuf *mp; |
int req_len; |
{ |
register int len = req_len; |
register struct mbuf *m; |
register int count; |
|
if ((m = mp) == NULL) |
return; |
if (len >= 0) { |
/* |
* Trim from head. |
*/ |
while (m != NULL && len > 0) { |
if (m->m_len <= len) { |
len -= m->m_len; |
m->m_len = 0; |
m = m->m_next; |
} else { |
m->m_len -= len; |
m->m_data += len; |
len = 0; |
} |
} |
m = mp; |
if (mp->m_flags & M_PKTHDR) |
m->m_pkthdr.len -= (req_len - len); |
} else { |
/* |
* Trim from tail. Scan the mbuf chain, |
* calculating its length and finding the last mbuf. |
* If the adjustment only affects this mbuf, then just |
* adjust and return. Otherwise, rescan and truncate |
* after the remaining size. |
*/ |
len = -len; |
count = 0; |
for (;;) { |
count += m->m_len; |
if (m->m_next == NULL) |
break; |
m = m->m_next; |
} |
if (m->m_len >= len) { |
m->m_len -= len; |
if (mp->m_flags & M_PKTHDR) |
mp->m_pkthdr.len -= len; |
return; |
} |
count -= len; |
if (count < 0) |
count = 0; |
/* |
* Correct length for chain is "count". |
* Find the mbuf with last data, adjust its length, |
* and toss data from remaining mbufs on chain. |
*/ |
m = mp; |
if (m->m_flags & M_PKTHDR) |
m->m_pkthdr.len = count; |
for (; m; m = m->m_next) { |
if (m->m_len >= count) { |
m->m_len = count; |
break; |
} |
count -= m->m_len; |
} |
while ((m = m->m_next) != NULL) |
m->m_len = 0; |
} |
} |
|
/* |
* Rearange an mbuf chain so that len bytes are contiguous |
* and in the data area of an mbuf (so that mtod and dtom |
* will work for a structure of size len). Returns the resulting |
* mbuf chain on success, frees it and returns null on failure. |
* If there is room, it will add up to max_protohdr-len extra bytes to the |
* contiguous region in an attempt to avoid being called next time. |
*/ |
int MPFail; |
|
struct mbuf * |
m_pullup(n, len) |
register struct mbuf *n; |
int len; |
{ |
register struct mbuf *m; |
register int count; |
int space; |
|
/* |
* If first mbuf has no cluster, and has room for len bytes |
* without shifting current data, pullup into it, |
* otherwise allocate a new mbuf to prepend to the chain. |
*/ |
if ((n->m_flags & M_EXT) == 0 && |
n->m_data + len < &n->m_dat[MLEN] && n->m_next) { |
if (n->m_len >= len) |
return (n); |
m = n; |
n = n->m_next; |
len -= m->m_len; |
} else { |
if (len > MHLEN) |
goto bad; |
MGET(m, M_DONTWAIT, n->m_type); |
if (m == NULL) |
goto bad; |
m->m_len = 0; |
if (n->m_flags & M_PKTHDR) { |
M_COPY_PKTHDR(m, n); |
n->m_flags &= ~M_PKTHDR; |
} |
} |
space = &m->m_dat[MLEN] - (m->m_data + m->m_len); |
do { |
count = min(min(max(len, max_protohdr), space), n->m_len); |
bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, |
(unsigned)count); |
len -= count; |
m->m_len += count; |
n->m_len -= count; |
space -= count; |
if (n->m_len) |
n->m_data += count; |
else |
n = m_free(n); |
} while (len > 0 && n); |
if (len > 0) { |
(void)m_free(m); |
goto bad; |
} |
m->m_next = n; |
return (m); |
bad: |
m_freem(n); |
MPFail++; |
return (NULL); |
} |
|
/* |
* m_pullup2() works like m_pullup, save that len can be <= MCLBYTES. |
* m_pullup2() only works on values of len such that MHLEN < len <= MCLBYTES, |
* it calls m_pullup() for values <= MHLEN. It also only coagulates the |
* reqested number of bytes. (For those of us who expect unwieldly option |
* headers. |
* |
* KEBE SAYS: Remember that dtom() calls with data in clusters does not work! |
*/ |
struct mbuf * |
m_pullup2(n, len) |
register struct mbuf *n; |
int len; |
{ |
register struct mbuf *m; |
register int count; |
int space; |
if (len <= MHLEN) |
return m_pullup(n, len); |
|
if ((n->m_flags & M_EXT) != 0 && |
n->m_data + len < &n->m_data[MCLBYTES] && n->m_next) { |
if (n->m_len >= len) |
return (n); |
m = n; |
n = n->m_next; |
len -= m->m_len; |
} else { |
if (len > MCLBYTES) |
goto bad; |
MGET(m, M_DONTWAIT, n->m_type); |
if (m == NULL) |
goto bad; |
MCLGET(m, M_DONTWAIT); |
if ((m->m_flags & M_EXT) == 0) |
goto bad; |
m->m_len = 0; |
if (n->m_flags & M_PKTHDR) { |
/* M_COPY_PKTHDR(m, n);*//* Too many adverse side effects. */ |
m->m_pkthdr = n->m_pkthdr; |
m->m_flags = (n->m_flags & M_COPYFLAGS) | M_EXT; |
n->m_flags &= ~M_PKTHDR; |
/* n->m_data is cool. */ |
} |
} |
|
do { |
count = min(len, n->m_len); |
bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, |
(unsigned)count); |
len -= count; |
m->m_len += count; |
n->m_len -= count; |
space -= count; |
if (n->m_len) |
n->m_data += count; |
else |
n = m_free(n); |
} while (len > 0 && n); |
if (len > 0) { |
(void)m_free(m); |
goto bad; |
} |
m->m_next = n; |
|
return (m); |
bad: |
m_freem(n); |
MPFail++; |
return (NULL); |
} |
|
/* |
* Inject a new mbuf chain of length siz in mbuf chain m0 at |
* position len0. Returns a pointer to the first injected mbuf, or |
* NULL on failure (m0 is left undisturbed). Note that if there is |
* enough space for an object of size siz in the appropriate position, |
* no memory will be allocated. Also, there will be no data movement in |
* the first len0 bytes (pointers to that will remain valid). |
* |
* XXX It is assumed that siz is less than the size of an mbuf at the moment. |
*/ |
struct mbuf * |
m_inject(m0, len0, siz, wait) |
register struct mbuf *m0; |
int len0, siz, wait; |
{ |
register struct mbuf *m, *n, *n2 = NULL, *n3; |
unsigned len = len0, remain; |
|
if ((siz >= MHLEN) || (len0 <= 0)) |
return (NULL); |
for (m = m0; m && len > m->m_len; m = m->m_next) |
len -= m->m_len; |
if (m == NULL) |
return (NULL); |
remain = m->m_len - len; |
if (remain == 0) { |
if ((m->m_next) && (M_LEADINGSPACE(m->m_next) >= siz)) { |
m->m_next->m_len += siz; |
m0->m_pkthdr.len += siz; |
m->m_next->m_data -= siz; |
return m->m_next; |
} |
} else { |
n2 = m_copym2(m, len, remain, wait); |
if (n2 == NULL) |
return (NULL); |
} |
|
MGET(n, wait, MT_DATA); |
if (n == NULL) { |
if (n2) |
m_freem(n2); |
return (NULL); |
} |
|
n->m_len = siz; |
m0->m_pkthdr.len += siz; |
m->m_len -= remain; /* Trim */ |
if (n2) { |
for (n3 = n; n3->m_next != NULL; n3 = n3->m_next) |
; |
n3->m_next = n2; |
} else |
n3 = n; |
for (; n3->m_next != NULL; n3 = n3->m_next) |
; |
n3->m_next = m->m_next; |
m->m_next = n; |
return n; |
} |
|
/* |
* Partition an mbuf chain in two pieces, returning the tail -- |
* all but the first len0 bytes. In case of failure, it returns NULL and |
* attempts to restore the chain to its original state. |
*/ |
struct mbuf * |
m_split(m0, len0, wait) |
register struct mbuf *m0; |
int len0, wait; |
{ |
register struct mbuf *m, *n; |
unsigned len = len0, remain, olen; |
|
for (m = m0; m && len > m->m_len; m = m->m_next) |
len -= m->m_len; |
if (m == NULL) |
return (NULL); |
remain = m->m_len - len; |
if (m0->m_flags & M_PKTHDR) { |
MGETHDR(n, wait, m0->m_type); |
if (n == NULL) |
return (NULL); |
n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif; |
n->m_pkthdr.len = m0->m_pkthdr.len - len0; |
olen = m0->m_pkthdr.len; |
m0->m_pkthdr.len = len0; |
if (m->m_flags & M_EXT) |
goto extpacket; |
if (remain > MHLEN) { |
/* m can't be the lead packet */ |
MH_ALIGN(n, 0); |
n->m_next = m_split(m, len, wait); |
if (n->m_next == NULL) { |
(void) m_free(n); |
m0->m_pkthdr.len = olen; |
return (NULL); |
} else |
return (n); |
} else |
MH_ALIGN(n, remain); |
} else if (remain == 0) { |
n = m->m_next; |
m->m_next = NULL; |
return (n); |
} else { |
MGET(n, wait, m->m_type); |
if (n == NULL) |
return (NULL); |
M_ALIGN(n, remain); |
} |
extpacket: |
if (m->m_flags & M_EXT) { |
n->m_flags |= M_EXT; |
n->m_ext = m->m_ext; |
if(!m->m_ext.ext_ref) |
mclrefcnt[mtocl(m->m_ext.ext_buf)]++; |
else |
(*(m->m_ext.ext_ref))(m); |
m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */ |
n->m_data = m->m_data + len; |
} else { |
bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain); |
} |
n->m_len = remain; |
m->m_len = len; |
n->m_next = m->m_next; |
m->m_next = NULL; |
return (n); |
} |
/* |
* Routine to copy from device local memory into mbufs. |
*/ |
struct mbuf * |
m_devget(buf, totlen, off0, ifp, copy) |
char *buf; |
int totlen, off0; |
struct ifnet *ifp; |
void (*copy) __P((const void *, void *, size_t)); |
{ |
register struct mbuf *m; |
struct mbuf *top = NULL, **mp = ⊤ |
register int off = off0, len; |
register char *cp; |
char *epkt; |
|
cp = buf; |
epkt = cp + totlen; |
if (off) { |
/* |
* If 'off' is non-zero, packet is trailer-encapsulated, |
* so we have to skip the type and length fields. |
*/ |
cp += off + 2 * sizeof(u_int16_t); |
totlen -= 2 * sizeof(u_int16_t); |
} |
MGETHDR(m, M_DONTWAIT, MT_DATA); |
if (m == NULL) |
return (NULL); |
m->m_pkthdr.rcvif = ifp; |
m->m_pkthdr.len = totlen; |
m->m_len = MHLEN; |
|
while (totlen > 0) { |
if (top != NULL) { |
MGET(m, M_DONTWAIT, MT_DATA); |
if (m == NULL) { |
m_freem(top); |
return (NULL); |
} |
m->m_len = MLEN; |
} |
len = min(totlen, epkt - cp); |
if (len >= MINCLSIZE) { |
MCLGET(m, M_DONTWAIT); |
if (m->m_flags & M_EXT) |
m->m_len = len = min(len, MCLBYTES); |
else |
len = m->m_len; |
} else { |
/* |
* Place initial small packet/header at end of mbuf. |
*/ |
if (len < m->m_len) { |
if (top == NULL && |
len + max_linkhdr <= m->m_len) |
m->m_data += max_linkhdr; |
m->m_len = len; |
} else |
len = m->m_len; |
} |
if (copy) |
copy(cp, mtod(m, caddr_t), (size_t)len); |
else |
bcopy(cp, mtod(m, caddr_t), (size_t)len); |
cp += len; |
*mp = m; |
mp = &m->m_next; |
totlen -= len; |
if (cp == epkt) |
cp = buf; |
} |
return (top); |
} |
|
void |
m_zero(m) |
struct mbuf *m; |
{ |
while (m) { |
if (m->m_flags & M_PKTHDR) |
bzero((unsigned char *)m + sizeof(struct m_hdr) + |
sizeof(struct pkthdr), MHLEN); |
else |
bzero((unsigned char *)m + sizeof(struct m_hdr), MLEN); |
if ((m->m_flags & M_EXT) && |
(m->m_ext.ext_free == NULL) && |
!mclrefcnt[mtocl((m)->m_ext.ext_buf)]) |
bzero(m->m_ext.ext_buf, m->m_ext.ext_size); |
m = m->m_next; |
} |
} |
|
/* |
* Apply function f to the data in an mbuf chain starting "off" bytes from the |
* beginning, continuing for "len" bytes. |
*/ |
int |
m_apply(m, off, len, f, fstate) |
struct mbuf *m; |
int off; |
int len; |
/* fstate, data, len */ |
int (*f)(caddr_t, caddr_t, unsigned int); |
caddr_t fstate; |
{ |
int rval; |
unsigned int count; |
|
if (len < 0) |
panic("m_apply: len %d < 0", len); |
if (off < 0) |
panic("m_apply: off %d < 0", off); |
while (off > 0) { |
if (m == NULL) |
panic("m_apply: null mbuf in skip"); |
if (off < m->m_len) |
break; |
off -= m->m_len; |
m = m->m_next; |
} |
while (len > 0) { |
if (m == NULL) |
panic("m_apply: null mbuf"); |
count = min(m->m_len - off, len); |
|
rval = f(fstate, mtod(m, caddr_t) + off, count); |
if (rval) |
return (rval); |
|
len -= count; |
off = 0; |
m = m->m_next; |
} |
|
return (0); |
} |
|
/kern_subr.c
0,0 → 1,360
//========================================================================== |
// |
// sys/kern/kern_subr.c |
// |
// |
// |
//========================================================================== |
//####BSDCOPYRIGHTBEGIN#### |
// |
// ------------------------------------------- |
// |
// Portions of this software may have been derived from OpenBSD or other sources, |
// and are covered by the appropriate copyright disclaimers included herein. |
// |
// ------------------------------------------- |
// |
//####BSDCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): gthomas |
// Contributors: gthomas |
// Date: 2000-01-10 |
// Purpose: |
// Description: |
// |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
|
/* $OpenBSD: kern_subr.c,v 1.10 1999/11/07 17:39:14 provos Exp $ */ |
/* $NetBSD: kern_subr.c,v 1.15 1996/04/09 17:21:56 ragge Exp $ */ |
|
/* |
* Copyright (c) 1982, 1986, 1991, 1993 |
* The Regents of the University of California. All rights reserved. |
* (c) UNIX System Laboratories, Inc. |
* All or some portions of this file are derived from material licensed |
* to the University of California by American Telephone and Telegraph |
* Co. or Unix System Laboratories, Inc. and are reproduced herein with |
* the permission of UNIX System Laboratories, Inc. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
* |
* @(#)kern_subr.c 8.3 (Berkeley) 1/21/94 |
*/ |
|
#include <sys/param.h> |
#ifndef __ECOS |
#include <sys/systm.h> |
#include <sys/proc.h> |
#endif // __ECOS |
#include <sys/malloc.h> |
#include <sys/queue.h> |
|
int |
uiomove(cp, n, uio) |
register caddr_t cp; |
register int n; |
register struct uio *uio; |
{ |
register struct iovec *iov; |
u_int cnt; |
int error = 0; |
|
#ifdef DIAGNOSTIC |
if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE) |
panic("uiomove: mode"); |
if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) |
panic("uiomove proc"); |
#endif |
while (n > 0 && uio->uio_resid) { |
iov = uio->uio_iov; |
cnt = iov->iov_len; |
if (cnt == 0) { |
uio->uio_iov++; |
uio->uio_iovcnt--; |
continue; |
} |
if (cnt > n) |
cnt = n; |
switch (uio->uio_segflg) { |
|
case UIO_USERSPACE: |
if (uio->uio_rw == UIO_READ) |
error = copyout(cp, iov->iov_base, cnt); |
else |
error = copyin(iov->iov_base, cp, cnt); |
if (error) |
return (error); |
break; |
|
case UIO_SYSSPACE: |
#if defined(UVM) |
if (uio->uio_rw == UIO_READ) |
error = kcopy(cp, iov->iov_base, cnt); |
else |
error = kcopy(iov->iov_base, cp, cnt); |
if (error) |
return(error); |
#else |
if (uio->uio_rw == UIO_READ) |
bcopy((caddr_t)cp, iov->iov_base, cnt); |
else |
bcopy(iov->iov_base, (caddr_t)cp, cnt); |
break; |
#endif |
} |
(char *)(iov->iov_base) += cnt; |
iov->iov_len -= cnt; |
uio->uio_resid -= cnt; |
uio->uio_offset += cnt; |
cp += cnt; |
n -= cnt; |
} |
return (error); |
} |
|
#ifndef __ECOS |
/* |
* Give next character to user as result of read. |
*/ |
int |
ureadc(c, uio) |
register int c; |
register struct uio *uio; |
{ |
register struct iovec *iov; |
|
if (uio->uio_resid == 0) |
#ifdef DIAGNOSTIC |
panic("ureadc: zero resid"); |
#else |
return (EINVAL); |
#endif |
again: |
if (uio->uio_iovcnt <= 0) |
#ifdef DIAGNOSTIC |
panic("ureadc: non-positive iovcnt"); |
#else |
return (EINVAL); |
#endif |
iov = uio->uio_iov; |
if (iov->iov_len <= 0) { |
uio->uio_iovcnt--; |
uio->uio_iov++; |
goto again; |
} |
switch (uio->uio_segflg) { |
|
case UIO_USERSPACE: |
if (subyte(iov->iov_base, c) < 0) |
return (EFAULT); |
break; |
|
case UIO_SYSSPACE: |
*(char *)iov->iov_base = c; |
break; |
} |
iov->iov_base++; |
iov->iov_len--; |
uio->uio_resid--; |
uio->uio_offset++; |
return (0); |
} |
#endif // __ECOS |
|
/* |
* General routine to allocate a hash table. |
*/ |
#ifdef __ECOS |
void * |
hashinit(int elements, int type, int flags, u_long *hashmask) |
#else |
void * |
hashinit(elements, type, flags, hashmask) |
int elements, type, flags; |
u_long *hashmask; |
#endif |
{ |
long hashsize; |
LIST_HEAD(generic, generic) *hashtbl; |
int i; |
|
if (elements <= 0) |
panic("hashinit: bad cnt"); |
for (hashsize = 1; hashsize <= elements; hashsize <<= 1) |
continue; |
hashsize >>= 1; |
hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, flags); |
for (i = 0; i < hashsize; i++) |
LIST_INIT(&hashtbl[i]); |
*hashmask = hashsize - 1; |
return (hashtbl); |
} |
|
#ifndef __ECOS |
/* |
* "Shutdown hook" types, functions, and variables. |
*/ |
|
struct shutdownhook_desc { |
LIST_ENTRY(shutdownhook_desc) sfd_list; |
void (*sfd_fn) __P((void *)); |
void *sfd_arg; |
}; |
|
LIST_HEAD(, shutdownhook_desc) shutdownhook_list; |
|
int shutdownhooks_done; |
|
void * |
shutdownhook_establish(fn, arg) |
void (*fn) __P((void *)); |
void *arg; |
{ |
struct shutdownhook_desc *ndp; |
|
ndp = (struct shutdownhook_desc *) |
malloc(sizeof (*ndp), M_DEVBUF, M_NOWAIT); |
if (ndp == NULL) |
return NULL; |
|
ndp->sfd_fn = fn; |
ndp->sfd_arg = arg; |
LIST_INSERT_HEAD(&shutdownhook_list, ndp, sfd_list); |
|
return (ndp); |
} |
|
void |
shutdownhook_disestablish(vhook) |
void *vhook; |
{ |
#ifdef DIAGNOSTIC |
struct shutdownhook_desc *dp; |
|
for (dp = shutdownhook_list.lh_first; dp != NULL; |
dp = dp->sfd_list.le_next) |
if (dp == vhook) |
break; |
if (dp == NULL) |
panic("shutdownhook_disestablish: hook not established"); |
#endif |
|
LIST_REMOVE((struct shutdownhook_desc *)vhook, sfd_list); |
} |
|
/* |
* Run shutdown hooks. Should be invoked immediately before the |
* system is halted or rebooted, i.e. after file systems unmounted, |
* after crash dump done, etc. |
*/ |
void |
doshutdownhooks() |
{ |
struct shutdownhook_desc *dp; |
|
if (shutdownhooks_done) |
return; |
|
for (dp = shutdownhook_list.lh_first; dp != NULL; dp = |
dp->sfd_list.le_next) |
(*dp->sfd_fn)(dp->sfd_arg); |
} |
|
/* |
* "Power hook" types, functions, and variables. |
*/ |
|
struct powerhook_desc { |
LIST_ENTRY(powerhook_desc) sfd_list; |
void (*sfd_fn) __P((int, void *)); |
void *sfd_arg; |
}; |
|
LIST_HEAD(, powerhook_desc) powerhook_list; |
|
void * |
powerhook_establish(fn, arg) |
void (*fn) __P((int, void *)); |
void *arg; |
{ |
struct powerhook_desc *ndp; |
|
ndp = (struct powerhook_desc *) |
malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT); |
if (ndp == NULL) |
return NULL; |
|
ndp->sfd_fn = fn; |
ndp->sfd_arg = arg; |
LIST_INSERT_HEAD(&powerhook_list, ndp, sfd_list); |
|
return (ndp); |
} |
|
void |
powerhook_disestablish(vhook) |
void *vhook; |
{ |
#ifdef DIAGNOSTIC |
struct powerhook_desc *dp; |
|
for (dp = powerhook_list.lh_first; dp != NULL; |
dp = dp->sfd_list.le_next) |
if (dp == vhook) |
break; |
if (dp == NULL) |
panic("powerhook_disestablish: hook not established"); |
#endif |
|
LIST_REMOVE((struct powerhook_desc *)vhook, sfd_list); |
free(vhook, M_DEVBUF); |
} |
|
/* |
* Run power hooks. |
*/ |
void |
dopowerhooks(why) |
int why; |
{ |
struct powerhook_desc *dp; |
|
for (dp = LIST_FIRST(&powerhook_list); |
dp != NULL; |
dp = LIST_NEXT(dp, sfd_list)) { |
(*dp->sfd_fn)(why, dp->sfd_arg); |
} |
} |
#endif // __ECOS |
/sys_generic.c
0,0 → 1,1025
//========================================================================== |
// |
// sys/kern/sys_generic.c |
// |
// |
// |
//========================================================================== |
//####BSDCOPYRIGHTBEGIN#### |
// |
// ------------------------------------------- |
// |
// Portions of this software may have been derived from OpenBSD or other sources, |
// and are covered by the appropriate copyright disclaimers included herein. |
// |
// ------------------------------------------- |
// |
//####BSDCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): gthomas |
// Contributors: gthomas |
// Date: 2000-01-10 |
// Purpose: |
// Description: |
// |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
|
/* $OpenBSD: sys_generic.c,v 1.22 1999/11/29 22:02:14 deraadt Exp $ */ |
/* $NetBSD: sys_generic.c,v 1.24 1996/03/29 00:25:32 cgd Exp $ */ |
|
/* |
* Copyright (c) 1996 Theo de Raadt |
* Copyright (c) 1982, 1986, 1989, 1993 |
* The Regents of the University of California. All rights reserved. |
* (c) UNIX System Laboratories, Inc. |
* All or some portions of this file are derived from material licensed |
* to the University of California by American Telephone and Telegraph |
* Co. or Unix System Laboratories, Inc. and are reproduced herein with |
* the permission of UNIX System Laboratories, Inc. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
* |
* @(#)sys_generic.c 8.5 (Berkeley) 1/21/94 |
*/ |
|
#include <sys/param.h> |
#ifndef __ECOS |
#include <sys/systm.h> |
#include <sys/filedesc.h> |
#endif // __ECOS |
#include <sys/ioctl.h> |
#ifdef __ECOS |
#include <cyg/io/file.h> |
#else // __ECOS |
#include <sys/file.h> |
#include <sys/proc.h> |
#include <sys/resourcevar.h> |
#endif // __ECOS |
#include <sys/socketvar.h> |
#ifndef __ECOS |
#include <sys/signalvar.h> |
#include <sys/kernel.h> |
#include <sys/uio.h> |
#include <sys/stat.h> |
#endif // __ECOS |
#include <sys/malloc.h> |
#ifndef __ECOS |
#include <sys/poll.h> |
#endif // __ECOS |
#ifdef KTRACE |
#include <sys/ktrace.h> |
#endif |
|
#ifndef __ECOS |
#include <sys/mount.h> |
#endif // __ECOS |
#include <sys/syscallargs.h> |
|
#ifndef __ECOS |
int selscan __P((struct proc *, fd_set *, fd_set *, int, register_t *)); |
int seltrue __P((dev_t, int, struct proc *)); |
void pollscan __P((struct proc *, struct pollfd *, int, register_t *)); |
#endif // __ECOS |
|
/* |
* Read system call. |
*/ |
#ifdef __ECOS |
int |
sys_read(struct sys_read_args *uap, register_t *retval) |
#else |
/* ARGSUSED */ |
int |
sys_read(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
#endif |
{ |
#ifndef __ECOS |
register struct sys_read_args /* { |
syscallarg(int) fd; |
syscallarg(void *) buf; |
syscallarg(size_t) nbyte; |
} */ *uap = v; |
register struct filedesc *fdp = p->p_fd; |
#endif |
struct file *fp; |
struct uio auio; |
struct iovec aiov; |
long cnt, error = 0; |
#ifdef KTRACE |
struct iovec ktriov; |
#endif |
|
#ifdef __ECOS |
if (getfp((u_int)SCARG(uap, fd), &fp) || |
#else |
if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles || |
(fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL || |
#endif |
(fp->f_flag & FREAD) == 0) |
return (EBADF); |
/* Don't allow nbyte to be larger than max return val */ |
if (SCARG(uap, nbyte) > SSIZE_MAX) |
return(EINVAL); |
aiov.iov_base = (caddr_t)SCARG(uap, buf); |
aiov.iov_len = SCARG(uap, nbyte); |
auio.uio_iov = &aiov; |
auio.uio_iovcnt = 1; |
auio.uio_resid = SCARG(uap, nbyte); |
auio.uio_rw = UIO_READ; |
auio.uio_segflg = UIO_USERSPACE; |
#ifndef __ECOS |
auio.uio_procp = p; |
#endif |
#ifdef KTRACE |
/* |
* if tracing, save a copy of iovec |
*/ |
if (KTRPOINT(p, KTR_GENIO)) |
ktriov = aiov; |
#endif |
cnt = SCARG(uap, nbyte); |
#ifdef __ECOS |
error = (*fp->f_ops->fo_read)(fp, &auio); |
#else |
error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred); |
#endif |
if (error) |
#ifdef __ECOS |
if (auio.uio_resid != cnt && ( |
#else |
if (auio.uio_resid != cnt && (error == ERESTART || |
#endif |
error == EINTR || error == EWOULDBLOCK)) |
error = 0; |
cnt -= auio.uio_resid; |
#ifdef KTRACE |
if (KTRPOINT(p, KTR_GENIO) && error == 0) |
ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_READ, &ktriov, |
cnt, error); |
#endif |
*retval = cnt; |
return (error); |
} |
|
|
#ifndef __ECOS |
/* |
* Scatter read system call. |
*/ |
int |
sys_readv(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_readv_args /* { |
syscallarg(int) fd; |
syscallarg(struct iovec *) iovp; |
syscallarg(int) iovcnt; |
} */ *uap = v; |
register struct file *fp; |
register struct filedesc *fdp = p->p_fd; |
struct uio auio; |
register struct iovec *iov; |
struct iovec *needfree; |
struct iovec aiov[UIO_SMALLIOV]; |
long i, cnt, error = 0; |
u_int iovlen; |
#ifdef KTRACE |
struct iovec *ktriov = NULL; |
#endif |
|
if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles || |
(fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL || |
(fp->f_flag & FREAD) == 0) |
return (EBADF); |
if (SCARG(uap, iovcnt) <= 0) |
return (EINVAL); |
/* note: can't use iovlen until iovcnt is validated */ |
iovlen = SCARG(uap, iovcnt) * sizeof (struct iovec); |
if (SCARG(uap, iovcnt) > UIO_SMALLIOV) { |
if (SCARG(uap, iovcnt) > IOV_MAX) |
return (EINVAL); |
MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); |
needfree = iov; |
} else { |
iov = aiov; |
needfree = NULL; |
} |
auio.uio_iov = iov; |
auio.uio_iovcnt = SCARG(uap, iovcnt); |
auio.uio_rw = UIO_READ; |
auio.uio_segflg = UIO_USERSPACE; |
auio.uio_procp = p; |
error = copyin((caddr_t)SCARG(uap, iovp), (caddr_t)iov, iovlen); |
if (error) |
goto done; |
auio.uio_resid = 0; |
for (i = 0; i < SCARG(uap, iovcnt); i++, iov++) { |
/* Don't allow sum > SSIZE_MAX */ |
if (iov->iov_len > SSIZE_MAX || |
(auio.uio_resid += iov->iov_len) > SSIZE_MAX) { |
error = EINVAL; |
goto done; |
} |
} |
#ifdef KTRACE |
/* |
* if tracing, save a copy of iovec |
*/ |
if (KTRPOINT(p, KTR_GENIO)) { |
MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); |
bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); |
} |
#endif |
cnt = auio.uio_resid; |
error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred); |
if (error) |
if (auio.uio_resid != cnt && (error == ERESTART || |
error == EINTR || error == EWOULDBLOCK)) |
error = 0; |
cnt -= auio.uio_resid; |
#ifdef KTRACE |
if (ktriov != NULL) { |
if (error == 0) |
ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_READ, ktriov, |
cnt, error); |
FREE(ktriov, M_TEMP); |
} |
#endif |
*retval = cnt; |
done: |
if (needfree) |
FREE(needfree, M_IOV); |
return (error); |
} |
#endif |
|
/* |
* Write system call |
*/ |
#ifdef __ECOS |
int |
sys_write(struct sys_write_args *uap, register_t *retval) |
#else |
int |
sys_write(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
#endif |
{ |
#ifndef __ECOS |
register struct sys_write_args /* { |
syscallarg(int) fd; |
syscallarg(void *) buf; |
syscallarg(size_t) nbyte; |
} */ *uap = v; |
register struct filedesc *fdp = p->p_fd; |
#endif |
struct file *fp; |
struct uio auio; |
struct iovec aiov; |
long cnt, error = 0; |
#ifdef KTRACE |
struct iovec ktriov; |
#endif |
|
#ifdef __ECOS |
if (getfp((u_int)SCARG(uap, fd), &fp) || |
#else |
if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles || |
(fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL || |
#endif |
(fp->f_flag & FWRITE) == 0) |
return (EBADF); |
/* Don't allow nbyte to be larger than max return val */ |
if (SCARG(uap, nbyte) > SSIZE_MAX) |
return(EINVAL); |
aiov.iov_base = (caddr_t)SCARG(uap, buf); |
aiov.iov_len = SCARG(uap, nbyte); |
auio.uio_iov = &aiov; |
auio.uio_iovcnt = 1; |
auio.uio_resid = SCARG(uap, nbyte); |
auio.uio_rw = UIO_WRITE; |
auio.uio_segflg = UIO_USERSPACE; |
#ifndef __ECOS |
auio.uio_procp = p; |
#endif |
#ifdef KTRACE |
/* |
* if tracing, save a copy of iovec |
*/ |
if (KTRPOINT(p, KTR_GENIO)) |
ktriov = aiov; |
#endif |
cnt = SCARG(uap, nbyte); |
#ifdef __ECOS |
error = (*fp->f_ops->fo_write)(fp, &auio); |
#else |
error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred); |
#endif |
if (error) { |
#ifdef __ECOS |
if (auio.uio_resid != cnt && |
(error == EINTR || error == EWOULDBLOCK)) |
error = 0; |
#else |
if (auio.uio_resid != cnt && (error == ERESTART || |
error == EINTR || error == EWOULDBLOCK)) |
error = 0; |
if (error == EPIPE) |
psignal(p, SIGPIPE); |
#endif |
} |
cnt -= auio.uio_resid; |
#ifdef KTRACE |
if (KTRPOINT(p, KTR_GENIO) && error == 0) |
ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_WRITE, |
&ktriov, cnt, error); |
#endif |
*retval = cnt; |
return (error); |
} |
|
#ifndef __ECOS |
/* |
* Gather write system call |
*/ |
int |
sys_writev(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_writev_args /* { |
syscallarg(int) fd; |
syscallarg(struct iovec *) iovp; |
syscallarg(int) iovcnt; |
} */ *uap = v; |
register struct file *fp; |
register struct filedesc *fdp = p->p_fd; |
struct uio auio; |
register struct iovec *iov; |
struct iovec *needfree; |
struct iovec aiov[UIO_SMALLIOV]; |
long i, cnt, error = 0; |
u_int iovlen; |
#ifdef KTRACE |
struct iovec *ktriov = NULL; |
#endif |
|
if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles || |
(fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL || |
(fp->f_flag & FWRITE) == 0) |
return (EBADF); |
if (SCARG(uap, iovcnt) <= 0) |
return (EINVAL); |
/* note: can't use iovlen until iovcnt is validated */ |
iovlen = SCARG(uap, iovcnt) * sizeof (struct iovec); |
if (SCARG(uap, iovcnt) > UIO_SMALLIOV) { |
if (SCARG(uap, iovcnt) > IOV_MAX) |
return (EINVAL); |
MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); |
needfree = iov; |
} else { |
iov = aiov; |
needfree = NULL; |
} |
auio.uio_iov = iov; |
auio.uio_iovcnt = SCARG(uap, iovcnt); |
auio.uio_rw = UIO_WRITE; |
auio.uio_segflg = UIO_USERSPACE; |
auio.uio_procp = p; |
error = copyin((caddr_t)SCARG(uap, iovp), (caddr_t)iov, iovlen); |
if (error) |
goto done; |
auio.uio_resid = 0; |
for (i = 0; i < SCARG(uap, iovcnt); i++, iov++) { |
/* Don't allow sum > SSIZE_MAX */ |
if (iov->iov_len > SSIZE_MAX || |
(auio.uio_resid += iov->iov_len) > SSIZE_MAX) { |
error = EINVAL; |
goto done; |
} |
} |
#ifdef KTRACE |
/* |
* if tracing, save a copy of iovec |
*/ |
if (KTRPOINT(p, KTR_GENIO)) { |
MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); |
bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); |
} |
#endif |
cnt = auio.uio_resid; |
error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred); |
if (error) { |
if (auio.uio_resid != cnt && (error == ERESTART || |
error == EINTR || error == EWOULDBLOCK)) |
error = 0; |
if (error == EPIPE) |
psignal(p, SIGPIPE); |
} |
cnt -= auio.uio_resid; |
#ifdef KTRACE |
if (ktriov != NULL) { |
if (error == 0) |
ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_WRITE, |
ktriov, cnt, error); |
FREE(ktriov, M_TEMP); |
} |
#endif |
*retval = cnt; |
done: |
if (needfree) |
FREE(needfree, M_IOV); |
return (error); |
} |
#endif |
|
/* |
* Ioctl system call |
*/ |
#ifdef __ECOS |
int |
sys_ioctl(struct sys_ioctl_args *uap, register_t *retval) |
#else |
/* ARGSUSED */ |
int |
sys_ioctl(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
#endif |
{ |
#ifndef __ECOS |
register struct sys_ioctl_args /* { |
syscallarg(int) fd; |
syscallarg(u_long) com; |
syscallarg(caddr_t) data; |
} */ *uap = v; |
register struct filedesc *fdp; |
#endif |
int tmp; |
struct file *fp; |
register u_long com; |
register int error; |
register u_int size; |
caddr_t data, memp; |
#define STK_PARAMS 128 |
char stkbuf[STK_PARAMS]; |
|
#ifdef __ECOS |
if (getfp(SCARG(uap, fd), &fp)) |
#else |
fdp = p->p_fd; |
if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || |
(fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) |
#endif |
return (EBADF); |
|
if ((fp->f_flag & (FREAD | FWRITE)) == 0) |
return (EBADF); |
|
#ifdef __ECOS |
com = SCARG(uap, com); |
#else |
switch (com = SCARG(uap, com)) { |
case FIONCLEX: |
fdp->fd_ofileflags[SCARG(uap, fd)] &= ~UF_EXCLOSE; |
return (0); |
case FIOCLEX: |
fdp->fd_ofileflags[SCARG(uap, fd)] |= UF_EXCLOSE; |
return (0); |
} |
#endif |
|
/* |
* Interpret high order word to find amount of data to be |
* copied to/from the user's address space. |
*/ |
size = IOCPARM_LEN(com); |
#ifndef __ECOS |
if (size > IOCPARM_MAX) |
return (ENOTTY); |
#endif |
memp = NULL; |
if (size > sizeof (stkbuf)) { |
memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK); |
data = memp; |
} else |
data = stkbuf; |
if (com&IOC_IN) { |
if (size) { |
error = copyin(SCARG(uap, data), data, (u_int)size); |
if (error) { |
if (memp) |
free(memp, M_IOCTLOPS); |
return (error); |
} |
} else |
*(caddr_t *)data = SCARG(uap, data); |
} else if ((com&IOC_OUT) && size) |
/* |
* Zero the buffer so the user always |
* gets back something deterministic. |
*/ |
bzero(data, size); |
else if (com&IOC_VOID) |
*(caddr_t *)data = SCARG(uap, data); |
|
switch (com) { |
|
case FIONBIO: |
if ((tmp = *(int *)data) != 0) |
fp->f_flag |= FNONBLOCK; |
else |
fp->f_flag &= ~FNONBLOCK; |
#ifdef __ECOS |
error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (CYG_ADDRWORD)&tmp); |
#else |
error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); |
#endif |
break; |
|
case FIOASYNC: |
if ((tmp = *(int *)data) != 0) |
fp->f_flag |= FASYNC; |
else |
fp->f_flag &= ~FASYNC; |
#ifdef __ECOS |
error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (CYG_ADDRWORD)&tmp); |
#else |
error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p); |
#endif |
break; |
|
#ifndef __ECOS |
case FIOSETOWN: |
tmp = *(int *)data; |
if (fp->f_type == DTYPE_SOCKET) { |
struct socket *so = (struct socket *)fp->f_data; |
|
so->so_pgid = tmp; |
so->so_siguid = p->p_cred->p_ruid; |
so->so_sigeuid = p->p_ucred->cr_uid; |
error = 0; |
break; |
} |
if (tmp <= 0) { |
tmp = -tmp; |
} else { |
struct proc *p1 = pfind(tmp); |
if (p1 == 0) { |
error = ESRCH; |
break; |
} |
tmp = p1->p_pgrp->pg_id; |
} |
error = (*fp->f_ops->fo_ioctl) |
(fp, TIOCSPGRP, (caddr_t)&tmp, p); |
break; |
|
case FIOGETOWN: |
if (fp->f_type == DTYPE_SOCKET) { |
error = 0; |
*(int *)data = ((struct socket *)fp->f_data)->so_pgid; |
break; |
} |
error = (*fp->f_ops->fo_ioctl)(fp, TIOCGPGRP, data, p); |
*(int *)data = -*(int *)data; |
break; |
#endif |
default: |
#ifdef __ECOS |
error = (*fp->f_ops->fo_ioctl)(fp, com, (CYG_ADDRWORD)data); |
#else |
error = (*fp->f_ops->fo_ioctl)(fp, com, data, p); |
#endif |
/* |
* Copy any data to user, size was |
* already set and checked above. |
*/ |
if (error == 0 && (com&IOC_OUT) && size) |
error = copyout(data, SCARG(uap, data), (u_int)size); |
break; |
} |
if (memp) |
free(memp, M_IOCTLOPS); |
return (error); |
} |
|
#ifndef __ECOS |
int selwait, nselcoll; |
|
/* |
* Select system call. |
*/ |
int |
sys_select(p, v, retval) |
register struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_select_args /* { |
syscallarg(int) nd; |
syscallarg(fd_set *) in; |
syscallarg(fd_set *) ou; |
syscallarg(fd_set *) ex; |
syscallarg(struct timeval *) tv; |
} */ *uap = v; |
fd_set bits[6], *pibits[3], *pobits[3]; |
struct timeval atv; |
int s, ncoll, error = 0, timo; |
u_int ni; |
|
if (SCARG(uap, nd) > p->p_fd->fd_nfiles) { |
/* forgiving; slightly wrong */ |
SCARG(uap, nd) = p->p_fd->fd_nfiles; |
} |
ni = howmany(SCARG(uap, nd), NFDBITS) * sizeof(fd_mask); |
if (SCARG(uap, nd) > FD_SETSIZE) { |
caddr_t mbits; |
|
if ((mbits = malloc(ni * 6, M_TEMP, M_WAITOK)) == NULL) { |
error = EINVAL; |
goto cleanup; |
} |
bzero(mbits, ni * 6); |
pibits[0] = (fd_set *)&mbits[ni * 0]; |
pibits[1] = (fd_set *)&mbits[ni * 1]; |
pibits[2] = (fd_set *)&mbits[ni * 2]; |
pobits[0] = (fd_set *)&mbits[ni * 3]; |
pobits[1] = (fd_set *)&mbits[ni * 4]; |
pobits[2] = (fd_set *)&mbits[ni * 5]; |
} else { |
bzero((caddr_t)bits, sizeof(bits)); |
pibits[0] = &bits[0]; |
pibits[1] = &bits[1]; |
pibits[2] = &bits[2]; |
pobits[0] = &bits[3]; |
pobits[1] = &bits[4]; |
pobits[2] = &bits[5]; |
} |
|
#define getbits(name, x) \ |
if (SCARG(uap, name) && (error = copyin((caddr_t)SCARG(uap, name), \ |
(caddr_t)pibits[x], ni))) \ |
goto done; |
getbits(in, 0); |
getbits(ou, 1); |
getbits(ex, 2); |
#undef getbits |
|
if (SCARG(uap, tv)) { |
error = copyin((caddr_t)SCARG(uap, tv), (caddr_t)&atv, |
sizeof (atv)); |
if (error) |
goto done; |
if (itimerfix(&atv)) { |
error = EINVAL; |
goto done; |
} |
s = splclock(); |
timeradd(&atv, &time, &atv); |
timo = hzto(&atv); |
/* |
* Avoid inadvertently sleeping forever. |
*/ |
if (timo == 0) |
timo = 1; |
splx(s); |
} else |
timo = 0; |
retry: |
ncoll = nselcoll; |
p->p_flag |= P_SELECT; |
error = selscan(p, pibits[0], pobits[0], SCARG(uap, nd), retval); |
if (error || *retval) |
goto done; |
s = splhigh(); |
/* this should be timercmp(&time, &atv, >=) */ |
if (SCARG(uap, tv) && (time.tv_sec > atv.tv_sec || |
(time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec))) { |
splx(s); |
goto done; |
} |
if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) { |
splx(s); |
goto retry; |
} |
p->p_flag &= ~P_SELECT; |
error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo); |
splx(s); |
if (error == 0) |
goto retry; |
done: |
p->p_flag &= ~P_SELECT; |
/* select is not restarted after signals... */ |
if (error == ERESTART) |
error = EINTR; |
if (error == EWOULDBLOCK) |
error = 0; |
#define putbits(name, x) \ |
if (SCARG(uap, name) && (error2 = copyout((caddr_t)pobits[x], \ |
(caddr_t)SCARG(uap, name), ni))) \ |
error = error2; |
if (error == 0) { |
int error2; |
|
putbits(in, 0); |
putbits(ou, 1); |
putbits(ex, 2); |
#undef putbits |
} |
|
cleanup: |
if (pibits[0] != &bits[0]) |
free(pibits[0], M_TEMP); |
return (error); |
} |
|
int |
selscan(p, ibits, obits, nfd, retval) |
struct proc *p; |
fd_set *ibits, *obits; |
int nfd; |
register_t *retval; |
{ |
caddr_t cibits = (caddr_t)ibits, cobits = (caddr_t)obits; |
register struct filedesc *fdp = p->p_fd; |
register int msk, i, j, fd; |
register fd_mask bits; |
struct file *fp; |
int ni, n = 0; |
static int flag[3] = { FREAD, FWRITE, 0 }; |
|
/* |
* if nfd > FD_SETSIZE then the fd_set's contain nfd bits (rounded |
* up to the next byte) otherwise the fd_set's are normal sized. |
*/ |
ni = sizeof(fd_set); |
if (nfd > FD_SETSIZE) |
ni = howmany(nfd, NFDBITS) * sizeof(fd_mask); |
|
for (msk = 0; msk < 3; msk++) { |
fd_set *pibits = (fd_set *)&cibits[msk*ni]; |
fd_set *pobits = (fd_set *)&cobits[msk*ni]; |
|
for (i = 0; i < nfd; i += NFDBITS) { |
bits = pibits->fds_bits[i/NFDBITS]; |
while ((j = ffs(bits)) && (fd = i + --j) < nfd) { |
bits &= ~(1 << j); |
fp = fdp->fd_ofiles[fd]; |
if (fp == NULL) |
return (EBADF); |
if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) { |
FD_SET(fd, pobits); |
n++; |
} |
} |
} |
} |
*retval = n; |
return (0); |
} |
|
/*ARGSUSED*/ |
int |
seltrue(dev, flag, p) |
dev_t dev; |
int flag; |
struct proc *p; |
{ |
|
return (1); |
} |
|
/* |
* Record a select request. |
*/ |
void |
selrecord(selector, sip) |
struct proc *selector; |
struct selinfo *sip; |
{ |
struct proc *p; |
pid_t mypid; |
|
mypid = selector->p_pid; |
if (sip->si_selpid == mypid) |
return; |
if (sip->si_selpid && (p = pfind(sip->si_selpid)) && |
p->p_wchan == (caddr_t)&selwait) |
sip->si_flags |= SI_COLL; |
else |
sip->si_selpid = mypid; |
} |
|
/* |
* Do a wakeup when a selectable event occurs. |
*/ |
void |
selwakeup(sip) |
register struct selinfo *sip; |
{ |
register struct proc *p; |
int s; |
|
if (sip->si_selpid == 0) |
return; |
if (sip->si_flags & SI_COLL) { |
nselcoll++; |
sip->si_flags &= ~SI_COLL; |
wakeup((caddr_t)&selwait); |
} |
p = pfind(sip->si_selpid); |
sip->si_selpid = 0; |
if (p != NULL) { |
s = splhigh(); |
if (p->p_wchan == (caddr_t)&selwait) { |
if (p->p_stat == SSLEEP) |
setrunnable(p); |
else |
unsleep(p); |
} else if (p->p_flag & P_SELECT) |
p->p_flag &= ~P_SELECT; |
splx(s); |
} |
} |
|
void |
pollscan(p, pl, nfd, retval) |
struct proc *p; |
struct pollfd *pl; |
int nfd; |
register_t *retval; |
{ |
register struct filedesc *fdp = p->p_fd; |
register int msk, i; |
struct file *fp; |
int x, n = 0; |
static int flag[3] = { FREAD, FWRITE, 0 }; |
static int pflag[3] = { POLLIN|POLLRDNORM, POLLOUT, POLLERR }; |
|
/* |
* XXX: We need to implement the rest of the flags. |
*/ |
for (i = 0; i < nfd; i++) { |
/* Check the file descriptor. */ |
if (pl[i].fd < 0) |
continue; |
if (pl[i].fd >= fdp->fd_nfiles) { |
pl[i].revents = POLLNVAL; |
n++; |
continue; |
} |
|
fp = fdp->fd_ofiles[pl[i].fd]; |
if (fp == NULL) { |
pl[i].revents = POLLNVAL; |
n++; |
continue; |
} |
for (x = msk = 0; msk < 3; msk++) { |
if (pl[i].events & pflag[msk]) { |
if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) { |
pl[i].revents |= pflag[msk] & |
pl[i].events; |
x++; |
} |
} |
} |
if (x) |
n++; |
} |
*retval = n; |
} |
|
/* |
* We are using the same mechanism as select only we encode/decode args |
* differently. |
*/ |
int |
sys_poll(p, v, retval) |
register struct proc *p; |
void *v; |
register_t *retval; |
{ |
struct sys_poll_args *uap = v; |
size_t sz; |
struct pollfd pfds[4], *pl = pfds; |
int msec = SCARG(uap, timeout); |
struct timeval atv; |
int timo, ncoll, i, s, error, error2; |
extern int nselcoll, selwait; |
|
/* Standards say no more than MAX_OPEN; this is possibly better. */ |
if (SCARG(uap, nfds) > min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, |
maxfiles)) |
return (EINVAL); |
|
sz = sizeof(struct pollfd) * SCARG(uap, nfds); |
|
/* optimize for the default case, of a small nfds value */ |
if (sz > sizeof(pfds)) |
pl = (struct pollfd *) malloc(sz, M_TEMP, M_WAITOK); |
|
if ((error = copyin(SCARG(uap, fds), pl, sz)) != 0) |
goto bad; |
|
for (i = 0; i < SCARG(uap, nfds); i++) |
pl[i].revents = 0; |
|
if (msec != -1) { |
atv.tv_sec = msec / 1000; |
atv.tv_usec = (msec - (atv.tv_sec * 1000)) * 1000; |
|
if (itimerfix(&atv)) { |
error = EINVAL; |
goto done; |
} |
s = splclock(); |
timeradd(&atv, &time, &atv); |
timo = hzto(&atv); |
/* |
* Avoid inadvertently sleeping forever. |
*/ |
if (timo == 0) |
timo = 1; |
splx(s); |
} else |
timo = 0; |
|
retry: |
ncoll = nselcoll; |
p->p_flag |= P_SELECT; |
pollscan(p, pl, SCARG(uap, nfds), retval); |
if (*retval) |
goto done; |
s = splhigh(); |
if (timo && timercmp(&time, &atv, >=)) { |
splx(s); |
goto done; |
} |
if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) { |
splx(s); |
goto retry; |
} |
p->p_flag &= ~P_SELECT; |
error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "poll", timo); |
splx(s); |
if (error == 0) |
goto retry; |
|
done: |
p->p_flag &= ~P_SELECT; |
/* poll is not restarted after signals... */ |
if (error == ERESTART) |
error = EINTR; |
if (error == EWOULDBLOCK) |
error = 0; |
if ((error2 = copyout(pl, SCARG(uap, fds), sz)) != 0) |
error = error2; |
bad: |
if (pl != pfds) |
free((char *) pl, M_TEMP); |
return (error); |
} |
#endif |
/uipc_socket2.c
0,0 → 1,909
//========================================================================== |
// |
// sys/kern/uipc_socket2.c |
// |
// |
// |
//========================================================================== |
//####BSDCOPYRIGHTBEGIN#### |
// |
// ------------------------------------------- |
// |
// Portions of this software may have been derived from OpenBSD or other sources, |
// and are covered by the appropriate copyright disclaimers included herein. |
// |
// ------------------------------------------- |
// |
//####BSDCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): gthomas |
// Contributors: gthomas |
// Date: 2000-01-10 |
// Purpose: |
// Description: |
// |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
|
/* $OpenBSD: uipc_socket2.c,v 1.11 1999/12/08 06:50:17 itojun Exp $ */ |
/* $NetBSD: uipc_socket2.c,v 1.11 1996/02/04 02:17:55 christos Exp $ */ |
|
/* |
* Copyright (c) 1982, 1986, 1988, 1990, 1993 |
* The Regents of the University of California. All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
* |
* @(#)uipc_socket2.c 8.1 (Berkeley) 6/10/93 |
*/ |
|
#include <sys/param.h> |
#ifndef __ECOS |
#include <sys/systm.h> |
#include <sys/proc.h> |
#include <sys/file.h> |
#include <sys/buf.h> |
#endif |
#include <sys/malloc.h> |
#include <sys/mbuf.h> |
#include <sys/protosw.h> |
#include <sys/socket.h> |
#include <sys/socketvar.h> |
#ifndef __ECOS |
#include <sys/signalvar.h> |
#endif |
|
#ifdef __ECOS |
#include <cyg/infra/diag.h> |
#endif |
|
/* |
* Primitive routines for operating on sockets and socket buffers |
*/ |
|
/* strings for sleep message: */ |
char netio[] = "netio"; |
char netcon[] = "netcon"; |
char netcls[] = "netcls"; |
|
u_long sb_max = SB_MAX; /* patchable */ |
|
/* |
* Procedures to manipulate state flags of socket |
* and do appropriate wakeups. Normal sequence from the |
* active (originating) side is that soisconnecting() is |
* called during processing of connect() call, |
* resulting in an eventual call to soisconnected() if/when the |
* connection is established. When the connection is torn down |
* soisdisconnecting() is called during processing of disconnect() call, |
* and soisdisconnected() is called when the connection to the peer |
* is totally severed. The semantics of these routines are such that |
* connectionless protocols can call soisconnected() and soisdisconnected() |
* only, bypassing the in-progress calls when setting up a ``connection'' |
* takes no time. |
* |
* From the passive side, a socket is created with |
* two queues of sockets: so_q0 for connections in progress |
* and so_q for connections already made and awaiting user acceptance. |
* As a protocol is preparing incoming connections, it creates a socket |
* structure queued on so_q0 by calling sonewconn(). When the connection |
* is established, soisconnected() is called, and transfers the |
* socket structure to so_q, making it available to accept(). |
* |
* If a socket is closed with sockets on either |
* so_q0 or so_q, these sockets are dropped. |
* |
* If higher level protocols are implemented in |
* the kernel, the wakeups done here will sometimes |
* cause software-interrupt process scheduling. |
*/ |
|
void |
soisconnecting(so) |
register struct socket *so; |
{ |
|
so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING); |
so->so_state |= SS_ISCONNECTING; |
} |
|
void |
soisconnected(so) |
register struct socket *so; |
{ |
register struct socket *head = so->so_head; |
|
so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING); |
so->so_state |= SS_ISCONNECTED; |
if (head && soqremque(so, 0)) { |
soqinsque(head, so, 1); |
sorwakeup(head); |
wakeup((caddr_t)&head->so_timeo); |
} else { |
wakeup((caddr_t)&so->so_timeo); |
sorwakeup(so); |
sowwakeup(so); |
} |
} |
|
void |
soisdisconnecting(so) |
register struct socket *so; |
{ |
|
so->so_state &= ~SS_ISCONNECTING; |
so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE); |
wakeup((caddr_t)&so->so_timeo); |
sowwakeup(so); |
sorwakeup(so); |
} |
|
void |
soisdisconnected(so) |
register struct socket *so; |
{ |
|
so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); |
so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED); |
wakeup((caddr_t)&so->so_timeo); |
sowwakeup(so); |
sorwakeup(so); |
} |
|
/* |
* When an attempt at a new connection is noted on a socket |
* which accepts connections, sonewconn is called. If the |
* connection is possible (subject to space constraints, etc.) |
* then we allocate a new structure, propoerly linked into the |
* data structure of the original socket, and return this. |
* Connstatus may be 0, or SO_ISCONFIRMING, or SO_ISCONNECTED. |
* |
* Currently, sonewconn() is defined as sonewconn1() in socketvar.h |
* to catch calls that are missing the (new) second parameter. |
*/ |
struct socket * |
sonewconn1(head, connstatus) |
register struct socket *head; |
int connstatus; |
{ |
register struct socket *so; |
int soqueue = connstatus ? 1 : 0; |
|
if (head->so_qlen + head->so_q0len > head->so_qlimit * 3) |
return ((struct socket *)0); |
MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_DONTWAIT); |
if (so == NULL) |
return ((struct socket *)0); |
bzero((caddr_t)so, sizeof(*so)); |
so->so_type = head->so_type; |
so->so_options = head->so_options &~ SO_ACCEPTCONN; |
so->so_linger = head->so_linger; |
so->so_state = head->so_state | SS_NOFDREF; |
so->so_proto = head->so_proto; |
so->so_timeo = head->so_timeo; |
so->so_pgid = head->so_pgid; |
so->so_euid = head->so_euid; |
so->so_ruid = head->so_ruid; |
(void) soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat); |
soqinsque(head, so, soqueue); |
if ((*so->so_proto->pr_usrreq)(so, PRU_ATTACH, |
(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)) { |
(void) soqremque(so, soqueue); |
(void) free((caddr_t)so, M_SOCKET); |
return ((struct socket *)0); |
} |
if (connstatus) { |
sorwakeup(head); |
wakeup((caddr_t)&head->so_timeo); |
so->so_state |= connstatus; |
} |
return (so); |
} |
|
void |
soqinsque(head, so, q) |
register struct socket *head, *so; |
int q; |
{ |
|
register struct socket **prev; |
so->so_head = head; |
if (q == 0) { |
head->so_q0len++; |
so->so_q0 = 0; |
for (prev = &(head->so_q0); *prev; ) |
prev = &((*prev)->so_q0); |
} else { |
head->so_qlen++; |
so->so_q = 0; |
for (prev = &(head->so_q); *prev; ) |
prev = &((*prev)->so_q); |
} |
*prev = so; |
} |
|
int |
soqremque(so, q) |
register struct socket *so; |
int q; |
{ |
register struct socket *head, *prev, *next; |
|
head = so->so_head; |
prev = head; |
for (;;) { |
next = q ? prev->so_q : prev->so_q0; |
if (next == so) |
break; |
if (next == 0) |
return (0); |
prev = next; |
} |
if (q == 0) { |
prev->so_q0 = next->so_q0; |
head->so_q0len--; |
} else { |
prev->so_q = next->so_q; |
head->so_qlen--; |
} |
next->so_q0 = next->so_q = 0; |
next->so_head = 0; |
return (1); |
} |
|
/* |
* Socantsendmore indicates that no more data will be sent on the |
* socket; it would normally be applied to a socket when the user |
* informs the system that no more data is to be sent, by the protocol |
* code (in case PRU_SHUTDOWN). Socantrcvmore indicates that no more data |
* will be received, and will normally be applied to the socket by a |
* protocol when it detects that the peer will send no more data. |
* Data queued for reading in the socket may yet be read. |
*/ |
|
void |
socantsendmore(so) |
struct socket *so; |
{ |
|
so->so_state |= SS_CANTSENDMORE; |
sowwakeup(so); |
} |
|
void |
socantrcvmore(so) |
struct socket *so; |
{ |
|
so->so_state |= SS_CANTRCVMORE; |
sorwakeup(so); |
} |
|
/* |
* Wait for data to arrive at/drain from a socket buffer. |
*/ |
int |
sbwait(sb) |
struct sockbuf *sb; |
{ |
|
sb->sb_flags |= SB_WAIT; |
return (tsleep((caddr_t)&sb->sb_cc, |
(sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH, netio, |
sb->sb_timeo)); |
} |
|
/* |
* Lock a sockbuf already known to be locked; |
* return any error returned from sleep (EINTR). |
*/ |
int |
sb_lock(sb) |
register struct sockbuf *sb; |
{ |
int error; |
|
while (sb->sb_flags & SB_LOCK) { |
sb->sb_flags |= SB_WANT; |
error = tsleep((caddr_t)&sb->sb_flags, |
(sb->sb_flags & SB_NOINTR) ? |
PSOCK : PSOCK|PCATCH, netio, 0); |
if (error) |
return (error); |
} |
sb->sb_flags |= SB_LOCK; |
return (0); |
} |
|
#ifdef __ECOS |
/* |
* Set lock on sockbuf sb; sleep if lock is already held. |
* Unless SB_NOINTR is set on sockbuf, sleep is interruptible. |
* Returns error without lock if sleep is interrupted. |
*/ |
int |
sblock(struct sockbuf *sb, int wf) |
{ |
int res; |
cyg_scheduler_safe_lock(); |
if (sb->sb_flags & SB_LOCK) { |
// Already locked by another thread |
if (wf == M_WAITOK) { |
res = sb_lock(sb); |
// Note: scheduler unlocked by 'sb_lock()' |
} else { |
res = EWOULDBLOCK; |
cyg_scheduler_unlock(); |
} |
} else { |
sb->sb_flags |= SB_LOCK; |
res = 0; |
cyg_scheduler_unlock(); |
} |
return res; |
} |
|
/* release lock on sockbuf sb */ |
void |
sbunlock(struct sockbuf *sb) |
{ |
cyg_scheduler_lock(); |
sb->sb_flags &= ~SB_LOCK; |
if (sb->sb_flags & SB_WANT) { |
sb->sb_flags &= ~SB_WANT; |
wakeup((caddr_t)&sb->sb_flags); |
} |
cyg_scheduler_unlock(); |
} |
#endif |
|
/* |
* Wakeup processes waiting on a socket buffer. |
* Do asynchronous notification via SIGIO |
* if the socket has the SS_ASYNC flag set. |
*/ |
void |
sowakeup(so, sb) |
register struct socket *so; |
register struct sockbuf *sb; |
{ |
selwakeup(&sb->sb_sel); |
sb->sb_flags &= ~SB_SEL; |
if (sb->sb_flags & SB_WAIT) { |
sb->sb_flags &= ~SB_WAIT; |
wakeup((caddr_t)&sb->sb_cc); |
} |
#ifndef __ECOS |
if (so->so_state & SS_ASYNC) |
csignal(so->so_pgid, SIGIO, so->so_siguid, so->so_sigeuid); |
#endif |
} |
|
/* |
* Socket buffer (struct sockbuf) utility routines. |
* |
* Each socket contains two socket buffers: one for sending data and |
* one for receiving data. Each buffer contains a queue of mbufs, |
* information about the number of mbufs and amount of data in the |
* queue, and other fields allowing select() statements and notification |
* on data availability to be implemented. |
* |
* Data stored in a socket buffer is maintained as a list of records. |
* Each record is a list of mbufs chained together with the m_next |
* field. Records are chained together with the m_nextpkt field. The upper |
* level routine soreceive() expects the following conventions to be |
* observed when placing information in the receive buffer: |
* |
* 1. If the protocol requires each message be preceded by the sender's |
* name, then a record containing that name must be present before |
* any associated data (mbuf's must be of type MT_SONAME). |
* 2. If the protocol supports the exchange of ``access rights'' (really |
* just additional data associated with the message), and there are |
* ``rights'' to be received, then a record containing this data |
* should be present (mbuf's must be of type MT_CONTROL). |
* 3. If a name or rights record exists, then it must be followed by |
* a data record, perhaps of zero length. |
* |
* Before using a new socket structure it is first necessary to reserve |
* buffer space to the socket, by calling sbreserve(). This should commit |
* some of the available buffer space in the system buffer pool for the |
* socket (currently, it does nothing but enforce limits). The space |
* should be released by calling sbrelease() when the socket is destroyed. |
*/ |
|
int |
soreserve(so, sndcc, rcvcc) |
register struct socket *so; |
u_long sndcc, rcvcc; |
{ |
|
if (sbreserve(&so->so_snd, sndcc) == 0) |
goto bad; |
if (sbreserve(&so->so_rcv, rcvcc) == 0) |
goto bad2; |
if (so->so_rcv.sb_lowat == 0) |
so->so_rcv.sb_lowat = 1; |
if (so->so_snd.sb_lowat == 0) |
so->so_snd.sb_lowat = MCLBYTES; |
if (so->so_snd.sb_lowat > so->so_snd.sb_hiwat) |
so->so_snd.sb_lowat = so->so_snd.sb_hiwat; |
return (0); |
bad2: |
sbrelease(&so->so_snd); |
bad: |
return (ENOBUFS); |
} |
|
/* |
* Allot mbufs to a sockbuf. |
* Attempt to scale mbmax so that mbcnt doesn't become limiting |
* if buffering efficiency is near the normal case. |
*/ |
int |
sbreserve(sb, cc) |
struct sockbuf *sb; |
u_long cc; |
{ |
|
if (cc == 0 || cc > sb_max * MCLBYTES / (MSIZE + MCLBYTES)) |
return (0); |
sb->sb_hiwat = cc; |
sb->sb_mbmax = min(cc * 2, sb_max); |
if (sb->sb_lowat > sb->sb_hiwat) |
sb->sb_lowat = sb->sb_hiwat; |
return (1); |
} |
|
/* |
* Free mbufs held by a socket, and reserved mbuf space. |
*/ |
void |
sbrelease(sb) |
struct sockbuf *sb; |
{ |
|
sbflush(sb); |
sb->sb_hiwat = sb->sb_mbmax = 0; |
} |
|
/* |
* Routines to add and remove |
* data from an mbuf queue. |
* |
* The routines sbappend() or sbappendrecord() are normally called to |
* append new mbufs to a socket buffer, after checking that adequate |
* space is available, comparing the function sbspace() with the amount |
* of data to be added. sbappendrecord() differs from sbappend() in |
* that data supplied is treated as the beginning of a new record. |
* To place a sender's address, optional access rights, and data in a |
* socket receive buffer, sbappendaddr() should be used. To place |
* access rights and data in a socket receive buffer, sbappendrights() |
* should be used. In either case, the new data begins a new record. |
* Note that unlike sbappend() and sbappendrecord(), these routines check |
* for the caller that there will be enough space to store the data. |
* Each fails if there is not enough space, or if it cannot find mbufs |
* to store additional information in. |
* |
* Reliable protocols may use the socket send buffer to hold data |
* awaiting acknowledgement. Data is normally copied from a socket |
* send buffer in a protocol with m_copy for output to a peer, |
* and then removing the data from the socket buffer with sbdrop() |
* or sbdroprecord() when the data is acknowledged by the peer. |
*/ |
|
/* |
* Append mbuf chain m to the last record in the |
* socket buffer sb. The additional space associated |
* the mbuf chain is recorded in sb. Empty mbufs are |
* discarded and mbufs are compacted where possible. |
*/ |
void |
sbappend(sb, m) |
struct sockbuf *sb; |
struct mbuf *m; |
{ |
register struct mbuf *n; |
|
if (m == 0) |
return; |
if ((n = sb->sb_mb) != NULL) { |
while (n->m_nextpkt) |
n = n->m_nextpkt; |
do { |
if (n->m_flags & M_EOR) { |
sbappendrecord(sb, m); /* XXXXXX!!!! */ |
return; |
} |
} while (n->m_next && (n = n->m_next)); |
} |
sbcompress(sb, m, n); |
} |
|
#ifdef SOCKBUF_DEBUG |
void |
sbcheck(sb) |
register struct sockbuf *sb; |
{ |
register struct mbuf *m; |
register int len = 0, mbcnt = 0; |
|
for (m = sb->sb_mb; m; m = m->m_next) { |
len += m->m_len; |
mbcnt += MSIZE; |
if (m->m_flags & M_EXT) |
mbcnt += m->m_ext.ext_size; |
if (m->m_nextpkt) |
panic("sbcheck nextpkt"); |
} |
if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { |
printf("cc %d != %d || mbcnt %d != %d\n", len, sb->sb_cc, |
mbcnt, sb->sb_mbcnt); |
panic("sbcheck"); |
} |
} |
#endif |
|
/* |
* As above, except the mbuf chain |
* begins a new record. |
*/ |
void |
sbappendrecord(sb, m0) |
register struct sockbuf *sb; |
register struct mbuf *m0; |
{ |
register struct mbuf *m; |
|
if (m0 == 0) |
return; |
if ((m = sb->sb_mb) != NULL) |
while (m->m_nextpkt) |
m = m->m_nextpkt; |
/* |
* Put the first mbuf on the queue. |
* Note this permits zero length records. |
*/ |
sballoc(sb, m0); |
if (m) |
m->m_nextpkt = m0; |
else |
sb->sb_mb = m0; |
m = m0->m_next; |
m0->m_next = 0; |
if (m && (m0->m_flags & M_EOR)) { |
m0->m_flags &= ~M_EOR; |
m->m_flags |= M_EOR; |
} |
sbcompress(sb, m, m0); |
} |
|
/* |
* As above except that OOB data |
* is inserted at the beginning of the sockbuf, |
* but after any other OOB data. |
*/ |
void |
sbinsertoob(sb, m0) |
register struct sockbuf *sb; |
register struct mbuf *m0; |
{ |
register struct mbuf *m; |
register struct mbuf **mp; |
|
if (m0 == 0) |
return; |
for (mp = &sb->sb_mb; (m = *mp) != NULL; mp = &((*mp)->m_nextpkt)) { |
again: |
switch (m->m_type) { |
|
case MT_OOBDATA: |
continue; /* WANT next train */ |
|
case MT_CONTROL: |
if ((m = m->m_next) != NULL) |
goto again; /* inspect THIS train further */ |
} |
break; |
} |
/* |
* Put the first mbuf on the queue. |
* Note this permits zero length records. |
*/ |
sballoc(sb, m0); |
m0->m_nextpkt = *mp; |
*mp = m0; |
m = m0->m_next; |
m0->m_next = 0; |
if (m && (m0->m_flags & M_EOR)) { |
m0->m_flags &= ~M_EOR; |
m->m_flags |= M_EOR; |
} |
sbcompress(sb, m, m0); |
} |
|
/* |
* Append address and data, and optionally, control (ancillary) data |
* to the receive queue of a socket. If present, |
* m0 must include a packet header with total length. |
* Returns 0 if no space in sockbuf or insufficient mbufs. |
*/ |
int |
sbappendaddr(sb, asa, m0, control) |
register struct sockbuf *sb; |
struct sockaddr *asa; |
struct mbuf *m0, *control; |
{ |
register struct mbuf *m, *n; |
int space = asa->sa_len; |
|
if (m0 && (m0->m_flags & M_PKTHDR) == 0) |
panic("sbappendaddr"); |
if (m0) |
space += m0->m_pkthdr.len; |
for (n = control; n; n = n->m_next) { |
space += n->m_len; |
if (n->m_next == 0) /* keep pointer to last control buf */ |
break; |
} |
if (space > sbspace(sb)) |
return (0); |
if (asa->sa_len > MLEN) |
return (0); |
MGET(m, M_DONTWAIT, MT_SONAME); |
if (m == 0) |
return (0); |
m->m_len = asa->sa_len; |
bcopy((caddr_t)asa, mtod(m, caddr_t), asa->sa_len); |
if (n) |
n->m_next = m0; /* concatenate data to control */ |
else |
control = m0; |
m->m_next = control; |
for (n = m; n; n = n->m_next) |
sballoc(sb, n); |
if ((n = sb->sb_mb) != NULL) { |
while (n->m_nextpkt) |
n = n->m_nextpkt; |
n->m_nextpkt = m; |
} else |
sb->sb_mb = m; |
return (1); |
} |
|
int |
sbappendcontrol(sb, m0, control) |
struct sockbuf *sb; |
struct mbuf *m0, *control; |
{ |
register struct mbuf *m, *n; |
int space = 0; |
|
if (control == 0) |
panic("sbappendcontrol"); |
for (m = control; ; m = m->m_next) { |
space += m->m_len; |
if (m->m_next == 0) |
break; |
} |
n = m; /* save pointer to last control buffer */ |
for (m = m0; m; m = m->m_next) |
space += m->m_len; |
if (space > sbspace(sb)) |
return (0); |
n->m_next = m0; /* concatenate data to control */ |
for (m = control; m; m = m->m_next) |
sballoc(sb, m); |
if ((n = sb->sb_mb) != NULL) { |
while (n->m_nextpkt) |
n = n->m_nextpkt; |
n->m_nextpkt = control; |
} else |
sb->sb_mb = control; |
return (1); |
} |
|
/* |
* Compress mbuf chain m into the socket |
* buffer sb following mbuf n. If n |
* is null, the buffer is presumed empty. |
*/ |
void |
sbcompress(sb, m, n) |
register struct sockbuf *sb; |
register struct mbuf *m, *n; |
{ |
register int eor = 0; |
register struct mbuf *o; |
|
while (m) { |
eor |= m->m_flags & M_EOR; |
if (m->m_len == 0 && |
(eor == 0 || |
(((o = m->m_next) || (o = n)) && |
o->m_type == m->m_type))) { |
m = m_free(m); |
continue; |
} |
if (n && (n->m_flags & (M_EXT | M_EOR)) == 0 && |
(n->m_data + n->m_len + m->m_len) < &n->m_dat[MLEN] && |
n->m_type == m->m_type) { |
bcopy(mtod(m, caddr_t), mtod(n, caddr_t) + n->m_len, |
(unsigned)m->m_len); |
n->m_len += m->m_len; |
sb->sb_cc += m->m_len; |
m = m_free(m); |
continue; |
} |
if (n) |
n->m_next = m; |
else |
sb->sb_mb = m; |
sballoc(sb, m); |
n = m; |
m->m_flags &= ~M_EOR; |
m = m->m_next; |
n->m_next = 0; |
} |
if (eor) { |
if (n) |
n->m_flags |= eor; |
else |
#ifdef __ECOS |
diag_printf("semi-panic: sbcompress\n"); |
#else |
printf("semi-panic: sbcompress\n"); |
#endif |
} |
} |
|
/* |
* Free all mbufs in a sockbuf. |
* Check that all resources are reclaimed. |
*/ |
void |
sbflush(sb) |
register struct sockbuf *sb; |
{ |
|
if (sb->sb_flags & SB_LOCK) |
panic("sbflush"); |
while (sb->sb_mbcnt) |
sbdrop(sb, (int)sb->sb_cc); |
if (sb->sb_cc || sb->sb_mb) |
panic("sbflush 2"); |
} |
|
/* |
* Drop data from (the front of) a sockbuf. |
*/ |
void |
sbdrop(sb, len) |
register struct sockbuf *sb; |
register int len; |
{ |
register struct mbuf *m, *mn; |
struct mbuf *next; |
|
next = (m = sb->sb_mb) ? m->m_nextpkt : 0; |
while (len > 0) { |
if (m == 0) { |
if (next == 0) |
panic("sbdrop"); |
m = next; |
next = m->m_nextpkt; |
continue; |
} |
if (m->m_len > len) { |
m->m_len -= len; |
m->m_data += len; |
sb->sb_cc -= len; |
break; |
} |
len -= m->m_len; |
sbfree(sb, m); |
MFREE(m, mn); |
m = mn; |
} |
while (m && m->m_len == 0) { |
sbfree(sb, m); |
MFREE(m, mn); |
m = mn; |
} |
if (m) { |
sb->sb_mb = m; |
m->m_nextpkt = next; |
} else |
sb->sb_mb = next; |
} |
|
/* |
* Drop a record off the front of a sockbuf |
* and move the next record to the front. |
*/ |
void |
sbdroprecord(sb) |
register struct sockbuf *sb; |
{ |
register struct mbuf *m, *mn; |
|
m = sb->sb_mb; |
if (m) { |
sb->sb_mb = m->m_nextpkt; |
do { |
sbfree(sb, m); |
MFREE(m, mn); |
} while ((m = mn) != NULL); |
} |
} |
|
/* |
* Create a "control" mbuf containing the specified data |
* with the specified type for presentation on a socket buffer. |
*/ |
struct mbuf * |
sbcreatecontrol(p, size, type, level) |
caddr_t p; |
register int size; |
int type, level; |
{ |
register struct cmsghdr *cp; |
struct mbuf *m; |
|
if (size + sizeof(*cp) > MCLBYTES) { |
#ifdef __ECOS |
diag_printf("sbcreatecontrol: message too large %d\n", size); |
#else |
printf("sbcreatecontrol: message too large %d\n", size); |
#endif |
return NULL; |
} |
|
if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) |
return ((struct mbuf *) NULL); |
if (size + sizeof(*cp) > MLEN) { |
MCLGET(m, M_DONTWAIT); |
if ((m->m_flags & M_EXT) == 0) { |
m_free(m); |
return NULL; |
} |
} |
cp = mtod(m, struct cmsghdr *); |
bcopy(p, CMSG_DATA(cp), size); |
size += sizeof(*cp); |
m->m_len = size; |
cp->cmsg_len = size; |
cp->cmsg_level = level; |
cp->cmsg_type = type; |
return (m); |
} |
/uipc_syscalls.c
0,0 → 1,1272
//========================================================================== |
// |
// sys/kern/uipc_syscalls.c |
// |
// |
// |
//========================================================================== |
//####BSDCOPYRIGHTBEGIN#### |
// |
// ------------------------------------------- |
// |
// Portions of this software may have been derived from OpenBSD or other sources, |
// and are covered by the appropriate copyright disclaimers included herein. |
// |
// ------------------------------------------- |
// |
//####BSDCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): gthomas |
// Contributors: gthomas |
// Date: 2000-01-10 |
// Purpose: |
// Description: |
// |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
|
/* $OpenBSD: uipc_syscalls.c,v 1.29 1999/12/08 06:50:17 itojun Exp $ */ |
/* $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $ */ |
|
/* |
* Copyright (c) 1982, 1986, 1989, 1990, 1993 |
* The Regents of the University of California. All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
* |
* @(#)uipc_syscalls.c 8.4 (Berkeley) 2/21/94 |
*/ |
|
#include <sys/param.h> |
#ifdef __ECOS |
#include <cyg/io/file.h> |
static int ecos_getsock(int fdes, struct file **fpp); |
#define getsock(fdp, fdes, fpp) ecos_getsock(fdes, fpp) |
#else |
#include <sys/systm.h> |
#include <sys/proc.h> |
#include <sys/filedesc.h> |
#include <sys/file.h> |
#include <sys/buf.h> |
#endif |
#include <sys/malloc.h> |
#include <sys/mbuf.h> |
#include <sys/protosw.h> |
#include <sys/socket.h> |
#include <sys/socketvar.h> |
#ifndef __ECOS |
#include <sys/signalvar.h> |
#include <sys/un.h> |
#endif |
#ifdef KTRACE |
#include <sys/ktrace.h> |
#endif |
|
#ifndef __ECOS |
#include <sys/mount.h> |
#endif |
#include <sys/syscallargs.h> |
|
/* |
* System call interface to the socket abstraction. |
*/ |
extern struct fileops socketops; |
|
#ifdef __ECOS |
int |
sys_socket(struct sys_socket_args *uap, register_t *retval) |
{ |
#else |
int |
sys_socket(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_socket_args /* { |
syscallarg(int) domain; |
syscallarg(int) type; |
syscallarg(int) protocol; |
} */ *uap = v; |
struct filedesc *fdp = p->p_fd; |
#endif // __ECOS |
struct socket *so; |
struct file *fp; |
int fd, error; |
|
#ifdef __ECOS |
if ((error = falloc(&fp, &fd)) != 0) |
#else |
if ((error = falloc(p, &fp, &fd)) != 0) |
#endif |
return (error); |
fp->f_flag = FREAD|FWRITE; |
fp->f_type = DTYPE_SOCKET; |
fp->f_ops = &socketops; |
error = socreate(SCARG(uap, domain), &so, SCARG(uap, type), |
SCARG(uap, protocol)); |
if (error) { |
#ifndef __ECOS |
fdremove(fdp, fd); |
#endif |
ffree(fp); |
} else { |
#ifdef __ECOS |
fp->f_data = (CYG_ADDRWORD)so; |
#else |
fp->f_data = (caddr_t)so; |
#endif |
*retval = fd; |
} |
return (error); |
} |
|
#ifdef __ECOS |
int |
sys_bind(struct sys_bind_args *uap, register_t *retval) |
{ |
#else |
/* ARGSUSED */ |
int |
sys_bind(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_bind_args /* { |
syscallarg(int) s; |
syscallarg(struct sockaddr *) name; |
syscallarg(socklen_t) namelen; |
} */ *uap = v; |
#endif // __ECOS |
struct file *fp; |
struct mbuf *nam; |
int error; |
|
if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) |
return (error); |
error = sockargs(&nam, (caddr_t)SCARG(uap, name), SCARG(uap, namelen), |
MT_SONAME); |
if (error) |
return (error); |
error = sobind((struct socket *)fp->f_data, nam); |
m_freem(nam); |
return (error); |
} |
|
/* ARGSUSED */ |
#ifdef __ECOS |
int |
sys_listen(struct sys_listen_args *uap, register_t *retval) |
{ |
#else |
int |
sys_listen(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_listen_args /* { |
syscallarg(int) s; |
syscallarg(int) backlog; |
} */ *uap = v; |
#endif // __ECOS |
struct file *fp; |
int error; |
|
if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) |
return (error); |
return (solisten((struct socket *)fp->f_data, SCARG(uap, backlog))); |
} |
|
#ifdef __ECOS |
int |
sys_accept(struct sys_accept_args *uap, register_t *retval) |
{ |
#else |
int |
sys_accept(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_accept_args /* { |
syscallarg(int) s; |
syscallarg(struct sockaddr *) name; |
syscallarg(socklen_t *) anamelen; |
} */ *uap = v; |
#endif |
struct file *fp; |
struct mbuf *nam; |
socklen_t namelen; |
int error, s, tmpfd; |
register struct socket *so; |
|
if (SCARG(uap, name) && (error = copyin((caddr_t)SCARG(uap, anamelen), |
(caddr_t)&namelen, sizeof (namelen)))) |
return (error); |
if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) |
return (error); |
s = splsoftnet(); |
so = (struct socket *)fp->f_data; |
if ((so->so_options & SO_ACCEPTCONN) == 0) { |
splx(s); |
return (EINVAL); |
} |
if ((so->so_state & SS_NBIO) && so->so_qlen == 0) { |
splx(s); |
return (EWOULDBLOCK); |
} |
while (so->so_qlen == 0 && so->so_error == 0) { |
if (so->so_state & SS_CANTRCVMORE) { |
so->so_error = ECONNABORTED; |
break; |
} |
error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH, |
netcon, 0); |
if (error) { |
splx(s); |
return (error); |
} |
} |
if (so->so_error) { |
error = so->so_error; |
so->so_error = 0; |
splx(s); |
return (error); |
} |
#ifdef __ECOS |
if ((error = falloc(&fp, &tmpfd)) != 0) { |
#else |
if ((error = falloc(p, &fp, &tmpfd)) != 0) { |
#endif |
splx(s); |
return (error); |
} |
*retval = tmpfd; |
{ struct socket *aso = so->so_q; |
if (soqremque(aso, 1) == 0) |
panic("accept"); |
so = aso; |
} |
fp->f_type = DTYPE_SOCKET; |
fp->f_flag = FREAD|FWRITE; |
fp->f_ops = &socketops; |
#ifdef __ECOS |
fp->f_data = (CYG_ADDRWORD)so; |
#else |
fp->f_data = (caddr_t)so; |
#endif |
nam = m_get(M_WAIT, MT_SONAME); |
(void) soaccept(so, nam); |
if (SCARG(uap, name)) { |
if (namelen > nam->m_len) |
namelen = nam->m_len; |
/* SHOULD COPY OUT A CHAIN HERE */ |
if ((error = copyout(mtod(nam, caddr_t), |
(caddr_t)SCARG(uap, name), namelen)) == 0) |
error = copyout((caddr_t)&namelen, |
(caddr_t)SCARG(uap, anamelen), |
sizeof (*SCARG(uap, anamelen))); |
} |
m_freem(nam); |
splx(s); |
return (error); |
} |
|
#ifdef __ECOS |
int |
sys_connect(struct sys_connect_args *uap, register_t *retval) |
{ |
#else |
/* ARGSUSED */ |
int |
sys_connect(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_connect_args /* { |
syscallarg(int) s; |
syscallarg(struct sockaddr *) name; |
syscallarg(socklen_t) namelen; |
} */ *uap = v; |
#endif // __ECOS |
struct file *fp; |
register struct socket *so; |
struct mbuf *nam; |
int error, s; |
|
if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) |
return (error); |
so = (struct socket *)fp->f_data; |
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) |
return (EALREADY); |
error = sockargs(&nam, (caddr_t)SCARG(uap, name), SCARG(uap, namelen), |
MT_SONAME); |
if (error) |
return (error); |
error = soconnect(so, nam); |
if (error) |
goto bad; |
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { |
m_freem(nam); |
return (EINPROGRESS); |
} |
s = splsoftnet(); |
while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { |
error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH, |
netcon, 0); |
if (error) |
break; |
} |
if (error == 0) { |
error = so->so_error; |
so->so_error = 0; |
} |
splx(s); |
bad: |
so->so_state &= ~SS_ISCONNECTING; |
m_freem(nam); |
#ifndef __ECOS |
if (error == ERESTART) |
error = EINTR; |
#endif |
return (error); |
} |
|
#ifndef __ECOS |
int |
sys_socketpair(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_socketpair_args /* { |
syscallarg(int) domain; |
syscallarg(int) type; |
syscallarg(int) protocol; |
syscallarg(int *) rsv; |
} */ *uap = v; |
register struct filedesc *fdp = p->p_fd; |
struct file *fp1, *fp2; |
struct socket *so1, *so2; |
int fd, error, sv[2]; |
|
error = socreate(SCARG(uap, domain), &so1, SCARG(uap, type), |
SCARG(uap, protocol)); |
if (error) |
return (error); |
error = socreate(SCARG(uap, domain), &so2, SCARG(uap, type), |
SCARG(uap, protocol)); |
if (error) |
goto free1; |
if ((error = falloc(p, &fp1, &fd)) != 0) |
goto free2; |
sv[0] = fd; |
fp1->f_flag = FREAD|FWRITE; |
fp1->f_type = DTYPE_SOCKET; |
fp1->f_ops = &socketops; |
fp1->f_data = (caddr_t)so1; |
if ((error = falloc(p, &fp2, &fd)) != 0) |
goto free3; |
fp2->f_flag = FREAD|FWRITE; |
fp2->f_type = DTYPE_SOCKET; |
fp2->f_ops = &socketops; |
fp2->f_data = (caddr_t)so2; |
sv[1] = fd; |
if ((error = soconnect2(so1, so2)) != 0) |
goto free4; |
if (SCARG(uap, type) == SOCK_DGRAM) { |
/* |
* Datagram socket connection is asymmetric. |
*/ |
if ((error = soconnect2(so2, so1)) != 0) |
goto free4; |
} |
error = copyout((caddr_t)sv, (caddr_t)SCARG(uap, rsv), |
2 * sizeof (int)); |
if (error == 0) |
return (error); |
free4: |
ffree(fp2); |
fdremove(fdp, sv[1]); |
free3: |
ffree(fp1); |
fdremove(fdp, sv[0]); |
free2: |
(void)soclose(so2); |
free1: |
(void)soclose(so1); |
return (error); |
} |
#endif |
|
#ifdef __ECOS |
int |
sys_sendto(struct sys_sendto_args *uap, register_t *retval) |
{ |
#else |
int |
sys_sendto(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_sendto_args /* { |
syscallarg(int) s; |
syscallarg(caddr_t) buf; |
syscallarg(size_t) len; |
syscallarg(int) flags; |
syscallarg(struct sockaddr *) to; |
syscallarg(socklen_t) tolen; |
} */ *uap = v; |
#endif // __ECOS |
struct msghdr msg; |
struct iovec aiov; |
|
msg.msg_name = (caddr_t)SCARG(uap, to); |
msg.msg_namelen = SCARG(uap, tolen); |
msg.msg_iov = &aiov; |
msg.msg_iovlen = 1; |
msg.msg_control = 0; |
#ifdef COMPAT_OLDSOCK |
msg.msg_flags = 0; |
#endif |
aiov.iov_base = (char *)SCARG(uap, buf); |
aiov.iov_len = SCARG(uap, len); |
#ifdef __ECOS |
return (sendit(SCARG(uap, s), &msg, SCARG(uap, flags), retval)); |
#else |
return (sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval)); |
#endif |
} |
|
#ifndef __ECOS |
int |
sys_sendmsg(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_sendmsg_args /* { |
syscallarg(int) s; |
syscallarg(caddr_t) msg; |
syscallarg(int) flags; |
} */ *uap = v; |
struct msghdr msg; |
struct iovec aiov[UIO_SMALLIOV], *iov; |
int error; |
|
error = copyin(SCARG(uap, msg), (caddr_t)&msg, sizeof (msg)); |
if (error) |
return (error); |
if (msg.msg_iovlen <= 0 || msg.msg_iovlen > IOV_MAX) |
return (EMSGSIZE); |
if (msg.msg_iovlen > UIO_SMALLIOV) |
MALLOC(iov, struct iovec *, |
sizeof(struct iovec) * msg.msg_iovlen, M_IOV, M_WAITOK); |
else |
iov = aiov; |
if (msg.msg_iovlen && |
(error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov, |
(unsigned)(msg.msg_iovlen * sizeof (struct iovec))))) |
goto done; |
msg.msg_iov = iov; |
#ifdef COMPAT_OLDSOCK |
msg.msg_flags = 0; |
#endif |
error = sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval); |
done: |
if (iov != aiov) |
FREE(iov, M_IOV); |
return (error); |
} |
#endif |
|
#ifdef __ECOS |
int |
sendit(int s, struct msghdr *mp, int flags, register_t *retsize) |
{ |
#else |
int |
sendit(p, s, mp, flags, retsize) |
register struct proc *p; |
int s; |
register struct msghdr *mp; |
int flags; |
register_t *retsize; |
{ |
#endif // __ECOS |
struct file *fp; |
struct uio auio; |
register struct iovec *iov; |
register int i; |
struct mbuf *to, *control; |
int len, error; |
#ifdef KTRACE |
struct iovec *ktriov = NULL; |
#endif |
|
if ((error = getsock(p->p_fd, s, &fp)) != 0) |
return (error); |
auio.uio_iov = mp->msg_iov; |
auio.uio_iovcnt = mp->msg_iovlen; |
auio.uio_segflg = UIO_USERSPACE; |
auio.uio_rw = UIO_WRITE; |
#ifndef __ECOS |
auio.uio_procp = p; |
#endif |
auio.uio_offset = 0; /* XXX */ |
auio.uio_resid = 0; |
iov = mp->msg_iov; |
for (i = 0; i < mp->msg_iovlen; i++, iov++) { |
/* Don't allow sum > SSIZE_MAX */ |
if (iov->iov_len > SSIZE_MAX || |
(auio.uio_resid += iov->iov_len) > SSIZE_MAX) |
return (EINVAL); |
} |
if (mp->msg_name) { |
error = sockargs(&to, mp->msg_name, mp->msg_namelen, |
MT_SONAME); |
if (error) |
return (error); |
} else |
to = 0; |
if (mp->msg_control) { |
if (mp->msg_controllen < sizeof(struct cmsghdr) |
#ifdef COMPAT_OLDSOCK |
&& mp->msg_flags != MSG_COMPAT |
#endif |
) { |
error = EINVAL; |
goto bad; |
} |
error = sockargs(&control, mp->msg_control, |
mp->msg_controllen, MT_CONTROL); |
if (error) |
goto bad; |
#ifdef COMPAT_OLDSOCK |
if (mp->msg_flags == MSG_COMPAT) { |
register struct cmsghdr *cm; |
|
M_PREPEND(control, sizeof(*cm), M_WAIT); |
if (control == 0) { |
error = ENOBUFS; |
goto bad; |
} else { |
cm = mtod(control, struct cmsghdr *); |
cm->cmsg_len = control->m_len; |
cm->cmsg_level = SOL_SOCKET; |
cm->cmsg_type = SCM_RIGHTS; |
} |
} |
#endif |
} else |
control = 0; |
#ifdef KTRACE |
if (KTRPOINT(p, KTR_GENIO)) { |
int iovlen = auio.uio_iovcnt * sizeof (struct iovec); |
|
MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); |
bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); |
} |
#endif |
len = auio.uio_resid; |
error = sosend((struct socket *)fp->f_data, to, &auio, |
NULL, control, flags); |
if (error) { |
#ifdef __ECOS |
if (auio.uio_resid != len && |
(error == EINTR || error == EWOULDBLOCK)) |
#else |
if (auio.uio_resid != len && (error == ERESTART || |
error == EINTR || error == EWOULDBLOCK)) |
#endif |
error = 0; |
#ifndef __ECOS |
if (error == EPIPE) |
psignal(p, SIGPIPE); |
#endif |
} |
if (error == 0) |
*retsize = len - auio.uio_resid; |
#ifdef KTRACE |
if (ktriov != NULL) { |
if (error == 0) |
ktrgenio(p->p_tracep, s, UIO_WRITE, |
ktriov, *retsize, error); |
FREE(ktriov, M_TEMP); |
} |
#endif |
bad: |
if (to) |
m_freem(to); |
return (error); |
} |
|
#ifdef __ECOS |
int |
sys_recvfrom(struct sys_recvfrom_args *uap, register_t *retval) |
{ |
#else |
int |
sys_recvfrom(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_recvfrom_args /* { |
syscallarg(int) s; |
syscallarg(caddr_t) buf; |
syscallarg(size_t) len; |
syscallarg(int) flags; |
syscallarg(struct sockaddr *) from; |
syscallarg(socklen_t *) fromlenaddr; |
} */ *uap = v; |
#endif // __ECOS |
struct msghdr msg; |
struct iovec aiov; |
int error; |
|
if (SCARG(uap, fromlenaddr)) { |
error = copyin((caddr_t)SCARG(uap, fromlenaddr), |
(caddr_t)&msg.msg_namelen, |
sizeof (msg.msg_namelen)); |
if (error) |
return (error); |
} else |
msg.msg_namelen = 0; |
msg.msg_name = (caddr_t)SCARG(uap, from); |
msg.msg_iov = &aiov; |
msg.msg_iovlen = 1; |
aiov.iov_base = SCARG(uap, buf); |
aiov.iov_len = SCARG(uap, len); |
msg.msg_control = 0; |
msg.msg_flags = SCARG(uap, flags); |
#ifdef __ECOS |
return (recvit(SCARG(uap, s), &msg, |
(caddr_t)SCARG(uap, fromlenaddr), retval)); |
#else |
return (recvit(p, SCARG(uap, s), &msg, |
(caddr_t)SCARG(uap, fromlenaddr), retval)); |
#endif |
} |
|
#ifndef __ECOS |
int |
sys_recvmsg(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_recvmsg_args /* { |
syscallarg(int) s; |
syscallarg(struct msghdr *) msg; |
syscallarg(int) flags; |
} */ *uap = v; |
struct msghdr msg; |
struct iovec aiov[UIO_SMALLIOV], *uiov, *iov; |
register int error; |
|
error = copyin((caddr_t)SCARG(uap, msg), (caddr_t)&msg, |
sizeof (msg)); |
if (error) |
return (error); |
if (msg.msg_iovlen <= 0 || msg.msg_iovlen > IOV_MAX) |
return (EMSGSIZE); |
if (msg.msg_iovlen > UIO_SMALLIOV) |
MALLOC(iov, struct iovec *, |
sizeof(struct iovec) * msg.msg_iovlen, M_IOV, M_WAITOK); |
else |
iov = aiov; |
#ifdef COMPAT_OLDSOCK |
msg.msg_flags = SCARG(uap, flags) &~ MSG_COMPAT; |
#else |
msg.msg_flags = SCARG(uap, flags); |
#endif |
uiov = msg.msg_iov; |
msg.msg_iov = iov; |
error = copyin((caddr_t)uiov, (caddr_t)iov, |
(unsigned)(msg.msg_iovlen * sizeof (struct iovec))); |
if (error) |
goto done; |
if ((error = recvit(p, SCARG(uap, s), &msg, (caddr_t)0, retval)) == 0) { |
msg.msg_iov = uiov; |
error = copyout((caddr_t)&msg, (caddr_t)SCARG(uap, msg), |
sizeof(msg)); |
} |
done: |
if (iov != aiov) |
FREE(iov, M_IOV); |
return (error); |
} |
#endif |
|
#ifdef __ECOS |
int |
recvit(int s, struct msghdr *mp, caddr_t namelenp, register_t *retsize) |
{ |
#else |
int |
recvit(p, s, mp, namelenp, retsize) |
register struct proc *p; |
int s; |
register struct msghdr *mp; |
caddr_t namelenp; |
register_t *retsize; |
{ |
#endif // __ECOS |
struct file *fp; |
struct uio auio; |
register struct iovec *iov; |
register int i; |
size_t len; |
int error; |
struct mbuf *from = 0, *control = 0; |
#ifdef KTRACE |
struct iovec *ktriov = NULL; |
#endif |
|
if ((error = getsock(p->p_fd, s, &fp)) != 0) |
return (error); |
auio.uio_iov = mp->msg_iov; |
auio.uio_iovcnt = mp->msg_iovlen; |
auio.uio_segflg = UIO_USERSPACE; |
auio.uio_rw = UIO_READ; |
#ifndef __ECOS |
auio.uio_procp = p; |
#endif |
auio.uio_offset = 0; /* XXX */ |
auio.uio_resid = 0; |
iov = mp->msg_iov; |
for (i = 0; i < mp->msg_iovlen; i++, iov++) { |
/* Don't allow sum > SSIZE_MAX */ |
if (iov->iov_len > SSIZE_MAX || |
(auio.uio_resid += iov->iov_len) > SSIZE_MAX) |
return (EINVAL); |
} |
#ifdef KTRACE |
if (KTRPOINT(p, KTR_GENIO)) { |
int iovlen = auio.uio_iovcnt * sizeof (struct iovec); |
|
MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); |
bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); |
} |
#endif |
len = auio.uio_resid; |
error = soreceive((struct socket *)fp->f_data, &from, &auio, |
NULL, mp->msg_control ? &control : NULL, |
&mp->msg_flags); |
if (error) { |
#ifdef __ECOS |
if (auio.uio_resid != len && |
(error == EINTR || error == EWOULDBLOCK)) |
#else |
if (auio.uio_resid != len && (error == ERESTART || |
error == EINTR || error == EWOULDBLOCK)) |
#endif |
error = 0; |
} |
#ifdef KTRACE |
if (ktriov != NULL) { |
if (error == 0) |
ktrgenio(p->p_tracep, s, UIO_READ, |
ktriov, len - auio.uio_resid, error); |
FREE(ktriov, M_TEMP); |
} |
#endif |
if (error) |
goto out; |
*retsize = len - auio.uio_resid; |
if (mp->msg_name) { |
len = mp->msg_namelen; |
if (len <= 0 || from == 0) |
len = 0; |
else { |
/* save sa_len before it is destroyed by MSG_COMPAT */ |
if (len > from->m_len) |
len = from->m_len; |
/* else if len < from->m_len ??? */ |
#ifdef COMPAT_OLDSOCK |
if (mp->msg_flags & MSG_COMPAT) |
mtod(from, struct osockaddr *)->sa_family = |
mtod(from, struct sockaddr *)->sa_family; |
#endif |
error = copyout(mtod(from, caddr_t), |
(caddr_t)mp->msg_name, (unsigned)len); |
if (error) |
goto out; |
} |
mp->msg_namelen = len; |
if (namelenp && |
(error = copyout((caddr_t)&len, namelenp, sizeof (int)))) { |
#ifdef COMPAT_OLDSOCK |
if (mp->msg_flags & MSG_COMPAT) |
error = 0; /* old recvfrom didn't check */ |
else |
#endif |
goto out; |
} |
} |
if (mp->msg_control) { |
#ifdef COMPAT_OLDSOCK |
/* |
* We assume that old recvmsg calls won't receive access |
* rights and other control info, esp. as control info |
* is always optional and those options didn't exist in 4.3. |
* If we receive rights, trim the cmsghdr; anything else |
* is tossed. |
*/ |
if (control && mp->msg_flags & MSG_COMPAT) { |
if (mtod(control, struct cmsghdr *)->cmsg_level != |
SOL_SOCKET || |
mtod(control, struct cmsghdr *)->cmsg_type != |
SCM_RIGHTS) { |
mp->msg_controllen = 0; |
goto out; |
} |
control->m_len -= sizeof (struct cmsghdr); |
control->m_data += sizeof (struct cmsghdr); |
} |
#endif |
len = mp->msg_controllen; |
if (len <= 0 || control == 0) |
len = 0; |
else { |
struct mbuf *m = control; |
caddr_t p = (caddr_t)mp->msg_control; |
|
do { |
i = m->m_len; |
if (len < i) { |
mp->msg_flags |= MSG_CTRUNC; |
i = len; |
} |
error = copyout(mtod(m, caddr_t), p, |
(unsigned)i); |
if (m->m_next) |
i = ALIGN(i); |
p += i; |
len -= i; |
if (error != 0 || len <= 0) |
break; |
} while ((m = m->m_next) != NULL); |
len = p - (caddr_t)mp->msg_control; |
} |
mp->msg_controllen = len; |
} |
out: |
if (from) |
m_freem(from); |
if (control) |
m_freem(control); |
return (error); |
} |
|
/* ARGSUSED */ |
#ifdef __ECOS |
int |
sys_shutdown(struct sys_shutdown_args *uap, register_t *retval) |
{ |
#else |
int |
sys_shutdown(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_shutdown_args /* { |
syscallarg(int) s; |
syscallarg(int) how; |
} */ *uap = v; |
#endif // __ECOS |
struct file *fp; |
int error; |
|
if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) |
return (error); |
return (soshutdown((struct socket *)fp->f_data, SCARG(uap, how))); |
} |
|
#ifdef __ECOS |
int |
sys_setsockopt(struct sys_setsockopt_args *uap, register_t *retval) |
{ |
#else |
/* ARGSUSED */ |
int |
sys_setsockopt(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_setsockopt_args /* { |
syscallarg(int) s; |
syscallarg(int) level; |
syscallarg(int) name; |
syscallarg(caddr_t) val; |
syscallarg(socklen_t) valsize; |
} */ *uap = v; |
#endif // __ECOS |
struct file *fp; |
struct mbuf *m = NULL; |
int error; |
|
if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) |
return (error); |
if (SCARG(uap, valsize) > MCLBYTES) |
return (EINVAL); |
if (SCARG(uap, val)) { |
m = m_get(M_WAIT, MT_SOOPTS); |
if (SCARG(uap, valsize) > MLEN) { |
MCLGET(m, M_DONTWAIT); |
if ((m->m_flags & M_EXT) == 0) { |
m_freem(m); |
return (ENOBUFS); |
} |
} |
if (m == NULL) |
return (ENOBUFS); |
error = copyin(SCARG(uap, val), mtod(m, caddr_t), |
SCARG(uap, valsize)); |
if (error) { |
(void) m_free(m); |
return (error); |
} |
m->m_len = SCARG(uap, valsize); |
} |
return (sosetopt((struct socket *)fp->f_data, SCARG(uap, level), |
SCARG(uap, name), m)); |
} |
|
#ifdef __ECOS |
int |
sys_getsockopt(struct sys_getsockopt_args *uap, register_t *retval) |
{ |
#else |
/* ARGSUSED */ |
int |
sys_getsockopt(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_getsockopt_args /* { |
syscallarg(int) s; |
syscallarg(int) level; |
syscallarg(int) name; |
syscallarg(caddr_t) val; |
syscallarg(socklen_t *) avalsize; |
} */ *uap = v; |
#endif // __ECOS |
struct file *fp; |
struct mbuf *m = NULL; |
socklen_t valsize; |
int error; |
|
if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) |
return (error); |
if (SCARG(uap, val)) { |
error = copyin((caddr_t)SCARG(uap, avalsize), |
(caddr_t)&valsize, sizeof (valsize)); |
if (error) |
return (error); |
} else |
valsize = 0; |
if ((error = sogetopt((struct socket *)fp->f_data, SCARG(uap, level), |
SCARG(uap, name), &m)) == 0 && SCARG(uap, val) && valsize && |
m != NULL) { |
if (valsize > m->m_len) |
valsize = m->m_len; |
error = copyout(mtod(m, caddr_t), SCARG(uap, val), valsize); |
if (error == 0) |
error = copyout((caddr_t)&valsize, |
(caddr_t)SCARG(uap, avalsize), sizeof (valsize)); |
} |
if (m != NULL) |
(void) m_free(m); |
return (error); |
} |
|
#ifndef __ECOS |
int |
sys_pipe(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_pipe_args /* { |
syscallarg(int *) fdp; |
} */ *uap = v; |
int error, fds[2]; |
register_t rval[2]; |
|
if ((error = sys_opipe(p, v, rval)) == -1) |
return (error); |
|
fds[0] = rval[0]; |
fds[1] = rval[1]; |
error = copyout((caddr_t)fds, (caddr_t)SCARG(uap, fdp), |
2 * sizeof (int)); |
if (error) { |
fdrelease(p, retval[0]); |
fdrelease(p, retval[1]); |
} |
return (error); |
} |
|
#ifdef OLD_PIPE |
|
/* ARGSUSED */ |
int |
sys_opipe(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct filedesc *fdp = p->p_fd; |
struct file *rf, *wf; |
struct socket *rso, *wso; |
int fd, error; |
|
if ((error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0)) != 0) |
return (error); |
if ((error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0)) != 0) |
goto free1; |
if ((error = falloc(p, &rf, &fd)) != 0) |
goto free2; |
retval[0] = fd; |
rf->f_flag = FREAD; |
rf->f_type = DTYPE_SOCKET; |
rf->f_ops = &socketops; |
rf->f_data = (caddr_t)rso; |
if ((error = falloc(p, &wf, &fd)) != 0) |
goto free3; |
wf->f_flag = FWRITE; |
wf->f_type = DTYPE_SOCKET; |
wf->f_ops = &socketops; |
wf->f_data = (caddr_t)wso; |
retval[1] = fd; |
if ((error = unp_connect2(wso, rso)) != 0) |
goto free4; |
return (0); |
free4: |
ffree(wf); |
fdremove(fdp, retval[1]); |
free3: |
ffree(rf); |
fdremove(fdp, retval[0]); |
free2: |
(void)soclose(wso); |
free1: |
(void)soclose(rso); |
return (error); |
} |
#endif |
#endif // __ECOS |
|
/* |
* Get socket name. |
*/ |
#ifdef __ECOS |
int |
sys_getsockname(struct sys_getsockname_args *uap, register_t *retval) |
{ |
#else |
/* ARGSUSED */ |
int |
sys_getsockname(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_getsockname_args /* { |
syscallarg(int) fdes; |
syscallarg(caddr_t) asa; |
syscallarg(socklen_t *) alen; |
} */ *uap = v; |
#endif // __ECOS |
struct file *fp; |
register struct socket *so; |
struct mbuf *m; |
socklen_t len; |
int error; |
|
if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0) |
return (error); |
error = copyin((caddr_t)SCARG(uap, alen), (caddr_t)&len, sizeof (len)); |
if (error) |
return (error); |
so = (struct socket *)fp->f_data; |
m = m_getclr(M_WAIT, MT_SONAME); |
if (m == NULL) |
return (ENOBUFS); |
error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0); |
if (error) |
goto bad; |
if (len > m->m_len) |
len = m->m_len; |
error = copyout(mtod(m, caddr_t), (caddr_t)SCARG(uap, asa), len); |
if (error == 0) |
error = copyout((caddr_t)&len, (caddr_t)SCARG(uap, alen), |
sizeof (len)); |
bad: |
m_freem(m); |
return (error); |
} |
|
/* |
* Get name of peer for connected socket. |
*/ |
/* ARGSUSED */ |
#ifdef __ECOS |
int |
sys_getpeername(struct sys_getpeername_args *uap, register_t *retval) |
{ |
#else |
int |
sys_getpeername(p, v, retval) |
struct proc *p; |
void *v; |
register_t *retval; |
{ |
register struct sys_getpeername_args /* { |
syscallarg(int) fdes; |
syscallarg(caddr_t) asa; |
syscallarg(socklen_t *) alen; |
} */ *uap = v; |
#endif // __ECOS |
struct file *fp; |
register struct socket *so; |
struct mbuf *m; |
socklen_t len; |
int error; |
|
if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0) |
return (error); |
so = (struct socket *)fp->f_data; |
if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) |
return (ENOTCONN); |
error = copyin((caddr_t)SCARG(uap, alen), (caddr_t)&len, sizeof (len)); |
if (error) |
return (error); |
m = m_getclr(M_WAIT, MT_SONAME); |
if (m == NULL) |
return (ENOBUFS); |
error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0); |
if (error) |
goto bad; |
if (len > m->m_len) |
len = m->m_len; |
error = copyout(mtod(m, caddr_t), (caddr_t)SCARG(uap, asa), len); |
if (error == 0) |
error = copyout((caddr_t)&len, (caddr_t)SCARG(uap, alen), |
sizeof (len)); |
bad: |
m_freem(m); |
return (error); |
} |
|
int |
sockargs(mp, buf, buflen, type) |
struct mbuf **mp; |
caddr_t buf; |
socklen_t buflen; |
int type; |
{ |
register struct sockaddr *sa; |
register struct mbuf *m; |
int error; |
|
if (buflen > MLEN) { |
#ifdef COMPAT_OLDSOCK |
if (type == MT_SONAME && buflen <= 112) |
buflen = MLEN; /* unix domain compat. hack */ |
else |
#endif |
return (EINVAL); |
} |
m = m_get(M_WAIT, type); |
if (m == NULL) |
return (ENOBUFS); |
m->m_len = buflen; |
error = copyin(buf, mtod(m, caddr_t), buflen); |
if (error) { |
(void) m_free(m); |
return (error); |
} |
*mp = m; |
if (type == MT_SONAME) { |
sa = mtod(m, struct sockaddr *); |
|
#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN |
if (sa->sa_family == 0 && sa->sa_len < AF_MAX) |
sa->sa_family = sa->sa_len; |
#endif |
sa->sa_len = buflen; |
} |
return (0); |
} |
|
#ifdef __ECOS |
static int |
ecos_getsock(int fdes, struct file **fpp) |
{ |
struct file *fp; |
if (getfp(fdes, &fp)) |
return (EBADF); |
if (fp->f_type != DTYPE_SOCKET) |
return (ENOTSOCK); |
*fpp = fp; |
return (0); |
} |
#else |
int |
getsock(fdp, fdes, fpp) |
struct filedesc *fdp; |
int fdes; |
struct file **fpp; |
{ |
register struct file *fp; |
|
if ((unsigned)fdes >= fdp->fd_nfiles || |
(fp = fdp->fd_ofiles[fdes]) == NULL) |
return (EBADF); |
if (fp->f_type != DTYPE_SOCKET) |
return (ENOTSOCK); |
*fpp = fp; |
return (0); |
} |
#endif |