Author: tuexen
Date: Wed Jun 15 23:50:27 2011
New Revision: 223132
URL: http://svn.freebsd.org/changeset/base/223132

Log:
  Add support for the newly added SCTP API.
  In particular add support for:
  * SCTP_SNDINFO, SCTP_PRINFO, SCTP_AUTHINFO, SCTP_DSTADDRV4, and
    SCTP_DSTADDRV6 cmsgs.
  * SCTP_NXTINFO and SCTP_RCVINFO cmgs.
  * SCTP_EVENT, SCTP_RECVRCVINFO, SCTP_RECVNXTINFO and SCTP_DEFAULT_SNDINFO
    socket option.
  * Special association ids (SCTP_FUTURE_ASSOC, ...)
  * sctp_recvv() and sctp_sendv() functions.
  
  MFC after: 1 month.

Modified:
  head/lib/libc/net/sctp_sys_calls.c
  head/sys/netinet/sctp.h
  head/sys/netinet/sctp_auth.c
  head/sys/netinet/sctp_indata.c
  head/sys/netinet/sctp_output.c
  head/sys/netinet/sctp_pcb.c
  head/sys/netinet/sctp_structs.h
  head/sys/netinet/sctp_uio.h
  head/sys/netinet/sctp_usrreq.c
  head/sys/netinet/sctp_var.h
  head/sys/netinet/sctputil.c

