Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 16 Jun 2011 15:36:09 +0000 (UTC)
From:      Michael Tuexen <tuexen@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r223152 - in head: lib/libc/net sys/netinet
Message-ID:  <201106161536.p5GFa9F3034968@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106161536.p5GFa9F3034968>