svn commit: r275567 - head/sys/netinet

Michael Tuexen tuexen at FreeBSD.org
Sat Dec 6 20:00:10 UTC 2014


Author: tuexen
Date: Sat Dec  6 20:00:08 2014
New Revision: 275567
URL: https://svnweb.freebsd.org/changeset/base/275567

Log:
  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

Modified:
  head/sys/netinet/sctp_usrreq.c
  head/sys/netinet/sctputil.c

Modified: head/sys/netinet/sctp_usrreq.c
==============================================================================
--- head/sys/netinet/sctp_usrreq.c	Sat Dec  6 17:50:37 2014	(r275566)
+++ head/sys/netinet/sctp_usrreq.c	Sat Dec  6 20:00:08 2014	(r275567)
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
 #include <netinet/sctp_header.h>
 #include <netinet/sctp_var.h>
 #ifdef INET6
+#include <netinet6/sctp6_var.h>
 #endif
 #include <netinet/sctp_sysctl.h>
 #include <netinet/sctp_output.h>
@@ -1373,10 +1374,14 @@ sctp_count_max_addresses_vrf(struct sctp
 				switch (sctp_ifa->address.sa.sa_family) {
 #ifdef INET
 				case AF_INET:
+#ifdef INET6
 					if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
 						cnt += sizeof(struct sockaddr_in6);
 					else
 						cnt += sizeof(struct sockaddr_in);
+#else
+					cnt += sizeof(struct sockaddr_in);
+#endif
 					break;
 #endif
 #ifdef INET6
@@ -1396,10 +1401,14 @@ sctp_count_max_addresses_vrf(struct sctp
 			switch (laddr->ifa->address.sa.sa_family) {
 #ifdef INET
 			case AF_INET:
+#ifdef INET6
 				if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
 					cnt += sizeof(struct sockaddr_in6);
 				else
 					cnt += sizeof(struct sockaddr_in);
+#else
+				cnt += sizeof(struct sockaddr_in);
+#endif
 				break;
 #endif
 #ifdef INET6
@@ -2216,23 +2225,27 @@ flags_out:
 				size = 0;
 				/* Count the sizes */
 				TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
-					if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
-						size += sizeof(struct sockaddr_in6);
-					} else {
-						switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) {
+					switch (net->ro._l_addr.sa.sa_family) {
 #ifdef INET
-						case AF_INET:
+					case AF_INET:
+#ifdef INET6
+						if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
+							size += sizeof(struct sockaddr_in6);
+						} else {
 							size += sizeof(struct sockaddr_in);
-							break;
+						}
+#else
+						size += sizeof(struct sockaddr_in);
+#endif
+						break;
 #endif
 #ifdef INET6
-						case AF_INET6:
-							size += sizeof(struct sockaddr_in6);
-							break;
+					case AF_INET6:
+						size += sizeof(struct sockaddr_in6);
+						break;
 #endif
-						default:
-							break;
-						}
+					default:
+						break;
 					}
 				}
 				SCTP_TCB_UNLOCK(stcb);
@@ -2264,24 +2277,28 @@ flags_out:
 				sas = (struct sockaddr_storage *)&saddr->addr[0];
 
 				TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
-					if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
-						cpsz = sizeof(struct sockaddr_in6);
-					} else {
-						switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) {
+					switch (net->ro._l_addr.sa.sa_family) {
 #ifdef INET
-						case AF_INET:
+					case AF_INET:
+#ifdef INET6
+						if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
+							cpsz = sizeof(struct sockaddr_in6);
+						} else {
 							cpsz = sizeof(struct sockaddr_in);
-							break;
+						}
+#else
+						cpsz = sizeof(struct sockaddr_in);
+#endif
+						break;
 #endif
 #ifdef INET6
-						case AF_INET6:
-							cpsz = sizeof(struct sockaddr_in6);
-							break;
+					case AF_INET6:
+						cpsz = sizeof(struct sockaddr_in6);
+						break;
 #endif
-						default:
-							cpsz = 0;
-							break;
-						}
+					default:
+						cpsz = 0;
+						break;
 					}
 					if (cpsz == 0) {
 						break;
@@ -2292,15 +2309,15 @@ flags_out:
 					}
 #if defined(INET) && defined(INET6)
 					if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) &&
