diff options
author | tuexen <tuexen@FreeBSD.org> | 2011-06-16 15:36:09 +0000 |
---|---|---|
committer | tuexen <tuexen@FreeBSD.org> | 2011-06-16 15:36:09 +0000 |
commit | 1c7060f746aa61b1e64ab5d7c28f505778df5341 (patch) | |
tree | 8f8d1f1a57df0cccb08a36cab3fe5617506e336b /lib/libc | |
parent | 9edb76f49f5032758e6d132fd9ad6d736d9efcde (diff) | |
download | FreeBSD-src-1c7060f746aa61b1e64ab5d7c28f505778df5341.zip FreeBSD-src-1c7060f746aa61b1e64ab5d7c28f505778df5341.tar.gz |
* 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
Diffstat (limited to 'lib/libc')
-rw-r--r-- | lib/libc/net/sctp_sys_calls.c | 125 |
1 files changed, 83 insertions, 42 deletions
diff --git a/lib/libc/net/sctp_sys_calls.c b/lib/libc/net/sctp_sys_calls.c index a450c17..c43243b 100644 --- a/lib/libc/net/sctp_sys_calls.c +++ b/lib/libc/net/sctp_sys_calls.c @@ -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; |