diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index e1ad178135e0..617e48014d3d 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include #include #ifdef INET6 +#include #endif #include #include @@ -1373,10 +1374,14 @@ sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) 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_inpcb *inp, uint32_t vrf_id) 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 optname, void *optval, size_t optsize, { 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 optname, void *optval, size_t optsize, * 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 optname, void *optval, size_t optsize, } 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 optname, void *optval, size_t optsize, 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 optname, void *optval, size_t optsize, } /* 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 optname, void *optval, size_t optsize, #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 optname, void *optval, size_t optsize, } } 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 optname, void *optval, size_t optsize, * 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 optname, void *optval, size_t optsize, { 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 optname, void *optval, size_t optsize, * 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 optname, void *optval, size_t optsize, 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 optname, void *optval, size_t optsize, 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 optname, void *optval, size_t optsize, 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 optname, void *optval, size_t optsize, { 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 optname, void *optval, size_t optsize, 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 optname, void *optval, size_t optsize, { 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 optname, void *optval, size_t optsize, * 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 optname, void *optval, size_t optsize, } 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 optname, void *optval, size_t optsize, 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 optname, void *optval, size_t optsize, { 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 optname, void *optval, size_t optsize, */ 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 optname, void *optval, size_t optsize, } 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 optname, void *optval, size_t optsize, break; } } - if (stcb) { - if (net) { + if (stcb != NULL) { + if (net != NULL) { net->port = encaps->sue_port; } else { stcb->asoc.port = encaps->sue_port; 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