diff options
author | Michael Tuexen <tuexen@FreeBSD.org> | 2014-12-06 20:00:08 +0000 |
---|---|---|
committer | Michael Tuexen <tuexen@FreeBSD.org> | 2014-12-06 20:00:08 +0000 |
commit | d59107f700c226ebf009c823dd4d72c7a23c6eed (patch) | |
tree | 3a8069534a16053842add50e463677e34e587d05 /sys/netinet/sctputil.c | |
parent | f9307cced717999bc5dee2b8a4e2c0a1861c2793 (diff) | |
download | src-d59107f700c226ebf009c823dd4d72c7a23c6eed.tar.gz src-d59107f700c226ebf009c823dd4d72c7a23c6eed.zip |
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
Notes
Notes:
svn path=/head/; revision=275567
Diffstat (limited to 'sys/netinet/sctputil.c')
-rw-r--r-- | sys/netinet/sctputil.c | 72 |
1 files changed, 45 insertions, 27 deletions
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index b6aa3ea54d83..d066c741206d 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 |