Modified: head/lib/libc/net/sctp_sys_calls.c
==============================================================================
--- head/lib/libc/net/sctp_sys_calls.c  Wed Jun 15 23:45:35 2011        
(r223131)
+++ head/lib/libc/net/sctp_sys_calls.c  Wed Jun 15 23:50:27 2011        
(r223132)
@@ -141,7 +141,7 @@ in6_sin6_2_sin(struct sockaddr_in *sin, 
 int
 sctp_getaddrlen(sa_family_t family)
 {
-       int error, sd;
+       int ret, sd;
        socklen_t siz;
        struct sctp_assoc_value av;
 
@@ -151,13 +151,15 @@ sctp_getaddrlen(sa_family_t family)
        sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
 #elif defined(AF_INET6)
        sd = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP);
+#else
+       sd = -1;
 #endif
        if (sd == -1) {
                return (-1);
        }
-       error = getsockopt(sd, IPPROTO_SCTP, SCTP_GET_ADDR_LEN, &av, &siz);
+       ret = getsockopt(sd, IPPROTO_SCTP, SCTP_GET_ADDR_LEN, &av, &siz);
        close(sd);
-       if (error == 0) {
+       if (ret == 0) {
                return ((int)av.assoc_value);
        } else {
                return (-1);
@@ -402,6 +404,9 @@ sctp_opt_info(int sd, sctp_assoc_t id, i
        case SCTP_TIMEOUTS:
                ((struct sctp_timeouts *)arg)->stimo_assoc_id = id;
                break;
+       case SCTP_EVENT:
+               ((struct sctp_event *)arg)->se_assoc_id = id;
+               break;
        default:
                break;
        }
@@ -919,32 +924,259 @@ sctp_recvmsg(int s,
 #endif
 }
 
+ssize_t 
+sctp_recvv(int sd,
+    const struct iovec *iov,
+    int iovlen,
+    struct sockaddr *from,
+    socklen_t * fromlen,
+    void *info,
+    socklen_t * infolen,
+    unsigned int *infotype,
+    int *flags)
+{
+       char ctlbuf[SCTP_CONTROL_VEC_SIZE_RCV];
+       struct msghdr msg;
+       struct cmsghdr *cmsg;
+       ssize_t n;
+       struct sctp_rcvinfo *rcvinfo;
+       struct sctp_nxtinfo *nxtinfo;
 
-#if defined(HAVE_SCTP_PEELOFF_SOCKOPT)
-#include <netinet/sctp_peeloff.h>
+       if (infotype) {
+               *infotype = SCTP_RECVV_NOINFO;
+       }
+       msg.msg_name = from;
+       if (fromlen == NULL) {
+               msg.msg_namelen = 0;
+       } else {
+               msg.msg_namelen = *fromlen;
+       }
+       msg.msg_iov = (struct iovec *)iov;
+       msg.msg_iovlen = iovlen;
+       msg.msg_control = ctlbuf;
+       msg.msg_controllen = sizeof(ctlbuf);
+       errno = 0;
+       n = recvmsg(sd, &msg, *flags);
+       *flags = msg.msg_flags;
+       if ((n > 0) &&
+           (msg.msg_controllen > 0) &&
+           (infotype != NULL) &&
+           (infolen != NULL) &&
+           (*infolen > 0)) {
+               rcvinfo = NULL;
+               nxtinfo = NULL;
+               for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, 
cmsg)) {
+                       if (cmsg->cmsg_level != IPPROTO_SCTP) {
+                               continue;
+                       }
+                       if (cmsg->cmsg_type == SCTP_RCVINFO) {
+                               rcvinfo = (struct sctp_rcvinfo 
*)CMSG_DATA(cmsg);
+                       }
+                       if (cmsg->cmsg_type == SCTP_NXTINFO) {
+                               nxtinfo = (struct sctp_nxtinfo 
*)CMSG_DATA(cmsg);
+                       }
+                       if (rcvinfo && nxtinfo) {
+                               break;
+                       }
+               }
+               if (rcvinfo) {
+                       if (nxtinfo) {
+                               if (*infolen >= sizeof(struct sctp_recvv_rn)) {
+                                       struct sctp_recvv_rn *rn_info;
+
+                                       rn_info = (struct sctp_recvv_rn *)info;
+                                       rn_info->recvv_rcvinfo = *rcvinfo;
+                                       rn_info->recvv_nxtinfo = *nxtinfo;
+                                       *infolen = (socklen_t) sizeof(struct 
sctp_recvv_rn);
+                                       *infotype = SCTP_RECVV_RN;
+                               }
+                       } else {
+                               if (*infolen >= sizeof(struct sctp_rcvinfo)) {
+                                       memcpy(info, rcvinfo, sizeof(struct 
sctp_rcvinfo));
+                                       *infolen = (socklen_t) sizeof(struct 
sctp_rcvinfo);
+                                       *infotype = SCTP_RECVV_RCVINFO;
+                               }
+                       }
+               } else if (nxtinfo) {
+                       if (*infolen >= sizeof(struct sctp_rcvinfo)) {
+                               memcpy(info, nxtinfo, sizeof(struct 
sctp_nxtinfo));
+                               *infolen = (socklen_t) sizeof(struct 
sctp_nxtinfo);
+                               *infotype = SCTP_RECVV_NXTINFO;
+                       }
+               }
+       }
+       return (n);
+}
 
-int
-sctp_peeloff(int sd, sctp_assoc_t assoc_id)
+ssize_t
+sctp_sendv(int sd,
+    const struct iovec *iov, int iovcnt,
+    struct sockaddr *addrs, int addrcnt,
+    void *info, socklen_t infolen, unsigned int infotype,
+    int flags)
 {
-       struct sctp_peeloff_opt peeloff;
-       int result;
-       socklen_t optlen;
-
-       /* set in the socket option params */
-       memset(&peeloff, 0, sizeof(peeloff));
-       peeloff.s = sd;
-       peeloff.assoc_id = assoc_id;
-       optlen = sizeof(peeloff);
-       result = getsockopt(sd, IPPROTO_SCTP, SCTP_PEELOFF, (void *)&peeloff, 
&optlen);
+       ssize_t ret;
+       int i;
+       size_t addr_len;
+       struct sctp_sendv_spa *spa_info;
+       struct msghdr msg;
+       struct cmsghdr *cmsg;
+       char *cmsgbuf;
+       struct sockaddr *addr;
+       struct sockaddr_in *addr_in;
+       struct sockaddr_in6 *addr_in6;
 
-       if (result < 0) {
+       if ((addrcnt < 0) || (iovcnt < 0)) {
+               errno = EINVAL;
+               return (-1);
+       }
+       cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) +
+           CMSG_SPACE(sizeof(struct sctp_prinfo)) +
+           CMSG_SPACE(sizeof(struct sctp_authinfo)) +
+           addrcnt * CMSG_SPACE(sizeof(struct in6_addr)));
+       if (cmsgbuf == NULL) {
+               errno = ENOBUFS;
                return (-1);
+       }
+       msg.msg_control = cmsgbuf;
+       msg.msg_controllen = 0;
+       cmsg = (struct cmsghdr *)cmsgbuf;
+       switch (infotype) {
+       case SCTP_SENDV_SNDINFO:
+               if (infolen < sizeof(struct sctp_sndinfo)) {
+                       free(cmsgbuf);
+                       errno = EINVAL;
+                       return (-1);
+               }
+               cmsg->cmsg_level = IPPROTO_SCTP;
+               cmsg->cmsg_type = SCTP_SNDINFO;
+               cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
+               memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo));
+               msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
+               cmsg = (struct cmsghdr *)((caddr_t)cmsg + 
CMSG_SPACE(sizeof(struct sctp_sndinfo)));
+               break;
+       case SCTP_SENDV_PRINFO:
+               if (infolen < sizeof(struct sctp_prinfo)) {
+                       free(cmsgbuf);
+                       errno = EINVAL;
+                       return (-1);
+               }
+               cmsg->cmsg_level = IPPROTO_SCTP;
+               cmsg->cmsg_type = SCTP_PRINFO;
+               cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
+               memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo));
+               msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
+               cmsg = (struct cmsghdr *)((caddr_t)cmsg + 
CMSG_SPACE(sizeof(struct sctp_prinfo)));
+               break;
+       case SCTP_SENDV_AUTHINFO:
+               if (infolen < sizeof(struct sctp_authinfo)) {
+                       free(cmsgbuf);
+                       errno = EINVAL;
+                       return (-1);
+               }
+               cmsg->cmsg_level = IPPROTO_SCTP;
+               cmsg->cmsg_type = SCTP_AUTHINFO;
+               cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
+               memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo));
+               msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
+               cmsg = (struct cmsghdr *)((caddr_t)cmsg + 
CMSG_SPACE(sizeof(struct sctp_authinfo)));
+               break;
+       case SCTP_SENDV_SPA:
+               if (infolen < sizeof(struct sctp_sendv_spa)) {
+                       free(cmsgbuf);
+                       errno = EINVAL;
+                       return (-1);
+               }
+               spa_info = (struct sctp_sendv_spa *)info;
+               if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) {
+                       cmsg->cmsg_level = IPPROTO_SCTP;
+                       cmsg->cmsg_type = SCTP_SNDINFO;
+                       cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
+                       memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, 
sizeof(struct sctp_sndinfo));
+                       msg.msg_controllen += CMSG_SPACE(sizeof(struct 
sctp_sndinfo));
+                       cmsg = (struct cmsghdr *)((caddr_t)cmsg + 
CMSG_SPACE(sizeof(struct sctp_sndinfo)));
+               }
+               if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) {
+                       cmsg->cmsg_level = IPPROTO_SCTP;
+                       cmsg->cmsg_type = SCTP_PRINFO;
+                       cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
+                       memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, 
sizeof(struct sctp_prinfo));
+                       msg.msg_controllen += CMSG_SPACE(sizeof(struct 
sctp_prinfo));
+                       cmsg = (struct cmsghdr *)((caddr_t)cmsg + 
CMSG_SPACE(sizeof(struct sctp_prinfo)));
+               }
+               if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) {
+                       cmsg->cmsg_level = IPPROTO_SCTP;
+                       cmsg->cmsg_type = SCTP_AUTHINFO;
+                       cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
+                       memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, 
sizeof(struct sctp_authinfo));
+                       msg.msg_controllen += CMSG_SPACE(sizeof(struct 
sctp_authinfo));
+                       cmsg = (struct cmsghdr *)((caddr_t)cmsg + 
CMSG_SPACE(sizeof(struct sctp_authinfo)));
+               }
+               break;
+       default:
+               free(cmsgbuf);
+               errno = EINVAL;
+               return (-1);
+       }
+       addr = addrs;
+       if (addrcnt == 1) {
+               msg.msg_name = addr;
+               switch (addr->sa_family) {
+               case AF_INET:
+                       msg.msg_namelen = sizeof(struct sockaddr_in);
+                       break;
+               case AF_INET6:
+                       msg.msg_namelen = sizeof(struct sockaddr_in6);
+                       break;
+               default:
+                       free(cmsgbuf);
+                       errno = EINVAL;
+                       return (-1);
+               }
        } else {
-               return (peeloff.new_sd);
+               msg.msg_name = NULL;
+               msg.msg_namelen = 0;
+               for (i = 0; i < addrcnt; i++) {
+                       switch (addr->sa_family) {
+                       case AF_INET:
+                               addr_len = sizeof(struct sockaddr_in);
+                               addr_in = (struct sockaddr_in *)addr;
+                               cmsg->cmsg_level = IPPROTO_SCTP;
+                               cmsg->cmsg_type = SCTP_DSTADDRV4;
+                               cmsg->cmsg_len = CMSG_LEN(sizeof(struct 
in_addr));
+                               memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, 
sizeof(struct in_addr));
+                               msg.msg_controllen += CMSG_SPACE(sizeof(struct 
in_addr));
+                               cmsg = (struct cmsghdr *)((caddr_t)cmsg + 
CMSG_SPACE(sizeof(struct in_addr)));
+                               break;
+                       case AF_INET6:
+                               addr_len = sizeof(struct sockaddr_in6);
+                               addr_in6 = (struct sockaddr_in6 *)addr;
+                               cmsg->cmsg_level = IPPROTO_SCTP;
+                               cmsg->cmsg_type = SCTP_DSTADDRV6;
+                               cmsg->cmsg_len = CMSG_LEN(sizeof(struct 
in6_addr));
+                               memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, 
sizeof(struct in6_addr));
+                               msg.msg_controllen += CMSG_SPACE(sizeof(struct 
in6_addr));
+                               cmsg = (struct cmsghdr *)((caddr_t)cmsg + 
CMSG_SPACE(sizeof(struct in6_addr)));
+                               break;
+                       default:
+                               free(cmsgbuf);
+                               errno = EINVAL;
+                               return (-1);
+                       }
+                       addr = (struct sockaddr *)((caddr_t)addr + addr_len);
+               }
        }
