* 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
This commit is contained in:
Michael Tuexen 2011-06-16 15:36:09 +00:00
parent c1434464b8
commit 0b064106dd
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=223152
2 changed files with 84 additions and 42 deletions

View File

@ -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;

View File

@ -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