Author: tuexen
Date: Sun Sep  5 20:13:07 2010
New Revision: 212242
URL: http://svn.freebsd.org/changeset/base/212242

Log:
  Implement correct handling of address parameter and
  sendinfo for SCTP send calls.
  
  MFC after: 4 weeks.

Modified:
  head/sys/kern/uipc_syscalls.c
  head/sys/netinet/sctp_output.c
  head/sys/netinet/sctp_uio.h

Modified: head/sys/kern/uipc_syscalls.c
==============================================================================
--- head/sys/kern/uipc_syscalls.c       Sun Sep  5 20:04:54 2010        
(r212241)
+++ head/sys/kern/uipc_syscalls.c       Sun Sep  5 20:13:07 2010        
(r212242)
@@ -2381,7 +2381,6 @@ sctp_generic_sendmsg (td, uap)
        struct sctp_sndrcvinfo sinfo, *u_sinfo = NULL;
        struct socket *so;
        struct file *fp = NULL;
-       int use_rcvinfo = 1;
        int error = 0, len;
        struct sockaddr *to = NULL;
 #ifdef KTRACE
@@ -2434,7 +2433,7 @@ sctp_generic_sendmsg (td, uap)
        CURVNET_SET(so->so_vnet);
        error = sctp_lower_sosend(so, to, &auio,
                    (struct mbuf *)NULL, (struct mbuf *)NULL,
-                   uap->flags, use_rcvinfo, u_sinfo, td);
+                   uap->flags, u_sinfo, td);
        CURVNET_RESTORE();
        if (error) {
                if (auio.uio_resid != len && (error == ERESTART ||
@@ -2485,7 +2484,6 @@ sctp_generic_sendmsg_iov(td, uap)
        struct sctp_sndrcvinfo sinfo, *u_sinfo = NULL;
        struct socket *so;
        struct file *fp = NULL;
-       int use_rcvinfo = 1;
        int error=0, len, i;
        struct sockaddr *to = NULL;
 #ifdef KTRACE
@@ -2552,7 +2550,7 @@ sctp_generic_sendmsg_iov(td, uap)
        CURVNET_SET(so->so_vnet);
        error = sctp_lower_sosend(so, to, &auio,
                    (struct mbuf *)NULL, (struct mbuf *)NULL,
-                   uap->flags, use_rcvinfo, u_sinfo, td);
+                   uap->flags, u_sinfo, td);
        CURVNET_RESTORE();
        if (error) {
                if (auio.uio_resid != len && (error == ERESTART ||

Modified: head/sys/netinet/sctp_output.c
==============================================================================
--- head/sys/netinet/sctp_output.c      Sun Sep  5 20:04:54 2010        
(r212241)
+++ head/sys/netinet/sctp_output.c      Sun Sep  5 20:13:07 2010        
(r212242)
@@ -12158,7 +12158,7 @@ sctp_sosend(struct socket *so,
        error = sctp_lower_sosend(so, addr_to_use, uio, top,
            control,
            flags,
-           use_rcvinfo, &srcv
+           use_rcvinfo ? &srcv : NULL
            ,p
            );
        return (error);
@@ -12172,7 +12172,6 @@ sctp_lower_sosend(struct socket *so,
     struct mbuf *i_pak,
     struct mbuf *control,
     int flags,
-    int use_rcvinfo,
     struct sctp_sndrcvinfo *srcv
     ,
     struct thread *p
@@ -12200,8 +12199,10 @@ sctp_lower_sosend(struct socket *so,
        int got_all_of_the_send = 0;
        int hold_tcblock = 0;
        int non_blocking = 0;
-       int temp_flags = 0;
        uint32_t local_add_more, local_soresv = 0;
+       uint16_t port;
+       uint16_t sinfo_flags;
+       sctp_assoc_t sinfo_assoc_id;
 
        error = 0;
        net = NULL;
@@ -12236,28 +12237,39 @@ sctp_lower_sosend(struct socket *so,
        SCTPDBG(SCTP_DEBUG_OUTPUT1, "Send called addr:%p send length %d\n",
            addr,
            sndlen);
+       if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
+           (inp->sctp_socket->so_qlimit)) {
+               /* The listener can NOT send */
+               SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, 
ENOTCONN);
+               error = ENOTCONN;
+               goto out_unlocked;
+       }
        /**
         * Pre-screen address, if one is given the sin-len
         * must be set correctly!
         */
        if (addr) {
-               switch (addr->sa_family) {
+               union sctp_sockstore *raddr = (union sctp_sockstore *)addr;
+
+               switch (raddr->sa.sa_family) {
 #if defined(INET)
                case AF_INET:
-                       if (addr->sa_len != sizeof(struct sockaddr_in)) {
+                       if (raddr->sin.sin_len != sizeof(struct sockaddr_in)) {
                                SCTP_LTRACE_ERR_RET(inp, stcb, net, 
SCTP_FROM_SCTP_OUTPUT, EINVAL);
                                error = EINVAL;
                                goto out_unlocked;
                        }
+                       port = raddr->sin.sin_port;
                        break;
 #endif
 #if defined(INET6)
                case AF_INET6:
-                       if (addr->sa_len != sizeof(struct sockaddr_in6)) {
+                       if (raddr->sin6.sin6_len != sizeof(struct 
sockaddr_in6)) {
                                SCTP_LTRACE_ERR_RET(inp, stcb, net, 
SCTP_FROM_SCTP_OUTPUT, EINVAL);
                                error = EINVAL;
                                goto out_unlocked;
                        }
+                       port = raddr->sin6.sin6_port;
                        break;
 #endif
                default:
@@ -12265,32 +12277,34 @@ sctp_lower_sosend(struct socket *so,
                        error = EAFNOSUPPORT;
                        goto out_unlocked;
                }
-       }
-       hold_tcblock = 0;
+       } else
+               port = 0;
 
-       if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
-           (inp->sctp_socket->so_qlimit)) {
-               /* The listener can NOT send */
-               SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, 
ENOTCONN);
-               error = ENOTCONN;
-               goto out_unlocked;
-       }
-       if ((use_rcvinfo) && srcv) {
-               if (INVALID_SINFO_FLAG(srcv->sinfo_flags) ||
-                   PR_SCTP_INVALID_POLICY(srcv->sinfo_flags)) {
+       if (srcv) {
+               sinfo_flags = srcv->sinfo_flags;
+               sinfo_assoc_id = srcv->sinfo_assoc_id;
+               if (INVALID_SINFO_FLAG(sinfo_flags) ||
+                   PR_SCTP_INVALID_POLICY(sinfo_flags)) {
                        SCTP_LTRACE_ERR_RET(inp, stcb, net, 
SCTP_FROM_SCTP_OUTPUT, EINVAL);
                        error = EINVAL;
                        goto out_unlocked;
                }
                if (srcv->sinfo_flags)
                        SCTP_STAT_INCR(sctps_sends_with_flags);
-
-               if (srcv->sinfo_flags & SCTP_SENDALL) {
-                       /* its a sendall */
-                       error = sctp_sendall(inp, uio, top, srcv);
-                       top = NULL;
-                       goto out_unlocked;
-               }
+       } else {
+               sinfo_flags = inp->def_send.sinfo_flags;
+               sinfo_assoc_id = inp->def_send.sinfo_assoc_id;
+       }
+       if (sinfo_flags & SCTP_SENDALL) {
+               /* its a sendall */
+               error = sctp_sendall(inp, uio, top, srcv);
+               top = NULL;
+               goto out_unlocked;
+       }
+       if ((sinfo_flags & SCTP_ADDR_OVER) && (addr == NULL)) {
+               SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, 
EINVAL);
+               error = EINVAL;
+               goto out_unlocked;
        }
        /* now we must find the assoc */
        if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) ||
@@ -12306,80 +12320,8 @@ sctp_lower_sosend(struct socket *so,
                SCTP_TCB_LOCK(stcb);
                hold_tcblock = 1;
                SCTP_INP_RUNLOCK(inp);
-               if (addr) {
-                       /* Must locate the net structure if addr given */
-                       net = sctp_findnet(stcb, addr);
-                       if (net) {
-                               /* validate port was 0 or correct */
-                               struct sockaddr_in *sin;
-
-                               sin = (struct sockaddr_in *)addr;
-                               if ((sin->sin_port != 0) &&
-                                   (sin->sin_port != stcb->rport)) {
-                                       net = NULL;
-                               }
-                       }
-                       temp_flags |= SCTP_ADDR_OVER;
-               } else
-                       net = stcb->asoc.primary_destination;
-               if (addr && (net == NULL)) {
-                       /* Could not find address, was it legal */
-                       if (addr->sa_family == AF_INET) {
-                               struct sockaddr_in *sin;
-
-                               sin = (struct sockaddr_in *)addr;
-                               if (sin->sin_addr.s_addr == 0) {
-                                       if ((sin->sin_port == 0) ||
-                                           (sin->sin_port == stcb->rport)) {
-                                               net = 
stcb->asoc.primary_destination;
-                                       }
-                               }
-                       } else {
-                               struct sockaddr_in6 *sin6;
-
-                               sin6 = (struct sockaddr_in6 *)addr;
-                               if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
-                                       if ((sin6->sin6_port == 0) ||
-                                           (sin6->sin6_port == stcb->rport)) {
-                                               net = 
stcb->asoc.primary_destination;
-                                       }
-                               }
-                       }
-               }
-               if (net == NULL) {
-                       SCTP_LTRACE_ERR_RET(inp, stcb, net, 
SCTP_FROM_SCTP_OUTPUT, EINVAL);
-                       error = EINVAL;
-                       goto out_unlocked;
-               }
-       } else if (use_rcvinfo && srcv && srcv->sinfo_assoc_id) {
-               stcb = sctp_findassociation_ep_asocid(inp, 
srcv->sinfo_assoc_id, 0);
-               if (stcb) {
-                       if (addr)
-                               /*
-                                * Must locate the net structure if addr
-                                * given
-                                */
-                               net = sctp_findnet(stcb, addr);
-                       else
-                               net = stcb->asoc.primary_destination;
-                       if ((srcv->sinfo_flags & SCTP_ADDR_OVER) &&
-                           ((net == NULL) || (addr == NULL))) {
-                               struct sockaddr_in *sin;
-
-                               if (addr == NULL) {
-                                       SCTP_LTRACE_ERR_RET(inp, stcb, net, 
SCTP_FROM_SCTP_OUTPUT, EINVAL);
-                                       error = EINVAL;
-                                       goto out_unlocked;
-                               }
-                               sin = (struct sockaddr_in *)addr;
-                               /* Validate port is 0 or correct */
-                               if ((sin->sin_port != 0) &&
-                                   (sin->sin_port != stcb->rport)) {
-                                       net = NULL;
-                               }
-                       }
-               }
-               hold_tcblock = 0;
+       } else if (sinfo_assoc_id) {
+               stcb = sctp_findassociation_ep_asocid(inp, sinfo_assoc_id, 0);
        } else if (addr) {
                /*-
                 * Since we did not use findep we must
@@ -12452,10 +12394,8 @@ sctp_lower_sosend(struct socket *so,
                         */
                        uint32_t vrf_id;
 
-                       if ((use_rcvinfo) && (srcv) &&
-                           ((srcv->sinfo_flags & SCTP_ABORT) ||
-                           ((srcv->sinfo_flags & SCTP_EOF) &&
-                           (sndlen == 0)))) {
+                       if ((sinfo_flags & SCTP_ABORT) ||
+                           ((sinfo_flags & SCTP_EOF) && (sndlen == 0))) {
                                /*-
                                 * User asks to abort a non-existant assoc,
                                 * or EOF a non-existant assoc with no data
@@ -12584,10 +12524,25 @@ sctp_lower_sosend(struct socket *so,
                         * structure may now have an update and thus we may 
need to
                         * change it BEFORE we append the message.
                         */
-                       net = stcb->asoc.primary_destination;
-                       asoc = &stcb->asoc;
                }
        }
+       if (srcv == NULL)
+               srcv = (struct sctp_sndrcvinfo *)&stcb->asoc.def_send;
+       if (srcv->sinfo_flags & SCTP_ADDR_OVER) {
+               if (addr)
+                       net = sctp_findnet(stcb, addr);
+               else
+                       net = NULL;
+               if ((net == NULL) ||
+                   ((port != 0) && (port != stcb->rport))) {
+                       SCTP_LTRACE_ERR_RET(inp, stcb, net, 
SCTP_FROM_SCTP_OUTPUT, EINVAL);
+                       error = EINVAL;
+                       goto out_unlocked;
+               }
+       } else {
+               net = stcb->asoc.primary_destination;
+       }
+
        if ((SCTP_SO_IS_NBIO(so)
            || (flags & MSG_NBIO)
            )) {
@@ -12658,10 +12613,6 @@ sctp_lower_sosend(struct socket *so,
            (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) {
                queue_only = 1;
        }
-       if ((use_rcvinfo == 0) || (srcv == NULL)) {
-               /* Grab the default stuff from the asoc */
-               srcv = (struct sctp_sndrcvinfo *)&stcb->asoc.def_send;
-       }
        /* we are now done with all control */
        if (control) {
                sctp_m_freem(control);
@@ -12671,8 +12622,7 @@ sctp_lower_sosend(struct socket *so,
            (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) ||
            (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT) ||
            (asoc->state & SCTP_STATE_SHUTDOWN_PENDING)) {
-               if ((use_rcvinfo) &&
-                   (srcv->sinfo_flags & SCTP_ABORT)) {
+               if (srcv->sinfo_flags & SCTP_ABORT) {
                        ;
                } else {
                        SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, 
SCTP_FROM_SCTP_OUTPUT, ECONNRESET);
@@ -12684,16 +12634,6 @@ sctp_lower_sosend(struct socket *so,
        if (p) {
                p->td_ru.ru_msgsnd++;
        }
-       if (stcb) {
-               if (((srcv->sinfo_flags | temp_flags) & SCTP_ADDR_OVER) == 0) {
-                       net = stcb->asoc.primary_destination;
-               }
-       }
-       if (net == NULL) {
-               SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, 
EINVAL);
-               error = EINVAL;
-               goto out_unlocked;
-       }
        if ((net->flight_size > net->cwnd) &&
            (asoc->sctp_cmt_on_off == 0)) {
                /*-

Modified: head/sys/netinet/sctp_uio.h
==============================================================================
--- head/sys/netinet/sctp_uio.h Sun Sep  5 20:04:54 2010        (r212241)
+++ head/sys/netinet/sctp_uio.h Sun Sep  5 20:13:07 2010        (r212242)
@@ -982,6 +982,23 @@ union sctp_sockstore {
        struct sockaddr sa;
 };
 
+
+/***********************************/
+/* And something for us old timers */
+/***********************************/
+
+#ifndef ntohll
+#include <sys/endian.h>
+#define ntohll(x) be64toh(x)
+#endif
+
+#ifndef htonll
+#include <sys/endian.h>
+#define htonll(x) htobe64(x)
+#endif
+/***********************************/
+
+
 struct xsctp_inpcb {
        uint32_t last;
        uint32_t flags;
@@ -1079,7 +1096,6 @@ sctp_lower_sosend(struct socket *so,
     struct mbuf *i_pak,
     struct mbuf *control,
     int flags,
-    int use_rcvinfo,
     struct sctp_sndrcvinfo *srcv
     ,struct thread *p
 );
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to