+       if (msg.msg_controllen == 0) {
+               msg.msg_control = NULL;
+       }
+       msg.msg_iov = (struct iovec *)iov;
+       msg.msg_iovlen = iovcnt;
+       msg.msg_flags = 0;
+       ret = sendmsg(sd, &msg, flags);
+       free(cmsgbuf);
+       return (ret);
 }
 
-#endif
 
 #if !defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT)
 

Modified: head/sys/netinet/sctp.h
==============================================================================
--- head/sys/netinet/sctp.h     Wed Jun 15 23:45:35 2011        (r223131)
+++ head/sys/netinet/sctp.h     Wed Jun 15 23:50:27 2011        (r223132)
@@ -91,7 +91,7 @@ struct sctp_paramhdr {
 #define SCTP_PEER_ADDR_PARAMS          0x0000000a
 #define SCTP_DEFAULT_SEND_PARAM                0x0000000b
 /* ancillary data/notification interest options */
-#define SCTP_EVENTS                    0x0000000c
+#define SCTP_EVENTS                    0x0000000c      /* deprecated */
 /* Without this applied we will give V4 and V6 addresses on a V6 socket */
 #define SCTP_I_WANT_MAPPED_V4_ADDR     0x0000000d
 #define SCTP_MAXSEG                    0x0000000e
@@ -114,6 +114,10 @@ struct sctp_paramhdr {
 #define SCTP_EXPLICIT_EOR               0x0000001b
 #define SCTP_REUSE_PORT                 0x0000001c     /* rw */
 #define SCTP_AUTH_DEACTIVATE_KEY       0x0000001d
+#define SCTP_EVENT                      0x0000001e
+#define SCTP_RECVRCVINFO                0x0000001f
+#define SCTP_RECVNXTINFO                0x00000020
+#define SCTP_DEFAULT_SNDINFO            0x00000021
 
 /*
  * read-only options
@@ -490,7 +494,7 @@ struct sctp_error_unrecognized_chunk {
 /*
  * PCB Features (in sctp_features bitmask)
  */
-#define SCTP_PCB_FLAGS_EXT_RCVINFO      0x00000002
+#define SCTP_PCB_FLAGS_EXT_RCVINFO      0x00000002     /* deprecated */
 #define SCTP_PCB_FLAGS_DONOT_HEARTBEAT  0x00000004
 #define SCTP_PCB_FLAGS_FRAG_INTERLEAVE  0x00000008
 #define SCTP_PCB_FLAGS_INTERLEAVE_STRMS        0x00000010
@@ -500,7 +504,7 @@ struct sctp_error_unrecognized_chunk {
 /* socket options */
 #define SCTP_PCB_FLAGS_NODELAY         0x00000100
 #define SCTP_PCB_FLAGS_AUTOCLOSE       0x00000200
-#define SCTP_PCB_FLAGS_RECVDATAIOEVNT  0x00000400
+#define SCTP_PCB_FLAGS_RECVDATAIOEVNT  0x00000400      /* deprecated */
 #define SCTP_PCB_FLAGS_RECVASSOCEVNT   0x00000800
 #define SCTP_PCB_FLAGS_RECVPADDREVNT   0x00001000
 #define SCTP_PCB_FLAGS_RECVPEERERR     0x00002000
@@ -516,6 +520,9 @@ struct sctp_error_unrecognized_chunk {
 #define SCTP_PCB_FLAGS_MULTIPLE_ASCONFS        0x01000000
 #define SCTP_PCB_FLAGS_PORTREUSE        0x02000000
 #define SCTP_PCB_FLAGS_DRYEVNT          0x04000000
+#define SCTP_PCB_FLAGS_RECVRCVINFO      0x08000000
+#define SCTP_PCB_FLAGS_RECVNXTINFO      0x10000000
+
 /*-
  * mobility_features parameters (by micchie).Note
  * these features are applied against the

Modified: head/sys/netinet/sctp_auth.c
==============================================================================
--- head/sys/netinet/sctp_auth.c        Wed Jun 15 23:45:35 2011        
(r223131)
+++ head/sys/netinet/sctp_auth.c        Wed Jun 15 23:50:27 2011        
(r223132)
@@ -1866,7 +1866,7 @@ sctp_notify_authentication(struct sctp_t
                /* If the socket is gone we are out of here */
                return;
        }
-       if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_AUTHEVNT))
+       if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, 
SCTP_PCB_FLAGS_AUTHEVNT))
                /* event not enabled */
                return;
 

