Improve compilation of SCTP code without INET support.

Some bugs where fixed while doing this:
* ASCONF-ACK messages might use wrong port number when using
  IPv6.
* Checking for additional addresses takes the correct address
  into account and also does not do more comparisons than
  necessary.

This patch is based on one received from bz@ who was
sponsored by The FreeBSD Foundation and iXsystems.

MFC after: 1 week
This commit is contained in:
Michael Tuexen 2011-04-30 11:18:16 +00:00
parent 79288c112c
commit e6194c2ed4
11 changed files with 2183 additions and 1370 deletions

File diff suppressed because it is too large Load Diff

View File

@ -228,10 +228,14 @@ sctp_init_ifns_for_vrf(int vrfid)
*/
struct ifnet *ifn;
struct ifaddr *ifa;
struct in6_ifaddr *ifa6;
struct sctp_ifa *sctp_ifa;
uint32_t ifa_flags;
#ifdef INET6
struct in6_ifaddr *ifa6;
#endif
IFNET_RLOCK();
TAILQ_FOREACH(ifn, &MODULE_GLOBAL(ifnet), if_list) {
IF_ADDR_LOCK(ifn);
@ -239,29 +243,44 @@ sctp_init_ifns_for_vrf(int vrfid)
if (ifa->ifa_addr == NULL) {
continue;
}
if ((ifa->ifa_addr->sa_family != AF_INET) && (ifa->ifa_addr->sa_family != AF_INET6)) {
/* non inet/inet6 skip */
switch (ifa->ifa_addr->sa_family) {
#ifdef INET
case AF_INET:
if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == 0) {
continue;
}
if (ifa->ifa_addr->sa_family == AF_INET6) {
break;
#endif
#ifdef INET6
case AF_INET6:
if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) {
/* skip unspecifed addresses */
continue;
}
} else {
if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == 0) {
break;
#endif
default:
continue;
}
}
if (sctp_is_desired_interface_type(ifa) == 0) {
/* non desired type */
continue;
}
if (ifa->ifa_addr->sa_family == AF_INET6) {
switch (ifa->ifa_addr->sa_family) {
#ifdef INET
case AF_INET:
ifa_flags = 0;
break;
#endif
#ifdef INET6
case AF_INET6:
ifa6 = (struct in6_ifaddr *)ifa;
ifa_flags = ifa6->ia6_flags;
} else {
break;
#endif
default:
ifa_flags = 0;
break;
}
sctp_ifa = sctp_add_addr_to_vrf(vrfid,
(void *)ifn,
@ -320,21 +339,27 @@ sctp_addr_change(struct ifaddr *ifa, int cmd)
if (ifa->ifa_addr == NULL) {
return;
}
if ((ifa->ifa_addr->sa_family != AF_INET) && (ifa->ifa_addr->sa_family != AF_INET6)) {
/* non inet/inet6 skip */
switch (ifa->ifa_addr->sa_family) {
#ifdef INET
case AF_INET:
if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == 0) {
return;
}
if (ifa->ifa_addr->sa_family == AF_INET6) {
break;
#endif
#ifdef INET6
case AF_INET6:
ifa_flags = ((struct in6_ifaddr *)ifa)->ia6_flags;
if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) {
/* skip unspecifed addresses */
return;
}
} else {
if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == 0) {
break;
#endif
default:
/* non inet/inet6 skip */
return;
}
}
if (sctp_is_desired_interface_type(ifa) == 0) {
/* non desired type */

View File

@ -530,29 +530,43 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
struct sctp_tcb *stcb, struct sctp_nets *net)
{
struct sockaddr_storage store;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
struct sctp_nets *r_net, *f_net;
struct timeval tv;
int req_prim = 0;
#ifdef INET
struct sockaddr_in *sin;
#endif
#ifdef INET6
struct sockaddr_in6 *sin6;
#endif
if (ntohs(cp->ch.chunk_length) != sizeof(struct sctp_heartbeat_chunk)) {
/* Invalid length */
return;
}
sin = (struct sockaddr_in *)&store;
sin6 = (struct sockaddr_in6 *)&store;
memset(&store, 0, sizeof(store));
if (cp->heartbeat.hb_info.addr_family == AF_INET &&
cp->heartbeat.hb_info.addr_len == sizeof(struct sockaddr_in)) {
switch (cp->heartbeat.hb_info.addr_family) {
#ifdef INET
case AF_INET:
if (cp->heartbeat.hb_info.addr_len == sizeof(struct sockaddr_in)) {
sin = (struct sockaddr_in *)&store;
sin->sin_family = cp->heartbeat.hb_info.addr_family;
sin->sin_len = cp->heartbeat.hb_info.addr_len;
sin->sin_port = stcb->rport;
memcpy(&sin->sin_addr, cp->heartbeat.hb_info.address,
sizeof(sin->sin_addr));
} else if (cp->heartbeat.hb_info.addr_family == AF_INET6 &&
cp->heartbeat.hb_info.addr_len == sizeof(struct sockaddr_in6)) {
} else {
return;
}
break;
#endif
#ifdef INET6
case AF_INET6:
if (cp->heartbeat.hb_info.addr_len == sizeof(struct sockaddr_in6)) {
sin6 = (struct sockaddr_in6 *)&store;
sin6->sin6_family = cp->heartbeat.hb_info.addr_family;
sin6->sin6_len = cp->heartbeat.hb_info.addr_len;
sin6->sin6_port = stcb->rport;
@ -561,7 +575,12 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
} else {
return;
}
r_net = sctp_findnet(stcb, (struct sockaddr *)sin);
break;
#endif
default:
return;
}
r_net = sctp_findnet(stcb, (struct sockaddr *)&store);
if (r_net == NULL) {
SCTPDBG(SCTP_DEBUG_INPUT1, "Huh? I can't find the address I sent it to, discard\n");
return;
@ -1940,8 +1959,6 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
struct sctp_init_ack_chunk *initack_cp, initack_buf;
struct sockaddr_storage sa_store;
struct sockaddr *initack_src = (struct sockaddr *)&sa_store;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
struct sctp_association *asoc;
int chk_length;
int init_offset, initack_offset, initack_limit;
@ -1950,6 +1967,14 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
uint32_t old_tag;
uint8_t auth_chunk_buf[SCTP_PARAM_BUFFER_SIZE];
#ifdef INET
struct sockaddr_in *sin;
#endif
#ifdef INET6
struct sockaddr_in6 *sin6;
#endif
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
struct socket *so;
@ -2169,14 +2194,19 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
/* warning, we re-use sin, sin6, sa_store here! */
/* pull in local_address (our "from" address) */
if (cookie->laddr_type == SCTP_IPV4_ADDRESS) {
switch (cookie->laddr_type) {
#ifdef INET
case SCTP_IPV4_ADDRESS:
/* source addr is IPv4 */
sin = (struct sockaddr_in *)initack_src;
memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
sin->sin_len = sizeof(struct sockaddr_in);
sin->sin_addr.s_addr = cookie->laddress[0];
} else if (cookie->laddr_type == SCTP_IPV6_ADDRESS) {
break;
#endif
#ifdef INET6
case SCTP_IPV6_ADDRESS:
/* source addr is IPv6 */
sin6 = (struct sockaddr_in6 *)initack_src;
memset(sin6, 0, sizeof(*sin6));
@ -2185,7 +2215,9 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
sin6->sin6_scope_id = cookie->scope_id;
memcpy(&sin6->sin6_addr, cookie->laddress,
sizeof(sin6->sin6_addr));
} else {
break;
#endif
default:
atomic_add_int(&stcb->asoc.refcnt, 1);
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
SCTP_TCB_UNLOCK(stcb);
@ -2295,8 +2327,6 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
struct sctp_tcb **locked_tcb, uint32_t vrf_id, uint16_t port)
{
struct sctp_state_cookie *cookie;
struct sockaddr_in6 sin6;
struct sockaddr_in sin;
struct sctp_tcb *l_stcb = *stcb;
struct sctp_inpcb *l_inp;
struct sockaddr *to;
@ -2318,6 +2348,15 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
int had_a_existing_tcb = 0;
int send_int_conf = 0;
#ifdef INET
struct sockaddr_in sin;
#endif
#ifdef INET6
struct sockaddr_in6 sin6;
#endif
SCTPDBG(SCTP_DEBUG_INPUT2,
"sctp_handle_cookie: handling COOKIE-ECHO\n");
@ -2327,6 +2366,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
/* First get the destination address setup too. */
iph = mtod(m, struct ip *);
switch (iph->ip_v) {
#ifdef INET
case IPVERSION:
{
/* its IPv4 */
@ -2341,6 +2381,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
size_of_pkt = SCTP_GET_IPV4_LENGTH(iph);
break;
}
#endif
#ifdef INET6
case IPV6_VERSION >> 4:
{
@ -2535,7 +2576,9 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
* up.
*/
to = NULL;
if (cookie->addr_type == SCTP_IPV6_ADDRESS) {
switch (cookie->addr_type) {
#ifdef INET6
case SCTP_IPV6_ADDRESS:
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
sin6.sin6_len = sizeof(sin6);
@ -2544,14 +2587,19 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
memcpy(&sin6.sin6_addr.s6_addr, cookie->address,
sizeof(sin6.sin6_addr.s6_addr));
to = (struct sockaddr *)&sin6;
} else if (cookie->addr_type == SCTP_IPV4_ADDRESS) {
break;
#endif
#ifdef INET
case SCTP_IPV4_ADDRESS:
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_len = sizeof(sin);
sin.sin_port = sh->src_port;
sin.sin_addr.s_addr = cookie->address[0];
to = (struct sockaddr *)&sin;
} else {
break;
#endif
default:
/* This should not happen */
return (NULL);
}
@ -5705,6 +5753,7 @@ sctp_print_mbuf_chain(struct mbuf *m)
#endif
#ifdef INET
void
sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port)
{
@ -6003,3 +6052,5 @@ sctp_input(struct mbuf *m, int off)
#endif
sctp_input_with_port(m, off, 0);
}
#endif

View File

@ -39,7 +39,9 @@ __FBSDID("$FreeBSD$");
#include "opt_ipsec.h"
#include "opt_compat.h"
#include "opt_inet6.h"
#if 1
#include "opt_inet.h"
#endif
#include "opt_sctp.h"
#include <sys/param.h>

File diff suppressed because it is too large Load Diff

View File

@ -426,10 +426,20 @@ sctp_add_ifa_to_ifn(struct sctp_ifn *sctp_ifnp, struct sctp_ifa *sctp_ifap)
/* update address counts */
sctp_ifnp->ifa_count++;
ifa_af = sctp_ifap->address.sa.sa_family;
if (ifa_af == AF_INET)
switch (ifa_af) {
#ifdef INET
case AF_INET:
sctp_ifnp->num_v4++;
else
break;
#endif
#ifdef INET6
case AF_INET6:
sctp_ifnp->num_v6++;
break;
#endif
default:
break;
}
if (sctp_ifnp->ifa_count == 1) {
/* register the new interface */
SCTP_REGISTER_INTERFACE(sctp_ifnp->ifn_index, ifa_af);
@ -452,10 +462,20 @@ sctp_remove_ifa_from_ifn(struct sctp_ifa *sctp_ifap)
if (sctp_ifap->ifn_p) {
/* update address counts */
sctp_ifap->ifn_p->ifa_count--;
if (sctp_ifap->address.sa.sa_family == AF_INET6)
sctp_ifap->ifn_p->num_v6--;
else if (sctp_ifap->address.sa.sa_family == AF_INET)
switch (sctp_ifap->address.sa.sa_family) {
#ifdef INET
case AF_INET:
sctp_ifap->ifn_p->num_v4--;
break;
#endif
#ifdef INET6
case AF_INET6:
sctp_ifap->ifn_p->num_v6--;
break;
#endif
default:
break;
}
ifn_index = sctp_ifap->ifn_p->ifn_index;
if (LIST_EMPTY(&sctp_ifap->ifn_p->ifalist)) {
@ -613,6 +633,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
sctp_ifap->flags = ifa_flags;
/* Set scope */
switch (sctp_ifap->address.sa.sa_family) {
#ifdef INET
case AF_INET:
{
struct sockaddr_in *sin;
@ -630,6 +651,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
new_ifn_af = AF_INET;
break;
}
#endif
#ifdef INET6
case AF_INET6:
{
@ -846,14 +868,29 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
if ((to == NULL) || (from == NULL)) {
return (NULL);
}
if (to->sa_family == AF_INET && from->sa_family == AF_INET) {
switch (to->sa_family) {
#ifdef INET
case AF_INET:
if (from->sa_family == AF_INET) {
lport = ((struct sockaddr_in *)to)->sin_port;
rport = ((struct sockaddr_in *)from)->sin_port;
} else if (to->sa_family == AF_INET6 && from->sa_family == AF_INET6) {
} else {
return (NULL);
}
break;
#endif
#ifdef INET6
case AF_INET6:
if (from->sa_family == AF_INET6) {
lport = ((struct sockaddr_in6 *)to)->sin6_port;
rport = ((struct sockaddr_in6 *)from)->sin6_port;
} else {
return NULL;
return (NULL);
}
break;
#endif
default:
return (NULL);
}
ephead = &SCTP_BASE_INFO(sctp_tcpephash)[SCTP_PCBHASH_ALLADDR((lport | rport), SCTP_BASE_INFO(hashtcpmark))];
/*
@ -894,17 +931,21 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
if (laddr->ifa->address.sa.sa_family ==
to->sa_family) {
/* see if it matches */
struct sockaddr_in *intf_addr, *sin;
#ifdef INET
if (from->sa_family == AF_INET) {
struct sockaddr_in *intf_addr,
*sin;
intf_addr = &laddr->ifa->address.sin;
sin = (struct sockaddr_in *)to;
if (from->sa_family == AF_INET) {
if (sin->sin_addr.s_addr ==
intf_addr->sin_addr.s_addr) {
match = 1;
break;
}
}
#endif
#ifdef INET6
if (from->sa_family == AF_INET6) {
struct sockaddr_in6 *intf_addr6;
@ -959,6 +1000,7 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
continue;
}
switch (from->sa_family) {
#ifdef INET
case AF_INET:
{
struct sockaddr_in *sin, *rsin;
@ -981,6 +1023,7 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
}
break;
}
#endif
#ifdef INET6
case AF_INET6:
{
@ -1256,6 +1299,7 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote,
continue;
}
switch (remote->sa_family) {
#ifdef INET
case AF_INET:
{
struct sockaddr_in *sin,
@ -1284,6 +1328,7 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote,
}
break;
}
#endif
#ifdef INET6
case AF_INET6:
{
@ -1357,6 +1402,7 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote,
continue;
}
switch (remote->sa_family) {
#ifdef INET
case AF_INET:
{
struct sockaddr_in *sin,
@ -1385,6 +1431,7 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote,
}
break;
}
#endif
#ifdef INET6
case AF_INET6:
{
@ -1505,15 +1552,14 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head,
uint16_t lport, uint32_t vrf_id)
{
struct sctp_inpcb *inp;
struct sockaddr_in *sin;
#ifdef INET6
struct sockaddr_in6 *sin6;
#endif
struct sctp_laddr *laddr;
#ifdef INET
struct sockaddr_in *sin;
#endif
#ifdef INET6
struct sockaddr_in6 *sin6;
struct sockaddr_in6 *intf_addr6;
#endif
@ -1523,14 +1569,18 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head,
/*
* Endpoint probe expects that the INP_INFO is locked.
*/
#ifdef INET
sin = NULL;
#endif
#ifdef INET6
sin6 = NULL;
#endif
switch (nam->sa_family) {
#ifdef INET
case AF_INET:
sin = (struct sockaddr_in *)nam;
break;
#endif
#ifdef INET6
case AF_INET6:
sin6 = (struct sockaddr_in6 *)nam;
@ -1553,6 +1603,7 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head,
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) &&
(inp->sctp_lport == lport)) {
/* got it */
#ifdef INET
if ((nam->sa_family == AF_INET) &&
(inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
SCTP_IPV6_V6ONLY(inp)) {
@ -1560,12 +1611,15 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head,
SCTP_INP_RUNLOCK(inp);
continue;
}
#endif
#ifdef INET6
/* A V6 address and the endpoint is NOT bound V6 */
if (nam->sa_family == AF_INET6 &&
(inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
SCTP_INP_RUNLOCK(inp);
continue;
}
#endif
/* does a VRF id match? */
fnd = 0;
if (inp->def_vrf_id == vrf_id)
@ -1578,18 +1632,26 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head,
}
SCTP_INP_RUNLOCK(inp);
}
if ((nam->sa_family == AF_INET) &&
(sin->sin_addr.s_addr == INADDR_ANY)) {
/* Can't hunt for one that has no address specified */
return (NULL);
}
#ifdef INET6
if ((nam->sa_family == AF_INET6) &&
(IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))) {
switch (nam->sa_family) {
#ifdef INET
case AF_INET:
if (sin->sin_addr.s_addr == INADDR_ANY) {
/* Can't hunt for one that has no address specified */
return (NULL);
}
break;
#endif
#ifdef INET6
case AF_INET6:
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
/* Can't hunt for one that has no address specified */
return (NULL);
}
break;
#endif
default:
break;
}
/*
* ok, not bound to all so see if we can find a EP bound to this
* address.
@ -1635,17 +1697,16 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head,
}
if (laddr->ifa->address.sa.sa_family == nam->sa_family) {
/* possible, see if it matches */
struct sockaddr_in *intf_addr;
intf_addr = &laddr->ifa->address.sin;
switch (nam->sa_family) {
#ifdef INET
case AF_INET:
if (sin->sin_addr.s_addr ==
intf_addr->sin_addr.s_addr) {
laddr->ifa->address.sin.sin_addr.s_addr) {
SCTP_INP_RUNLOCK(inp);
return (inp);
}
break;
#endif
#ifdef INET6
case AF_INET6:
intf_addr6 = &laddr->ifa->address.sin6;
@ -1774,19 +1835,32 @@ sctp_pcb_findep(struct sockaddr *nam, int find_tcp_pool, int have_lock,
*/
struct sctp_inpcb *inp;
struct sctppcbhead *head;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
int lport;
unsigned int i;
if (nam->sa_family == AF_INET) {
#ifdef INET
struct sockaddr_in *sin;
#endif
#ifdef INET6
struct sockaddr_in6 *sin6;
#endif
switch (nam->sa_family) {
#ifdef INET
case AF_INET:
sin = (struct sockaddr_in *)nam;
lport = ((struct sockaddr_in *)nam)->sin_port;
} else if (nam->sa_family == AF_INET6) {
break;
#endif
#ifdef INET6
case AF_INET6:
sin6 = (struct sockaddr_in6 *)nam;
lport = ((struct sockaddr_in6 *)nam)->sin6_port;
} else {
/* unsupported family */
break;
#endif
default:
return (NULL);
}
/*
@ -1893,20 +1967,31 @@ sctp_findassociation_special_addr(struct mbuf *m, int iphlen, int offset,
struct sctphdr *sh, struct sctp_inpcb **inp_p, struct sctp_nets **netp,
struct sockaddr *dest)
{
struct sockaddr_in sin4;
struct sockaddr_in6 sin6;
struct sctp_paramhdr *phdr, parm_buf;
struct sctp_tcb *retval;
uint32_t ptype, plen;
#ifdef INET
struct sockaddr_in sin4;
#endif
#ifdef INET6
struct sockaddr_in6 sin6;
#endif
#ifdef INET
memset(&sin4, 0, sizeof(sin4));
memset(&sin6, 0, sizeof(sin6));
sin4.sin_len = sizeof(sin4);
sin4.sin_family = AF_INET;
sin4.sin_port = sh->src_port;
#endif
#ifdef INET6
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_len = sizeof(sin6);
sin6.sin6_family = AF_INET6;
sin6.sin6_port = sh->src_port;
#endif
retval = NULL;
offset += sizeof(struct sctp_init_chunk);
@ -1919,6 +2004,7 @@ sctp_findassociation_special_addr(struct mbuf *m, int iphlen, int offset,
if (plen == 0) {
break;
}
#ifdef INET
if (ptype == SCTP_IPV4_ADDRESS &&
plen == sizeof(struct sctp_ipv4addr_param)) {
/* Get the rest of the address */
@ -1937,7 +2023,10 @@ sctp_findassociation_special_addr(struct mbuf *m, int iphlen, int offset,
if (retval != NULL) {
return (retval);
}
} else if (ptype == SCTP_IPV6_ADDRESS &&
}
#endif
#ifdef INET6
if (ptype == SCTP_IPV6_ADDRESS &&
plen == sizeof(struct sctp_ipv6addr_param)) {
/* Get the rest of the address */
struct sctp_ipv6addr_param ip6_parm, *p6;
@ -1956,6 +2045,7 @@ sctp_findassociation_special_addr(struct mbuf *m, int iphlen, int offset,
return (retval);
}
}
#endif
offset += SCTP_SIZE32(plen);
phdr = sctp_get_next_param(m, offset, &parm_buf,
sizeof(parm_buf));
@ -2082,6 +2172,7 @@ sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset,
iph = mtod(m, struct ip *);
switch (iph->ip_v) {
#ifdef INET
case IPVERSION:
{
/* its IPv4 */
@ -2095,6 +2186,7 @@ sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset,
from4->sin_port = sh->src_port;
break;
}
#endif
#ifdef INET6
case IPV6_VERSION >> 4:
{
@ -2123,6 +2215,7 @@ sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset,
switch (iph->ip_v) {
#ifdef INET
case IPVERSION:
{
/* its IPv4 */
@ -2136,6 +2229,7 @@ sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset,
to4->sin_port = sh->dest_port;
break;
}
#endif
#ifdef INET6
case IPV6_VERSION >> 4:
{
@ -2224,24 +2318,22 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int iphlen, int offset,
struct sctphdr *sh, struct sctp_inpcb **inp_p, struct sctp_nets **netp, uint32_t vrf_id)
{
struct sctp_tcb *stcb;
struct sockaddr_in *sin;
#ifdef INET6
struct sockaddr_in6 *sin6;
#endif
struct sockaddr_storage local_store, remote_store;
struct sockaddr *to;
struct ip *iph;
#ifdef INET6
struct ip6_hdr *ip6;
#endif
struct sctp_paramhdr parm_buf, *phdr;
int ptype;
int zero_address = 0;
#ifdef INET
struct sockaddr_in *sin;
#endif
#ifdef INET6
struct ip6_hdr *ip6;
struct sockaddr_in6 *sin6;
#endif
memset(&local_store, 0, sizeof(local_store));
memset(&remote_store, 0, sizeof(remote_store));
@ -2249,6 +2341,7 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int iphlen, int offset,
/* First get the destination address setup too. */
iph = mtod(m, struct ip *);
switch (iph->ip_v) {
#ifdef INET
case IPVERSION:
/* its IPv4 */
sin = (struct sockaddr_in *)&local_store;
@ -2257,6 +2350,7 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int iphlen, int offset,
sin->sin_port = sh->dest_port;
sin->sin_addr.s_addr = iph->ip_dst.s_addr;
break;
#endif
#ifdef INET6
case IPV6_VERSION >> 4:
/* its IPv6 */
@ -2309,6 +2403,7 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int iphlen, int offset,
break;
}
#endif
#ifdef INET
case SCTP_IPV4_ADDRESS:
{
/* ipv4 address param */
@ -2334,6 +2429,7 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int iphlen, int offset,
zero_address = 1;
break;
}
#endif
default:
/* invalid address param type */
return NULL;
@ -2733,6 +2829,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
#endif
if (addr != NULL) {
switch (addr->sa_family) {
#ifdef INET
case AF_INET:
{
struct sockaddr_in *sin;
@ -2762,6 +2859,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
}
break;
}
#endif
#ifdef INET6
case AF_INET6:
{
@ -3033,18 +3131,27 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
struct sockaddr_storage store_sa;
memset(&store_sa, 0, sizeof(store_sa));
if (addr->sa_family == AF_INET) {
switch (addr->sa_family) {
case AF_INET:
{
struct sockaddr_in *sin;
sin = (struct sockaddr_in *)&store_sa;
memcpy(sin, addr, sizeof(struct sockaddr_in));
sin->sin_port = 0;
} else if (addr->sa_family == AF_INET6) {
break;
}
case AF_INET6:
{
struct sockaddr_in6 *sin6;
sin6 = (struct sockaddr_in6 *)&store_sa;
memcpy(sin6, addr, sizeof(struct sockaddr_in6));
sin6->sin6_port = 0;
break;
}
default:
break;
}
/*
* first find the interface with the bound address need to
@ -3069,6 +3176,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EADDRNOTAVAIL);
return (EADDRNOTAVAIL);
}
#ifdef INET6
if (addr->sa_family == AF_INET6) {
/* GAK, more FIXME IFA lock? */
if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
@ -3079,6 +3187,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
return (EINVAL);
}
}
#endif
/* we're not bound all */
inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUNDALL;
/* allow bindx() to send ASCONF's for binding changes */
@ -3612,10 +3721,13 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
(void)sctp_m_free(ip_pcb->inp_options);
ip_pcb->inp_options = 0;
}
#ifdef INET
if (ip_pcb->inp_moptions) {
inp_freemoptions(ip_pcb->inp_moptions);
ip_pcb->inp_moptions = 0;
}
#endif
#ifdef INET6
if (ip_pcb->inp_vflag & INP_IPV6) {
struct in6pcb *in6p;
@ -3740,7 +3852,10 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
return (0);
}
addr_inscope = 1;
if (newaddr->sa_family == AF_INET) {
switch (newaddr->sa_family) {
#ifdef INET
case AF_INET:
{
struct sockaddr_in *sin;
sin = (struct sockaddr_in *)newaddr;
@ -3768,8 +3883,12 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
addr_inscope = 0;
}
}
break;
}
#endif
#ifdef INET6
} else if (newaddr->sa_family == AF_INET6) {
case AF_INET6:
{
struct sockaddr_in6 *sin6;
sin6 = (struct sockaddr_in6 *)newaddr;
@ -3787,19 +3906,22 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
stcb->asoc.site_scope = 1;
} else if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
/*
* If the new destination is a LINK_LOCAL we
* must have common site scope. Don't set
* the local scope since we may not share
* all links, only loopback can do this.
* Links on the local network would also be
* on our private network for v4 too.
* If the new destination is a
* LINK_LOCAL we must have common
* site scope. Don't set the local
* scope since we may not share all
* links, only loopback can do this.
* Links on the local network would
* also be on our private network
* for v4 too.
*/
stcb->asoc.ipv4_local_scope = 1;
stcb->asoc.site_scope = 1;
} else if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
/*
* If the new destination is SITE_LOCAL then
* we must have site scope in common.
* If the new destination is
* SITE_LOCAL then we must have site
* scope in common.
*/
stcb->asoc.site_scope = 1;
}
@ -3816,8 +3938,10 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
addr_inscope = 0;
}
}
break;
}
#endif
} else {
default:
/* not supported family type */
return (-1);
}
@ -3829,10 +3953,19 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
bzero(net, sizeof(*net));
(void)SCTP_GETTIME_TIMEVAL(&net->start_time);
memcpy(&net->ro._l_addr, newaddr, newaddr->sa_len);
if (newaddr->sa_family == AF_INET) {
switch (newaddr->sa_family) {
#ifdef INET
case AF_INET:
((struct sockaddr_in *)&net->ro._l_addr)->sin_port = stcb->rport;
} else if (newaddr->sa_family == AF_INET6) {
break;
#endif
#ifdef INET6
case AF_INET6:
((struct sockaddr_in6 *)&net->ro._l_addr)->sin6_port = stcb->rport;
break;
#endif
default:
break;
}
net->addr_is_local = sctp_is_address_on_local_host(newaddr, stcb->asoc.vrf_id);
if (net->addr_is_local && ((set_scope || (from == SCTP_ADDR_IS_CONFIRMED)))) {
@ -4136,13 +4269,30 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
#ifdef SCTP_DEBUG
if (firstaddr) {
SCTPDBG_ADDR(SCTP_DEBUG_PCB3, firstaddr);
switch (firstaddr->sa_family) {
#ifdef INET
case AF_INET:
SCTPDBG(SCTP_DEBUG_PCB3, "Port:%d\n",
ntohs(((struct sockaddr_in *)firstaddr)->sin_port));
break;
#endif
#ifdef INET6
case AF_INET6:
SCTPDBG(SCTP_DEBUG_PCB3, "Port:%d\n",
ntohs(((struct sockaddr_in6 *)firstaddr)->sin6_port));
break;
#endif
default:
break;
}
} else {
SCTPDBG(SCTP_DEBUG_PCB3, "None\n");
}
#endif /* SCTP_DEBUG */
if (firstaddr->sa_family == AF_INET) {
switch (firstaddr->sa_family) {
#ifdef INET
case AF_INET:
{
struct sockaddr_in *sin;
sin = (struct sockaddr_in *)firstaddr;
@ -4154,7 +4304,12 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
return (NULL);
}
rport = sin->sin_port;
} else if (firstaddr->sa_family == AF_INET6) {
break;
}
#endif
#ifdef INET6
case AF_INET6:
{
struct sockaddr_in6 *sin6;
sin6 = (struct sockaddr_in6 *)firstaddr;
@ -4167,7 +4322,10 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
return (NULL);
}
rport = sin6->sin6_port;
} else {
break;
}
#endif
default:
/* not supported family type */
SCTP_INP_RUNLOCK(inp);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
@ -5135,13 +5293,17 @@ sctp_destination_is_reachable(struct sctp_tcb *stcb, struct sockaddr *destaddr)
return (1);
}
/* NOTE: all "scope" checks are done when local addresses are added */
if (destaddr->sa_family == AF_INET6) {
switch (destaddr->sa_family) {
case AF_INET6:
answer = inp->ip_inp.inp.inp_vflag & INP_IPV6;
} else if (destaddr->sa_family == AF_INET) {
break;
case AF_INET:
answer = inp->ip_inp.inp.inp_vflag & INP_IPV4;
} else {
break;
default:
/* invalid family, so it's unreachable */
answer = 0;
break;
}
return (answer);
}
@ -5166,10 +5328,19 @@ sctp_update_ep_vflag(struct sctp_inpcb *inp)
if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) {
continue;
}
if (laddr->ifa->address.sa.sa_family == AF_INET6) {
switch (laddr->ifa->address.sa.sa_family) {
#ifdef INET6
case AF_INET6:
inp->ip_inp.inp.inp_vflag |= INP_IPV6;
} else if (laddr->ifa->address.sa.sa_family == AF_INET) {
break;
#endif
#ifdef INET
case AF_INET:
inp->ip_inp.inp.inp_vflag |= INP_IPV4;
break;
#endif
default:
break;
}
}
}
@ -5190,12 +5361,14 @@ sctp_add_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa, uint32_t ac
/* You are already bound to all. You have it already */
return;
}
#ifdef INET6
if (ifa->address.sa.sa_family == AF_INET6) {
if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
/* Can't bind a non-useable addr. */
return;
}
}
#endif
/* first, is it already present? */
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
if (laddr->ifa == ifa) {
@ -5211,10 +5384,19 @@ sctp_add_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa, uint32_t ac
return;
inp->laddr_count++;
/* update inp_vflag flags */
if (ifa->address.sa.sa_family == AF_INET6) {
switch (ifa->address.sa.sa_family) {
#ifdef INET6
case AF_INET6:
inp->ip_inp.inp.inp_vflag |= INP_IPV6;
} else if (ifa->address.sa.sa_family == AF_INET) {
break;
#endif
#ifdef INET6
case AF_INET:
inp->ip_inp.inp.inp_vflag |= INP_IPV4;
break;
#endif
default:
break;
}
}
return;
@ -5343,12 +5525,14 @@ sctp_add_local_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa)
list = &stcb->asoc.sctp_restricted_addrs;
inp = stcb->sctp_ep;
#ifdef INET6
if (ifa->address.sa.sa_family == AF_INET6) {
if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
/* Can't bind a non-existent addr. */
return;
}
}
#endif
/* does the address already exist? */
LIST_FOREACH(laddr, list, sctp_nxt_addr) {
if (laddr->ifa == ifa) {
@ -5906,8 +6090,6 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
struct sockaddr *sa;
struct sockaddr_storage dest_store;
struct sockaddr *local_sa = (struct sockaddr *)&dest_store;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
uint8_t random_store[SCTP_PARAM_BUFFER_SIZE];
struct sctp_auth_random *p_random = NULL;
uint16_t random_len = 0;
@ -5924,20 +6106,32 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
int got_random = 0, got_hmacs = 0, got_chklist = 0;
uint8_t ecn_allowed;
/* First get the destination address setup too. */
memset(&sin, 0, sizeof(sin));
memset(&sin6, 0, sizeof(sin6));
#ifdef INET
struct sockaddr_in sin;
#endif
#ifdef INET6
struct sockaddr_in6 sin6;
#endif
/* First get the destination address setup too. */
#ifdef INET
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_len = sizeof(sin);
sin.sin_port = stcb->rport;
#endif
#ifdef INET6
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
sin6.sin6_len = sizeof(struct sockaddr_in6);
sin6.sin6_port = stcb->rport;
#endif
if (altsa == NULL) {
iph = mtod(m, struct ip *);
switch (iph->ip_v) {
#ifdef INET
case IPVERSION:
{
/* its IPv4 */
@ -5953,6 +6147,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
sa = (struct sockaddr *)&sin;
break;
}
#endif
#ifdef INET6
case IPV6_VERSION >> 4:
{
@ -5998,17 +6193,28 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
if ((stcb_tmp == NULL && inp == stcb->sctp_ep) || inp == NULL) {
/* we must add the source address */
/* no scope set here since we have a tcb already. */
if ((sa->sa_family == AF_INET) &&
(stcb->asoc.ipv4_addr_legal)) {
switch (sa->sa_family) {
#ifdef INET
case AF_INET:
if (stcb->asoc.ipv4_addr_legal) {
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_2)) {
return (-1);
}
} else if ((sa->sa_family == AF_INET6) &&
(stcb->asoc.ipv6_addr_legal)) {
}
break;
#endif
#ifdef INET6
case AF_INET6:
if (stcb->asoc.ipv6_addr_legal) {
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) {
return (-2);
}
}
break;
#endif
default:
break;
}
} else {
if (net_tmp != NULL && stcb_tmp == stcb) {
net_tmp->dest_state &= ~SCTP_ADDR_NOT_IN_ASSOC;
@ -6044,6 +6250,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
if (plen == 0) {
break;
}
#ifdef INET
if (ptype == SCTP_IPV4_ADDRESS) {
if (stcb->asoc.ipv4_addr_legal) {
struct sctp_ipv4addr_param *p4, p4_buf;
@ -6127,7 +6334,10 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
return (-13);
}
}
} else if (ptype == SCTP_IPV6_ADDRESS) {
} else
#endif
#ifdef INET6
if (ptype == SCTP_IPV6_ADDRESS) {
if (stcb->asoc.ipv6_addr_legal) {
/* ok get the v6 address and check/add */
struct sctp_ipv6addr_param *p6, p6_buf;
@ -6215,7 +6425,9 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
return (-22);
}
}
} else if (ptype == SCTP_ECN_CAPABLE) {
} else
#endif
if (ptype == SCTP_ECN_CAPABLE) {
ecn_allowed = 1;
} else if (ptype == SCTP_ULP_ADAPTATION) {
if (stcb->asoc.state != SCTP_STATE_OPEN) {
@ -6232,10 +6444,14 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
} else if (ptype == SCTP_SET_PRIM_ADDR) {
struct sctp_asconf_addr_param lstore, *fee;
struct sctp_asconf_addrv4_param *fii;
int lptype;
struct sockaddr *lsa = NULL;
#ifdef INET
struct sctp_asconf_addrv4_param *fii;
#endif
stcb->asoc.peer_supports_asconf = 1;
if (plen > sizeof(lstore)) {
return (-23);
@ -6248,7 +6464,9 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
fee = (struct sctp_asconf_addr_param *)phdr;
lptype = ntohs(fee->addrp.ph.param_type);
if (lptype == SCTP_IPV4_ADDRESS) {
switch (lptype) {
#ifdef INET
case SCTP_IPV4_ADDRESS:
if (plen !=
sizeof(struct sctp_asconf_addrv4_param)) {
SCTP_PRINTF("Sizeof setprim in init/init ack not %d but %d - ignored\n",
@ -6259,7 +6477,10 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
sin.sin_addr.s_addr = fii->addrp.addr;
lsa = (struct sockaddr *)&sin;
}
} else if (lptype == SCTP_IPV6_ADDRESS) {
break;
#endif
#ifdef INET6
case SCTP_IPV6_ADDRESS:
if (plen !=
sizeof(struct sctp_asconf_addr_param)) {
SCTP_PRINTF("Sizeof setprim (v6) in init/init ack not %d but %d - ignored\n",
@ -6271,6 +6492,10 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
sizeof(fee->addrp.addr));
lsa = (struct sockaddr *)&sin6;
}
break;
#endif
default:
break;
}
if (lsa) {
(void)sctp_set_primary_addr(stcb, sa, NULL);

View File

@ -155,17 +155,33 @@ number_of_addresses(struct sctp_inpcb *inp)
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
if ((sctp_ifa->address.sa.sa_family == AF_INET) ||
(sctp_ifa->address.sa.sa_family == AF_INET6)) {
switch (sctp_ifa->address.sa.sa_family) {
#ifdef INET
case AF_INET:
#endif
#ifdef INET6
case AF_INET6:
#endif
cnt++;
break;
default:
break;
}
}
}
} else {
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
if ((laddr->ifa->address.sa.sa_family == AF_INET) ||
(laddr->ifa->address.sa.sa_family == AF_INET6)) {
switch (laddr->ifa->address.sa.sa_family) {
#ifdef INET
case AF_INET:
#endif
#ifdef INET6
case AF_INET6:
#endif
cnt++;
break;
default:
break;
}
}
}
@ -233,6 +249,7 @@ copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct s
continue;
}
switch (sctp_ifa->address.sa.sa_family) {
#ifdef INET
case AF_INET:
if (ipv4_addr_legal) {
struct sockaddr_in *sin;
@ -246,6 +263,7 @@ copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct s
continue;
}
break;
#endif
#ifdef INET6
case AF_INET6:
if (ipv6_addr_legal) {
@ -535,6 +553,8 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
if ((var) < (min)) { (var) = (min); } \
else if ((var) > (max)) { (var) = (max); }
/* XXX: Remove the #if after tunneling over IPv6 works also on FreeBSD. */
#if !defined(__FreeBSD__) || defined(INET)
static int
sysctl_sctp_udp_tunneling_check(SYSCTL_HANDLER_ARGS)
{
@ -566,6 +586,8 @@ sysctl_sctp_udp_tunneling_check(SYSCTL_HANDLER_ARGS)
return (error);
}
#endif
static int
sysctl_sctp_check(SYSCTL_HANDLER_ARGS)
@ -646,7 +668,10 @@ sysctl_sctp_check(SYSCTL_HANDLER_ARGS)
RANGECHK(SCTP_BASE_SYSCTL(sctp_use_dccc_ecn), SCTPCTL_RTTVAR_DCCCECN_MIN, SCTPCTL_RTTVAR_DCCCECN_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_mobility_base), SCTPCTL_MOBILITY_BASE_MIN, SCTPCTL_MOBILITY_BASE_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_mobility_fasthandoff), SCTPCTL_MOBILITY_FASTHANDOFF_MIN, SCTPCTL_MOBILITY_FASTHANDOFF_MAX);
/* XXX: Remove the #if after tunneling over IPv6 works also on FreeBSD. */
#if !defined(__FreeBSD__) || defined(INET)
RANGECHK(SCTP_BASE_SYSCTL(sctp_udp_tunneling_for_client_enable), SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_MIN, SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_MAX);
#endif
RANGECHK(SCTP_BASE_SYSCTL(sctp_enable_sack_immediately), SCTPCTL_SACK_IMMEDIATELY_ENABLE_MIN, SCTPCTL_SACK_IMMEDIATELY_ENABLE_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly), SCTPCTL_NAT_FRIENDLY_INITS_MIN, SCTPCTL_NAT_FRIENDLY_INITS_MAX);
@ -1083,6 +1108,8 @@ SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, clear_trace, CTLTYPE_UINT | CTLFLAG_R
"Clear SCTP Logging buffer");
#endif
/* XXX: Remove the #if after tunneling over IPv6 works also on FreeBSD. */
#if !defined(__FreeBSD__) || defined(INET)
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, udp_tunneling_for_client_enable, CTLTYPE_UINT | CTLFLAG_RW,
&SCTP_BASE_SYSCTL(sctp_udp_tunneling_for_client_enable), 0, sysctl_sctp_check, "IU",
SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_DESC);
@ -1090,6 +1117,7 @@ SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, udp_tunneling_for_client_enable, CTLT
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, udp_tunneling_port, CTLTYPE_UINT | CTLFLAG_RW,
&SCTP_BASE_SYSCTL(sctp_udp_tunneling_port), 0, sysctl_sctp_udp_tunneling_check, "IU",
SCTPCTL_UDP_TUNNELING_PORT_DESC);
#endif
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, enable_sack_immediately, CTLTYPE_UINT | CTLFLAG_RW,
&SCTP_BASE_SYSCTL(sctp_enable_sack_immediately), 0, sysctl_sctp_check, "IU",

View File

@ -150,6 +150,7 @@ sctp_pathmtu_adjustment(struct sctp_inpcb *inp,
}
}
#ifdef INET
static void
sctp_notify_mbuf(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
@ -220,6 +221,7 @@ sctp_notify_mbuf(struct sctp_inpcb *inp,
SCTP_TCB_UNLOCK(stcb);
}
#endif
void
sctp_notify(struct sctp_inpcb *inp,
@ -335,6 +337,7 @@ sctp_notify(struct sctp_inpcb *inp,
}
}
#ifdef INET
void
sctp_ctlinput(cmd, sa, vip)
int cmd;
@ -404,6 +407,8 @@ sctp_ctlinput(cmd, sa, vip)
return;
}
#endif
static int
sctp_getcred(SYSCTL_HANDLER_ARGS)
{
@ -466,6 +471,7 @@ SYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection");
#ifdef INET
static void
sctp_abort(struct socket *so)
{
@ -599,6 +605,7 @@ sctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
return error;
}
#endif
void
sctp_close(struct socket *so)
{
@ -1209,6 +1216,7 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
}
}
switch (sctp_ifa->address.sa.sa_family) {
#ifdef INET
case AF_INET:
if (ipv4_addr_legal) {
struct sockaddr_in *sin;
@ -1248,6 +1256,7 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
continue;
}
break;
#endif
#ifdef INET6
case AF_INET6:
if (ipv6_addr_legal) {
@ -1373,28 +1382,46 @@ sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id)
LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
/* Count them if they are the right type */
if (sctp_ifa->address.sa.sa_family == AF_INET) {
switch (sctp_ifa->address.sa.sa_family) {
#ifdef INET
case AF_INET:
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
cnt += sizeof(struct sockaddr_in6);
else
cnt += sizeof(struct sockaddr_in);
} else if (sctp_ifa->address.sa.sa_family == AF_INET6)
break;
#endif
#ifdef INET6
case AF_INET6:
cnt += sizeof(struct sockaddr_in6);
break;
#endif
default:
break;
}
}
}
} else {
struct sctp_laddr *laddr;
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
if (laddr->ifa->address.sa.sa_family == AF_INET) {
switch (laddr->ifa->address.sa.sa_family) {
#ifdef INET
case AF_INET:
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
cnt += sizeof(struct sockaddr_in6);
else
cnt += sizeof(struct sockaddr_in);
} else if (laddr->ifa->address.sa.sa_family == AF_INET6)
break;
#endif
#ifdef INET6
case AF_INET6:
cnt += sizeof(struct sockaddr_in6);
break;
#endif
default:
break;
}
}
}
return (cnt);
@ -1517,10 +1544,20 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
}
SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
/* move to second address */
if (sa->sa_family == AF_INET)
switch (sa->sa_family) {
#ifdef INET
case AF_INET:
sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in));
else
break;
#endif
#ifdef INET6
case AF_INET6:
sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6));
break;
#endif
default:
break;
}
error = 0;
added = sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error);
@ -2126,14 +2163,23 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
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)) ||
(((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) {
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
size += sizeof(struct sockaddr_in6);
} else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) {
size += sizeof(struct sockaddr_in);
} else {
/* huh */
switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) {
#ifdef INET
case AF_INET:
size += sizeof(struct sockaddr_in);
break;
#endif
#ifdef INET6
case AF_INET6:
size += sizeof(struct sockaddr_in6);
break;
#endif
default:
break;
}
}
}
SCTP_TCB_UNLOCK(stcb);
@ -2165,20 +2211,33 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
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)) ||
(((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) {
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
cpsz = sizeof(struct sockaddr_in6);
} else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) {
cpsz = sizeof(struct sockaddr_in);
} else {
/* huh */
switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) {
#ifdef INET
case AF_INET:
cpsz = sizeof(struct sockaddr_in);
break;
#endif
#ifdef INET6
case AF_INET6:
cpsz = sizeof(struct sockaddr_in6);
break;
#endif
default:
cpsz = 0;
break;
}
}
if (cpsz == 0) {
break;
}
if (left < cpsz) {
/* not enough room. */
break;
}
#ifdef INET6
#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)) {
/* Must map the address */
@ -2187,7 +2246,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
} else {
#endif
memcpy(sas, &net->ro._l_addr, cpsz);
#ifdef INET6
#if defined(INET) && defined(INET6)
}
#endif
((struct sockaddr_in *)sas)->sin_port = stcb->rport;
@ -2250,6 +2309,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
struct sockaddr *sa;
sa = (struct sockaddr *)&paddrp->spp_address;
#ifdef INET
if (sa->sa_family == AF_INET) {
struct sockaddr_in *sin;
@ -2260,7 +2320,10 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
break;
}
} else if (sa->sa_family == AF_INET6) {
} else
#endif
#ifdef INET6
if (sa->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6;
sin6 = (struct sockaddr_in6 *)sa;
@ -2270,7 +2333,9 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
break;
}
} else {
} else
#endif
{
error = EAFNOSUPPORT;
SCTP_TCB_UNLOCK(stcb);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
@ -3857,7 +3922,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
struct sockaddr *sa;
sa = (struct sockaddr *)&paddrp->spp_address;
#ifdef INET
if (sa->sa_family == AF_INET) {
struct sockaddr_in *sin;
sin = (struct sockaddr_in *)sa;
@ -3867,7 +3934,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
error = EINVAL;
break;
}
} else if (sa->sa_family == AF_INET6) {
} else
#endif
#ifdef INET6
if (sa->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6;
sin6 = (struct sockaddr_in6 *)sa;
@ -3877,7 +3947,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
error = EINVAL;
break;
}
} else {
} else
#endif
{
error = EAFNOSUPPORT;
SCTP_TCB_UNLOCK(stcb);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
@ -4305,6 +4377,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
td = (struct thread *)p;
SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses,
optsize);
#ifdef INET
if (addrs->addr->sa_family == AF_INET) {
sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in);
if (optsize < sz) {
@ -4316,8 +4389,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
break;
}
} else
#endif
#ifdef INET6
} else if (addrs->addr->sa_family == AF_INET6) {
if (addrs->addr->sa_family == AF_INET6) {
sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6);
if (optsize < sz) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@ -4329,8 +4404,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
break;
}
} else
#endif
} else {
{
error = EAFNOSUPPORT;
break;
}
@ -4348,6 +4424,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
td = (struct thread *)p;
SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize);
#ifdef INET
if (addrs->addr->sa_family == AF_INET) {
sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in);
if (optsize < sz) {
@ -4359,8 +4436,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
break;
}
} else
#endif
#ifdef INET6
} else if (addrs->addr->sa_family == AF_INET6) {
if (addrs->addr->sa_family == AF_INET6) {
sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6);
if (optsize < sz) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@ -4372,8 +4451,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
break;
}
} else
#endif
} else {
{
error = EAFNOSUPPORT;
break;
}
@ -4410,9 +4490,13 @@ sctp_ctloutput(struct socket *so, struct sockopt *sopt)
#ifdef INET6
if (INP_CHECK_SOCKAF(so, AF_INET6))
error = ip6_ctloutput(so, sopt);
else
#endif /* INET6 */
#if defined(INET) && defined (INET6)
else
#endif
#ifdef INET
error = ip_ctloutput(so, sopt);
#endif
return (error);
}
optsize = sopt->sopt_valsize;
@ -4447,7 +4531,7 @@ sctp_ctloutput(struct socket *so, struct sockopt *sopt)
return (error);
}
#ifdef INET
static int
sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
{
@ -4467,8 +4551,10 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return EINVAL;
}
switch (addr->sa_family) {
#ifdef INET6
if (addr->sa_family == AF_INET6) {
case AF_INET6:
{
struct sockaddr_in6 *sin6p;
if (addr->sa_len != sizeof(struct sockaddr_in6)) {
@ -4480,9 +4566,12 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
return (error);
}
} else
break;
}
#endif
if (addr->sa_family == AF_INET) {
#ifdef INET
case AF_INET:
{
struct sockaddr_in *sinp;
if (addr->sa_len != sizeof(struct sockaddr_in)) {
@ -4494,7 +4583,10 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
return (error);
}
} else {
break;
}
#endif
default:
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
return (EAFNOSUPPORT);
}
@ -4601,6 +4693,8 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
return error;
}
#endif
int
sctp_listen(struct socket *so, int backlog, struct thread *p)
{
@ -4634,7 +4728,20 @@ sctp_listen(struct socket *so, int backlog, struct thread *p)
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
memcpy(&store, &laddr->ifa->address, sizeof(store));
switch (sp->sa.sa_family) {
#ifdef INET
case AF_INET:
sp->sin.sin_port = inp->sctp_lport;
break;
#endif
#ifdef INET6
case AF_INET6:
sp->sin6.sin6_port = inp->sctp_lport;
break;
#endif
default:
break;
}
tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id);
if (tinp && (tinp != inp) &&
((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
@ -4653,17 +4760,32 @@ sctp_listen(struct socket *so, int backlog, struct thread *p)
} else {
/* Setup a local addr bound all */
memset(&store, 0, sizeof(store));
switch (sp->sa.sa_family) {
#ifdef INET
case AF_INET:
store.sin.sin_port = inp->sctp_lport;
break;
#endif
#ifdef INET6
case AF_INET6:
sp->sin6.sin6_port = inp->sctp_lport;
break;
#endif
default:
break;
}
#ifdef INET6
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
store.sa.sa_family = AF_INET6;
store.sa.sa_len = sizeof(struct sockaddr_in6);
}
#endif
#ifdef INET
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
store.sa.sa_family = AF_INET;
store.sa.sa_len = sizeof(struct sockaddr_in);
}
#endif
tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id);
if (tinp && (tinp != inp) &&
((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
@ -4780,6 +4902,7 @@ sctp_accept(struct socket *so, struct sockaddr **addr)
stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE;
SCTP_TCB_UNLOCK(stcb);
switch (store.sa.sa_family) {
#ifdef INET
case AF_INET:
{
struct sockaddr_in *sin;
@ -4794,6 +4917,7 @@ sctp_accept(struct socket *so, struct sockaddr **addr)
*addr = (struct sockaddr *)sin;
break;
}
#endif
#ifdef INET6
case AF_INET6:
{
@ -4855,6 +4979,7 @@ sctp_accept(struct socket *so, struct sockaddr **addr)
return (0);
}
#ifdef INET
int
sctp_ingetaddr(struct socket *so, struct sockaddr **addr)
{
@ -5015,6 +5140,7 @@ sctp_peeraddr(struct socket *so, struct sockaddr **addr)
return (0);
}
#ifdef INET
struct pr_usrreqs sctp_usrreqs = {
.pru_abort = sctp_abort,
.pru_accept = sctp_accept,
@ -5035,3 +5161,6 @@ struct pr_usrreqs sctp_usrreqs = {
.pru_sosend = sctp_sosend,
.pru_soreceive = sctp_soreceive
};
#endif
#endif

View File

@ -300,8 +300,15 @@ int sctp_disconnect(struct socket *so);
void sctp_ctlinput __P((int, struct sockaddr *, void *));
int sctp_ctloutput __P((struct socket *, struct sockopt *));
#ifdef INET
void sctp_input_with_port __P((struct mbuf *, int, uint16_t));
#endif
#ifdef INET
void sctp_input __P((struct mbuf *, int));
#endif
void sctp_pathmtu_adjustment __P((struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *, uint16_t));
void sctp_drain __P((void));
void sctp_init __P((void));

View File

@ -4826,6 +4826,7 @@ sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr,
continue;
if (addr->sa_family != laddr->ifa->address.sa.sa_family)
continue;
#ifdef INET
if (addr->sa_family == AF_INET) {
if (((struct sockaddr_in *)addr)->sin_addr.s_addr ==
laddr->ifa->address.sin.sin_addr.s_addr) {
@ -4837,6 +4838,7 @@ sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr,
break;
}
}
#endif
#ifdef INET6
if (addr->sa_family == AF_INET6) {
if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr,
@ -4924,6 +4926,7 @@ sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock)
}
if (addr->sa_family != sctp_ifap->address.sa.sa_family)
continue;
#ifdef INET
if (addr->sa_family == AF_INET) {
if (((struct sockaddr_in *)addr)->sin_addr.s_addr ==
sctp_ifap->address.sin.sin_addr.s_addr) {
@ -4934,6 +4937,7 @@ sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock)
break;
}
}
#endif
#ifdef INET6
if (addr->sa_family == AF_INET6) {
if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr,
@ -6729,7 +6733,7 @@ sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *ignored)
struct ip *iph;
struct mbuf *sp, *last;
struct udphdr *uhdr;
uint16_t port = 0, len;
uint16_t port = 0;
int header_size = sizeof(struct udphdr) + sizeof(struct sctphdr);
/*
@ -6779,8 +6783,11 @@ sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *ignored)
/* Now its ready for sctp_input or sctp6_input */
iph = mtod(m, struct ip *);
switch (iph->ip_v) {
#ifdef INET
case IPVERSION:
{
uint16_t len;
/* its IPv4 */
len = SCTP_GET_IPV4_LENGTH(iph);
len -= sizeof(struct udphdr);
@ -6788,6 +6795,7 @@ sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *ignored)
sctp_input_with_port(m, off, port);
break;
}
#endif
#ifdef INET6
case IPV6_VERSION >> 4:
{

View File

@ -745,13 +745,24 @@ sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
return EINVAL;
}
if (addr) {
if ((addr->sa_family == AF_INET6) &&
(addr->sa_len != sizeof(struct sockaddr_in6))) {
switch (addr->sa_family) {
#ifdef INET
case AF_INET:
if (addr->sa_len != sizeof(struct sockaddr_in)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
}
if ((addr->sa_family == AF_INET) &&
(addr->sa_len != sizeof(struct sockaddr_in))) {
break;
#endif
#ifdef INET6
case AF_INET6:
if (addr->sa_len != sizeof(struct sockaddr_in6)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
}
break;
#endif
default:
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
}
@ -760,18 +771,26 @@ sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
inp6->inp_vflag &= ~INP_IPV4;
inp6->inp_vflag |= INP_IPV6;
if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp6) == 0)) {
if (addr->sa_family == AF_INET) {
switch (addr->sa_family) {
#ifdef INET
case AF_INET:
/* binding v4 addr to v6 socket, so reset flags */
inp6->inp_vflag |= INP_IPV4;
inp6->inp_vflag &= ~INP_IPV6;
} else {
break;
#endif
#ifdef INET6
case AF_INET6:
{
struct sockaddr_in6 *sin6_p;
sin6_p = (struct sockaddr_in6 *)addr;
if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) {
inp6->inp_vflag |= INP_IPV4;
} else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
}
#ifdef INET
if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
struct sockaddr_in sin;
in6_sin6_2_sin(&sin, sin6_p);
@ -780,16 +799,24 @@ sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, NULL, p);
return error;
}
#endif
break;
}
#endif
default:
break;
}
} else if (addr != NULL) {
struct sockaddr_in6 *sin6_p;
/* IPV6_V6ONLY socket */
#ifdef INET
if (addr->sa_family == AF_INET) {
/* can't bind v4 addr to v6 only socket! */
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return EINVAL;
} else {
struct sockaddr_in6 *sin6_p;
}
#endif
sin6_p = (struct sockaddr_in6 *)addr;
if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
@ -799,7 +826,6 @@ sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
return EINVAL;
}
}
}
error = sctp_inpcb_bind(so, addr, NULL, p);
return error;
}
@ -950,7 +976,7 @@ sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
struct sockaddr_in6 *sin6;
struct sockaddr_storage ss;
#endif /* INET */
#endif
inp6 = (struct in6pcb *)so->so_pcb;
inp = (struct sctp_inpcb *)so->so_pcb;
@ -963,14 +989,28 @@ sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
}
if ((addr->sa_family == AF_INET6) && (addr->sa_len != sizeof(struct sockaddr_in6))) {
switch (addr->sa_family) {
#ifdef INET
case AF_INET:
if (addr->sa_len != sizeof(struct sockaddr_in)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
}
if ((addr->sa_family == AF_INET) && (addr->sa_len != sizeof(struct sockaddr_in))) {
break;
#endif
#ifdef INET6
case AF_INET6:
if (addr->sa_len != sizeof(struct sockaddr_in6)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
}
break;
#endif
default:
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
}
vrf_id = inp->def_vrf_id;
SCTP_ASOC_CREATE_LOCK(inp);
SCTP_INP_RLOCK(inp);
@ -1093,7 +1133,7 @@ sctp6_getaddr(struct socket *so, struct sockaddr **addr)
/*
* Do the malloc first in case it blocks.
*/
SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof(*sin6));
if (sin6 == NULL)
return ENOMEM;
sin6->sin6_family = AF_INET6;
@ -1249,7 +1289,10 @@ sctp6_peeraddr(struct socket *so, struct sockaddr **addr)
static int
sctp6_in6getaddr(struct socket *so, struct sockaddr **nam)
{
#ifdef INET
struct sockaddr *addr;
#endif
struct in6pcb *inp6 = sotoin6pcb(so);
int error;
@ -1259,6 +1302,7 @@ sctp6_in6getaddr(struct socket *so, struct sockaddr **nam)
}
/* allow v6 addresses precedence */
error = sctp6_getaddr(so, nam);
#ifdef INET
if (error) {
/* try v4 next if v6 failed */
error = sctp_ingetaddr(so, nam);
@ -1272,9 +1316,9 @@ sctp6_in6getaddr(struct socket *so, struct sockaddr **nam)
in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
}
}
#endif
return (error);
}
@ -1282,7 +1326,10 @@ sctp6_in6getaddr(struct socket *so, struct sockaddr **nam)
static int
sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam)
{
struct sockaddr *addr = *nam;
#ifdef INET
struct sockaddr *addr;
#endif
struct in6pcb *inp6 = sotoin6pcb(so);
int error;
@ -1292,12 +1339,14 @@ sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam)
}
/* allow v6 addresses precedence */
error = sctp6_peeraddr(so, nam);
#ifdef INET
if (error) {
/* try v4 next if v6 failed */
error = sctp_peeraddr(so, nam);
if (error) {
return (error);
}
addr = *nam;
/* if I'm V6ONLY, convert it to v4-mapped */
if (SCTP_IPV6_V6ONLY(inp6)) {
struct sockaddr_in6 sin6;
@ -1306,6 +1355,7 @@ sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam)
memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
}
}
#endif
return error;
}