diff options
author | rrs <rrs@FreeBSD.org> | 2006-11-03 15:23:16 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2006-11-03 15:23:16 +0000 |
commit | 3d3e3f2242423b47549f89486754bc40030fbe9f (patch) | |
tree | 0ec895f64207afbb268edd872d01288ffc058501 /sys/kern | |
parent | d23275fe7d190eab56c82bf462ecb67346e58ab3 (diff) | |
download | FreeBSD-src-3d3e3f2242423b47549f89486754bc40030fbe9f.zip FreeBSD-src-3d3e3f2242423b47549f89486754bc40030fbe9f.tar.gz |
Ok, here it is, we finally add SCTP to current. Note that this
work is not just mine, but it is also the works of Peter Lei
and Michael Tuexen. They both are my two key other developers
working on the project.. and they need ata-boy's too:
****
peterlei@cisco.com
tuexen@fh-muenster.de
****
I did do a make sysent which updated the
syscall's and sysproto.. I hope that is correct... without
it you don't build since we have new syscalls for SCTP :-0
So go out and look at the NOTES, add
option SCTP (make sure inet and inet6 are present too)
and play with SCTP.
I will see about comitting some test tools I have after I
figure out where I should place them. I also have a
lib (libsctp.a) that adds some of the missing socketapi
functions that I need to put into lib's.. I will talk
to George about this :-)
There may still be some 64 bit issues in here, none of
us have a 64 bit processor to test with yet.. Michael
may have a MAC but thats another beast too..
If you have a mac and want to use SCTP contact Michael
he maintains a web site with a loadable module with
this code :-)
Reviewed by: gnn
Approved by: gnn
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/init_sysent.c | 4 | ||||
-rw-r--r-- | sys/kern/syscalls.c | 4 | ||||
-rw-r--r-- | sys/kern/syscalls.master | 10 | ||||
-rw-r--r-- | sys/kern/systrace_args.c | 47 | ||||
-rw-r--r-- | sys/kern/uipc_syscalls.c | 451 |
5 files changed, 516 insertions, 0 deletions
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index b98c6d4..35de9e9 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -500,4 +500,8 @@ struct sysent sysent[] = { { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0 }, /* 468 = nosys */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0 }, /* 469 = __getpath_fromfd */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0 }, /* 470 = __getpath_fromaddr */ + { AS(sctp_peeloff_args), (sy_call_t *)sctp_peeloff, AUE_NULL, NULL, 0, 0 }, /* 471 = sctp_peeloff */ + { AS(sctp_generic_sendmsg_args), (sy_call_t *)sctp_generic_sendmsg, AUE_NULL, NULL, 0, 0 }, /* 472 = sctp_generic_sendmsg */ + { AS(sctp_generic_sendmsg_iov_args), (sy_call_t *)sctp_generic_sendmsg_iov, AUE_NULL, NULL, 0, 0 }, /* 473 = sctp_generic_sendmsg_iov */ + { AS(sctp_generic_recvmsg_args), (sy_call_t *)sctp_generic_recvmsg, AUE_NULL, NULL, 0, 0 }, /* 474 = sctp_generic_recvmsg */ }; diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index c72425c..0fa7b5b 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -478,4 +478,8 @@ const char *syscallnames[] = { "#468", /* 468 = nosys */ "#469", /* 469 = __getpath_fromfd */ "#470", /* 470 = __getpath_fromaddr */ + "sctp_peeloff", /* 471 = sctp_peeloff */ + "sctp_generic_sendmsg", /* 472 = sctp_generic_sendmsg */ + "sctp_generic_sendmsg_iov", /* 473 = sctp_generic_sendmsg_iov */ + "sctp_generic_recvmsg", /* 474 = sctp_generic_recvmsg */ }; diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 54e7c39..dd9e25f 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -825,5 +825,15 @@ 468 AUE_NULL UNIMPL nosys 469 AUE_NULL UNIMPL __getpath_fromfd 470 AUE_NULL UNIMPL __getpath_fromaddr +471 AUE_NULL STD { int sctp_peeloff(int sd, uint32_t name); } +472 AUE_NULL STD { int sctp_generic_sendmsg(int sd, caddr_t msg, int mlen, \ + caddr_t to, __socklen_t tolen, \ + struct sctp_sndrcvinfo *sinfo, int flags); } +473 AUE_NULL STD { int sctp_generic_sendmsg_iov(int sd, struct iovec *iov, int iovlen, \ + caddr_t to, __socklen_t tolen, \ + struct sctp_sndrcvinfo *sinfo, int flags); } +474 AUE_NULL STD { int sctp_generic_recvmsg(int sd, struct iovec *iov, int iovlen, \ + struct sockaddr * from, __socklen_t *fromlenaddr, \ + struct sctp_sndrcvinfo *sinfo, int *msg_flags); } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c index aa7e726..6aef4a0 100644 --- a/sys/kern/systrace_args.c +++ b/sys/kern/systrace_args.c @@ -2758,6 +2758,53 @@ systrace_args(int sysnum, void *params, u_int64_t *uarg, int *n_args) *n_args = 3; break; } + /* sctp_peeloff */ + case 471: { + struct sctp_peeloff_args *p = params; + iarg[0] = p->sd; /* int */ + uarg[1] = p->name; /* uint32_t */ + *n_args = 2; + break; + } + /* sctp_generic_sendmsg */ + case 472: { + struct sctp_generic_sendmsg_args *p = params; + iarg[0] = p->sd; /* int */ + uarg[1] = (intptr_t) p->msg; /* caddr_t */ + iarg[2] = p->mlen; /* int */ + uarg[3] = (intptr_t) p->to; /* caddr_t */ + iarg[4] = p->tolen; /* __socklen_t */ + uarg[5] = (intptr_t) p->sinfo; /* struct sctp_sndrcvinfo * */ + iarg[6] = p->flags; /* int */ + *n_args = 7; + break; + } + /* sctp_generic_sendmsg_iov */ + case 473: { + struct sctp_generic_sendmsg_iov_args *p = params; + iarg[0] = p->sd; /* int */ + uarg[1] = (intptr_t) p->iov; /* struct iovec * */ + iarg[2] = p->iovlen; /* int */ + uarg[3] = (intptr_t) p->to; /* caddr_t */ + iarg[4] = p->tolen; /* __socklen_t */ + uarg[5] = (intptr_t) p->sinfo; /* struct sctp_sndrcvinfo * */ + iarg[6] = p->flags; /* int */ + *n_args = 7; + break; + } + /* sctp_generic_recvmsg */ + case 474: { + struct sctp_generic_recvmsg_args *p = params; + iarg[0] = p->sd; /* int */ + uarg[1] = (intptr_t) p->iov; /* struct iovec * */ + iarg[2] = p->iovlen; /* int */ + uarg[3] = (intptr_t) p->from; /* struct sockaddr * */ + uarg[4] = (intptr_t) p->fromlenaddr; /* __socklen_t * */ + uarg[5] = (intptr_t) p->sinfo; /* struct sctp_sndrcvinfo * */ + uarg[6] = (intptr_t) p->msg_flags; /* int * */ + *n_args = 7; + break; + } default: *n_args = 0; break; diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 1636a69..6951f4c 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -35,6 +35,7 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_sctp.h" #include "opt_compat.h" #include "opt_ktrace.h" #include "opt_mac.h" @@ -76,6 +77,11 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_kern.h> #include <vm/vm_extern.h> +#ifdef SCTP +#include <netinet/sctp.h> +#include <netinet/sctp_peeloff.h> +#endif /* SCTP */ + static int sendit(struct thread *td, int s, struct msghdr *mp, int flags); static int recvit(struct thread *td, int s, struct msghdr *mp, void *namelenp); @@ -2319,3 +2325,448 @@ done: return (error); } + + +int +sctp_peeloff(td, uap) + struct thread *td; + register struct sctp_peeloff_args /* { + int sd; + caddr_t name; + } */ *uap; +{ +#ifdef SCTP + struct filedesc *fdp; + struct file *nfp = NULL; + int error; + struct socket *head, *so; + int fd; + u_int fflag; + + fdp = td->td_proc->p_fd; + error = fgetsock(td, uap->sd, &head, &fflag); + if (error) + goto done2; + error = sctp_can_peel_off(head, (sctp_assoc_t)uap->name); + if (error) + goto done2; + /* + * At this point we know we do have a assoc to pull + * we proceed to get the fd setup. This may block + * but that is ok. + */ + + error = falloc(td, &nfp, &fd); + if (error) + goto done; + td->td_retval[0] = fd; + + so = sonewconn(head, SS_ISCONNECTED); + if (so == NULL) + goto noconnection; + /* + * Before changing the flags on the socket, we have to bump the + * reference count. Otherwise, if the protocol calls sofree(), + * the socket will be released due to a zero refcount. + */ + SOCK_LOCK(so); + soref(so); /* file descriptor reference */ + SOCK_UNLOCK(so); + + ACCEPT_LOCK(); + + TAILQ_REMOVE(&head->so_comp, so, so_list); + head->so_qlen--; + so->so_state |= (head->so_state & SS_NBIO); + so->so_state &= ~SS_NOFDREF; + so->so_qstate &= ~SQ_COMP; + so->so_head = NULL; + + ACCEPT_UNLOCK(); + + error = sctp_do_peeloff(head, so, (sctp_assoc_t)uap->name); + if (error) + goto noconnection; + if (head->so_sigio != NULL) + fsetown(fgetown(&head->so_sigio), &so->so_sigio); + + FILE_LOCK(nfp); + nfp->f_data = so; + nfp->f_flag = fflag; + nfp->f_ops = &socketops; + nfp->f_type = DTYPE_SOCKET; + FILE_UNLOCK(nfp); + + noconnection: + /* + * close the new descriptor, assuming someone hasn't ripped it + * out from under us. + */ + if (error) + fdclose(fdp, nfp, fd, td); + + /* + * Release explicitly held references before returning. + */ + done: + if (nfp != NULL) + fdrop(nfp, td); + fputsock(head); + done2: + return (error); +#else + return (EOPNOTSUPP); +#endif +} + + +int sctp_generic_sendmsg (td, uap) + struct thread *td; + register struct sctp_generic_sendmsg_args /* { + int sd, + caddr_t msg, + int mlen, + caddr_t to, + __socklen_t tolen, + struct sctp_sndrcvinfo *sinfo, + int flags + } */ *uap; +{ +#ifdef SCTP + struct sctp_sndrcvinfo sinfo, *u_sinfo=NULL; + struct socket *so; + struct file *fp; + int use_rcvinfo=1; + int error=0, len; + struct sockaddr *to=NULL; +#ifdef KTRACE + struct uio *ktruio = NULL; +#endif + struct uio auio; + struct iovec iov[1]; + + if(uap->sinfo) { + error = copyin(uap->sinfo, &sinfo, sizeof (sinfo)); + if (error) + return (error); + u_sinfo = &sinfo; + } + + if(uap->tolen) { + error = getsockaddr(&to, uap->to, uap->tolen); + if (error) { + to = NULL; + goto sctp_bad2; + } + } + error = getsock(td->td_proc->p_fd, uap->sd, &fp, NULL); + if (error) + goto sctp_bad; + + iov[0].iov_base = uap->msg; + iov[0].iov_len = uap->mlen; + + so = (struct socket *)fp->f_data; +#ifdef MAC + SOCK_LOCK(so); + error = mac_check_socket_send(td->td_ucred, so); + SOCK_UNLOCK(so); + if (error) + goto sctp_bad; +#endif + + + auio.uio_iov = iov; + auio.uio_iovcnt = 1; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_rw = UIO_WRITE; + auio.uio_td = td; + auio.uio_offset = 0; /* XXX */ + auio.uio_resid = 0; + len = auio.uio_resid = uap->mlen; + error = sctp_lower_sosend(so, + to, + &auio, + (struct mbuf *)NULL, + (struct mbuf *)NULL, + uap->flags, + use_rcvinfo, + u_sinfo, + td ); + + if (error) { + if (auio.uio_resid != len && (error == ERESTART || + error == EINTR || error == EWOULDBLOCK)) + error = 0; + /* Generation of SIGPIPE can be controlled per socket */ + if (error == EPIPE && !(so->so_options & SO_NOSIGPIPE) && + !(uap->flags & MSG_NOSIGNAL)) { + PROC_LOCK(td->td_proc); + psignal(td->td_proc, SIGPIPE); + PROC_UNLOCK(td->td_proc); + } + } + if (error == 0) + td->td_retval[0] = len - auio.uio_resid; +#ifdef KTRACE + if (ktruio != NULL) { + ktruio->uio_resid = td->td_retval[0]; + ktrgenio(uap->sd, UIO_WRITE, ktruio, error); + } +#endif + sctp_bad: + fdrop(fp, td); + sctp_bad2: + if (to) + FREE(to, M_SONAME); + + return (error); +#else + return (EOPNOTSUPP); +#endif +} + + +int sctp_generic_sendmsg_iov(td, uap) + struct thread *td; + register struct sctp_generic_sendmsg_iov_args /* { + int sd, + struct iovec *iov, + int iovlen, + caddr_t to, + __socklen_t tolen, + struct sctp_sndrcvinfo *sinfo, + int flags + } */ *uap; +{ +#ifdef SCTP + struct sctp_sndrcvinfo sinfo, *u_sinfo=NULL; + struct socket *so; + struct file *fp; + int use_rcvinfo=1; + int error=0, len, i; + struct sockaddr *to=NULL; +#ifdef KTRACE + struct uio *ktruio = NULL; +#endif + struct uio auio; + struct iovec *iov, *tiov; + + if(uap->sinfo) { + error = copyin(uap->sinfo, &sinfo, sizeof (sinfo)); + if (error) + return (error); + u_sinfo = &sinfo; + } + + if(uap->tolen) { + error = getsockaddr(&to, uap->to, uap->tolen); + if (error) { + to = NULL; + goto sctp_bad2; + } + } + error = getsock(td->td_proc->p_fd, uap->sd, &fp, NULL); + if (error) + goto sctp_bad1; + + error = copyiniov(uap->iov, uap->iovlen, &iov, EMSGSIZE); + if (error) + goto sctp_bad1; + + + so = (struct socket *)fp->f_data; +#ifdef MAC + SOCK_LOCK(so); + error = mac_check_socket_send(td->td_ucred, so); + SOCK_UNLOCK(so); + if (error) + goto sctp_bad; +#endif + + + auio.uio_iov = iov; + auio.uio_iovcnt = uap->iovlen; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_rw = UIO_WRITE; + auio.uio_td = td; + auio.uio_offset = 0; /* XXX */ + auio.uio_resid = 0; + tiov = iov; + for (i = 0; i <uap->iovlen; i++, tiov++) { + if ((auio.uio_resid += tiov->iov_len) < 0) { + error = EINVAL; + goto sctp_bad; + } + } + len = auio.uio_resid; + error = sctp_lower_sosend(so, + to, + &auio, + (struct mbuf *)NULL, + (struct mbuf *)NULL, + uap->flags, + use_rcvinfo, + u_sinfo, + td ); + + if (error) { + if (auio.uio_resid != len && (error == ERESTART || + error == EINTR || error == EWOULDBLOCK)) + error = 0; + /* Generation of SIGPIPE can be controlled per socket */ + if (error == EPIPE && !(so->so_options & SO_NOSIGPIPE) && + !(uap->flags & MSG_NOSIGNAL)) { + PROC_LOCK(td->td_proc); + psignal(td->td_proc, SIGPIPE); + PROC_UNLOCK(td->td_proc); + } + } + if (error == 0) + td->td_retval[0] = len - auio.uio_resid; +#ifdef KTRACE + if (ktruio != NULL) { + ktruio->uio_resid = td->td_retval[0]; + ktrgenio(uap->sd, UIO_WRITE, ktruio, error); + } +#endif + sctp_bad: + free(iov, M_IOV); + sctp_bad1: + fdrop(fp, td); + sctp_bad2: + if (to) + FREE(to, M_SONAME); + + return (error); +#else + return (EOPNOTSUPP); +#endif +} + +int sctp_generic_recvmsg(td, uap) + struct thread *td; + register struct sctp_generic_recvmsg_args /* { + int sd, + struct iovec *iov, + int iovlen, + struct sockaddr *from, + __socklen_t *fromlenaddr, + struct sctp_sndrcvinfo *sinfo, + int *msg_flags + } */ *uap; +{ +#ifdef SCTP + u_int8_t sockbufstore[256]; + struct uio auio; + struct iovec *iov, *tiov; + struct sctp_sndrcvinfo sinfo; + struct socket *so; + struct file *fp; + struct sockaddr *fromsa; + int fromlen; + int len, i, msg_flags=0; + int error=0; +#ifdef KTRACE + struct uio *ktruio = NULL; +#endif + error = getsock(td->td_proc->p_fd, uap->sd, &fp, NULL); + if (error) { + return (error); + } + error = copyiniov(uap->iov, uap->iovlen, &iov, EMSGSIZE); + if (error) { + goto out1; + } + so = fp->f_data; +#ifdef MAC + SOCK_LOCK(so); + error = mac_check_socket_receive(td->td_ucred, so); + SOCK_UNLOCK(so); + if (error) { + goto out; + return (error); + } +#endif + if (uap->fromlenaddr) { + error = copyin(uap->fromlenaddr, + &fromlen, sizeof (fromlen)); + if (error) { + goto out; + } + } else { + fromlen = 0; + } + + + auio.uio_iov = iov; + auio.uio_iovcnt = uap->iovlen; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_rw = UIO_READ; + auio.uio_td = td; + auio.uio_offset = 0; /* XXX */ + auio.uio_resid = 0; + tiov = iov; + for (i = 0; i <uap->iovlen; i++, tiov++) { + if ((auio.uio_resid += tiov->iov_len) < 0) { + error = EINVAL; + goto out; + } + } + len = auio.uio_resid; + fromsa = (struct sockaddr *)sockbufstore; +#ifdef KTRACE + if (KTRPOINT(td, KTR_GENIO)) + ktruio = cloneuio(&auio); +#endif + error = sctp_sorecvmsg(so, &auio, (struct mbuf **)NULL, + fromsa, fromlen, &msg_flags, (struct sctp_sndrcvinfo *)&sinfo, + 1); + if (error) { + if (auio.uio_resid != (int)len && (error == ERESTART || + error == EINTR || error == EWOULDBLOCK)) + error = 0; + } else { + if(uap->sinfo) + error = copyout(&sinfo, uap->sinfo, sizeof (sinfo)); + } +#ifdef KTRACE + if (ktruio != NULL) { + ktruio->uio_resid = (int)len - auio.uio_resid; + ktrgenio(uap->sd, UIO_READ, ktruio, error); + } +#endif + if (error) + goto out; + td->td_retval[0] = (int)len - auio.uio_resid; + if (fromlen && uap->from) { + len = fromlen; + if (len <= 0 || fromsa == 0) + len = 0; + else { + len = MIN(len, fromsa->sa_len); + error = copyout(fromsa, uap->from, (unsigned)len); + if (error) + goto out; + } + error = copyout(&len, uap->fromlenaddr, sizeof (socklen_t)); + if(error) { + goto out; + } + } + if (uap->msg_flags) { + error = copyout(&msg_flags, uap->msg_flags, sizeof (int)); + if(error) { + goto out; + } + } +out: + free(iov, M_IOV); +out1: + fdrop(fp, td); + return (error); +#else + return (EOPNOTSUPP); +#endif + +} |