summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctputil.c
diff options
context:
space:
mode:
authortuexen <tuexen@FreeBSD.org>2014-12-06 20:00:08 +0000
committertuexen <tuexen@FreeBSD.org>2014-12-06 20:00:08 +0000
commit8a74463a63e023b9cbe1a42b39d94fdf4e963491 (patch)
tree3a8069534a16053842add50e463677e34e587d05 /sys/netinet/sctputil.c
parent4b9dde8b13f81a3d2e1a4371338b53caed6da4ee (diff)
downloadFreeBSD-src-8a74463a63e023b9cbe1a42b39d94fdf4e963491.zip
FreeBSD-src-8a74463a63e023b9cbe1a42b39d94fdf4e963491.tar.gz
Fix the support of mapped IPv4 addresses.
Thanks to Mark Bonnekessel and Markus Boese for making me aware of the problems. MFC after: 1 week
Diffstat (limited to 'sys/netinet/sctputil.c')
-rw-r--r--sys/netinet/sctputil.c72
1 files changed, 45 insertions, 27 deletions
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index b6aa3ea..d066c74 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -2760,7 +2760,16 @@ sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
switch (sa->sa_family) {
#ifdef INET
case AF_INET:
+#ifdef INET6
+ if (sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
+ in6_sin_2_v4mapsin6((struct sockaddr_in *)sa,
+ (struct sockaddr_in6 *)&spc->spc_aaddr);
+ } else {
+ memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in));
+ }
+#else
memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in));
+#endif
break;
#endif
#ifdef INET6
@@ -5653,43 +5662,43 @@ found_one:
entry->flgs = control->sinfo_flags;
}
#endif
- if (fromlen && from) {
- cp_len = min((size_t)fromlen, (size_t)control->whoFrom->ro._l_addr.sa.sa_len);
+ if ((fromlen > 0) && (from != NULL)) {
+ union sctp_sockstore store;
+ size_t len;
+
switch (control->whoFrom->ro._l_addr.sa.sa_family) {
#ifdef INET6
case AF_INET6:
- ((struct sockaddr_in6 *)from)->sin6_port = control->port_from;
+ len = sizeof(struct sockaddr_in6);
+ store.sin6 = control->whoFrom->ro._l_addr.sin6;
+ store.sin6.sin6_port = control->port_from;
break;
#endif
#ifdef INET
case AF_INET:
- ((struct sockaddr_in *)from)->sin_port = control->port_from;
+#ifdef INET6
+ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
+ len = sizeof(struct sockaddr_in6);
+ in6_sin_2_v4mapsin6(&control->whoFrom->ro._l_addr.sin,
+ &store.sin6);
+ store.sin6.sin6_port = control->port_from;
+ } else {
+ len = sizeof(struct sockaddr_in);
+ store.sin = control->whoFrom->ro._l_addr.sin;
+ store.sin.sin_port = control->port_from;
+ }
+#else
+ len = sizeof(struct sockaddr_in);
+ store.sin = control->whoFrom->ro._l_addr.sin;
+ store.sin.sin_port = control->port_from;
+#endif
break;
#endif
default:
+ len = 0;
break;
}
- memcpy(from, &control->whoFrom->ro._l_addr, cp_len);
-
-#if defined(INET) && defined(INET6)
- if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) &&
- (from->sa_family == AF_INET) &&
- ((size_t)fromlen >= sizeof(struct sockaddr_in6))) {
- struct sockaddr_in *sin;
- struct sockaddr_in6 sin6;
-
- sin = (struct sockaddr_in *)from;
- bzero(&sin6, sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_len = sizeof(struct sockaddr_in6);
- sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
- bcopy(&sin->sin_addr,
- &sin6.sin6_addr.s6_addr32[3],
- sizeof(sin6.sin6_addr.s6_addr32[3]));
- sin6.sin6_port = sin->sin_port;
- memcpy(from, &sin6, sizeof(struct sockaddr_in6));
- }
-#endif
+ memcpy(from, &store, min((size_t)fromlen, len));
#ifdef INET6
{
struct sockaddr_in6 lsa6, *from6;
@@ -6450,7 +6459,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
{
struct sockaddr *addr_touse;
-#ifdef INET6
+#if defined(INET) && defined(INET6)
struct sockaddr_in sin;
#endif
@@ -6464,8 +6473,10 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
addr_touse = sa;
#ifdef INET6
if (sa->sa_family == AF_INET6) {
+#ifdef INET
struct sockaddr_in6 *sin6;
+#endif
if (sa->sa_len != sizeof(struct sockaddr_in6)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
@@ -6477,6 +6488,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
*error = EINVAL;
return;
}
+#ifdef INET
sin6 = (struct sockaddr_in6 *)addr_touse;
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
@@ -6489,6 +6501,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
in6_sin6_2_sin(&sin, sin6);
addr_touse = (struct sockaddr *)&sin;
}
+#endif
}
#endif
#ifdef INET
@@ -6578,7 +6591,7 @@ sctp_bindx_delete_address(struct sctp_inpcb *inp,
{
struct sockaddr *addr_touse;
-#ifdef INET6
+#if defined(INET) && defined(INET6)
struct sockaddr_in sin;
#endif
@@ -6592,8 +6605,11 @@ sctp_bindx_delete_address(struct sctp_inpcb *inp,
addr_touse = sa;
#ifdef INET6
if (sa->sa_family == AF_INET6) {
+#ifdef INET
struct sockaddr_in6 *sin6;
+#endif
+
if (sa->sa_len != sizeof(struct sockaddr_in6)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
@@ -6605,6 +6621,7 @@ sctp_bindx_delete_address(struct sctp_inpcb *inp,
*error = EINVAL;
return;
}
+#ifdef INET
sin6 = (struct sockaddr_in6 *)addr_touse;
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
@@ -6617,6 +6634,7 @@ sctp_bindx_delete_address(struct sctp_inpcb *inp,
in6_sin6_2_sin(&sin, sin6);
addr_touse = (struct sockaddr *)&sin;
}
+#endif
}
#endif
#ifdef INET
OpenPOWER on IntegriCloud