-					    (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET)) {
+					    (net->ro._l_addr.sa.sa_family == AF_INET)) {
 						/* Must map the address */
-						in6_sin_2_v4mapsin6((struct sockaddr_in *)&net->ro._l_addr,
+						in6_sin_2_v4mapsin6(&net->ro._l_addr.sin,
 						    (struct sockaddr_in6 *)sas);
 					} else {
-#endif
 						memcpy(sas, &net->ro._l_addr, cpsz);
-#if defined(INET) && defined(INET6)
 					}
+#else
+					memcpy(sas, &net->ro._l_addr, cpsz);
 #endif
 					((struct sockaddr_in *)sas)->sin_port = stcb->rport;
 
@@ -2337,13 +2354,35 @@ flags_out:
 		{
 			struct sctp_paddrparams *paddrp;
 			struct sctp_nets *net;
+			struct sockaddr *addr;
+
+#if defined(INET) && defined(INET6)
+			struct sockaddr_in sin_store;
+
+#endif
 
 			SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize);
 			SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
 
-			net = NULL;
-			if (stcb) {
-				net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
+#if defined(INET) && defined(INET6)
+			if (paddrp->spp_address.ss_family == AF_INET6) {
+				struct sockaddr_in6 *sin6;
+
+				sin6 = (struct sockaddr_in6 *)&paddrp->spp_address;
+				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+					in6_sin6_2_sin(&sin_store, sin6);
+					addr = (struct sockaddr *)&sin_store;
+				} else {
+					addr = (struct sockaddr *)&paddrp->spp_address;
+				}
+			} else {
+				addr = (struct sockaddr *)&paddrp->spp_address;
+			}
+#else
+			addr = (struct sockaddr *)&paddrp->spp_address;
+#endif
+			if (stcb != NULL) {
+				net = sctp_findnet(stcb, addr);
 			} else {
 				/*
 				 * We increment here since
@@ -2352,22 +2391,20 @@ flags_out:
 				 * the locked tcb (last argument) is NOT a
 				 * TCB.. aka NULL.
 				 */
+				net = NULL;
 				SCTP_INP_INCR_REF(inp);
-				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddrp->spp_address, &net, NULL, NULL);
+				stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
 				if (stcb == NULL) {
 					SCTP_INP_DECR_REF(inp);
 				}
 			}
