Files
m241Neelima/components/ip_net2-6.9/ipsctp/src/ipsctp_ip4.c
T
2026-07-30 11:19:44 +05:30

1163 lines
36 KiB
C

/* ipsctp_ip4.c - IPV4 Address Related Routines in IPSCTP */
/*
* Copyright (c) 2008, 2018 Wind River Systems, Inc.
*
* The right to copy, distribute or otherwise make use of this software
* may be licensed only pursuant to the terms of an applicable Wind River
* license agreement. No license to Wind River intellectual property rights
* is granted herein. All rights not licensed by Wind River are reserved
* by Wind River.
*/
/*
modification history
--------------------
01b,31oct18,lan fix TOS value isn't applied in an IP Header of SCTP INIT ACK
Packet. (VXW6-86973)
01a,15jul08, .
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#ifndef IPCOM_KERNEL
#define IPCOM_KERNEL
#endif
#include "ipsctp_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_err.h>
#include <ipcom_inet.h>
#include <ipcom_os.h>
#include <ipcom_slab.h>
#include <ipcom_syslog.h>
#include <ipcom_sysvar.h>
#include <ipnet_h.h>
#include "ipsctp_h.h"
#ifdef IPCOM_WV_INSTRUMENTATION
#include <ipcom_windview.h>
#endif
#ifdef IPCOM_USE_INET
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
IP_STATIC Ip_bool ipsctp_v4_cmp_addr(const Ipsctp_addr *addr1, const Ipsctp_addr *addr2);
IP_STATIC Ip_bool ipsctp_v4_cmp_addr_key(IP_CONST Ipsctp_addr *addr, IP_CONST union Ip_in_addr_union *key, Ip_u16 domain);
IP_STATIC void ipsctp_load_in_addr(IP_CONST void *addr, union Ip_in_addr_union * in_address);
IP_STATIC void ipsctp_v4_transmit(IP_CONST void *dst, IP_CONST void *src, Ipcom_pkt *pkt);
IP_STATIC void ipsctp_v4_load_sctp_addr(IP_CONST void *addr, IP_CONST Ip_u16 port, Ipsctp_addr *sctp_addr);
IP_STATIC void *ipsctp_get_in_addr(IP_CONST Ipsctp_addr *addr);
IP_STATIC Ip_u32 ipsctp_get_scope_id(IP_CONST Ipsctp_addr *addr);
IP_STATIC void ipsctp_v4_get_mtu_and_mss(Ipsctp_tcb *tcb, \
Ipsctp_transport *transport, Ipnet_route_entry **rt_ret);
IP_STATIC void ipsctp_v4_addr_set_port(Ipsctp_addr *sctp_addr, IP_CONST Ip_u16 port);
IP_STATIC int ipsctp_v4_src_addr_selection(Ipsctp_tcb *tcb, Ipnet_route_entry *rt,\
Ip_u16 lport, Ipsctp_transport *transport);
IP_STATIC void ipsctp_v4_rotate_src_addr(Ipsctp_tcb *tcb, Ipsctp_transport *transport);
IP_STATIC void ipsctp_v4_set_addr_for_socket(Ipsctp_transport *transport, Ipsctp_socket *sock);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
#if 0
IP_STATIC Ipsctp_af_ops sctp_af_inet =
{
.sa_family = IP_AF_INET,
.cmp_addr = ipsctp_v4_cmp_addr,
.load_in_addr = ipsctp_load_in_addr,
.cmp_addr_key = ipsctp_v4_cmp_addr_key,
.ip_transmit = ipsctp_v4_transmit,
.load_soaddr = ipsctp_v4_load_sockaddr,
};
#endif
IP_STATIC Ipsctp_af_ops sctp_af_inet;
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipsctp_v4_init()
*===========================================================================
* Description: This routine initialize IPV4 related operations in SCTP.
* Parameters:
* Returns: void
*
*/
IP_PUBLIC void
ipsctp_v4_init()
{
ipcom_list_init(&sctp_af_inet.list);
sctp_af_inet.cmp_addr = ipsctp_v4_cmp_addr;
sctp_af_inet.cmp_addr_key = ipsctp_v4_cmp_addr_key;
sctp_af_inet.load_soaddr = ipsctp_v4_load_sctp_addr;
sctp_af_inet.load_in_addr = ipsctp_load_in_addr;
sctp_af_inet.get_in_addr = ipsctp_get_in_addr;
sctp_af_inet.get_scope_id = ipsctp_get_scope_id;
sctp_af_inet.ip_transmit = ipsctp_v4_transmit;
sctp_af_inet.get_mtu_and_mss = ipsctp_v4_get_mtu_and_mss;
sctp_af_inet.addr_set_port = ipsctp_v4_addr_set_port;
sctp_af_inet.src_addr_selection = ipsctp_v4_src_addr_selection;
sctp_af_inet.rotate_src_addr = ipsctp_v4_rotate_src_addr;
sctp_af_inet.set_addr_for_socket = ipsctp_v4_set_addr_for_socket;
sctp_af_inet.sa_family = IP_AF_INET;
ipsctp_register_af(&sctp_af_inet);
return;
}
/*
*===========================================================================
* ipsctp_v4_cmp_addr()
*===========================================================================
* Description: This routine compares two IPV4 SCTP address.
* Parameters:
* Returns: IP_TRUE if equal, otherwise IP_FALSE.
*
*/
IP_STATIC Ip_bool
ipsctp_v4_cmp_addr(const Ipsctp_addr *addr1,
const Ipsctp_addr *addr2)
{
if (addr1->sa.sa_family == addr2->sa.sa_family
&& addr1->sin.sin_port == addr2->sin.sin_port
&& addr1->sin.sin_addr.s_addr == addr2->sin.sin_addr.s_addr)
return IP_TRUE;
return IP_FALSE;
}
/*
*===========================================================================
* ipsctp_v4_cmp_addr_key()
*===========================================================================
* Description: This routine compares lookup key with sctp address.
* Parameters:
* Returns: IP_TRUE if equal, otherwise IP_FALSE.
*
*/
IP_STATIC Ip_bool
ipsctp_v4_cmp_addr_key(const Ipsctp_addr *addr,
const union Ip_in_addr_union *key,
Ip_u16 domain
)
{
if ((domain == IP_AF_INET)
&&(addr->sa.sa_family == IP_AF_INET)
&&(key->in.s_addr == addr->sin.sin_addr.s_addr))
{
return IP_TRUE;
}
return IP_FALSE;
}
/*
*===========================================================================
* ipsctp_load_in_addr()
*===========================================================================
* Description: This routine get ipv4 address from input buffer.
* Parameters:
* Returns: void.
*
*/
IP_STATIC void
ipsctp_load_in_addr(IP_CONST void *addr, union Ip_in_addr_union * in_address)
{
if (addr)
in_address->in.s_addr = IP_GET_32ON16((Ip_u32 *)addr);
else
in_address->in.s_addr = 0;
return;
}
/*
*===========================================================================
* ipsctp_ipv4_transmit()
*===========================================================================
* Description: This routine fills out Ipnet_ip4_output_param and transmit
* ipv4 packet.
* Parameters:
* Returns: void.
*
*/
IP_STATIC void
ipsctp_v4_transmit(IP_CONST void *dst,
IP_CONST void *src,
Ipcom_pkt *pkt)
{
Ipnet_socket * sock;
Ip_u8 tos = 0;
if (pkt->fd > 0)
{
IPNET_FD_TO_SOCKET(pkt->fd, sock);
tos = sock->ip4->type_of_service;
}
(void)ipnet_ip4_tx(tos,
255u,
IP_IPPROTO_SCTP,
src,
dst,
0,
pkt);
}
/*
*===========================================================================
* ipsctp_v4_load_sockaddr()
*===========================================================================
* Description: This routine make an Ipsctp_addr from a void addr buffer
* Parameters:
* Returns: void.
*
*/
IP_STATIC void
ipsctp_v4_load_sctp_addr(IP_CONST void *addr, IP_CONST Ip_u16 port, Ipsctp_addr *sctp_addr)
{
IPCOM_SA_LEN_SET(sctp_addr, sizeof(struct Ip_sockaddr_in));
sctp_addr->sin.sin_family = IP_AF_INET;
sctp_addr->sin.sin_port = ip_htons(port);
sctp_addr->sin.sin_addr.s_addr = *(Ip_u32 *)addr;
return;
}
/*
*===========================================================================
* ipsctp_get_in_addr()
*===========================================================================
* Description: This routine gets in_addr from Ipsctp_addr
* Parameters:
* Returns: void *.
*
*/
IP_STATIC void *
ipsctp_get_in_addr(IP_CONST Ipsctp_addr *addr)
{
return (void *)&(addr->sin.sin_addr.s_addr);
}
/*
*===========================================================================
* ipsctp_get_scope_id()
*===========================================================================
* Description: This routine gets scope id from Ipsctp_addr
* Parameters:
* Returns: Ip_u32.
*
*/
IP_STATIC Ip_u32
ipsctp_get_scope_id(IP_CONST Ipsctp_addr *addr)
{
return 0;
}
/*
*===========================================================================
* ipsctp_v4_get_mtu_and_mss()
*===========================================================================
* Description: This routine gets transport mtu and updates the transport
* mtu & mss if necessary.
* Parameters:
* Returns: void.
*
*/
IP_STATIC void
ipsctp_v4_get_mtu_and_mss(struct Ipsctp_tcb_struct *tcb,
struct Ipsctp_transport_struct *transport,
Ipnet_route_entry **rt_ret)
{
Ipnet_route_entry *rt;
int ret;
Ip_u32 mtu;
Ip_u32 mss;
IP_CONST void *saddr = IP_NULL;
Ipnet_flow_spec flow_spec;
/* Determine source address to use in policy lookup */
if (IP_BIT_ISTRUE(transport->state, IPSCTP_ADDR_SRC_SELECTED)
&& IP_BIT_ISFALSE(transport->state, IPSCTP_ADDR_NOT_IN_RT))
saddr = &transport->saddr.sin.sin_addr;
else
saddr = &ip_inaddr_any;
ipnet_flow_spec_from_info(&flow_spec,
tcb->sock->vr_index,
saddr,
&transport->paddr.sin.sin_addr,
0,
0,
IP_NULL,
IP_NULL,
ipnet_ip4_flow_spec_from_info);
/* Look up the route */
ret = ipnet_route_lookup_ecmp(IP_AF_INET,
tcb->sock->vr_index,
0,
&transport->paddr.sin.sin_addr,
0,
0,
IP_NULL,
&flow_spec,
&rt);
if (ret < 0) /* no route entry*/
mtu = ipnet_conf_ip4_min_mtu;
else
/* Note: if the path mtu has changed, IPNET should notify SCTP via callback.
So we don't need pmtu timer here. */
mtu = (rt->metrics.rmx_mtu == 0)
? rt->netif->ipcom.mtu
: IP_MIN(rt->netif->ipcom.mtu, rt->metrics.rmx_mtu);
transport->pmtu = mtu & ~0x3;
#if 0
#ifdef IPIPSEC2
{
struct Ip_sockaddr_in src;
struct Ip_sockaddr_in dst;
src.sin_family = IP_AF_INET;
src.sin_addr.s_addr = transport->paddr.sin.sin_addr.s_addr;
src.sin_port = ip_htons(tcb->instance->lport);
dst.sin_addr.s_addr = transport->saddr.sin.sin_addr.s_addr;
dst.sin_port = ip_htons(tcb->rport);
mtu -= (Ip_u32)ipipsec_get_header_space((Ip_u8)IP_IPPROTO_SCTP, (struct Ip_sockaddr *)&src, (struct Ip_sockaddr *)&dst);
}
#endif /* IPIPSEC2 */
#endif
mss = mtu - tcb->sock->max_hdrspace/* - sizeof(Ipsctp_data_chunk_hdr)*/;
mss = IP_MIN((Ip_u32)IPSCTP_SENDBUF_MAX(tcb), mss);
transport->mss = mss & ~0x3;
#if defined(IPSCTP_DEBUG)
IPSCTP_DBG6(IPSCTP_DBG_MTU,
"IPSCTP: transport's MTU changed (dst:%s, src:%s, pmtu:%u, "\
"mss:%u, state:0x%x, now:%u)."IP_LF,
ipsctp_addr_ntop(&transport->paddr, ipnet->log_buf, 128),
ipsctp_addr_ntop(&transport->saddr, &ipnet->log_buf[128], 128),
transport->pmtu,
transport->mss,
transport->state,
ipstack->msec_now
);
#endif
if (IP_BIT_ISFALSE(transport->state, IPSCTP_ADDR_UNCONFIRMED)
&& IP_BIT_ISSET(transport->state, IPSCTP_ADDR_REACHABLE))
{
if (tcb->pmtu == 0 /* first remote address for this occasion */
|| tcb->pmtu > transport->pmtu)
{
IPSCTP_DATA_TCBLOCK(tcb->instance->tcb_lock);
tcb->pmtu = transport->pmtu; /* update tcb path mtu */
IPSCTP_DATA_TCBUNLOCK(tcb->instance->tcb_lock);
}
if (tcb->mss == 0 || tcb->mss > transport->mss)
{
tcb->mss = transport->mss;
if (tcb->frag_point != 0)
{
tcb->mss = IP_MIN(tcb->mss, tcb->frag_point & ~0x3);
}
#if defined(IPSCTP_DEBUG)
IPSCTP_DBG6(IPSCTP_DBG_MTU,
"IPSCTP: tcb's MTU changed (vtag: %u, lport: %u, rport: %u, "\
"pmtu: %u, mss: %u, now: %u)."IP_LF,
tcb->my_vtag,
tcb->instance->lport,
tcb->rport,
tcb->pmtu,
tcb->mss,
ipstack->msec_now
);
#endif
}
}
if (rt_ret)
{
*rt_ret = rt;
}
return ;
}
/*
*===========================================================================
* ipsctp_icmp4_cb
*===========================================================================
* Description: Process the incoming ICMP packet, change path MTU and record
* other ICMP errors.
* Parameters: pkt - the ICMP packet, must not be modified or freed by
* this function
* Returns:
*
*/
IP_PUBLIC void
ipsctp_icmp4_cb(IP_CONST Ipcom_pkt *pkt)
{
Ipnet_pkt_icmp *icmp_hdr;
Ipnet_pkt_ip *failing_ip_pkt;
Ipsctp_sctp_hdr *sctp_hdr;
int icmp_len;
Ipsctp_tcb *tcb;
Ipsctp_transport *transport;
struct Ip_in_addr src;
struct Ip_in_addr dst;
Ipsctp_af_ops *af_ops;
Ip_bool has_init = IP_FALSE;
Ip_u16 sctp_len;
icmp_len = ipcom_pkt_get_length(pkt);
if (icmp_len < (8 /*IPNET_ICMP_HDR_SIZE*/ + IPNET_IP_HDR_SIZE + IPSCTP_SIZE_SCTP_HDR))
{
IPNET_STATS(icmp4_input_hdrsize2++);
IPCOM_MIB2(icmpInErrors++);
IPCOM_MIB2_SYSWI_U32_ADD(v4, icmpStatsInErrors, 1);
return;
}
/* get icmp header */
icmp_hdr = ipcom_pkt_get_data(pkt, 0);
if (icmp_hdr->type != 3 /*IPNET_ICMP4_TYPE_DST_UNREACHABLE*/
|| (icmp_hdr->code != 4 /*IPNET_ICMP4_CODE_DST_NEEDFRAG*/
&& icmp_hdr->code != 2 /*IPNET_ICMP4_CODE_DST_UNREACH_PROTO*/)
)
{
return;
}
failing_ip_pkt = (Ipnet_pkt_ip *) icmp_hdr->data.failing_pkt.ip;
sctp_hdr = (Ipsctp_sctp_hdr *)((Ip_u8 *)failing_ip_pkt + IPNET_IP4_GET_HDR_OCTET_LEN(failing_ip_pkt));
sctp_len = ip_ntohs(failing_ip_pkt->len) - IPNET_IP4_GET_HDR_OCTET_LEN(failing_ip_pkt);
dst.s_addr = IPNET_IP4_GET_IPADDR(failing_ip_pkt->dst);
src.s_addr = IPNET_IP4_GET_IPADDR(failing_ip_pkt->src);
/* get address family specific operations */
af_ops = ipsctp_get_af_ops(IP_AF_INET);
tcb = ipsctp_tcb_lookup(ip_ntohl(sctp_hdr->vtag),
pkt->vr_index,
IP_IPPROTO_SCTP,
&src, ip_ntohs(sctp_hdr->sport),
&dst, ip_ntohs(sctp_hdr->dport),
af_ops,
&transport
);
if (tcb == NULL || transport == NULL)
return;
/* Appendix C. ICMP Handling, RFC4960:
ICMP6) An implementation MUST validate that the Verification Tag
contained in the ICMP message matches the Verification Tag of
the peer. If the Verification Tag is not 0 and does NOT
match, discard the ICMP message. If it is 0 and the ICMP
message contains enough bytes to verify that the chunk type is
an INIT chunk and that the Initiate Tag matches the tag of the
peer, continue with ICMP7. If the ICMP message is too short
or the chunk type or the Initiate Tag does not match, silently
discard the packet.
ICMP7) If the ICMP message is either a v6 "Packet Too Big" or a v4
"Fragmentation Needed", an implementation MAY process this
information as defined for PATH MTU discovery.
*/
if (ip_ntohl(sctp_hdr->vtag) == 0)
{
Ipsctp_init_chunk_hdr *init_chunk;
/* Check if the init chunk length is valid */
if ((sctp_len - IPSCTP_SIZE_SCTP_HDR) < sizeof(Ipsctp_init_chunk_hdr))
{
return;
}
init_chunk = (Ipsctp_init_chunk_hdr *)((Ip_u8 *)sctp_hdr + IPSCTP_SIZE_SCTP_HDR);
if ((init_chunk->hdr.type != IPSCTP_CHUNK_TYPE_INIT)
|| (init_chunk->fixed_params.init_tag != tcb->my_vtag))
{
return;
}
has_init = IP_TRUE;
}
else if (ip_ntohl(sctp_hdr->vtag) != tcb->my_vtag)
return;
transport->err_cnt++;
switch(icmp_hdr->code)
{
case 4 /*IPNET_ICMP4_CODE_DST_NEEDFRAG*/:
ipsctp_notify_cb(tcb, transport, IPSCTP_NOTIFY_EVENT_PATH_MTU);
break;
case 2 /*IPNET_ICMP4_CODE_DST_UNREACH_PROTO*/:
/*
* ICMP8) If the ICMP code is an "Unrecognized Next Header Type Encountered"
* or a "Protocol Unreachable", an implementation MUST treat this message as
* an abort with the T bit set if it does not contain an INIT chunk.
* If it does contain an INITchunk and the association is in the COOKIE-WAIT state,
* handle the ICMP message like an ABORT.
*/
if (!has_init || IPSCTP_GET_STATE(tcb) == IPSCTP_STATE_COOKIE_WAIT)
{
ipsctp_handle_abort_for_icmp(tcb);
}
break;
default:
break;
}
/* TODO, report icmp error to application, see iptcp_icmp4_report */
/* TODO, process the ICMP errors */
}
/*
*===========================================================================
* ipsctp_v4_addr_set_port()
*===========================================================================
* Description: This routine set port of Ipsctp_addr.
* Parameters:
* Returns: void.
*
*/
IP_STATIC void
ipsctp_v4_addr_set_port(Ipsctp_addr *sctp_addr, IP_CONST Ip_u16 port)
{
sctp_addr->sin.sin_port = ip_htons(port);
return;
}
/*
*===========================================================================
* ipsctp_v4_src_addr_selection
*===========================================================================
* Description: This routine selects a source address for given peer address.
* If SCTP TCB bounds all addresses, we invoke general IPV4 or IPV6
* routine to select source address. Otherwise, for bounded local
* addresses and route entry's interface addresses, select the most
* matchable source address. We use ipsctp_addr_match_len to get address's
* match extent. If rt is NULL, don't select the source address.
* Parameters:
* Returns: 0 if success, or -1 if it fails to select one.
*
*/
IP_STATIC int
ipsctp_v4_src_addr_selection(Ipsctp_tcb *tcb, /* TCB pointer */
Ipnet_route_entry *rt, /* route entry for dstaddr, NULL if no route */
Ip_u16 lport,
Ipsctp_transport *transport /* selected source address */
)
{
Ipsctp_laddr_entry *addr;
Ip_u8 match_len = 0;
Ip_u8 new_match_len = 0;
IP_CONST struct Ip_in_addr *in_srcaddr = IP_NULL;
int ret = -1;
Ipsctp_addr *dstaddr = &transport->paddr; /* peer or dst address of transport */
Ipsctp_addr *srcaddr = &transport->saddr; /* selected source address */
*srcaddr = *dstaddr;
if (IP_BIT_ISSET(tcb->instance->inst_flags, IPSCTP_SOCKET_BOUNDALL)) /* bound all addresses */
{
in_srcaddr =
ipnet_ip4_get_src_addr(tcb->sock->vr_index,
&dstaddr->sin.sin_addr,
rt,
IP_NULL);
if (in_srcaddr)
{
goto src_selected;
}
}
/* Iterate all addresses of route entry's interface, and if the address is in
local bounded list, find the most matchable one */
if (rt && rt->netif)
{
Ipnet_ip4_addr_entry *inet4_addr;
/* iterate all ipv4 addresses of route entry's outgoing interface */
for (inet4_addr = rt->netif->inet4_addr_list;
inet4_addr;
inet4_addr = inet4_addr->next)
{
for(addr = (Ipsctp_laddr_entry *)ipcom_list_first(&tcb->instance->laddr_list);
addr; addr = (Ipsctp_laddr_entry *)ipcom_list_next(&addr->next)
)
{
if ((addr->laddr.sa.sa_family == IP_AF_INET)
&& (inet4_addr->ipaddr_n == addr->laddr.sin.sin_addr.s_addr))
{
/* find one match address, get its match length */
new_match_len = (Ip_u8)ipsctp_addr_match_len(
&dstaddr->sin.sin_addr,
&addr->laddr.sin.sin_addr,
sizeof(struct Ip_in_addr)/sizeof(Ip_u32));
if (new_match_len > match_len)
{
match_len = new_match_len;
in_srcaddr = &addr->laddr.sin.sin_addr;
}
}
}
}
if (in_srcaddr)
{
goto src_selected;
}
}
/* randomly select source address, and rotate the source address when re-transmitting */
for(addr = (Ipsctp_laddr_entry *)ipcom_list_first(&tcb->instance->laddr_list);
addr; addr = (Ipsctp_laddr_entry *)ipcom_list_next(&addr->next)
)
{
if (addr->laddr.sa.sa_family == IP_AF_INET)
{
in_srcaddr = &addr->laddr.sin.sin_addr;
IP_BIT_SET(transport->state, IPSCTP_ADDR_NOT_IN_RT);
break;
}
}
src_selected:
if (in_srcaddr)
{
srcaddr->sin.sin_addr.s_addr
= in_srcaddr->s_addr;
srcaddr->sin.sin_port = ip_htons(lport);
IP_BIT_SET(transport->state, IPSCTP_ADDR_SRC_SELECTED);
ret = 0;
}
else
{
/* report the error */
IPCOM_LOG0(ERR, "ipsctp_v4_src_addr_selection: failed to select source address when BOUNDALL\n");
}
return ret;
}
/*
*===========================================================================
* ipsctp_v4_set_addr_for_socket()
*===========================================================================
* Description: This routine set the src and dst address in socket.
* Parameters:
* Returns: void.
*
*/
IP_STATIC void
ipsctp_v4_set_addr_for_socket(Ipsctp_transport *transport,
Ipsctp_socket *sock)
{
sock->ip4->saddr_n = transport->saddr.sin.sin_addr.s_addr;
sock->ip4->daddr_n = transport->paddr.sin.sin_addr.s_addr;
return;
}
/*
*===========================================================================
* ipsctp_v4_rotate_src_addr()
*===========================================================================
* Description: This routine rotates the source address for transport.
* Parameters:
* Returns: void.
*
*/
IP_STATIC void
ipsctp_v4_rotate_src_addr(Ipsctp_tcb *tcb,
Ipsctp_transport *transport)
{
#if defined(IPSCTP_DEBUG)
IPSCTP_DBG7(IPSCTP_DBG_PATH,
"IPSCTP :transport before rotating source (dst:%s, src:%s, err_cnt:%u, "\
"tcb->oa_err_cnt:%u, state:0x%x, rto:%u, now:%u)."IP_LF,
ipsctp_addr_ntop(&transport->paddr, ipnet->log_buf, 128),
ipsctp_addr_ntop(&transport->saddr, &ipnet->log_buf[128], 128),
transport->err_cnt,
tcb->oa_err_cnt,
transport->state,
transport->rto,
ipstack->msec_now
);
#endif
if (tcb->instance->inst_flags & IPSCTP_SOCKET_BOUNDALL)
{
Ipnet_netif *netif;
struct Ipnet_ip4_addr_entry_struct *found_addr = IP_NULL;
Ip_bool found_match = IP_FALSE;
Ip_u32 i;
retry_first:
/* Search for all interfaces */
/*
* IPNET_NETIF_FOR_EACH_ON_VR sets netif to NULL after the for loop,
* this is a performance optimized defination
*/
/* coverity[result_independent_of_operands] */
IPNET_NETIF_FOR_EACH_ON_VR(netif, tcb->sock->vr_index, i)
{
/* Don't add loopback address */
if IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_LOOPBACK)
{
continue;
}
/* IPV4 is allowed */
if (tcb->instance->inst_flags & IPSCTP_SOCKET_BOUND_V4)
{
struct Ipnet_ip4_addr_entry_struct *addr_entry;
for (addr_entry = netif->inet4_addr_list;
IP_NULL != addr_entry;
addr_entry = addr_entry->next)
{
/* Don't add any kind of addresses except unicast */
if (addr_entry->type != IPNET_ADDR_TYPE_UNICAST)
{
/* Not in scope , unspecified */
continue;
}
if (found_match)
{
found_addr = addr_entry;
break;
}
if (addr_entry->ipaddr_n == transport->saddr.sin.sin_addr.s_addr)
{
found_match = IP_TRUE;
}
}
}
if (found_addr)
{
break;
}
}
if (found_match && found_addr == IP_NULL)
{
/* retry to get the first address */
goto retry_first;
}
if (found_match && found_addr)
{
transport->saddr.sin.sin_addr.s_addr = found_addr->ipaddr_n;
#if defined(IPSCTP_DEBUG)
IPSCTP_DBG7(IPSCTP_DBG_PATH,
"IPSCTP :transport after rotating source (dst:%s, src:%s, err_cnt:%u, "\
"tcb->oa_err_cnt:%u, state:0x%x, rto:%u, now:%u)."IP_LF,
ipsctp_addr_ntop(&transport->paddr, ipnet->log_buf, 128),
ipsctp_addr_ntop(&transport->saddr, &ipnet->log_buf[128], 128),
transport->err_cnt,
tcb->oa_err_cnt,
transport->state,
transport->rto,
ipstack->msec_now
);
#endif
}
return;
}
if (ipsctp_list_size(&tcb->instance->laddr_list) < 2)
{
return;
}
else
{
Ipsctp_laddr_entry *addr;
Ipsctp_laddr_entry *addr_next;
/* find next address in local address list*/
addr = (Ipsctp_laddr_entry *)ipcom_list_first(&tcb->instance->laddr_list);
while(addr)
{
if (addr->laddr.sa.sa_family == IP_AF_INET
&& addr->laddr.sin.sin_addr.s_addr == transport->saddr.sin.sin_addr.s_addr)
{
break;
}
else
{
addr = (Ipsctp_laddr_entry *)ipcom_list_next(&addr->next);
}
}
if (addr == IP_NULL)
{
return;
}
/* get next address in the local list */
addr_next = (Ipsctp_laddr_entry *)ipcom_list_next(&addr->next);
if (addr_next == IP_NULL)
{
addr_next = (Ipsctp_laddr_entry *)ipcom_list_first(&tcb->instance->laddr_list);
}
while (addr_next && addr_next != addr)
{
if (addr_next->laddr.sa.sa_family == IP_AF_INET)
{
transport->saddr.sin.sin_addr.s_addr = addr_next->laddr.sin.sin_addr.s_addr;
#if defined(IPSCTP_DEBUG)
IPSCTP_DBG7(IPSCTP_DBG_PATH,
"IPSCTP :transport after rotating source (dst:%s, src:%s, err_cnt:%u, "\
"tcb->oa_err_cnt:%u, state:0x%x, rto:%u, now:%u)."IP_LF,
ipsctp_addr_ntop(&transport->paddr, ipnet->log_buf, 128),
ipsctp_addr_ntop(&transport->saddr, &ipnet->log_buf[128], 128),
transport->err_cnt,
tcb->oa_err_cnt,
transport->state,
transport->rto,
ipstack->msec_now
);
#endif
break;
}
else
{
addr_next = (Ipsctp_laddr_entry *)ipcom_list_next(&addr_next->next);
if (addr_next == IP_NULL)
{
addr_next = (Ipsctp_laddr_entry *)ipcom_list_first(&tcb->instance->laddr_list);
}
}
}
return;
}
}
#endif /* IPCOM_USE_INET */
#ifdef IPCOM_FORWARDER_NAE
IP_PUBLIC Ip_bool
ipsctp_v4v6_cmp_addr(const Ipsctp_addr *addr1,
const Ipsctp_addr *addr2,
Ip_sa_family_t address_family);
IP_PUBLIC void *
ipsctp_v4v6_get_in_addr(IP_CONST Ipsctp_addr *addr,Ip_sa_family_t address_family);
IP_PUBLIC Ip_bool
ipsctp_v4v6_cmp_addr_key(const Ipsctp_addr *addr,
const union Ip_in_addr_union *key,
Ip_u16 domain,
Ip_sa_family_t address_family
);
IP_PUBLIC Ip_u32
ipsctp_v4v6_get_scope_id(IP_CONST Ipsctp_addr *addr,Ip_sa_family_t address_family);
IP_PUBLIC void
ipsctp_v4v6_get_mtu_and_mss(struct Ipsctp_tcb_struct *tcb,
struct Ipsctp_transport_struct *transport,
Ipnet_route_entry **rt_ret,
Ip_sa_family_t address_family);
IP_PUBLIC void
ipsctp_v4v6_rotate_src_addr(Ipsctp_tcb *tcb,
Ipsctp_transport *transport,
Ip_sa_family_t address_family);
IP_PUBLIC void
ipsctp_v4v6_set_addr_for_socket(Ipsctp_transport *transport,
Ipsctp_socket *sock,
Ip_sa_family_t address_family);
IP_PUBLIC void
ipsctp_v4v6_transmit(IP_CONST void *dst,
IP_CONST void *src,
Ipcom_pkt *pkt,
Ip_sa_family_t address_family);
Ip_bool ipsctp_v6_cmp_addr(IP_CONST Ipsctp_addr *addr1, IP_CONST Ipsctp_addr *addr2);
Ip_bool ipsctp_v6_cmp_addr_key(IP_CONST Ipsctp_addr *addr, IP_CONST union Ip_in_addr_union *key, Ip_u16 domain);
void ipsctp_v6_transmit(IP_CONST void *dst, IP_CONST void *src, Ipcom_pkt *pkt);
void *ipsctp_get_in6_addr(IP_CONST Ipsctp_addr *addr6);
Ip_u32 ipsctp_get6_scope_id(IP_CONST Ipsctp_addr *addr6);
void ipsctp_v6_get_mtu_and_mss(Ipsctp_tcb *tcb, Ipsctp_transport *transport, Ipnet_route_entry **rt_ret);
void ipsctp_v6_set_addr_for_socket(Ipsctp_transport *transport,Ipsctp_socket *sock);
void ipsctp_v6_rotate_src_addr(Ipsctp_tcb *tcb,Ipsctp_transport *transport);
IP_PUBLIC Ip_bool
ipsctp_v4v6_cmp_addr(const Ipsctp_addr *addr1,
const Ipsctp_addr *addr2,
Ip_sa_family_t address_family)
{
switch(address_family)
{
#ifdef IPCOM_USE_INET
case IP_AF_INET:
return ipsctp_v4_cmp_addr(addr1,addr2);
break;
#endif
#ifdef IPCOM_USE_INET6
case IP_AF_INET6:
return ipsctp_v6_cmp_addr(addr1,addr2);
break;
#endif
default:
return IP_FALSE;
}
}
IP_PUBLIC void *
ipsctp_v4v6_get_in_addr(IP_CONST Ipsctp_addr *addr,Ip_sa_family_t address_family)
{
switch(address_family)
{
#ifdef IPCOM_USE_INET
case IP_AF_INET:
return ipsctp_get_in_addr(addr);
break;
#endif
#ifdef IPCOM_USE_INET6
case IP_AF_INET6:
return ipsctp_get_in6_addr(addr);
break;
#endif
default:
return IP_NULL;
}
}
IP_PUBLIC Ip_bool
ipsctp_v4v6_cmp_addr_key(const Ipsctp_addr *addr,
const union Ip_in_addr_union *key,
Ip_u16 domain,
Ip_sa_family_t address_family)
{
switch(address_family)
{
#ifdef IPCOM_USE_INET
case IP_AF_INET:
return ipsctp_v4_cmp_addr_key(addr,key,domain);
break;
#endif
#ifdef IPCOM_USE_INET6
case IP_AF_INET6:
return ipsctp_v6_cmp_addr_key(addr,key,domain);
break;
#endif
default:
return IP_FALSE;
}
}
IP_PUBLIC Ip_u32
ipsctp_v4v6_get_scope_id(IP_CONST Ipsctp_addr *addr,Ip_sa_family_t address_family)
{
switch(address_family)
{
#ifdef IPCOM_USE_INET
case IP_AF_INET:
return ipsctp_get_scope_id(addr);
break;
#endif
#ifdef IPCOM_USE_INET6
case IP_AF_INET6:
return ipsctp_get6_scope_id(addr);
break;
#endif
default:
return 0;
}
}
IP_PUBLIC void
ipsctp_v4v6_get_mtu_and_mss(struct Ipsctp_tcb_struct *tcb,
struct Ipsctp_transport_struct *transport,
Ipnet_route_entry **rt_ret,
Ip_sa_family_t address_family)
{
switch(address_family)
{
#ifdef IPCOM_USE_INET
case IP_AF_INET:
return ipsctp_v4_get_mtu_and_mss(tcb,transport,rt_ret);
break;
#endif
#ifdef IPCOM_USE_INET6
case IP_AF_INET6:
return ipsctp_v6_get_mtu_and_mss(tcb,transport,rt_ret);
break;
#endif
default:
return;
}
}
IP_PUBLIC void
ipsctp_v4v6_rotate_src_addr(Ipsctp_tcb *tcb,
Ipsctp_transport *transport,
Ip_sa_family_t address_family)
{
switch(address_family)
{
#ifdef IPCOM_USE_INET
case IP_AF_INET:
return ipsctp_v4_rotate_src_addr(tcb,transport);
break;
#endif
#ifdef IPCOM_USE_INET6
case IP_AF_INET6:
return ipsctp_v6_rotate_src_addr(tcb,transport);
break;
#endif
default:
return;
}
}
IP_PUBLIC void
ipsctp_v4v6_set_addr_for_socket(Ipsctp_transport *transport,
Ipsctp_socket *sock,
Ip_sa_family_t address_family)
{
switch(address_family)
{
#ifdef IPCOM_USE_INET
case IP_AF_INET:
return ipsctp_v4_set_addr_for_socket(transport,sock);
break;
#endif
#ifdef IPCOM_USE_INET6
case IP_AF_INET6:
return ipsctp_v6_set_addr_for_socket(transport,sock);
break;
#endif
default:
return;
}
}
IP_PUBLIC void
ipsctp_v4v6_transmit(IP_CONST void *dst,
IP_CONST void *src,
Ipcom_pkt *pkt,
Ip_sa_family_t address_family)
{
switch(address_family)
{
#ifdef IPCOM_USE_INET
case IP_AF_INET:
return ipsctp_v4_transmit(dst,src,pkt);
break;
#endif
#ifdef IPCOM_USE_INET6
case IP_AF_INET6:
return ipsctp_v6_transmit(dst,src,pkt);
break;
#endif
default:
return;
}
}
#endif