summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2006-11-03 15:23:16 +0000
committerrrs <rrs@FreeBSD.org>2006-11-03 15:23:16 +0000
commit3d3e3f2242423b47549f89486754bc40030fbe9f (patch)
tree0ec895f64207afbb268edd872d01288ffc058501 /sys/kern
parentd23275fe7d190eab56c82bf462ecb67346e58ab3 (diff)
downloadFreeBSD-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.c4
-rw-r--r--sys/kern/syscalls.c4
-rw-r--r--sys/kern/syscalls.master10
-rw-r--r--sys/kern/systrace_args.c47
-rw-r--r--sys/kern/uipc_syscalls.c451
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
+
+}
OpenPOWER on IntegriCloud