-			if (stcb && (net == NULL)) {
-				struct sockaddr *sa;
-
-				sa = (struct sockaddr *)&paddrp->spp_address;
+			if ((stcb != NULL) && (net == NULL)) {
 #ifdef INET
-				if (sa->sa_family == AF_INET) {
+				if (addr->sa_family == AF_INET) {
 					struct sockaddr_in *sin;
 
-					sin = (struct sockaddr_in *)sa;
-					if (sin->sin_addr.s_addr) {
+					sin = (struct sockaddr_in *)addr;
+					if (sin->sin_addr.s_addr != INADDR_ANY) {
 						error = EINVAL;
 						SCTP_TCB_UNLOCK(stcb);
 						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
@@ -2376,10 +2413,10 @@ flags_out:
 				} else
 #endif
 #ifdef INET6
-				if (sa->sa_family == AF_INET6) {
+				if (addr->sa_family == AF_INET6) {
 					struct sockaddr_in6 *sin6;
 
-					sin6 = (struct sockaddr_in6 *)sa;
+					sin6 = (struct sockaddr_in6 *)addr;
 					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
 						error = EINVAL;
 						SCTP_TCB_UNLOCK(stcb);
@@ -2395,10 +2432,10 @@ flags_out:
 					break;
 				}
 			}
-			if (stcb) {
+			if (stcb != NULL) {
 				/* Applies to the specific association */
 				paddrp->spp_flags = 0;
-				if (net) {
+				if (net != NULL) {
 					int ovh;
 
 					if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
@@ -2514,13 +2551,35 @@ flags_out:
 		{
 			struct sctp_paddrinfo *paddri;
 			struct sctp_nets *net;
+			struct sockaddr *addr;
+
+#if defined(INET) && defined(INET6)
+			struct sockaddr_in sin_store;
+
+#endif
 
 			SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize);
 			SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id);
 
-			net = NULL;
-			if (stcb) {
-				net = sctp_findnet(stcb, (struct sockaddr *)&paddri->spinfo_address);
+#if defined(INET) && defined(INET6)
+			if (paddri->spinfo_address.ss_family == AF_INET6) {
+				struct sockaddr_in6 *sin6;
+
+				sin6 = (struct sockaddr_in6 *)&paddri->spinfo_address;
+				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+					in6_sin6_2_sin(&sin_store, sin6);
+					addr = (struct sockaddr *)&sin_store;
+				} else {
+					addr = (struct sockaddr *)&paddri->spinfo_address;
+				}
+			} else {
+				addr = (struct sockaddr *)&paddri->spinfo_address;
+			}
+#else
+			addr = (struct sockaddr *)&paddri->spinfo_address;
+#endif
+			if (stcb != NULL) {
+				net = sctp_findnet(stcb, addr);
 			} else {
 				/*
 				 * We increment here since
@@ -2529,14 +2588,15 @@ flags_out:
 				 * the locked tcb (last argument) is NOT a
 				 * TCB.. aka NULL.
 				 */
+				net = NULL;
 				SCTP_INP_INCR_REF(inp);
-				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddri->spinfo_address, &net, NULL, NULL);
+				stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
 				if (stcb == NULL) {
 					SCTP_INP_DECR_REF(inp);
 				}
 			}
 
-			if ((stcb) && (net)) {
+			if ((stcb != NULL) && (net != NULL)) {
 				if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
 					/* It's unconfirmed */
 					paddri->spinfo_state = SCTP_UNCONFIRMED;
@@ -2555,7 +2615,7 @@ flags_out:
 				SCTP_TCB_UNLOCK(stcb);
 				*optsize = sizeof(struct sctp_paddrinfo);
 			} else {
-				if (stcb) {
+				if (stcb != NULL) {
 					SCTP_TCB_UNLOCK(stcb);
 				}
 				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
@@ -2772,16 +2832,32 @@ flags_out:
 			SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id);
 
 			if (stcb) {
-				/* simply copy out the sockaddr_storage... */
-				size_t len;
+				union sctp_sockstore *addr;
 
-				len = *optsize;
-				if (len > stcb->asoc.primary_destination->ro._l_addr.sa.sa_len)
-					len = stcb->asoc.primary_destination->ro._l_addr.sa.sa_len;
-
-				memcpy(&ssp->ssp_addr,
-				    &stcb->asoc.primary_destination->ro._l_addr,
-				    len);
+				addr = &stcb->asoc.primary_destination->ro._l_addr;
+				switch (addr->sa.sa_family) {
+#ifdef INET
+				case AF_INET:
+#ifdef INET6
+					if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
+						in6_sin_2_v4mapsin6(&addr->sin,
+						    (struct sockaddr_in6 *)&ssp->ssp_addr);
+					} else {
+						memcpy(&ssp->ssp_addr, &addr->sin, sizeof(struct sockaddr_in));
+					}
+#else
+					memcpy(&ssp->ssp_addr, &addr->sin, sizeof(struct sockaddr_in));
+#endif
+					break;
+#endif
+#ifdef INET6
+				case AF_INET6:
+					memcpy(&ssp->ssp_addr, &addr->sin6, sizeof(struct sockaddr_in6));
+					break;
+#endif
+				default:
+					break;
+				}
 				SCTP_TCB_UNLOCK(stcb);
 				*optsize = sizeof(struct sctp_setprim);
 			} else {
@@ -3121,13 +3197,35 @@ flags_out:
 		{
 			struct sctp_paddrthlds *thlds;
 			struct sctp_nets *net;
+			struct sockaddr *addr;
+
+#if defined(INET) && defined(INET6)
+			struct sockaddr_in sin_store;
+
+#endif
 
 			SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize);
 			SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
 
-			net = NULL;
-			if (stcb) {
-				net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_address);
+#if defined(INET) && defined(INET6)
+			if (thlds->spt_address.ss_family == AF_INET6) {
+				struct sockaddr_in6 *sin6;
+
+				sin6 = (struct sockaddr_in6 *)&thlds->spt_address;
+				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+					in6_sin6_2_sin(&sin_store, sin6);
+					addr = (struct sockaddr *)&sin_store;
+				} else {
+					addr = (struct sockaddr *)&thlds->spt_address;
+				}
+			} else {
+				addr = (struct sockaddr *)&thlds->spt_address;
+			}
+#else
+			addr = (struct sockaddr *)&thlds->spt_address;
+#endif
+			if (stcb != NULL) {
+				net = sctp_findnet(stcb, addr);
 			} else {
 				/*
 				 * We increment here since
@@ -3136,22 +3234,20 @@ flags_out:
 				 * the locked tcb (last argument) is NOT a
 				 * TCB.. aka NULL.
 				 */
+				net = NULL;
 				SCTP_INP_INCR_REF(inp);
-				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&thlds->spt_address, &net, NULL, NULL);
+				stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
 				if (stcb == NULL) {
 					SCTP_INP_DECR_REF(inp);
 				}
 			}
-			if (stcb && (net == NULL)) {
-				struct sockaddr *sa;
-
-				sa = (struct sockaddr *)&thlds->spt_address;
+			if ((stcb != NULL) && (net == NULL)) {
 #ifdef INET
-				if (sa->sa_family == AF_INET) {
+				if (addr->sa_family == AF_INET) {
 					struct sockaddr_in *sin;
 
-					sin = (struct sockaddr_in *)sa;
-					if (sin->sin_addr.s_addr) {
+					sin = (struct sockaddr_in *)addr;
+					if (sin->sin_addr.s_addr != INADDR_ANY) {
 						error = EINVAL;
 						SCTP_TCB_UNLOCK(stcb);
 						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
@@ -3160,10 +3256,10 @@ flags_out:
 				} else
 #endif
 #ifdef INET6
-				if (sa->sa_family == AF_INET6) {
+				if (addr->sa_family == AF_INET6) {
 					struct sockaddr_in6 *sin6;
 
-					sin6 = (struct sockaddr_in6 *)sa;
+					sin6 = (struct sockaddr_in6 *)addr;
 					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
 						error = EINVAL;
 						SCTP_TCB_UNLOCK(stcb);
@@ -3179,8 +3275,8 @@ flags_out:
 					break;
 				}
 			}
-			if (stcb) {
-				if (net) {
+			if (stcb != NULL) {
+				if (net != NULL) {
 					thlds->spt_pathmaxrxt = net->failure_threshold;
 					thlds->spt_pathpfthld = net->pf_threshold;
 				} else {
@@ -3212,12 +3308,35 @@ flags_out:
 		{
 			struct sctp_udpencaps *encaps;
 			struct sctp_nets *net;
+			struct sockaddr *addr;
+
+#if defined(INET) && defined(INET6)
+			struct sockaddr_in sin_store;
+
+#endif
 
 			SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, *optsize);
 			SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id);
 
+#if defined(INET) && defined(INET6)
+			if (encaps->sue_address.ss_family == AF_INET6) {
+				struct sockaddr_in6 *sin6;
+
+				sin6 = (struct sockaddr_in6 *)&encaps->sue_address;
+				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+					in6_sin6_2_sin(&sin_store, sin6);
+					addr = (struct sockaddr *)&sin_store;
+				} else {
+					addr = (struct sockaddr *)&encaps->sue_address;
+				}
+			} else {
+				addr = (struct sockaddr *)&encaps->sue_address;
+			}
+#else
+			addr = (struct sockaddr *)&encaps->sue_address;
+#endif
 			if (stcb) {
-				net = sctp_findnet(stcb, (struct sockaddr *)&encaps->sue_address);
+				net = sctp_findnet(stcb, addr);
 			} else {
 				/*
 				 * We increment here since
@@ -3228,21 +3347,18 @@ flags_out:
 				 */
 				net = NULL;
 				SCTP_INP_INCR_REF(inp);
-				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&encaps->sue_address, &net, NULL, NULL);
+				stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
 				if (stcb == NULL) {
 					SCTP_INP_DECR_REF(inp);
 				}
 			}
-			if (stcb && (net == NULL)) {
-				struct sockaddr *sa;
-
-				sa = (struct sockaddr *)&encaps->sue_address;
+			if ((stcb != NULL) && (net == NULL)) {
 #ifdef INET
-				if (sa->sa_family == AF_INET) {
+				if (addr->sa_family == AF_INET) {
 					struct sockaddr_in *sin;
 
-					sin = (struct sockaddr_in *)sa;
-					if (sin->sin_addr.s_addr) {
+					sin = (struct sockaddr_in *)addr;
+					if (sin->sin_addr.s_addr != INADDR_ANY) {
 						error = EINVAL;
 						SCTP_TCB_UNLOCK(stcb);
 						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
@@ -3251,10 +3367,10 @@ flags_out:
 				} else
 #endif
 #ifdef INET6
-				if (sa->sa_family == AF_INET6) {
+				if (addr->sa_family == AF_INET6) {
 					struct sockaddr_in6 *sin6;
 
-					sin6 = (struct sockaddr_in6 *)sa;
+					sin6 = (struct sockaddr_in6 *)addr;
 					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
 						error = EINVAL;
 						SCTP_TCB_UNLOCK(stcb);
@@ -3270,7 +3386,7 @@ flags_out:
 					break;
 				}
 			}
-			if (stcb) {
+			if (stcb != NULL) {
 				if (net) {
 					encaps->sue_port = net->port;
 				} else {
@@ -4946,12 +5062,35 @@ sctp_setopt(struct socket *so, int optna
 		{
 			struct sctp_paddrparams *paddrp;
 			struct sctp_nets *net;
+			struct sockaddr *addr;
+
+#if defined(INET) && defined(INET6)
+			struct sockaddr_in sin_store;
+
+#endif
 
 			SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize);
 			SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
-			net = NULL;
-			if (stcb) {
-				net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
+
+#if defined(INET) && defined(INET6)
+			if (paddrp->spp_address.ss_family == AF_INET6) {
+				struct sockaddr_in6 *sin6;
+
+				sin6 = (struct sockaddr_in6 *)&paddrp->spp_address;
+				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+					in6_sin6_2_sin(&sin_store, sin6);
+					addr = (struct sockaddr *)&sin_store;
+				} else {
+					addr = (struct sockaddr *)&paddrp->spp_address;
+				}
+			} else {
+				addr = (struct sockaddr *)&paddrp->spp_address;
+			}
+#else
+			addr = (struct sockaddr *)&paddrp->spp_address;
+#endif
+			if (stcb != NULL) {
+				net = sctp_findnet(stcb, addr);
 			} else {
 				/*
 				 * We increment here since
@@ -4960,25 +5099,22 @@ sctp_setopt(struct socket *so, int optna
 				 * the locked tcb (last argument) is NOT a
 				 * TCB.. aka NULL.
 				 */
+				net = NULL;
 				SCTP_INP_INCR_REF(inp);
-				stcb = sctp_findassociation_ep_addr(&inp,
-				    (struct sockaddr *)&paddrp->spp_address,
+				stcb = sctp_findassociation_ep_addr(&inp, addr,
 				    &net, NULL, NULL);
 				if (stcb == NULL) {
 					SCTP_INP_DECR_REF(inp);
 				}
 			}
-			if (stcb && (net == NULL)) {
-				struct sockaddr *sa;
-
-				sa = (struct sockaddr *)&paddrp->spp_address;
+			if ((stcb != NULL) && (net == NULL)) {
 #ifdef INET
-				if (sa->sa_family == AF_INET) {
+				if (addr->sa_family == AF_INET) {
 
 					struct sockaddr_in *sin;
 
-					sin = (struct sockaddr_in *)sa;
-					if (sin->sin_addr.s_addr) {
+					sin = (struct sockaddr_in *)addr;
+					if (sin->sin_addr.s_addr != INADDR_ANY) {
 						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
 						SCTP_TCB_UNLOCK(stcb);
 						error = EINVAL;
@@ -4987,10 +5123,10 @@ sctp_setopt(struct socket *so, int optna
 				} else
 #endif
 #ifdef INET6
-				if (sa->sa_family == AF_INET6) {
+				if (addr->sa_family == AF_INET6) {
 					struct sockaddr_in6 *sin6;
 
-					sin6 = (struct sockaddr_in6 *)sa;
+					sin6 = (struct sockaddr_in6 *)addr;
 					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
 						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
 						SCTP_TCB_UNLOCK(stcb);
@@ -5019,7 +5155,7 @@ sctp_setopt(struct socket *so, int optna
 				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
 				return (EINVAL);
 			}
-			if (stcb) {
+			if (stcb != NULL) {
 				/************************TCB SPECIFIC SET ******************/
 				/*
 				 * do we change the timer for HB, we run
@@ -5034,7 +5170,7 @@ sctp_setopt(struct socket *so, int optna
 				}
 
 				/* network sets ? */
-				if (net) {
+				if (net != NULL) {
 					/************************NET SPECIFIC SET ******************/
 					if (paddrp->spp_flags & SPP_HB_DISABLE) {
 						if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
@@ -5119,7 +5255,7 @@ sctp_setopt(struct socket *so, int optna
 #endif
 				} else {
 					/************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/
-					if (paddrp->spp_pathmaxrxt) {
+					if (paddrp->spp_pathmaxrxt != 0) {
 						stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt;
 						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
 							if (net->dest_state & SCTP_ADDR_PF) {
@@ -5150,14 +5286,14 @@ sctp_setopt(struct socket *so, int optna
 						}
 					}
 					if (paddrp->spp_flags & SPP_HB_ENABLE) {
-						if (paddrp->spp_hbinterval) {
+						if (paddrp->spp_hbinterval != 0) {
 							stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval;
 						} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
 							stcb->asoc.heart_beat_delay = 0;
 						}
 						/* Turn back on the timer */
 						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
-							if (paddrp->spp_hbinterval) {
+							if (paddrp->spp_hbinterval != 0) {
 								net->heart_beat_delay = paddrp->spp_hbinterval;
 							} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
 								net->heart_beat_delay = 0;
@@ -5238,12 +5374,12 @@ sctp_setopt(struct socket *so, int optna
 					 * set it with the options on the
 					 * socket
 					 */
-					if (paddrp->spp_pathmaxrxt) {
+					if (paddrp->spp_pathmaxrxt != 0) {
 						inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt;
 					}
 					if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
 						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
-					else if (paddrp->spp_hbinterval) {
+					else if (paddrp->spp_hbinterval != 0) {
 						if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL)
 							paddrp->spp_hbinterval = SCTP_MAX_HB_INTERVAL;
 						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
@@ -5409,13 +5545,35 @@ sctp_setopt(struct socket *so, int optna
 		{
 			struct sctp_setprim *spa;
 			struct sctp_nets *net;
+			struct sockaddr *addr;
+
+#if defined(INET) && defined(INET6)
+			struct sockaddr_in sin_store;
+
+#endif
 
 			SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize);
 			SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id);
 
-			net = NULL;
-			if (stcb) {
-				net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr);
+#if defined(INET) && defined(INET6)
+			if (spa->ssp_addr.ss_family == AF_INET6) {
+				struct sockaddr_in6 *sin6;
+
+				sin6 = (struct sockaddr_in6 *)&spa->ssp_addr;
+				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+					in6_sin6_2_sin(&sin_store, sin6);
+					addr = (struct sockaddr *)&sin_store;
+				} else {
+					addr = (struct sockaddr *)&spa->ssp_addr;
+				}
+			} else {
+				addr = (struct sockaddr *)&spa->ssp_addr;
+			}
+#else
+			addr = (struct sockaddr *)&spa->ssp_addr;
+#endif
+			if (stcb != NULL) {
+				net = sctp_findnet(stcb, addr);
 			} else {
 				/*
 				 * We increment here since
@@ -5424,16 +5582,16 @@ sctp_setopt(struct socket *so, int optna
 				 * the locked tcb (last argument) is NOT a
 				 * TCB.. aka NULL.
 				 */
+				net = NULL;
 				SCTP_INP_INCR_REF(inp);
-				stcb = sctp_findassociation_ep_addr(&inp,
-				    (struct sockaddr *)&spa->ssp_addr,
+				stcb = sctp_findassociation_ep_addr(&inp, addr,
 				    &net, NULL, NULL);
 				if (stcb == NULL) {
 					SCTP_INP_DECR_REF(inp);
 				}
 			}
 
-			if ((stcb) && (net)) {
+			if ((stcb != NULL) && (net != NULL)) {
 				if ((net != stcb->asoc.primary_destination) &&
 				    (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
 					/* Ok we need to set it */
@@ -5450,7 +5608,7 @@ sctp_setopt(struct socket *so, int optna
 				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
 				error = EINVAL;
 			}
-			if (stcb) {
+			if (stcb != NULL) {
 				SCTP_TCB_UNLOCK(stcb);
 			}
 			break;
@@ -5472,14 +5630,36 @@ sctp_setopt(struct socket *so, int optna
 	case SCTP_SET_PEER_PRIMARY_ADDR:
 		{
 			struct sctp_setpeerprim *sspp;
+			struct sockaddr *addr;
+
+#if defined(INET) && defined(INET6)
+			struct sockaddr_in sin_store;
+
+#endif
 
 			SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize);
 			SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id);
 			if (stcb != NULL) {
 				struct sctp_ifa *ifa;
 
-				ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr,
-				    stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED);
+#if defined(INET) && defined(INET6)
+				if (sspp->sspp_addr.ss_family == AF_INET6) {
+					struct sockaddr_in6 *sin6;
+
+					sin6 = (struct sockaddr_in6 *)&sspp->sspp_addr;
+					if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+						in6_sin6_2_sin(&sin_store, sin6);
+						addr = (struct sockaddr *)&sin_store;
+					} else {
+						addr = (struct sockaddr *)&sspp->sspp_addr;
+					}
+				} else {
+					addr = (struct sockaddr *)&sspp->sspp_addr;
+				}
+#else
+				addr = (struct sockaddr *)&sspp->sspp_addr;
+#endif
+				ifa = sctp_find_ifa_by_addr(addr, stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED);
 				if (ifa == NULL) {
 					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
 					error = EINVAL;
@@ -5510,13 +5690,13 @@ sctp_setopt(struct socket *so, int optna
 						goto out_of_it;
 					}
 				} else {
-					switch (sspp->sspp_addr.ss_family) {
+					switch (addr->sa_family) {
 #ifdef INET
 					case AF_INET:
 						{
 							struct sockaddr_in *sin;
 
-							sin = (struct sockaddr_in *)&sspp->sspp_addr;
+							sin = (struct sockaddr_in *)addr;
 							if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
 							    &sin->sin_addr) != 0) {
 								SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -5531,7 +5711,7 @@ sctp_setopt(struct socket *so, int optna
 						{
 							struct sockaddr_in6 *sin6;
 
-							sin6 = (struct sockaddr_in6 *)&sspp->sspp_addr;
+							sin6 = (struct sockaddr_in6 *)addr;
 							if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
 							    &sin6->sin6_addr) != 0) {
 								SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -5547,8 +5727,7 @@ sctp_setopt(struct socket *so, int optna
 						goto out_of_it;
 					}
 				}
-				if (sctp_set_primary_ip_address_sa(stcb,
-				    (struct sockaddr *)&sspp->sspp_addr) != 0) {
+				if (sctp_set_primary_ip_address_sa(stcb, addr) != 0) {
 					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
 					error = EINVAL;
 				}
@@ -5899,12 +6078,35 @@ sctp_setopt(struct socket *so, int optna
 		{
 			struct sctp_paddrthlds *thlds;
 			struct sctp_nets *net;
+			struct sockaddr *addr;
+
+#if defined(INET) && defined(INET6)
+			struct sockaddr_in sin_store;
+
+#endif
 
 			SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize);
 			SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
-			net = NULL;
-			if (stcb) {
-				net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_address);
+
+#if defined(INET) && defined(INET6)
+			if (thlds->spt_address.ss_family == AF_INET6) {
+				struct sockaddr_in6 *sin6;
+
+				sin6 = (struct sockaddr_in6 *)&thlds->spt_address;
+				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+					in6_sin6_2_sin(&sin_store, sin6);
+					addr = (struct sockaddr *)&sin_store;
+				} else {
+					addr = (struct sockaddr *)&thlds->spt_address;
+				}
+			} else {
+				addr = (struct sockaddr *)&thlds->spt_address;
+			}
+#else
+			addr = (struct sockaddr *)&thlds->spt_address;
+#endif
+			if (stcb != NULL) {
+				net = sctp_findnet(stcb, addr);
 			} else {
 				/*
 				 * We increment here since
@@ -5913,25 +6115,22 @@ sctp_setopt(struct socket *so, int optna
 				 * the locked tcb (last argument) is NOT a
 				 * TCB.. aka NULL.
 				 */
+				net = NULL;
 				SCTP_INP_INCR_REF(inp);
-				stcb = sctp_findassociation_ep_addr(&inp,
-				    (struct sockaddr *)&thlds->spt_address,
+				stcb = sctp_findassociation_ep_addr(&inp, addr,
 				    &net, NULL, NULL);
 				if (stcb == NULL) {
 					SCTP_INP_DECR_REF(inp);
 				}
 			}
-			if (stcb && (net == NULL)) {
-				struct sockaddr *sa;
-
-				sa = (struct sockaddr *)&thlds->spt_address;
+			if ((stcb != NULL) && (net == NULL)) {
 #ifdef INET
-				if (sa->sa_family == AF_INET) {
+				if (addr->sa_family == AF_INET) {
 
 					struct sockaddr_in *sin;
 
-					sin = (struct sockaddr_in *)sa;
-					if (sin->sin_addr.s_addr) {
+					sin = (struct sockaddr_in *)addr;
+					if (sin->sin_addr.s_addr != INADDR_ANY) {
 						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
 						SCTP_TCB_UNLOCK(stcb);
 						error = EINVAL;
@@ -5940,10 +6139,10 @@ sctp_setopt(struct socket *so, int optna
 				} else
 #endif
 #ifdef INET6
-				if (sa->sa_family == AF_INET6) {
+				if (addr->sa_family == AF_INET6) {
 					struct sockaddr_in6 *sin6;
 
-					sin6 = (struct sockaddr_in6 *)sa;
+					sin6 = (struct sockaddr_in6 *)addr;
 					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
 						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
 						SCTP_TCB_UNLOCK(stcb);
@@ -5959,8 +6158,8 @@ sctp_setopt(struct socket *so, int optna
 					break;
 				}
 			}
-			if (stcb) {
-				if (net) {
+			if (stcb != NULL) {
+				if (net != NULL) {
 					if (net->dest_state & SCTP_ADDR_PF) {
 						if ((net->failure_threshold > thlds->spt_pathmaxrxt) ||
 						    (net->failure_threshold <= thlds->spt_pathpfthld)) {
@@ -6040,11 +6239,35 @@ sctp_setopt(struct socket *so, int optna
 		{
 			struct sctp_udpencaps *encaps;
 			struct sctp_nets *net;
+			struct sockaddr *addr;
+
+#if defined(INET) && defined(INET6)
+			struct sockaddr_in sin_store;
+
+#endif
 
 			SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, optsize);
 			SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id);
-			if (stcb) {
-				net = sctp_findnet(stcb, (struct sockaddr *)&encaps->sue_address);
+
+#if defined(INET) && defined(INET6)
+			if (encaps->sue_address.ss_family == AF_INET6) {
+				struct sockaddr_in6 *sin6;
+
+				sin6 = (struct sockaddr_in6 *)&encaps->sue_address;
+				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+					in6_sin6_2_sin(&sin_store, sin6);
+					addr = (struct sockaddr *)&sin_store;
+				} else {
+					addr = (struct sockaddr *)&encaps->sue_address;
+				}
+			} else {
+				addr = (struct sockaddr *)&encaps->sue_address;
+			}
+#else
+			addr = (struct sockaddr *)&encaps->sue_address;
+#endif
+			if (stcb != NULL) {
+				net = sctp_findnet(stcb, addr);
 			} else {
 				/*
 				 * We increment here since
@@ -6055,22 +6278,19 @@ sctp_setopt(struct socket *so, int optna
 				 */
 				net = NULL;
 				SCTP_INP_INCR_REF(inp);
-				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&encaps->sue_address, &net, NULL, NULL);
+				stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
 				if (stcb == NULL) {
 					SCTP_INP_DECR_REF(inp);
 				}
 			}
-			if (stcb && (net == NULL)) {
-				struct sockaddr *sa;
-
-				sa = (struct sockaddr *)&encaps->sue_address;
+			if ((stcb != NULL) && (net == NULL)) {
 #ifdef INET
-				if (sa->sa_family == AF_INET) {
+				if (addr->sa_family == AF_INET) {
 
 					struct sockaddr_in *sin;
 
-					sin = (struct sockaddr_in *)sa;
-					if (sin->sin_addr.s_addr) {
+					sin = (struct sockaddr_in *)addr;
+					if (sin->sin_addr.s_addr != INADDR_ANY) {
 						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
 						SCTP_TCB_UNLOCK(stcb);
 						error = EINVAL;
@@ -6079,10 +6299,10 @@ sctp_setopt(struct socket *so, int optna
 				} else
 #endif
 #ifdef INET6
-				if (sa->sa_family == AF_INET6) {
+				if (addr->sa_family == AF_INET6) {
 					struct sockaddr_in6 *sin6;
 
-					sin6 = (struct sockaddr_in6 *)sa;
+					sin6 = (struct sockaddr_in6 *)addr;
 					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
 						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
 						SCTP_TCB_UNLOCK(stcb);
@@ -6098,8 +6318,8 @@ sctp_setopt(struct socket *so, int optna
 					break;
 				}
 			}
-			if (stcb) {
-				if (net) {
+			if (stcb != NULL) {
+				if (net != NULL) {
 					net->port = encaps->sue_port;
 				} else {
 					stcb->asoc.port = encaps->sue_port;

Modified: head/sys/netinet/sctputil.c
==============================================================================
--- head/sys/netinet/sctputil.c	Sat Dec  6 17:50:37 2014	(r275566)
+++ head/sys/netinet/sctputil.c	Sat Dec  6 20:00:08 2014	(r275567)
@@ -2760,7 +2760,16 @@ sctp_notify_peer_addr_change(struct sctp
 	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)) {

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list