-/* uipc_syscalls.c 4.19 82/06/14 */
+/* uipc_syscalls.c 4.39 82/12/28 */
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/protosw.h"
#include "../h/socket.h"
#include "../h/socketvar.h"
-#include "../net/in.h"
-#include "../net/in_systm.h"
+#include "../h/descrip.h"
+#include "../h/uio.h"
/*
- * Socket system call interface.
- *
- * These routines interface the socket routines to UNIX,
- * isolating the system interface from the socket-protocol interface.
- *
- * TODO:
- * SO_INTNOTIFY
+ * System call interface to the socket abstraction.
*/
-static struct sockproto localproto = { PF_UNIX, 0 };
-/*
- * Pipe system call interface.
- */
-spipe()
+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);
+ register struct a {
+ int domain;
+ int type;
+ int protocol;
+ struct socketopt *opt;
+ } *uap = (struct a *)u.u_ap;
+ struct socket *so;
+ register struct file *fp;
+ struct socketopt aopt;
+
+ u.u_error = sockopt(&aopt, (caddr_t)uap->opt);
if (u.u_error)
return;
- u.u_error = socreate(&wso, SOCK_STREAM,
- &localproto, (struct sockaddr *)0, 0);
+ if ((fp = falloc()) == NULL)
+ goto freeopt;
+ fp->f_flag = FREAD|FWRITE;
+ fp->f_type = DTYPE_SOCKET;
+ u.u_error = socreate(uap->domain, &so, uap->type, uap->protocol, &aopt);
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_socket = so;
+freeopt:
+ if (uap->opt)
+ (void) m_free(dtom(aopt.so_optdata));
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_USERGONE;
- sofree(wso);
-free:
- rso->so_state |= SS_USERGONE;
- sofree(rso);
+bad:
+ u.u_ofile[u.u_r.r_val1] = 0;
+ fp->f_count = 0;
+ goto freeopt;
}
-/*
- * Socket system call interface. Copy sa arguments
- * set up file descriptor and call internal socket
- * creation routine.
- */
-ssocket()
+bind()
{
register struct a {
- int type;
- struct sockproto *asp;
- struct sockaddr *asa;
- int options;
+ int s;
+ caddr_t name;
+ int namelen;
+ struct socketopt *opt;
} *uap = (struct a *)u.u_ap;
- struct sockproto sp;
- struct sockaddr sa;
- struct socket *so;
register struct file *fp;
-COUNT(SSOCKET);
+ struct mbuf *nam;
+ struct socketopt aopt;
- if ((fp = falloc()) == NULL)
+ fp = getf(uap->s);
+ if (fp == 0)
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;
+ if (fp->f_type != DTYPE_SOCKET) {
+ u.u_error = ENOTSOCK;
return;
}
- u.u_error = socreate(&so, uap->type,
- uap->asp ? &sp : 0, uap->asa ? &sa : 0, uap->options);
+ u.u_error = sockname(&nam, uap->name, uap->namelen);
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;
+ return;
+ u.u_error = sockopt(&aopt, (caddr_t)uap->opt);
+ if (u.u_error) {
+ m_freem(nam);
+ goto freeopt;
+ }
+ u.u_error = sobind(fp->f_socket, nam, &aopt);
+ m_freem(nam);
+freeopt:
+ if (uap->opt)
+ (void) m_free(dtom(aopt.so_optdata));
}
-/*
- * Accept system call interface.
- */
-saccept()
+listen()
{
register struct a {
- int fdes;
- struct sockaddr *asa;
+ int s;
+ int backlog;
} *uap = (struct a *)u.u_ap;
- struct sockaddr sa;
register struct file *fp;
- struct socket *so;
+
+ fp = getf(uap->s);
+ if (fp == 0)
+ return;
+ if (fp->f_type != DTYPE_SOCKET) {
+ u.u_error = ENOTSOCK;
+ return;
+ }
+ u.u_error = solisten(fp->f_socket, uap->backlog);
+}
+
+accept()
+{
+ register struct a {
+ int s;
+ caddr_t name;
+ int *anamelen;
+ struct socketopt *opt;
+ } *uap = (struct a *)u.u_ap;
+ register struct file *fp;
+ struct mbuf *nam;
+ struct socketopt aopt;
+ 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);
- if (fp == 0)
+noname:
+ u.u_error = sockopt(&aopt, (caddr_t)uap->opt);
+ if (u.u_error)
return;
- if ((fp->f_flag & FSOCKET) == 0) {
+ fp = getf(uap->s);
+ if (fp == 0)
+ goto bad;
+ if (fp->f_type != DTYPE_SOCKET) {
u.u_error = ENOTSOCK;
- return;
+ goto bad;
}
s = splnet();
so = fp->f_socket;
- if ((so->so_state & SS_NBIO) &&
- (so->so_state & SS_CONNAWAITING) == 0) {
+ if ((so->so_options & SO_ACCEPTCONN) == 0) {
+ u.u_error = EINVAL;
+ splx(s);
+ goto bad;
+ }
+ if ((so->so_state & SS_NBIO) && so->so_qlen == 0) {
u.u_error = EWOULDBLOCK;
splx(s);
- return;
+ goto bad;
}
- while ((so->so_state & SS_CONNAWAITING) == 0 && so->so_error == 0) {
+ while (so->so_qlen == 0 && so->so_error == 0) {
if (so->so_state & SS_CANTRCVMORE) {
so->so_error = ECONNABORTED;
break;
if (so->so_error) {
u.u_error = so->so_error;
splx(s);
- return;
+ goto bad;
}
- u.u_error = soaccept(so, &sa);
- if (u.u_error) {
+ if ((so->so_options & SO_NEWFDONCONN) == 0) {
+ struct socket *nso = so->so_q;
+ (void) soqremque(nso, 1);
+ u.u_error = soclose(so, 1);
+ fp->f_socket = nso;
+ nso->so_q = 0;
+ so = nso;
+ goto ret;
+ }
+ if (ufalloc() < 0) {
splx(s);
- return;
+ goto bad;
}
- 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);
+ goto bad;
+ }
+ { 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_socket = so;
+ret:
+ nam = m_get(M_WAIT, MT_SONAME);
+ (void) soaccept(so, nam, &aopt);
+ 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);
+bad:
+ if (uap->opt)
+ (void) m_free(dtom(aopt.so_optdata));
}
-/*
- * 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;
+ struct socketopt *opt;
} *uap = (struct a *)u.u_ap;
- struct sockaddr sa;
register struct file *fp;
register struct socket *so;
+ struct mbuf *nam;
+ struct socketopt aopt;
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 = getf(uap->s);
if (fp == 0)
return;
- if ((fp->f_flag & FSOCKET) == 0) {
+ if (fp->f_type != DTYPE_SOCKET) {
u.u_error = ENOTSOCK;
return;
}
so = fp->f_socket;
- u.u_error = soconnect(so, &sa);
+ u.u_error = sockname(&nam, uap->name, uap->namelen);
if (u.u_error)
return;
+ u.u_error = sockopt(&aopt, (caddr_t)uap->opt);
+ if (u.u_error) {
+ m_freem(nam);
+ return;
+ }
+ u.u_error = soconnect(so, nam, &aopt);
+ if (u.u_error)
+ goto bad;
s = splnet();
if ((so->so_state & SS_NBIO) &&
(so->so_state & SS_ISCONNECTING)) {
u.u_error = EINPROGRESS;
splx(s);
- return;
+ goto bad;
}
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;
splx(s);
+bad:
+ m_freem(nam);
+ if (uap->opt)
+ (void) m_free(dtom(aopt.so_optdata));
+ return;
}
-/*
- * Send data on socket.
- */
-ssend()
+socketpair()
+{
+
+ u.u_error = ENOENT;
+}
+
+sendto()
{
register struct a {
- int fdes;
- struct sockaddr *asa;
- caddr_t cbuf;
- unsigned count;
+ int s;
+ caddr_t buf;
+ int len;
+ int flags;
+ caddr_t to;
+ int tolen;
} *uap = (struct a *)u.u_ap;
register struct file *fp;
- struct sockaddr sa;
-COUNT(SSEND);
+ struct uio auio;
+ struct iovec aiov;
+ struct mbuf *to;
- fp = getf(uap->fdes);
+ fp = getf(uap->s);
if (fp == 0)
return;
- if ((fp->f_flag & FSOCKET) == 0) {
+ if (fp->f_type != DTYPE_SOCKET) {
u.u_error = ENOTSOCK;
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))) {
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ aiov.iov_base = uap->buf;
+ aiov.iov_len = uap->len;
+ auio.uio_resid = uap->len;
+ auio.uio_segflg = 0;
+ auio.uio_offset = 0; /* XXX */
+ if (useracc(uap->buf, (u_int)uap->len, B_READ) == 0) {
u.u_error = EFAULT;
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 = sockname(&to, uap->to, uap->tolen);
+ if (u.u_error)
+ goto bad;
+ u.u_error = sosend(fp->f_socket, to, &auio, uap->flags);
+ u.u_r.r_val1 = uap->len - auio.uio_resid;
+bad:
+ m_freem(to);
}
-/*
- * Receive data on socket.
- */
-sreceive()
+send()
{
register struct a {
- int fdes;
- struct sockaddr *asa;
- caddr_t cbuf;
- u_int count;
+ int s;
+ caddr_t buf;
+ int len;
+ int flags;
} *uap = (struct a *)u.u_ap;
register struct file *fp;
- struct sockaddr sa;
-COUNT(SRECEIVE);
+ struct uio auio;
+ struct iovec aiov;
- fp = getf(uap->fdes);
+ fp = getf(uap->s);
+ if (fp == 0)
+ return;
+ if (fp->f_type != DTYPE_SOCKET) {
+ u.u_error = ENOTSOCK;
+ return;
+ }
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ aiov.iov_base = uap->buf;
+ aiov.iov_len = uap->len;
+ auio.uio_resid = uap->len;
+ auio.uio_segflg = 0;
+ auio.uio_offset = 0; /* XXX */
+ if (useracc(uap->buf, (u_int)uap->len, B_READ) == 0) {
+ u.u_error = EFAULT;
+ return;
+ }
+ if (u.u_error)
+ return;
+ u.u_error = sosend(fp->f_socket, (struct mbuf *)0, &auio, uap->flags);
+ u.u_r.r_val1 = uap->len - auio.uio_resid;
+}
+
+recvfrom()
+{
+ register struct a {
+ int s;
+ caddr_t buf;
+ int len;
+ int flags;
+ caddr_t from;
+ int *fromlenaddr;
+ } *uap = (struct a *)u.u_ap;
+ register struct file *fp;
+ struct uio auio;
+ struct iovec aiov;
+ struct mbuf *from;
+ int fromlen;
+
+ u.u_error = copyin((caddr_t)uap->fromlenaddr, (caddr_t)&fromlen,
+ sizeof (fromlen));
+ if (u.u_error)
+ return;
+ fp = getf(uap->s);
if (fp == 0)
return;
- if ((fp->f_flag & FSOCKET) == 0) {
+ if (fp->f_type != DTYPE_SOCKET) {
u.u_error = ENOTSOCK;
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))) {
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ aiov.iov_base = uap->buf;
+ aiov.iov_len = uap->len;
+ auio.uio_resid = uap->len;
+ auio.uio_segflg = 0;
+ auio.uio_offset = 0; /* XXX */
+ if (useracc(uap->buf, (u_int)uap->len, B_WRITE) == 0) {
u.u_error = EFAULT;
return;
}
- u.u_error = soreceive(fp->f_socket, uap->asa ? &sa : 0);
+ from = 0;
+ u.u_error = soreceive(fp->f_socket, &from, &auio, uap->flags);
if (u.u_error)
+ goto bad;
+ if (from == 0)
+ fromlen = 0;
+ else {
+ if (fromlen > from->m_len)
+ fromlen = from->m_len;
+ u.u_error = copyout(mtod(from, caddr_t), uap->from,
+ (u_int)fromlen);
+ if (u.u_error)
+ goto bad;
+ }
+ u.u_error = copyout((caddr_t)&fromlen, (caddr_t)uap->fromlenaddr,
+ sizeof (fromlen));
+ if (u.u_error)
+ goto bad;
+ u.u_r.r_val1 = uap->len - auio.uio_resid;
+bad:
+ if (from)
+ m_freem(from);
+ return;
+}
+
+recv()
+{
+ register struct a {
+ int s;
+ caddr_t buf;
+ int len;
+ int flags;
+ } *uap = (struct a *)u.u_ap;
+ register struct file *fp;
+ struct uio auio;
+ struct iovec aiov;
+
+ fp = getf(uap->s);
+ if (fp == 0)
+ return;
+ if (fp->f_type != DTYPE_SOCKET) {
+ u.u_error = ENOTSOCK;
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;
+ }
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ aiov.iov_base = uap->buf;
+ aiov.iov_len = uap->len;
+ auio.uio_resid = uap->len;
+ auio.uio_segflg = 0;
+ auio.uio_offset = 0; /* XXX */
+ if (useracc(uap->buf, (u_int)uap->len, B_WRITE) == 0) {
+ u.u_error = EFAULT;
+ return;
+ }
+ u.u_error =
+ soreceive(fp->f_socket, (struct mbuf **)0, &auio, uap->flags);
+ u.u_r.r_val1 = uap->len - auio.uio_resid;
+}
+
+sendmsg()
+{
+
+ u.u_error = EINVAL;
+}
+
+recvmsg()
+{
+
+ u.u_error = EINVAL;
+}
+
+shutdown()
+{
+
+ u.u_error = EINVAL;
+}
+
+pipe()
+{
+ register struct file *rf, *wf;
+ struct socket *rso, *wso;
+ int r;
+
+ u.u_error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0,
+ (struct socketopt *)0);
+ if (u.u_error)
+ return;
+ u.u_error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0,
+ (struct socketopt *)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_socket = rso;
+ wf = falloc();
+ if (wf == NULL)
+ goto free3;
+ wf->f_flag = FWRITE;
+ wf->f_type = DTYPE_SOCKET;
+ 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;
+ 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);
}
/*
} *uap = (struct a *)u.u_ap;
register struct file *fp;
register struct socket *so;
- struct sockaddr addr;
-COUNT(SSOCKETADDR);
+ struct mbuf *m;
fp = getf(uap->fdes);
if (fp == 0)
return;
- if ((fp->f_flag & FSOCKET) == 0) {
+ if (fp->f_type != DTYPE_SOCKET) {
u.u_error = ENOTSOCK;
return;
}
so = fp->f_socket;
+ m = m_getclr(M_WAIT, MT_SONAME);
u.u_error =
- (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, (caddr_t)&addr);
+ (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0);
if (u.u_error)
- return;
- if (copyout((caddr_t)&addr, (caddr_t)uap->asa, sizeof (addr)))
- u.u_error = EFAULT;
+ goto bad;
+ u.u_error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa,
+ sizeof (struct sockaddr));
+bad:
+ m_freem(m);
+}
+
+sockname(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);
+ 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);
+}
+
+sockopt(so, opt)
+ register struct socketopt *so;
+ caddr_t opt;
+{
+ register struct mbuf *m;
+ int error;
+
+ if (opt == 0) {
+ so->so_optlen = 0;
+ so->so_optdata = 0;
+ return (0);
+ }
+ error = copyin((caddr_t)opt, (caddr_t)so, sizeof (struct socketopt));
+ if (error)
+ return (error);
+ if (so->so_optlen < 0 || so->so_optlen > MLEN)
+ return (EINVAL);
+ m = m_get(M_WAIT, MT_SOOPTS);
+ m->m_len = so->so_optlen;
+ error = copyin(so->so_optdata, mtod(m, caddr_t), (u_int)m->m_len);
+ if (error) {
+ (void) m_free(m);
+ return (error);
+ }
+ so->so_optdata = mtod(m, caddr_t);
+ return (0);
}