Modified: head/sys/netinet/sctp_indata.c
==============================================================================
--- head/sys/netinet/sctp_indata.c      Wed Jun 15 23:45:35 2011        
(r223131)
+++ head/sys/netinet/sctp_indata.c      Wed Jun 15 23:50:27 2011        
(r223132)
@@ -201,48 +201,110 @@ failed_build:
 
 
 struct mbuf *
-sctp_build_ctl_nchunk(struct sctp_inpcb *inp,
-    struct sctp_sndrcvinfo *sinfo)
+sctp_build_ctl_nchunk(struct sctp_inpcb *inp, struct sctp_sndrcvinfo *sinfo)
 {
+       struct sctp_extrcvinfo *seinfo;
        struct sctp_sndrcvinfo *outinfo;
+       struct sctp_rcvinfo *rcvinfo;
+       struct sctp_nxtinfo *nxtinfo;
        struct cmsghdr *cmh;
        struct mbuf *ret;
        int len;
-       int use_extended = 0;
+       int use_extended;
+       int provide_nxt;
 
-       if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) {
-               /* user does not want the sndrcv ctl */
+       if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT) &&
+           sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO) &&
+           sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) {
+               /* user does not want any ancillary data */
                return (NULL);
        }
-       if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO)) {
-               use_extended = 1;
-               len = CMSG_LEN(sizeof(struct sctp_extrcvinfo));
+       len = 0;
+       if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO)) {
+               len += CMSG_SPACE(sizeof(struct sctp_rcvinfo));
+       }
+       seinfo = (struct sctp_extrcvinfo *)sinfo;
+       if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO) &&
+           (seinfo->sreinfo_next_flags & SCTP_NEXT_MSG_AVAIL)) {
+               provide_nxt = 1;
+               len += CMSG_SPACE(sizeof(struct sctp_rcvinfo));
        } else {
-               len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+               provide_nxt = 0;
+       }
+       if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) {
+               if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO)) {
+                       use_extended = 1;
+                       len += CMSG_SPACE(sizeof(struct sctp_extrcvinfo));
+               } else {
+                       use_extended = 0;
+                       len += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
+               }
+       } else {
+               use_extended = 0;
        }
 
-
-       ret = sctp_get_mbuf_for_msg(len,
-           0, M_DONTWAIT, 1, MT_DATA);
-
+       ret = sctp_get_mbuf_for_msg(len, 0, M_DONTWAIT, 1, MT_DATA);
        if (ret == NULL) {
                /* No space */
                return (ret);
        }
-       /* We need a CMSG header followed by the struct  */
+       SCTP_BUF_LEN(ret) = 0;
+
+       /* We need a CMSG header followed by the struct */
        cmh = mtod(ret, struct cmsghdr *);
-       outinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmh);
-       cmh->cmsg_level = IPPROTO_SCTP;
-       if (use_extended) {
-               cmh->cmsg_type = SCTP_EXTRCV;
-               cmh->cmsg_len = len;
-               memcpy(outinfo, sinfo, len);
-       } else {
-               cmh->cmsg_type = SCTP_SNDRCV;
-               cmh->cmsg_len = len;
-               *outinfo = *sinfo;
+       if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO)) {
+               cmh->cmsg_level = IPPROTO_SCTP;
+               cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_rcvinfo));
+               cmh->cmsg_type = SCTP_RCVINFO;
+               rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmh);
+               rcvinfo->rcv_sid = sinfo->sinfo_stream;
+               rcvinfo->rcv_ssn = sinfo->sinfo_ssn;
+               rcvinfo->rcv_flags = sinfo->sinfo_flags;
+               rcvinfo->rcv_ppid = sinfo->sinfo_ppid;
+               rcvinfo->rcv_tsn = sinfo->sinfo_tsn;
+               rcvinfo->rcv_cumtsn = sinfo->sinfo_cumtsn;
+               rcvinfo->rcv_context = sinfo->sinfo_context;
+               rcvinfo->rcv_assoc_id = sinfo->sinfo_assoc_id;
+               cmh = (struct cmsghdr *)((caddr_t)cmh + 
CMSG_SPACE(sizeof(struct sctp_rcvinfo)));
+               SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_rcvinfo));
+       }
+       if (provide_nxt) {
+               cmh->cmsg_level = IPPROTO_SCTP;
+               cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_nxtinfo));
+               cmh->cmsg_type = SCTP_NXTINFO;
+               nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmh);
+               nxtinfo->nxt_sid = seinfo->sreinfo_next_stream;
+               nxtinfo->nxt_flags = 0;
+               if (seinfo->sreinfo_next_flags & SCTP_NEXT_MSG_IS_UNORDERED) {
+                       nxtinfo->nxt_flags |= SCTP_UNORDERED;
+               }
+               if (seinfo->sreinfo_next_flags & SCTP_NEXT_MSG_IS_NOTIFICATION) 
{
+                       nxtinfo->nxt_flags |= SCTP_NOTIFICATION;
+               }
+               if (seinfo->sreinfo_next_flags & SCTP_NEXT_MSG_ISCOMPLETE) {
+                       nxtinfo->nxt_flags |= SCTP_COMPLETE;
+               }
+               nxtinfo->nxt_ppid = seinfo->sreinfo_next_ppid;
+               nxtinfo->nxt_length = seinfo->sreinfo_next_length;
+               nxtinfo->nxt_assoc_id = seinfo->sreinfo_next_aid;
+               cmh = (struct cmsghdr *)((caddr_t)cmh + 
CMSG_SPACE(sizeof(struct sctp_nxtinfo)));
+               SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_nxtinfo));
+       }
+       if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) {
+               cmh->cmsg_level = IPPROTO_SCTP;
+               outinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmh);
+               if (use_extended) {
+                       cmh->cmsg_len = CMSG_LEN(sizeof(struct 
sctp_extrcvinfo));
+                       cmh->cmsg_type = SCTP_EXTRCV;
+                       memcpy(outinfo, sinfo, sizeof(struct sctp_extrcvinfo));
+                       SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct 
sctp_extrcvinfo));
+               } else {
+                       cmh->cmsg_len = CMSG_LEN(sizeof(struct 
sctp_sndrcvinfo));
+                       cmh->cmsg_type = SCTP_SNDRCV;
+                       *outinfo = *sinfo;
+                       SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct 
sctp_sndrcvinfo));
+               }
        }
