Author: tuexen
Date: Thu Jun 16 15:36:09 2011
New Revision: 223152
URL: http://svn.freebsd.org/changeset/base/223152

Log:
  * Fix the handling of addresses in sctp_sendv().
  * Add support for SCTP_SENDV_NOINFO.
  * Improve the error handling of sctp_sendv() and sctp_recv().
  
  MFC after: 1 month

Modified:
  head/lib/libc/net/sctp_sys_calls.c
  head/sys/netinet/sctp_uio.h

Modified: head/lib/libc/net/sctp_sys_calls.c
==============================================================================
--- head/lib/libc/net/sctp_sys_calls.c  Thu Jun 16 15:35:12 2011        
(r223151)
+++ head/lib/libc/net/sctp_sys_calls.c  Thu Jun 16 15:36:09 2011        
(r223152)
@@ -942,6 +942,12 @@ sctp_recvv(int sd,
        struct sctp_rcvinfo *rcvinfo;
        struct sctp_nxtinfo *nxtinfo;
 
+       if (((info != NULL) && (infolen == NULL)) |
+           ((info == NULL) && (infolen != NULL) && (*infolen != 0)) ||
+           ((info != NULL) && (infotype == NULL))) {
+               errno = EINVAL;
+               return (-1);
+       }
        if (infotype) {
                *infotype = SCTP_RECVV_NOINFO;
        }
@@ -1017,16 +1023,22 @@ sctp_sendv(int sd,
 {
        ssize_t ret;
        int i;
-       size_t addr_len;
-       struct sctp_sendv_spa *spa_info;
+       socklen_t addr_len;
        struct msghdr msg;
+       in_port_t port;
+       struct sctp_sendv_spa *spa_info;
        struct cmsghdr *cmsg;
        char *cmsgbuf;
        struct sockaddr *addr;
        struct sockaddr_in *addr_in;
        struct sockaddr_in6 *addr_in6;
 
-       if ((addrcnt < 0) || (iovcnt < 0)) {
+       if ((addrcnt < 0) ||
+           (iovcnt < 0) ||
+           ((addr == NULL) && (addrcnt > 0)) ||
+           ((addr != NULL) && (addrcnt == 0)) ||
+           ((iov == NULL) && (iovcnt > 0)) ||
+           ((iov != NULL) && (iovcnt == 0))) {
                errno = EINVAL;
                return (-1);
        }
@@ -1042,8 +1054,15 @@ sctp_sendv(int sd,
        msg.msg_controllen = 0;
        cmsg = (struct cmsghdr *)cmsgbuf;
        switch (infotype) {
+       case SCTP_SENDV_NOINFO:
+               if ((infolen != 0) || (info != NULL)) {
+                       free(cmsgbuf);
+                       errno = EINVAL;
+                       return (-1);
+               }
+               break;
        case SCTP_SENDV_SNDINFO:
-               if (infolen < sizeof(struct sctp_sndinfo)) {
+               if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) {
                        free(cmsgbuf);
                        errno = EINVAL;
                        return (-1);
@@ -1056,7 +1075,7 @@ sctp_sendv(int sd,
                cmsg = (struct cmsghdr *)((caddr_t)cmsg + 
CMSG_SPACE(sizeof(struct sctp_sndinfo)));
                break;
        case SCTP_SENDV_PRINFO:
-               if (infolen < sizeof(struct sctp_prinfo)) {
+               if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) {
                        free(cmsgbuf);
                        errno = EINVAL;
                        return (-1);
@@ -1069,7 +1088,7 @@ sctp_sendv(int sd,
                cmsg = (struct cmsghdr *)((caddr_t)cmsg + 
CMSG_SPACE(sizeof(struct sctp_prinfo)));
                break;
        case SCTP_SENDV_AUTHINFO:
-               if (infolen < sizeof(struct sctp_authinfo)) {
+               if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) 
{
                        free(cmsgbuf);
                        errno = EINVAL;
                        return (-1);
@@ -1082,7 +1101,7 @@ sctp_sendv(int sd,
                cmsg = (struct cmsghdr *)((caddr_t)cmsg + 
CMSG_SPACE(sizeof(struct sctp_authinfo)));
                break;
        case SCTP_SENDV_SPA:
-               if (infolen < sizeof(struct sctp_sendv_spa)) {
+               if ((info == NULL) || (infolen < sizeof(struct 
sctp_sendv_spa))) {
                        free(cmsgbuf);
                        errno = EINVAL;
                        return (-1);
@@ -1119,52 +1138,74 @@ sctp_sendv(int sd,
                return (-1);
        }
        addr = addrs;
-       if (addrcnt == 1) {
-               msg.msg_name = addr;
+       msg.msg_name = NULL;
+       msg.msg_namelen = 0;
+
+       for (i = 0; i < addrcnt; i++) {
                switch (addr->sa_family) {
                case AF_INET:
-                       msg.msg_namelen = sizeof(struct sockaddr_in);
+                       addr_len = (socklen_t) sizeof(struct sockaddr_in);
+                       addr_in = (struct sockaddr_in *)addr;
+                       if (addr_in->sin_len != addr_len) {
+                               free(cmsgbuf);
+                               errno = EINVAL;
+                               return (-1);
+                       }
+                       if (i == 0) {
+                               port = addr_in->sin_port;
+                       } else {
+                               if (port == addr_in->sin_port) {
+                                       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)));
+                               } else {
+                                       free(cmsgbuf);
+                                       errno = EINVAL;
+                                       return (-1);
+                               }
+                       }
                        break;
                case AF_INET6:
-                       msg.msg_namelen = sizeof(struct sockaddr_in6);
+                       addr_len = (socklen_t) sizeof(struct sockaddr_in6);
+                       addr_in6 = (struct sockaddr_in6 *)addr;
+                       if (addr_in6->sin6_len != addr_len) {
+                               free(cmsgbuf);
+                               errno = EINVAL;
+                               return (-1);
+                       }
+                       if (i == 0) {
+                               port = addr_in6->sin6_port;
+                       } else {
+                               if (port == addr_in6->sin6_port) {
+                                       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)));
+                               } else {
+                                       free(cmsgbuf);
+                                       errno = EINVAL;
+                                       return (-1);
+                               }
+                       }
                        break;
                default:
                        free(cmsgbuf);
                        errno = EINVAL;
                        return (-1);
                }
-       } else {
-               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 (i == 0) {
+                       msg.msg_name = addr;
+                       msg.msg_namelen = addr_len;
                }
+               addr = (struct sockaddr *)((caddr_t)addr + addr_len);
+       }
+       if (msg.msg_controllen == 0) {
+               msg.msg_control = NULL;
        }
        if (msg.msg_controllen == 0) {
                msg.msg_control = NULL;

Modified: head/sys/netinet/sctp_uio.h
==============================================================================
--- head/sys/netinet/sctp_uio.h Thu Jun 16 15:35:12 2011        (r223151)
+++ head/sys/netinet/sctp_uio.h Thu Jun 16 15:36:09 2011        (r223152)
@@ -201,6 +201,7 @@ struct sctp_recvv_rn {
 #define SCTP_RECVV_NXTINFO 2
 #define SCTP_RECVV_RN      3
 
+#define SCTP_SENDV_NOINFO   0
 #define SCTP_SENDV_SNDINFO  1
 #define SCTP_SENDV_PRINFO   2
 #define SCTP_SENDV_AUTHINFO 3
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to