X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/d08c5322d357df78a10683f546626091e7f589d1..943685687a914f34bb028d07fefeff4a802b6d5b:/usr/src/sys/kern/uipc_syscalls.c diff --git a/usr/src/sys/kern/uipc_syscalls.c b/usr/src/sys/kern/uipc_syscalls.c index fab7a99ac2..bd683e81f1 100644 --- a/usr/src/sys/kern/uipc_syscalls.c +++ b/usr/src/sys/kern/uipc_syscalls.c @@ -1,388 +1,824 @@ -/* uipc_syscalls.c 4.12 81/12/20 */ - -#include "../h/param.h" -#include "../h/systm.h" -#include "../h/dir.h" -#include "../h/user.h" -#include "../h/proc.h" -#include "../h/file.h" -#include "../h/inode.h" -#include "../h/buf.h" -#include "../h/mbuf.h" -#include "../h/protosw.h" -#include "../h/socket.h" -#include "../h/socketvar.h" -#include "../net/in.h" -#include "../net/in_systm.h" +/* uipc_syscalls.c 6.4 84/08/29 */ -/* - * Socket system call interface. - * - * These routines interface the socket routines to UNIX, - * isolating the system interface from the socket-protocol interface. - * - * TODO: - * SO_INTNOTIFY - */ +#include "param.h" +#include "systm.h" +#include "dir.h" +#include "user.h" +#include "proc.h" +#include "file.h" +#include "inode.h" +#include "buf.h" +#include "mbuf.h" +#include "protosw.h" +#include "socket.h" +#include "socketvar.h" +#include "uio.h" -static struct sockproto localproto = { PF_UNIX, 0 }; /* - * Pipe system call interface. + * System call interface to the socket abstraction. */ -spipe() + +struct file *getsock(); +extern struct fileops socketops; + +socket() { - register struct file *rf, *wf; - struct socket *rso, *wso; - int r; -COUNT(SPIPE); - - u.u_error = socreate(&rso, SOCK_STREAM, - &localproto, (struct sockaddr *)0, 0); - if (u.u_error) + register struct a { + int domain; + int type; + int protocol; + } *uap = (struct a *)u.u_ap; + struct socket *so; + register struct file *fp; + + if ((fp = falloc()) == NULL) return; - u.u_error = socreate(&wso, SOCK_STREAM, - &localproto, (struct sockaddr *)0, 0); + fp->f_flag = FREAD|FWRITE; + fp->f_type = DTYPE_SOCKET; + fp->f_ops = &socketops; + u.u_error = socreate(uap->domain, &so, uap->type, uap->protocol); if (u.u_error) - goto free; - rf = falloc(); - if (rf == NULL) - goto free2; - r = u.u_r.r_val1; - rf->f_flag = FREAD|FSOCKET; - rf->f_socket = rso; - wf = falloc(); - if (wf == NULL) - goto free3; - wf->f_flag = FWRITE|FSOCKET; - wf->f_socket = wso; - u.u_r.r_val2 = u.u_r.r_val1; - u.u_r.r_val1 = r; - if (piconnect(wso, rso) == 0) - goto free4; + goto bad; + fp->f_data = (caddr_t)so; return; -free4: - wf->f_count = 0; +bad: u.u_ofile[u.u_r.r_val1] = 0; -free3: - rf->f_count = 0; - u.u_ofile[r] = 0; -free2: - wso->so_state |= SS_USERGONE; - sofree(wso); -free: - rso->so_state |= SS_USERGONE; - sofree(rso); + fp->f_count = 0; } -/* - * Splice system call interface. - */ -ssplice() +bind() { register struct a { - int fd1; - int fd2; - } *ap = (struct a *)u.u_ap; - struct file *f1, *f2; -COUNT(SSPLICE); + int s; + caddr_t name; + int namelen; + } *uap = (struct a *)u.u_ap; + register struct file *fp; + struct mbuf *nam; - f1 = getf(ap->fd1); - if (f1 == NULL) - return; - f2 = getf(ap->fd2); - if (f2 == NULL) - return; - if (f1 == f2) { - u.u_error = EINVAL; - return; - } - if ((f1->f_flag & FSOCKET) == 0 || (f2->f_flag & FSOCKET) == 0) { - u.u_error = ENOTSOCK; - return; - } - if (f1->f_count > 1 || f2->f_count > 1) { - u.u_error = ETOOMANYREFS; + fp = getsock(uap->s); + if (fp == 0) return; - } - u.u_error = sosplice(f1->f_socket, f2->f_socket); + u.u_error = sockargs(&nam, uap->name, uap->namelen); if (u.u_error) return; - u.u_ofile[ap->fd1] = 0; - u.u_ofile[ap->fd2] = 0; - f1->f_count = 0; - f2->f_count = 0; + u.u_error = sobind((struct socket *)fp->f_data, nam); + m_freem(nam); } -/* - * Socket system call interface. Copy sa arguments - * set up file descriptor and call internal socket - * creation routine. - */ -ssocket() +listen() { register struct a { - int type; - struct sockproto *asp; - struct sockaddr *asa; - int options; + int s; + int backlog; } *uap = (struct a *)u.u_ap; - struct sockproto sp; - struct sockaddr sa; - struct socket *so; register struct file *fp; -COUNT(SSOCKET); - if ((fp = falloc()) == NULL) - return; - fp->f_flag = FSOCKET|FREAD|FWRITE; - if (uap->asp && copyin((caddr_t)uap->asp, (caddr_t)&sp, sizeof (sp)) || - uap->asa && copyin((caddr_t)uap->asa, (caddr_t)&sa, sizeof (sa))) { - u.u_error = EFAULT; + fp = getsock(uap->s); + if (fp == 0) return; - } - u.u_error = socreate(&so, uap->type, - uap->asp ? &sp : 0, uap->asa ? &sa : 0, uap->options); - if (u.u_error) - goto bad; - fp->f_socket = so; - return; -bad: - u.u_ofile[u.u_r.r_val1] = 0; - fp->f_count = 0; + u.u_error = solisten((struct socket *)fp->f_data, uap->backlog); } -/* - * Accept system call interface. - */ -saccept() +accept() { register struct a { - int fdes; - struct sockaddr *asa; + int s; + caddr_t name; + int *anamelen; } *uap = (struct a *)u.u_ap; - struct sockaddr sa; register struct file *fp; - struct socket *so; + struct mbuf *nam; + int namelen; int s; -COUNT(SACCEPT); + register struct socket *so; - if (uap->asa && useracc((caddr_t)uap->asa, sizeof (sa), B_WRITE)==0) { + if (uap->name == 0) + goto noname; + u.u_error = copyin((caddr_t)uap->anamelen, (caddr_t)&namelen, + sizeof (namelen)); + if (u.u_error) + return; + if (useracc((caddr_t)uap->name, (u_int)namelen, B_WRITE) == 0) { u.u_error = EFAULT; return; } - fp = getf(uap->fdes); +noname: + fp = getsock(uap->s); if (fp == 0) return; - if ((fp->f_flag & FSOCKET) == 0) { - u.u_error = ENOTSOCK; + s = splnet(); + so = (struct socket *)fp->f_data; + if ((so->so_options & SO_ACCEPTCONN) == 0) { + u.u_error = EINVAL; + splx(s); return; } - s = splnet(); - so = fp->f_socket; - if ((so->so_options & SO_NBIO) && - (so->so_state & SS_CONNAWAITING) == 0) { + if ((so->so_state & SS_NBIO) && so->so_qlen == 0) { u.u_error = EWOULDBLOCK; splx(s); return; } - while ((so->so_state & SS_CONNAWAITING) == 0) + while (so->so_qlen == 0 && so->so_error == 0) { + if (so->so_state & SS_CANTRCVMORE) { + so->so_error = ECONNABORTED; + break; + } sleep((caddr_t)&so->so_timeo, PZERO+1); - u.u_error = soaccept(so, &sa); - if (u.u_error) { + } + if (so->so_error) { + u.u_error = so->so_error; + splx(s); + return; + } + if (ufalloc(0) < 0) { splx(s); return; } - if (uap->asa) - (void) copyout((caddr_t)&sa, (caddr_t)uap->asa, sizeof (sa)); - /* deal with new file descriptor case */ - /* u.u_r.r_val1 = ... */ + fp = falloc(); + if (fp == 0) { + u.u_ofile[u.u_r.r_val1] = 0; + splx(s); + return; + } + { 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; + fp->f_data = (caddr_t)so; + nam = m_get(M_WAIT, MT_SONAME); + (void) soaccept(so, nam); + if (uap->name) { + if (namelen > nam->m_len) + namelen = nam->m_len; + /* SHOULD COPY OUT A CHAIN HERE */ + (void) copyout(mtod(nam, caddr_t), (caddr_t)uap->name, + (u_int)namelen); + (void) copyout((caddr_t)&namelen, (caddr_t)uap->anamelen, + sizeof (*uap->anamelen)); + } + m_freem(nam); splx(s); } -/* - * Connect socket to foreign peer; system call - * interface. Copy sa arguments and call internal routine. - */ -sconnect() +connect() { register struct a { - int fdes; - struct sockaddr *a; + int s; + caddr_t name; + int namelen; } *uap = (struct a *)u.u_ap; - struct sockaddr sa; register struct file *fp; register struct socket *so; + struct mbuf *nam; int s; -COUNT(SCONNECT); - if (copyin((caddr_t)uap->a, (caddr_t)&sa, sizeof (sa))) { - u.u_error = EFAULT; - return; - } - fp = getf(uap->fdes); + fp = getsock(uap->s); if (fp == 0) return; - if ((fp->f_flag & FSOCKET) == 0) { - u.u_error = ENOTSOCK; - return; - } - so = fp->f_socket; - u.u_error = soconnect(so, &sa); + so = (struct socket *)fp->f_data; + u.u_error = sockargs(&nam, uap->name, uap->namelen); if (u.u_error) return; + u.u_error = soconnect(so, nam); + if (u.u_error) + goto bad; s = splnet(); - if ((so->so_options & SO_NBIO) && + if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { u.u_error = EINPROGRESS; - splx(s); - return; + goto bad2; + } + if (setjmp(&u.u_qsave)) { + if (u.u_error == 0) + u.u_error = EINTR; + goto bad2; } while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) sleep((caddr_t)&so->so_timeo, PZERO+1); u.u_error = so->so_error; so->so_error = 0; +bad2: splx(s); +bad: + m_freem(nam); } -/* - * Disconnect socket from foreign peer; system call - * interface. Copy sa arguments and call internal routine. - */ -sdisconnect() +socketpair() { register struct a { - int fdes; - struct sockaddr *asa; + int domain; + int type; + int protocol; + int *rsv; } *uap = (struct a *)u.u_ap; - struct sockaddr sa; - register struct file *fp; - register struct socket *so; - int s; -COUNT(SDISCONNECT); + register struct file *fp1, *fp2; + struct socket *so1, *so2; + int sv[2]; - if (uap->asa && - copyin((caddr_t)uap->asa, (caddr_t)&sa, sizeof (sa))) { + if (useracc((caddr_t)uap->rsv, 2 * sizeof (int), B_WRITE) == 0) { u.u_error = EFAULT; return; } - fp = getf(uap->fdes); - if (fp == 0) + u.u_error = socreate(uap->domain, &so1, uap->type, uap->protocol); + if (u.u_error) return; - if ((fp->f_flag & FSOCKET) == 0) { - u.u_error = ENOTSOCK; + u.u_error = socreate(uap->domain, &so2, uap->type, uap->protocol); + if (u.u_error) + goto free; + fp1 = falloc(); + if (fp1 == NULL) + goto free2; + sv[0] = u.u_r.r_val1; + fp1->f_flag = FREAD|FWRITE; + fp1->f_type = DTYPE_SOCKET; + fp1->f_ops = &socketops; + fp1->f_data = (caddr_t)so1; + fp2 = falloc(); + if (fp2 == NULL) + goto free3; + fp2->f_flag = FREAD|FWRITE; + fp2->f_type = DTYPE_SOCKET; + fp2->f_ops = &socketops; + fp2->f_data = (caddr_t)so2; + sv[1] = u.u_r.r_val1; + u.u_error = soconnect2(so1, so2); + if (u.u_error) + goto free4; + (void) copyout((caddr_t)sv, (caddr_t)uap->rsv, 2 * sizeof (int)); + return; +free4: + fp2->f_count = 0; + u.u_ofile[sv[1]] = 0; +free3: + fp1->f_count = 0; + u.u_ofile[sv[0]] = 0; +free2: + so2->so_state |= SS_NOFDREF; + sofree(so2); +free: + so1->so_state |= SS_NOFDREF; + sofree(so1); +} + +sendto() +{ + register struct a { + int s; + caddr_t buf; + int len; + int flags; + caddr_t to; + int tolen; + } *uap = (struct a *)u.u_ap; + struct msghdr msg; + struct iovec aiov; + + msg.msg_name = uap->to; + msg.msg_namelen = uap->tolen; + msg.msg_iov = &aiov; + msg.msg_iovlen = 1; + aiov.iov_base = uap->buf; + aiov.iov_len = uap->len; + msg.msg_accrights = 0; + msg.msg_accrightslen = 0; + sendit(uap->s, &msg, uap->flags); +} + +send() +{ + register struct a { + int s; + caddr_t buf; + int len; + int flags; + } *uap = (struct a *)u.u_ap; + struct msghdr msg; + struct iovec aiov; + + msg.msg_name = 0; + msg.msg_namelen = 0; + msg.msg_iov = &aiov; + msg.msg_iovlen = 1; + aiov.iov_base = uap->buf; + aiov.iov_len = uap->len; + msg.msg_accrights = 0; + msg.msg_accrightslen = 0; + sendit(uap->s, &msg, uap->flags); +} + +sendmsg() +{ + register struct a { + int s; + caddr_t msg; + int flags; + } *uap = (struct a *)u.u_ap; + struct msghdr msg; + struct iovec aiov[MSG_MAXIOVLEN]; + + u.u_error = copyin(uap->msg, (caddr_t)&msg, sizeof (msg)); + if (u.u_error) + return; + if ((u_int)msg.msg_iovlen >= sizeof (aiov) / sizeof (aiov[0])) { + u.u_error = EMSGSIZE; return; } - so = fp->f_socket; - u.u_error = sodisconnect(so, uap->asa ? &sa : 0); + u.u_error = + copyin((caddr_t)msg.msg_iov, (caddr_t)aiov, + (unsigned)(msg.msg_iovlen * sizeof (aiov[0]))); if (u.u_error) return; - s = splnet(); - if ((so->so_options&SO_NBIO) && (so->so_state&SS_ISDISCONNECTING)) { - u.u_error = EINPROGRESS; - splx(s); + msg.msg_iov = aiov; +#ifdef notdef +printf("sendmsg name %x namelen %d iov %x iovlen %d accrights %x &len %d\n", +msg.msg_name, msg.msg_namelen, msg.msg_iov, msg.msg_iovlen, +msg.msg_accrights, msg.msg_accrightslen); +#endif + sendit(uap->s, &msg, uap->flags); +} + +sendit(s, mp, flags) + int s; + register struct msghdr *mp; + int flags; +{ + register struct file *fp; + struct uio auio; + register struct iovec *iov; + register int i; + struct mbuf *to, *rights; + int len; + + fp = getsock(s); + if (fp == 0) return; + auio.uio_iov = mp->msg_iov; + auio.uio_iovcnt = mp->msg_iovlen; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_offset = 0; /* XXX */ + auio.uio_resid = 0; + iov = mp->msg_iov; + for (i = 0; i < mp->msg_iovlen; i++) { + if (iov->iov_len < 0) { + u.u_error = EINVAL; + return; + } + if (iov->iov_len == 0) + continue; + if (useracc(iov->iov_base, (u_int)iov->iov_len, B_READ) == 0) { + u.u_error = EFAULT; + return; + } + auio.uio_resid += iov->iov_len; + iov++; } - while ((so->so_state & SS_ISDISCONNECTING) && so->so_error == 0) - sleep((caddr_t)&so->so_timeo, PZERO+1); - u.u_error = so->so_error; - so->so_error = 0; - splx(s); + if (mp->msg_name) { + u.u_error = + sockargs(&to, mp->msg_name, mp->msg_namelen); + if (u.u_error) + return; + } else + to = 0; + if (mp->msg_accrights) { + u.u_error = + sockargs(&rights, mp->msg_accrights, mp->msg_accrightslen); + if (u.u_error) + goto bad; + } else + rights = 0; + len = auio.uio_resid; + u.u_error = + sosend((struct socket *)fp->f_data, to, &auio, flags, rights); + u.u_r.r_val1 = len - auio.uio_resid; + if (rights) + m_freem(rights); +bad: + if (to) + m_freem(to); } -/* - * Send data on socket. - */ -ssend() +recvfrom() { register struct a { - int fdes; - struct sockaddr *asa; - caddr_t cbuf; - unsigned count; + int s; + caddr_t buf; + int len; + int flags; + caddr_t from; + int *fromlenaddr; + } *uap = (struct a *)u.u_ap; + struct msghdr msg; + struct iovec aiov; + int len; + + u.u_error = copyin((caddr_t)uap->fromlenaddr, (caddr_t)&len, + sizeof (len)); + if (u.u_error) + return; + msg.msg_name = uap->from; + msg.msg_namelen = len; + msg.msg_iov = &aiov; + msg.msg_iovlen = 1; + aiov.iov_base = uap->buf; + aiov.iov_len = uap->len; + msg.msg_accrights = 0; + msg.msg_accrightslen = 0; + recvit(uap->s, &msg, uap->flags, (caddr_t)uap->fromlenaddr, (caddr_t)0); +} + +recv() +{ + register struct a { + int s; + caddr_t buf; + int len; + int flags; + } *uap = (struct a *)u.u_ap; + struct msghdr msg; + struct iovec aiov; + + msg.msg_name = 0; + msg.msg_namelen = 0; + msg.msg_iov = &aiov; + msg.msg_iovlen = 1; + aiov.iov_base = uap->buf; + aiov.iov_len = uap->len; + msg.msg_accrights = 0; + msg.msg_accrightslen = 0; + recvit(uap->s, &msg, uap->flags, (caddr_t)0, (caddr_t)0); +} + +recvmsg() +{ + register struct a { + int s; + struct msghdr *msg; + int flags; } *uap = (struct a *)u.u_ap; + struct msghdr msg; + struct iovec aiov[MSG_MAXIOVLEN]; + + u.u_error = copyin((caddr_t)uap->msg, (caddr_t)&msg, sizeof (msg)); + if (u.u_error) + return; + if ((u_int)msg.msg_iovlen >= sizeof (aiov) / sizeof (aiov[0])) { + u.u_error = EMSGSIZE; + return; + } + u.u_error = + copyin((caddr_t)msg.msg_iov, (caddr_t)aiov, + (unsigned)(msg.msg_iovlen * sizeof (aiov[0]))); + if (u.u_error) + return; + msg.msg_iov = aiov; + if (msg.msg_accrights) + if (useracc((caddr_t)msg.msg_accrights, + (unsigned)msg.msg_accrightslen, B_WRITE) == 0) { + u.u_error = EFAULT; + return; + } + recvit(uap->s, &msg, uap->flags, + (caddr_t)&uap->msg->msg_namelen, + (caddr_t)&uap->msg->msg_accrightslen); +} + +recvit(s, mp, flags, namelenp, rightslenp) + int s; + register struct msghdr *mp; + int flags; + caddr_t namelenp, rightslenp; +{ register struct file *fp; - struct sockaddr sa; -COUNT(SSEND); + struct uio auio; + register struct iovec *iov; + register int i; + struct mbuf *from, *rights; + int len; + + fp = getsock(s); + if (fp == 0) + return; + auio.uio_iov = mp->msg_iov; + auio.uio_iovcnt = mp->msg_iovlen; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_offset = 0; /* XXX */ + auio.uio_resid = 0; + iov = mp->msg_iov; + for (i = 0; i < mp->msg_iovlen; i++) { + if (iov->iov_len < 0) { + u.u_error = EINVAL; + return; + } + if (iov->iov_len == 0) + continue; + if (useracc(iov->iov_base, (u_int)iov->iov_len, B_WRITE) == 0) { + u.u_error = EFAULT; + return; + } + auio.uio_resid += iov->iov_len; + iov++; + } + len = auio.uio_resid; + u.u_error = + soreceive((struct socket *)fp->f_data, &from, &auio, + flags, &rights); + u.u_r.r_val1 = len - auio.uio_resid; + if (mp->msg_name) { + len = mp->msg_namelen; + if (len <= 0 || from == 0) + len = 0; + else { + if (len > from->m_len) + len = from->m_len; + (void) copyout((caddr_t)mtod(from, caddr_t), + (caddr_t)mp->msg_name, (unsigned)len); + } + (void) copyout((caddr_t)&len, namelenp, sizeof (int)); + } + if (mp->msg_accrights) { + len = mp->msg_accrightslen; + if (len <= 0 || rights == 0) + len = 0; + else { + if (len > rights->m_len) + len = rights->m_len; + (void) copyout((caddr_t)mtod(rights, caddr_t), + (caddr_t)mp->msg_accrights, (unsigned)len); + } + (void) copyout((caddr_t)&len, rightslenp, sizeof (int)); + } + if (rights) + m_freem(rights); + if (from) + m_freem(from); +} - fp = getf(uap->fdes); +shutdown() +{ + struct a { + int s; + int how; + } *uap = (struct a *)u.u_ap; + struct file *fp; + + fp = getsock(uap->s); if (fp == 0) return; - if ((fp->f_flag & FSOCKET) == 0) { - u.u_error = ENOTSOCK; + u.u_error = soshutdown((struct socket *)fp->f_data, uap->how); +} + +setsockopt() +{ + struct a { + int s; + int level; + int name; + caddr_t val; + int valsize; + } *uap = (struct a *)u.u_ap; + struct file *fp; + struct mbuf *m = NULL; + + fp = getsock(uap->s); + if (fp == 0) + return; + if (uap->valsize > MLEN) { + u.u_error = EINVAL; return; } - u.u_base = uap->cbuf; - u.u_count = uap->count; - u.u_segflg = 0; - if (useracc(uap->cbuf, uap->count, B_READ) == 0 || - uap->asa && copyin((caddr_t)uap->asa, (caddr_t)&sa, sizeof (sa))) { - u.u_error = EFAULT; + if (uap->val) { + m = m_get(M_WAIT, MT_SOOPTS); + if (m == NULL) { + u.u_error = ENOBUFS; + return; + } + u.u_error = + copyin(uap->val, mtod(m, caddr_t), (u_int)uap->valsize); + if (u.u_error) + goto bad; + m->m_len = uap->valsize; + } + u.u_error = + sosetopt((struct socket *)fp->f_data, uap->level, uap->name, m); +bad: + if (m != NULL) + (void) m_free(m); +} + +getsockopt() +{ + struct a { + int s; + int level; + int name; + caddr_t val; + int *avalsize; + } *uap = (struct a *)u.u_ap; + struct file *fp; + struct mbuf *m = NULL; + int valsize; + + fp = getsock(uap->s); + if (fp == 0) return; + if (uap->val) { + u.u_error = copyin((caddr_t)uap->avalsize, (caddr_t)&valsize, + sizeof (valsize)); + if (u.u_error) + return; + m = m_get(M_WAIT, MT_SOOPTS); + if (m == NULL) { + u.u_error = ENOBUFS; + return; + } } - u.u_error = sosend(fp->f_socket, uap->asa ? &sa : 0); - u.u_r.r_val1 = uap->count - u.u_count; + u.u_error = + sogetopt((struct socket *)fp->f_data, uap->level, uap->name, m); + if (u.u_error) + goto bad; + if (uap->val) { + if (valsize > m->m_len) + valsize = m->m_len; + u.u_error = copyout(mtod(m, caddr_t), uap->val, (u_int)valsize); + if (u.u_error) + goto bad; + u.u_error = copyout((caddr_t)&valsize, (caddr_t)uap->avalsize, + sizeof (valsize)); + } +bad: + if (m != NULL) + (void) m_free(m); +} + +pipe() +{ + register struct file *rf, *wf; + struct socket *rso, *wso; + int r; + + u.u_error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0); + if (u.u_error) + return; + u.u_error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0); + if (u.u_error) + goto free; + rf = falloc(); + if (rf == NULL) + goto free2; + r = u.u_r.r_val1; + rf->f_flag = FREAD; + rf->f_type = DTYPE_SOCKET; + rf->f_ops = &socketops; + rf->f_data = (caddr_t)rso; + wf = falloc(); + if (wf == NULL) + goto free3; + wf->f_flag = FWRITE; + wf->f_type = DTYPE_SOCKET; + wf->f_ops = &socketops; + wf->f_data = (caddr_t)wso; + u.u_r.r_val2 = u.u_r.r_val1; + u.u_r.r_val1 = r; + if (piconnect(wso, rso) == 0) + goto free4; + return; +free4: + wf->f_count = 0; + u.u_ofile[u.u_r.r_val2] = 0; +free3: + rf->f_count = 0; + u.u_ofile[r] = 0; +free2: + wso->so_state |= SS_NOFDREF; + sofree(wso); +free: + rso->so_state |= SS_NOFDREF; + sofree(rso); } /* - * Receive data on socket. + * Get socket name. */ -sreceive() +getsockname() { register struct a { int fdes; - struct sockaddr *asa; - caddr_t cbuf; - u_int count; + caddr_t asa; + int *alen; } *uap = (struct a *)u.u_ap; register struct file *fp; - struct sockaddr sa; -COUNT(SRECEIVE); + register struct socket *so; + struct mbuf *m; + int len; - fp = getf(uap->fdes); + fp = getsock(uap->fdes); if (fp == 0) return; - if ((fp->f_flag & FSOCKET) == 0) { - u.u_error = ENOTSOCK; + u.u_error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len)); + if (u.u_error) return; - } - u.u_base = uap->cbuf; - u.u_count = uap->count; - u.u_segflg = 0; - if (useracc(uap->cbuf, uap->count, B_WRITE) == 0 || - uap->asa && copyin((caddr_t)uap->asa, (caddr_t)&sa, sizeof (sa))) { - u.u_error = EFAULT; + so = (struct socket *)fp->f_data; + m = m_getclr(M_WAIT, MT_SONAME); + if (m == NULL) { + u.u_error = ENOBUFS; return; } - u.u_error = soreceive(fp->f_socket, uap->asa ? &sa : 0); + u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0); if (u.u_error) - return; - if (uap->asa) - (void) copyout((caddr_t)&sa, (caddr_t)uap->asa, sizeof (sa)); - u.u_r.r_val1 = uap->count - u.u_count; + goto bad; + if (len > m->m_len) + len = m->m_len; + u.u_error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len); + if (u.u_error) + goto bad; + u.u_error = copyout((caddr_t)&len, (caddr_t)uap->alen, sizeof (len)); +bad: + m_freem(m); } /* - * Get socket address. + * Get name of peer for connected socket. */ -ssocketaddr() +getpeername() { register struct a { int fdes; - struct sockaddr *asa; + caddr_t asa; + int *alen; } *uap = (struct a *)u.u_ap; register struct file *fp; -COUNT(SSOCKETADDR); + register struct socket *so; + struct mbuf *m; + int len; - fp = getf(uap->fdes); + fp = getsock(uap->fdes); if (fp == 0) return; - if ((fp->f_flag & FSOCKET) == 0) { - u.u_error = ENOTSOCK; + so = (struct socket *)fp->f_data; + if ((so->so_state & SS_ISCONNECTED) == 0) { + u.u_error = ENOTCONN; return; } - if (copyout((caddr_t)&fp->f_socket->so_addr, (caddr_t)uap->asa, - sizeof (struct sockaddr))) { - u.u_error = EFAULT; + m = m_getclr(M_WAIT, MT_SONAME); + if (m == NULL) { + u.u_error = ENOBUFS; return; } + u.u_error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len)); + if (u.u_error) + return; + u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0); + if (u.u_error) + goto bad; + if (len > m->m_len) + len = m->m_len; + u.u_error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len); + if (u.u_error) + goto bad; + u.u_error = copyout((caddr_t)&len, (caddr_t)uap->alen, sizeof (len)); +bad: + m_freem(m); +} + +sockargs(aname, name, namelen) + struct mbuf **aname; + caddr_t name; + int namelen; +{ + register struct mbuf *m; + int error; + + if (namelen > MLEN) + return (EINVAL); + m = m_get(M_WAIT, MT_SONAME); + if (m == NULL) + return (ENOBUFS); + m->m_len = namelen; + error = copyin(name, mtod(m, caddr_t), (u_int)namelen); + if (error) + (void) m_free(m); + else + *aname = m; + return (error); +} + +struct file * +getsock(fdes) + int fdes; +{ + register struct file *fp; + + fp = getf(fdes); + if (fp == NULL) + return (0); + if (fp->f_type != DTYPE_SOCKET) { + u.u_error = ENOTSOCK; + return (0); + } + return (fp); }