-       SCTP_BUF_LEN(ret) = cmh->cmsg_len;
        return (ret);
 }
 

Modified: head/sys/netinet/sctp_output.c
==============================================================================
--- head/sys/netinet/sctp_output.c      Wed Jun 15 23:45:35 2011        
(r223131)
+++ head/sys/netinet/sctp_output.c      Wed Jun 15 23:50:27 2011        
(r223132)
@@ -3355,54 +3355,338 @@ sctp_source_address_selection(struct sct
 }
 
 static int
-sctp_find_cmsg(int c_type, void *data, struct mbuf *control, int cpsize)
+sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize)
 {
        struct cmsghdr cmh;
-       int tlen, at;
+       int tlen, at, found;
+       struct sctp_sndinfo sndinfo;
+       struct sctp_prinfo prinfo;
+       struct sctp_authinfo authinfo;
 
        tlen = SCTP_BUF_LEN(control);
        at = 0;
+       found = 0;
        /*
         * Independent of how many mbufs, find the c_type inside the control
         * structure and copy out the data.
         */
        while (at < tlen) {
                if ((tlen - at) < (int)CMSG_ALIGN(sizeof(cmh))) {
-                       /* not enough room for one more we are done. */
-                       return (0);
+                       /* There is not enough room for one more. */
+                       return (found);
                }
                m_copydata(control, at, sizeof(cmh), (caddr_t)&cmh);
+               if (cmh.cmsg_len < CMSG_ALIGN(sizeof(struct cmsghdr))) {
+                       /* We dont't have a complete CMSG header. */
+                       return (found);
+               }
                if (((int)cmh.cmsg_len + at) > tlen) {
-                       /*
-                        * this is real messed up since there is not enough
-                        * data here to cover the cmsg header. We are done.
-                        */
-                       return (0);
+                       /* We don't have the complete CMSG. */
+                       return (found);
                }
                if ((cmh.cmsg_level == IPPROTO_SCTP) &&
-                   (c_type == cmh.cmsg_type)) {
-                       /* found the one we want, copy it out */
-                       at += CMSG_ALIGN(sizeof(struct cmsghdr));
-                       if ((int)(cmh.cmsg_len - CMSG_ALIGN(sizeof(struct 
cmsghdr))) < cpsize) {
-                               /*
-                                * space of cmsg_len after header not big
-                                * enough
-                                */
-                               return (0);
+                   ((c_type == cmh.cmsg_type) ||
+                   ((c_type == SCTP_SNDRCV) &&
+                   ((cmh.cmsg_type == SCTP_SNDINFO) ||
+                   (cmh.cmsg_type == SCTP_PRINFO) ||
+                   (cmh.cmsg_type == SCTP_AUTHINFO))))) {
+                       if (c_type == cmh.cmsg_type) {
+                               if ((size_t)(cmh.cmsg_len - 
CMSG_ALIGN(sizeof(struct cmsghdr))) < cpsize) {
+                                       return (found);
+                               }
+                               /* It is exactly what we want. Copy it out. */
+                               m_copydata(control, at + 
CMSG_ALIGN(sizeof(struct cmsghdr)), cpsize, (caddr_t)data);
+                               return (1);
+                       } else {
+                               struct sctp_sndrcvinfo *sndrcvinfo;
+
+                               sndrcvinfo = (struct sctp_sndrcvinfo *)data;
+                               if (found == 0) {
+                                       if (cpsize < sizeof(struct 
sctp_sndrcvinfo)) {
+                                               return (found);
+                                       }
+                                       memset(sndrcvinfo, 0, sizeof(struct 
sctp_sndrcvinfo));
+                               }
+                               switch (cmh.cmsg_type) {
+                               case SCTP_SNDINFO:
+                                       if ((size_t)(cmh.cmsg_len - 
CMSG_ALIGN(sizeof(struct cmsghdr))) < sizeof(struct sctp_sndinfo)) {
+                                               return (found);
+                                       }
+                                       m_copydata(control, at + 
CMSG_ALIGN(sizeof(struct cmsghdr)), sizeof(struct sctp_sndinfo), 
(caddr_t)&sndinfo);
+                                       sndrcvinfo->sinfo_stream = 
sndinfo.snd_sid;
+                                       sndrcvinfo->sinfo_flags = 
sndinfo.snd_flags;
+                                       sndrcvinfo->sinfo_ppid = 
sndinfo.snd_ppid;
+                                       sndrcvinfo->sinfo_context = 
sndinfo.snd_context;
+                                       sndrcvinfo->sinfo_assoc_id = 
sndinfo.snd_assoc_id;
+                                       break;
+                               case SCTP_PRINFO:
+                                       if ((size_t)(cmh.cmsg_len - 
CMSG_ALIGN(sizeof(struct cmsghdr))) < sizeof(struct sctp_prinfo)) {
+                                               return (found);
+                                       }
+                                       m_copydata(control, at + 
CMSG_ALIGN(sizeof(struct cmsghdr)), sizeof(struct sctp_prinfo), 
(caddr_t)&prinfo);
+                                       sndrcvinfo->sinfo_timetolive = 
prinfo.pr_value;
+                                       sndrcvinfo->sinfo_flags |= 
prinfo.pr_policy;
+                                       break;
+                               case SCTP_AUTHINFO:
+                                       if ((size_t)(cmh.cmsg_len - 
CMSG_ALIGN(sizeof(struct cmsghdr))) < sizeof(struct sctp_authinfo)) {
+                                               return (found);
+                                       }
+                                       m_copydata(control, at + 
CMSG_ALIGN(sizeof(struct cmsghdr)), sizeof(struct sctp_authinfo), 
(caddr_t)&authinfo);
+                                       sndrcvinfo->sinfo_keynumber_valid = 1;
+                                       sndrcvinfo->sinfo_keynumber = 
authinfo.auth_keyid;
+                                       break;
+                               default:
+                                       return (found);
+                               }
+                               found = 1;
                        }
-                       m_copydata(control, at, cpsize, data);
+               }
+               at += CMSG_ALIGN(cmh.cmsg_len);
+       }
+       return (found);
+}
+
+static int
+sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int 
*error)
+{
+       struct cmsghdr cmh;
+       int tlen, at;
+       struct sctp_initmsg initmsg;
+
+#ifdef INET
+       struct sockaddr_in sin;
+
+#endif
+#ifdef INET6
+       struct sockaddr_in6 sin6;
+
+#endif
+
+       tlen = SCTP_BUF_LEN(control);
+       at = 0;
+       while (at < tlen) {
+               if ((tlen - at) < (int)CMSG_ALIGN(sizeof(cmh))) {
+                       /* There is not enough room for one more. */
+                       *error = EINVAL;
                        return (1);
-               } else {
-                       at += CMSG_ALIGN(cmh.cmsg_len);
-                       if (cmh.cmsg_len == 0) {
+               }
+               m_copydata(control, at, sizeof(cmh), (caddr_t)&cmh);
+               if (cmh.cmsg_len < CMSG_ALIGN(sizeof(struct cmsghdr))) {
+                       /* We dont't have a complete CMSG header. */
+                       *error = EINVAL;
+                       return (1);
+               }
+               if (((int)cmh.cmsg_len + at) > tlen) {
+                       /* We don't have the complete CMSG. */
+                       *error = EINVAL;
+                       return (1);
+               }
+               if (cmh.cmsg_level == IPPROTO_SCTP) {
+                       switch (cmh.cmsg_type) {
+                       case SCTP_INIT:
+                               if ((size_t)(cmh.cmsg_len - 
CMSG_ALIGN(sizeof(struct cmsghdr))) < sizeof(struct sctp_initmsg)) {
+                                       *error = EINVAL;
+                                       return (1);
+                               }
+                               m_copydata(control, at + 
CMSG_ALIGN(sizeof(struct cmsghdr)), sizeof(struct sctp_initmsg), 
(caddr_t)&initmsg);
+                               if (initmsg.sinit_max_attempts)
+                                       stcb->asoc.max_init_times = 
initmsg.sinit_max_attempts;
+                               if (initmsg.sinit_num_ostreams)
+                                       stcb->asoc.pre_open_streams = 
initmsg.sinit_num_ostreams;
+                               if (initmsg.sinit_max_instreams)
+                                       stcb->asoc.max_inbound_streams = 
initmsg.sinit_max_instreams;
+                               if (initmsg.sinit_max_init_timeo)
+                                       stcb->asoc.initial_init_rto_max = 
initmsg.sinit_max_init_timeo;
+                               if (stcb->asoc.streamoutcnt < 
stcb->asoc.pre_open_streams) {
+                                       struct sctp_stream_out *tmp_str;
+                                       unsigned int i;
+
+                                       /* Default is NOT correct */
+                                       SCTPDBG(SCTP_DEBUG_OUTPUT1, "Ok, 
default:%d pre_open:%d\n",
+                                           stcb->asoc.streamoutcnt, 
stcb->asoc.pre_open_streams);
+                                       SCTP_TCB_UNLOCK(stcb);
+                                       SCTP_MALLOC(tmp_str,
+                                           struct sctp_stream_out *,
+                                           (stcb->asoc.pre_open_streams * 
sizeof(struct sctp_stream_out)),
+                                           SCTP_M_STRMO);
+                                       SCTP_TCB_LOCK(stcb);
+                                       if (tmp_str != NULL) {
+                                               SCTP_FREE(stcb->asoc.strmout, 
SCTP_M_STRMO);
+                                               stcb->asoc.strmout = tmp_str;
+                                               stcb->asoc.strm_realoutsize = 
stcb->asoc.streamoutcnt = stcb->asoc.pre_open_streams;
+                                       } else {
+                                               stcb->asoc.pre_open_streams = 
stcb->asoc.streamoutcnt;
+                                       }
+                                       for (i = 0; i < 
stcb->asoc.streamoutcnt; i++) {
+                                               
stcb->asoc.strmout[i].next_sequence_sent = 0;
+                                               
TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
+                                               stcb->asoc.strmout[i].stream_no 
= i;
+                                               
stcb->asoc.strmout[i].last_msg_incomplete = 0;
+                                               
stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL);
+                                       }
+                               }
+                               break;
+#ifdef INET
+                       case SCTP_DSTADDRV4:
+                               if ((size_t)(cmh.cmsg_len - 
CMSG_ALIGN(sizeof(struct cmsghdr))) < sizeof(struct in_addr)) {
+                                       *error = EINVAL;
+                                       return (1);
+                               }
+                               memset(&sin, 0, sizeof(struct sockaddr_in));
+                               sin.sin_family = AF_INET;
+                               sin.sin_len = sizeof(struct sockaddr_in);
+                               sin.sin_port = stcb->rport;
+                               m_copydata(control, at + 
CMSG_ALIGN(sizeof(struct cmsghdr)), sizeof(struct in_addr), 
(caddr_t)&sin.sin_addr);
+                               if ((sin.sin_addr.s_addr == INADDR_ANY) ||
+                                   (sin.sin_addr.s_addr == INADDR_BROADCAST) ||
+                                   IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) {
+                                       *error = EINVAL;
+                                       return (-1);
+                               }
+                               if (sctp_add_remote_addr(stcb, (struct sockaddr 
*)&sin, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
+                                       *error = ENOBUFS;
+                                       return (1);
+                               }
+                               break;
+#endif
+#ifdef INET6
+                       case SCTP_DSTADDRV6:
+                               if ((size_t)(cmh.cmsg_len - 
CMSG_ALIGN(sizeof(struct cmsghdr))) < sizeof(struct in6_addr)) {
+                                       *error = EINVAL;
+                                       return (1);
+                               }
+                               memset(&sin6, 0, sizeof(struct sockaddr_in6));
+                               sin6.sin6_family = AF_INET6;
+                               sin6.sin6_len = sizeof(struct sockaddr_in6);
+                               sin6.sin6_port = stcb->rport;
+                               m_copydata(control, at + 
CMSG_ALIGN(sizeof(struct cmsghdr)), sizeof(struct in6_addr), 
(caddr_t)&sin6.sin6_addr);
+                               if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr) ||
+                                   IN6_IS_ADDR_MULTICAST(&sin6.sin6_addr)) {
+                                       *error = EINVAL;
+                                       return (-1);
+                               }
+#ifdef INET
+                               if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) {
+                                       in6_sin6_2_sin(&sin, &sin6);
+                                       if ((sin.sin_addr.s_addr == INADDR_ANY) 
||
+                                           (sin.sin_addr.s_addr == 
INADDR_BROADCAST) ||
+                                           
IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) {
+                                               *error = EINVAL;
+                                               return (-1);
+                                       }
+                                       if (sctp_add_remote_addr(stcb, (struct 
sockaddr *)&sin, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
+                                               *error = ENOBUFS;
+                                               return (1);
+                                       }
+                               } else
+#endif
+                               if (sctp_add_remote_addr(stcb, (struct sockaddr 
*)&sin6, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
+                                       *error = ENOBUFS;
+                                       return (1);
+                               }
+                               break;
+#endif
+                       default:
                                break;
                        }
                }
+               at += CMSG_ALIGN(cmh.cmsg_len);
        }
-       /* not found */
        return (0);
 }
 
