/* ipc.c 4.20 82/06/20 */ #include "sys/param.h" #include "sys/config.h" #include "sys/types.h" #include "sys/mmu.h" #include "sys/sysmacros.h" #include "sys/systm.h" #include "sys/signal.h" #include "sys/errno.h" #include "sys/dir.h" #include "sys/user.h" #include "sys/proc.h" #include "sys/file.h" #include "sys/inode.h" #include "sys/buf.h" #include "net/misc.h" /* #include "net/mbuf.h" */ #include "net/protosw.h" #include "net/socket.h" #include "net/socketvar.h" #include "net/in.h" #include "net/in_systm.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 */ /* * Socket system call interface. Copy sa arguments * set up file descriptor and call internal socket * creation routine. */ ssocket() { register struct ua { int type; struct sockproto *asp; struct sockaddr *asa; int options; } *uap = (struct ua *)u.u_ap; struct sockproto sp; struct sockaddr sa; struct socket *so; register struct file *fp; if ((fp = falloc((struct inode *)0, FSOCKET|FREAD|FWRITE)) == NULL) return; 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->f_count = 0; fp->f_next = ffreelist; ffreelist = fp; 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 = (off_t)so; return; bad: u.u_ofile[u.u_rval1] = 0; fp->f_count = 0; fp->f_next = ffreelist; ffreelist = fp; } /* * Accept system call interface. */ saccept() { register struct a { int fdes; struct sockaddr *asa; } *uap = (struct a *)u.u_ap; struct sockaddr sa; register struct file *fp; struct socket *so; int s; if (uap->asa && useracc((caddr_t)uap->asa, sizeof (sa), B_WRITE)==0) { u.u_error = EFAULT; return; } fp = getf(uap->fdes); if (fp == 0) return; if ((fp->f_flag & FSOCKET) == 0) { u.u_error = ENOTSOCK; return; } s = splnet(); so = (struct socket *)fp->f_socket; if ((so->so_state & SS_NBIO) && (so->so_state & SS_CONNAWAITING) == 0) { u.u_error = EWOULDBLOCK; splx(s); return; } while ((so->so_state & SS_CONNAWAITING) == 0 && so->so_error == 0) { if (so->so_state & SS_CANTRCVMORE) { so->so_error = ECONNABORTED; break; } (void) sleep((caddr_t)&so->so_timeo, PZERO+1); } if (so->so_error) { u.u_error = so->so_error; splx(s); return; } u.u_error = soaccept(so, &sa); if (u.u_error) { 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 = ... */ splx(s); } /* * Connect socket to foreign peer; system call * interface. Copy sa arguments and call internal routine. */ sconnect() { register struct ua { int fdes; struct sockaddr *a; } *uap = (struct ua *)u.u_ap; struct sockaddr sa; register struct file *fp; register struct socket *so; int s; if (copyin((caddr_t)uap->a, (caddr_t)&sa, sizeof (sa))) { u.u_error = EFAULT; return; } fp = getf(uap->fdes); if (fp == 0) return; if ((fp->f_flag & FSOCKET) == 0) { u.u_error = ENOTSOCK; return; } so = (struct socket *)fp->f_socket; u.u_error = soconnect(so, &sa); if (u.u_error) return; s = splnet(); if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { u.u_error = EINPROGRESS; splx(s); return; } while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) (void) sleep((caddr_t)&so->so_timeo, PZERO+1); u.u_error = so->so_error; so->so_error = 0; splx(s); } /* * Send data on socket. */ ssend() { register struct a { int fdes; struct sockaddr *asa; caddr_t cbuf; unsigned count; } *uap = (struct a *)u.u_ap; register struct file *fp; struct sockaddr sa; fp = getf(uap->fdes); if (fp == 0) return; if ((fp->f_flag & FSOCKET) == 0) { 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))) { u.u_error = EFAULT; return; } u.u_error = sosend((struct socket *)fp->f_socket, uap->asa ? &sa : 0); u.u_rval1 = uap->count - u.u_count; } /* * Receive data on socket. */ sreceive() { register struct a { int fdes; struct sockaddr *asa; caddr_t cbuf; u_int count; } *uap = (struct a *)u.u_ap; register struct file *fp; struct sockaddr sa; fp = getf(uap->fdes); if (fp == 0) return; if ((fp->f_flag & FSOCKET) == 0) { 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))) { u.u_error = EFAULT; return; } u.u_error = soreceive((struct socket *)fp->f_socket, uap->asa ? &sa : 0); if (u.u_error) return; if (uap->asa) (void) copyout((caddr_t)&sa, (caddr_t)uap->asa, sizeof (sa)); u.u_rval1 = uap->count - u.u_count; } /* * Get socket address. */ ssocketaddr() { register struct a { int fdes; struct sockaddr *asa; } *uap = (struct a *)u.u_ap; register struct file *fp; register struct socket *so; struct sockaddr addr; fp = getf(uap->fdes); if (fp == 0) return; if ((fp->f_flag & FSOCKET) == 0) { u.u_error = ENOTSOCK; return; } so = (struct socket *)fp->f_socket; u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, (caddr_t)&addr); if (u.u_error) return; if (copyout((caddr_t)&addr, (caddr_t)uap->asa, sizeof (addr))) u.u_error = EFAULT; }