+static struct sctp_tcb *
+sctp_findassociation_cmsgs(struct sctp_inpcb **inp_p,
+    in_port_t port,
+    struct mbuf *control,
+    struct sctp_nets **net_p,
+    int *error)
+{
+       struct cmsghdr cmh;
+       int tlen, at;
+       struct sctp_tcb *stcb;
+       struct sockaddr *addr;
+
+#ifdef INET
+       struct sockaddr_in sin;
+
+#endif
+#ifdef INET6
+       struct sockaddr_in6 sin6;
+
+#endif
+
+       tlen = SCTP_BUF_LEN(control);
+       at = 0;
+       while (at < tlen) {
+               if ((tlen - at) < (int)CMSG_ALIGN(sizeof(cmh))) {
+                       /* There is not enough room for one more. */
+                       *error = EINVAL;
+                       return (NULL);
+               }
+               m_copydata(control, at, sizeof(cmh), (caddr_t)&cmh);
+               if (cmh.cmsg_len < CMSG_ALIGN(sizeof(struct cmsghdr))) {
+                       /* We dont't have a complete CMSG header. */
+                       *error = EINVAL;
+                       return (NULL);
+               }
+               if (((int)cmh.cmsg_len + at) > tlen) {
+                       /* We don't have the complete CMSG. */
+                       *error = EINVAL;
+                       return (NULL);
+               }
+               if (cmh.cmsg_level == IPPROTO_SCTP) {
+                       switch (cmh.cmsg_type) {
+#ifdef INET
+                       case SCTP_DSTADDRV4:
+                               if ((size_t)(cmh.cmsg_len - 
CMSG_ALIGN(sizeof(struct cmsghdr))) < sizeof(struct in_addr)) {
+                                       *error = EINVAL;
+                                       return (NULL);
+                               }
+                               memset(&sin, 0, sizeof(struct sockaddr_in));
+                               sin.sin_family = AF_INET;
+                               sin.sin_len = sizeof(struct sockaddr_in);
+                               sin.sin_port = port;
+                               m_copydata(control, at + 
CMSG_ALIGN(sizeof(struct cmsghdr)), sizeof(struct in_addr), 
(caddr_t)&sin.sin_addr);
+                               addr = (struct sockaddr *)&sin;
+                               break;
+#endif
+#ifdef INET6
+                       case SCTP_DSTADDRV6:
+                               if ((size_t)(cmh.cmsg_len - 
CMSG_ALIGN(sizeof(struct cmsghdr))) < sizeof(struct in6_addr)) {
+                                       *error = EINVAL;
+                                       return (NULL);
+                               }
+                               memset(&sin6, 0, sizeof(struct sockaddr_in6));
+                               sin6.sin6_family = AF_INET6;
+                               sin6.sin6_len = sizeof(struct sockaddr_in6);
+                               sin6.sin6_port = port;
+                               m_copydata(control, at + 
CMSG_ALIGN(sizeof(struct cmsghdr)), sizeof(struct in6_addr), 
(caddr_t)&sin6.sin6_addr);
+#ifdef INET
+                               if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) {
+                                       in6_sin6_2_sin(&sin, &sin6);
+                                       addr = (struct sockaddr *)&sin;
+                               } else
+#endif
+                                       addr = (struct sockaddr *)&sin6;
+                               break;
+#endif
+                       default:
+                               addr = NULL;
+                               break;
+                       }
+                       if (addr) {
+                               stcb = sctp_findassociation_ep_addr(inp_p, 
addr, net_p, NULL, NULL);
+                               if (stcb != NULL) {
+                                       return (stcb);
+                               }
+                       }
+               }
+               at += CMSG_ALIGN(cmh.cmsg_len);
+       }
+       return (NULL);
+}
+
 static struct mbuf *
 sctp_add_cookie(struct sctp_inpcb *inp, struct mbuf *init, int init_offset,
     struct mbuf *initack, int initack_offset, struct sctp_state_cookie 
*stc_in, uint8_t ** signature)
@@ -5989,19 +6273,26 @@ sctp_msg_append(struct sctp_tcb *stcb,
        sp->some_taken = 0;
        sp->data = m;
        sp->tail_mbuf = NULL;
-       sp->length = 0;
-       at = m;
        sctp_set_prsctp_policy(sp);
        /*
         * We could in theory (for sendall) sifa the length in, but we would
         * still have to hunt through the chain since we need to setup the
         * tail_mbuf
         */
-       while (at) {
+       sp->length = 0;
+       for (at = m; at; at = SCTP_BUF_NEXT(at)) {
                if (SCTP_BUF_NEXT(at) == NULL)
                        sp->tail_mbuf = at;
                sp->length += SCTP_BUF_LEN(at);
-               at = SCTP_BUF_NEXT(at);
+       }
+       if (srcv->sinfo_keynumber_valid) {
+               sp->auth_keyid = srcv->sinfo_keynumber;
+       } else {
+               sp->auth_keyid = stcb->asoc.authinfo.active_keyid;
+       }
+       if (sctp_auth_is_required_chunk(SCTP_DATA, 
stcb->asoc.peer_auth_chunks)) {
+               sctp_auth_key_acquire(stcb, sp->auth_keyid);
+               sp->holds_key_ref = 1;
        }
        SCTP_TCB_SEND_LOCK(stcb);
        sctp_snd_sb_alloc(stcb, sp->length);
@@ -6478,7 +6769,9 @@ sctp_sendall(struct sctp_inpcb *inp, str
        memset(ca, 0, sizeof(struct sctp_copy_all));
 
        ca->inp = inp;
-       memcpy(&ca->sndrcv, srcv, sizeof(struct sctp_nonpad_sndrcvinfo));
+       if (srcv) {
+               memcpy(&ca->sndrcv, srcv, sizeof(struct 
sctp_nonpad_sndrcvinfo));
+       }
        /*
         * take off the sendall flag, it would be bad if we failed to do
         * this :-0
@@ -12229,9 +12522,13 @@ sctp_copy_it_in(struct sctp_tcb *stcb,
                *error = 0;
                goto skip_copy;
        }
-       sp->auth_keyid = stcb->asoc.authinfo.active_keyid;
+       if (srcv->sinfo_keynumber_valid) {
+               sp->auth_keyid = srcv->sinfo_keynumber;
+       } else {
+               sp->auth_keyid = stcb->asoc.authinfo.active_keyid;
+       }
        if (sctp_auth_is_required_chunk(SCTP_DATA, 
stcb->asoc.peer_auth_chunks)) {
-               sctp_auth_key_acquire(stcb, stcb->asoc.authinfo.active_keyid);
+               sctp_auth_key_acquire(stcb, sp->auth_keyid);
                sp->holds_key_ref = 1;
        }
        *error = sctp_copy_one(sp, uio, resv_in_first);
@@ -12263,8 +12560,8 @@ sctp_sosend(struct socket *so,
     struct thread *p
 )
 {
-       int error, use_rcvinfo = 0;
-       struct sctp_sndrcvinfo srcv;
+       int error, use_sndinfo = 0;
+       struct sctp_sndrcvinfo sndrcvninfo;
        struct sockaddr *addr_to_use;
 
 #if defined(INET) && defined(INET6)
@@ -12274,10 +12571,10 @@ sctp_sosend(struct socket *so,
 
        if (control) {
                /* process cmsg snd/rcv info (maybe a assoc-id) */
-               if (sctp_find_cmsg(SCTP_SNDRCV, (void *)&srcv, control,
-                   sizeof(srcv))) {
+               if (sctp_find_cmsg(SCTP_SNDRCV, (void *)&sndrcvninfo, control,
+                   sizeof(sndrcvninfo))) {
                        /* got one */
-                       use_rcvinfo = 1;
+                       use_sndinfo = 1;
                }
        }
        addr_to_use = addr;
@@ -12295,7 +12592,7 @@ sctp_sosend(struct socket *so,
        error = sctp_lower_sosend(so, addr_to_use, uio, top,
            control,
            flags,
-           use_rcvinfo ? &srcv : NULL
+           use_sndinfo ? &sndrcvninfo : NULL
            ,p
            );
        return (error);
@@ -12500,6 +12797,9 @@ sctp_lower_sosend(struct socket *so,
                SCTP_INP_WUNLOCK(inp);
                /* With the lock applied look again */
                stcb = sctp_findassociation_ep_addr(&t_inp, addr, &net, NULL, 
NULL);
+               if ((stcb == NULL) && (control != NULL) && (port > 0)) {
+                       stcb = sctp_findassociation_cmsgs(&t_inp, port, 
control, &net, &error);
+               }
                if (stcb == NULL) {
                        SCTP_INP_WLOCK(inp);
                        SCTP_INP_DECR_REF(inp);
@@ -12507,6 +12807,9 @@ sctp_lower_sosend(struct socket *so,
                } else {
                        hold_tcblock = 1;
                }
+               if (error) {
+                       goto out_unlocked;
+               }
                if (t_inp != inp) {
                        SCTP_LTRACE_ERR_RET(inp, stcb, net, 
SCTP_FROM_SCTP_OUTPUT, ENOTCONN);
                        error = ENOTCONN;
@@ -12555,6 +12858,7 @@ sctp_lower_sosend(struct socket *so,
                                /* Error is setup for us in the call */
                                goto out_unlocked;
                        }
+                       hold_tcblock = 1;
                        if (create_lock_applied) {
                                SCTP_ASOC_CREATE_UNLOCK(inp);
                                create_lock_applied = 0;
@@ -12574,84 +12878,13 @@ sctp_lower_sosend(struct socket *so,

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
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