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

882 lines
29 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_sock_ip4.c,v $ $Revision: 1.51.10.13 $
* $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_sock_ip4.c,v $
* $Author: jren $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
* IPv4 specific socket operations.
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#ifndef IPCOM_KERNEL
#define IPCOM_KERNEL
#endif
#include "ipnet_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_cstyle.h>
#include <ipcom_syslog.h>
#include <ipcom_type.h>
#include "ipnet_h.h"
#include "ipnet_usr_sock.h"
#ifdef IPSCTP
#include "ipsctp.h"
#endif
#ifdef IPIPSEC2
#include "ipipsec.h"
#endif
#ifdef IPNET_USE_PER_SOCKET_VLAN_TAG
#include "ipnet_eth.h" /* ipnet_vlan_set_tag() */
#endif
#ifdef IPCOM_USE_INET
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipnet_sock_ip4_init
*===========================================================================
* Description: IPv4 specific initialization.
* Parameters: sock - The socket that is beeing created.
* Returns: 0 for success else negative error code.
*
*/
IP_STATIC int
ipnet_sock_ip4_init(Ipnet_socket *sock, Ip_bool user_context)
{
IPCOM_UNUSED_ARG(user_context);
/*
* Let the stack select the TTL form the per-interface
* configuration set via sysvar [ipnet|<ifname>].inet.BaseHopLimit
*/
sock->uni_hop_limit = 0;
sock->ip4 = ipnet_sock_alloc_private_data(sock, sizeof(Ipnet_ip4_socket));
#ifndef IPNET_USE_RESTRICTED_SOCKET_BROADCAST
IP_BIT_SET(sock->ip4->flags, IPNET_SOCKET_FLAG_IP4_ALLOW_BROADCAST);
#endif
#ifdef IPSCTP
if (IP_NULL != sock->sctp_inst)
IP_BIT_SET(sock->sctp_inst->inst_flags, IPSCTP_SOCKET_BOUND_V4);
#endif
switch (sock->ipcom.type)
{
case IP_SOCK_RAW:
if (sock->proto == IP_IPPROTO_ICMP)
{
sock->ip4->icmp_filter = ipnet_sock_alloc_private_data(sock, sizeof(struct Ip_icmp_filter));
IP_ICMP_FILTER_SETPASSALL(sock->ip4->icmp_filter);
}
break;
case IP_SOCK_STREAM:
case IP_SOCK_SEQPACKET:
sock->ip4->dont_frag = ipnet->conf.inet.sock_stream_dont_frag;
return 0;
case IP_SOCK_DGRAM:
return 0;
default:
IP_PANIC2();
return -IP_ERRNO_EINVAL;
}
return ipnet_sock_set_reachable(sock);
}
/*
*===========================================================================
* ipnet_sock_ip4_destroy
*===========================================================================
* Description: IPv4 specific cleanup during socket close.
* Parameters: sock - The socket that is beeing closed.
* Returns:
*
*/
IP_STATIC void
ipnet_sock_ip4_destroy(Ipnet_socket *sock)
{
ipnet_sock_unbind(sock);
ipcom_free(sock->ip4->opts);
#ifdef IPNET_USE_MCAST_ROUTING
if (IP_BIT_ISSET(sock->flags, IPNET_SOCKET_FLAG_MROUTE_CONTROL))
ipnet_ip4_mcast_mrt_done(sock);
#endif
}
/*
*===========================================================================
* ipnet_sock_ip4_connect
*===========================================================================
* Description: The IPv4 network layer connect.
* Parameters: sock - The socket to connect.
* to - The address to connect to.
* tolen - The size of the 'to' buffer.
* Returns: 0 = success, <0 = error code
*
*/
IP_STATIC int
ipnet_sock_ip4_connect(Ipnet_socket *sock, IP_CONST struct Ip_sockaddr *to, Ip_socklen_t tolen)
{
struct Ip_sockaddr_in in_name;
struct Ip_sockaddr_in *in_to;
IP_CONST struct Ip_in_addr *src_addr;
Ip_u16 sport = 0;
Ipnet_netif *netif = IP_NULL;
ipnet_sock_set_unreachable(sock);
sock->ip4->daddr_n = 0;
switch (to->sa_family)
{
case IP_AF_INET:
/* Setup the IPv4 destination (peer) address */
if (tolen < sizeof(struct Ip_sockaddr_in))
return -IP_ERRNO_EINVAL;
in_to = (struct Ip_sockaddr_in*) to;
if (in_to->sin_addr.s_addr == IP_INADDR_ANY)
return ipnet_sock_unconnect(sock);
sock->ip4->daddr_n = in_to->sin_addr.s_addr;
sock->dport = ip_ntohs(in_to->sin_port);
if (IP_IN_CLASSD(in_to->sin_addr.s_addr))
netif = ipnet_if_indextonetif(sock->vr_index, sock->ip4->multicast_if);
src_addr = ipnet_ip4_get_src_addr(sock->vr_index, &in_to->sin_addr, IP_NULL, netif);
if (src_addr == IP_NULL)
{
#ifndef IP_PORT_LKM
IPCOM_LOG2(WARNING, "connect failed on socket %d, %s is unreachable",
sock->ipcom.fd,
ipcom_inet_ntop(IP_AF_INET, &in_to->sin_addr, ipnet->log_buf, sizeof(ipnet->log_buf)));
#endif
return -IP_ERRNO_EHOSTUNREACH;
}
if (IP_BIT_ISFALSE(sock->flags, IPNET_SOCKET_FLAG_DONT_REBIND)
&& IP_BIT_ISSET(sock->flags, IPNET_SOCKET_FLAG_BOUND)
&& (ipnet_ip4_get_addr_type(sock->ip4->saddr_n, sock->vr_index, IP_NULL)
!= IPNET_ADDR_TYPE_UNICAST))
{
/*
* No unicast address specified when the socket was bound,
* need to rebind.
*/
sport = sock->sport;
ipnet_sock_unbind(sock);
}
if (IP_BIT_ISFALSE(sock->flags, IPNET_SOCKET_FLAG_BOUND))
{
Ipnet_sock_ops *ops;
in_name.sin_family = IP_AF_INET;
IPCOM_SA_LEN_SET(&in_name, sizeof(in_name));
in_name.sin_addr.s_addr = src_addr->s_addr;
in_name.sin_port = ip_htons(sport);
ops = ipnet_sock_get_ops(sock);
return ops->bind(sock, (struct Ip_sockaddr *) &in_name, IPCOM_SA_LEN_GET(&in_name), IP_TRUE);
}
/* else: already bound to an unicast address */
return ipnet_sock_set_reachable(sock);
case IP_AF_UNSPEC:
return ipnet_sock_unconnect(sock);
default:
return -IP_ERRNO_EAFNOSUPPORT;
}
}
/*
*===========================================================================
* ipnet_sock_ip4_raw_connect
*===========================================================================
* Description: Connects a RAW IPv4 socket.
* Parameters: sock - The socket to connect.
* to - The address to connect to.
* tolen - The size of the 'to' buffer.
* Returns: 0 = success, <0 = error code
*
*/
IP_STATIC int
ipnet_sock_ip4_raw_connect(Ipnet_socket *sock, IP_CONST struct Ip_sockaddr *to, Ip_socklen_t tolen)
{
int ret;
ret = ipnet_sock_ip4_connect(sock, to, tolen);
if (ret < 0)
return ret;
IP_BIT_SET(sock->flags, IPNET_SOCKET_FLAG_CONNECTED);
return 0;
}
/*
*===========================================================================
* ipnet_sock_ip4_raw_sendto
*===========================================================================
* Description: Transmitts a packet on a raw IPv4 socket.
* Parameters: sock - a raw IPv4 socket.
* msg - message structure passed to sendmsg()
* pkt - packet to transmit
* Returns: >=0 = success, magnitude is the number of bytes sent
* <0 = error code
*
*/
IP_STATIC int
ipnet_sock_ip4_raw_sendto(Ipnet_socket *sock,
IP_CONST struct Ip_msghdr *msg,
Ipcom_pkt *pkt)
{
Ipnet_pkt_ip *ip_hdr;
int hdr_len;
struct Ip_cmsghdr *cmsg;
void *rt_lookup_key = IP_NULL;
if (IP_BIT_ISFALSE(sock->ip4->flags, IPNET_SOCKET_FLAG_IP4_HDRINCL))
{
Ipnet_sock_inet_ops *ops;
/*
* No IP-header included, use the normal socket transmission
* path.
*/
ops = (Ipnet_sock_inet_ops *) ipnet_sock_get_ops(sock);
return ops->network_send(sock, msg, pkt);
}
#ifdef IPNET_USE_PER_SOCKET_VLAN_TAG
if (sock->vlan_tag)
{
ipnet_vlan_set_tag(pkt, sock->vlan_tag);
}
#endif
/*
* The user supplied the IP header
*/
pkt->ipstart = pkt->start;
ip_hdr = ipcom_pkt_get_iphdr(pkt);
if (ip_hdr->id == 0)
/*
* User did not specify a ID, set the next available
* one
*/
ip_hdr->id = (Ip_u16) ipnet->ip4.id++;
hdr_len = IPNET_IP4_GET_HDR_OCTET_LEN(ip_hdr);
if (hdr_len < IPNET_IP_HDR_SIZE)
{
ipcom_pkt_free(pkt);
return -IP_ERRNO_EINVAL;
}
/*
* Note: strangely enough the IP length is set in host endian!
*/
ip_hdr->len = (Ip_u16)ip_htons(pkt->end - pkt->ipstart);
/*
* Use specific interface?
*/
if (sock->bind_to_ifindex != 0)
/*
* Bound to a specific device
*/
pkt->ifindex = sock->bind_to_ifindex;
else if (sock->ip4->multicast_if != 0 && IP_IN_CLASSD(IPNET_IP4_GET_IPADDR(ip_hdr->dst)))
/*
* A specific interface was set with IP_IP_MULTICAST_IF socket
* option
*/
pkt->ifindex = sock->ip4->multicast_if;
else
pkt->ifindex = 0;
if (msg != IP_NULL && msg->msg_controllen > 0)
{
struct Ip_in_pktinfo *pktinfo = IP_NULL;
/* Set extensions header specified to sendmsg() (this overrides any sticky options) */
ip_assert(msg->msg_control != IP_NULL);
for (cmsg = IP_CMSG_FIRSTHDR(msg);
cmsg != IP_NULL;
cmsg = IP_CMSG_NXTHDR(msg, cmsg))
{
if (cmsg->cmsg_level != IP_IPPROTO_IP)
continue;
switch (cmsg->cmsg_type)
{
case IP_IP_PKTINFO:
pktinfo = IP_CMSG_DATA(cmsg);
if (pktinfo->ipi_ifindex != 0)
pkt->ifindex = pktinfo->ipi_ifindex;
break;
case IP_IP_X_VRID:
IPCOM_PKT_SET_VRID(pkt, *(Ip_u8*) IP_CMSG_DATA(cmsg));
break;
}
}
}
IP_BIT_SET(pkt->flags, IPCOM_PKT_FLAG_HAS_IP_HDR);
if((msg) && (msg->msg_name) && (IPNET_IP4_GET_IPADDR(ip_hdr->dst) != IP_INADDR_ANY))
{
rt_lookup_key = (void*) &((struct Ip_sockaddr_in *)msg->msg_name)->sin_addr;
}
return ipnet_ip4_pkt_with_iphdr_tx(pkt, rt_lookup_key);
}
/*
*===========================================================================
* ipnet_sock_ip4_bind
*===========================================================================
* Description: The IPv4 network layer bind.
* Parameters: sock - The socket to bind.
* name - The socket name.
* namelen - The length of the name variable.
* check_reuse - Set to IP_TRUE if the name should be checked
* for address reuse.
* Returns: 0 = success, <0 = error code
*
*/
IP_STATIC int
ipnet_sock_ip4_bind(struct Ipnet_socket_struct *sock,
IP_CONST struct Ip_sockaddr *name,
Ip_socklen_t namelen,
Ip_bool check_reuse)
{
struct Ip_sockaddr_in *name_in;
enum Ipnet_addr_type addr_type = IPNET_ADDR_TYPE_NOT_LOCAL;
Ipnet_ip4_addr_entry *addr_entry = IP_NULL;
IPCOM_UNUSED_ARG(check_reuse);
if (namelen < sizeof(struct Ip_sockaddr_in))
{
IPCOM_LOG3(WARNING, "socket %d: namelen too small in bind is %d must be at least %d",
sock->ipcom.fd, namelen, sizeof(struct Ip_sockaddr_in));
return -IP_ERRNO_EINVAL;
}
name_in = (struct Ip_sockaddr_in*)name;
/*
* Verify that IP address is either ANY (0) or one of my
* addresses. Note: it is ok to bind to any multicast address or
* the broadcast address.
*/
if (name_in->sin_addr.s_addr == IP_INADDR_ANY)
addr_type = IPNET_ADDR_TYPE_ANY;
else if (name_in->sin_addr.s_addr == IP_INADDR_BROADCAST)
addr_type = IPNET_ADDR_TYPE_BROADCAST;
else if (IP_IN_CLASSD(name_in->sin_addr.s_addr))
addr_type = IPNET_ADDR_TYPE_MULTICAST;
else
{
/*
* Check for matching unicast address
*/
addr_entry = ipnet_ip4_get_addr_entry(name_in->sin_addr.s_addr, sock->vr_index, IP_NULL);
if (addr_entry == IP_NULL)
{
/*
* Check all network broadcast addresses
*/
Ipnet_netif *netif;
Ip_u32 i;
/*
* 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, sock->vr_index, i)
{
addr_entry = ipnet_ip4_get_addr_entry(name_in->sin_addr.s_addr, sock->vr_index, netif);
if (addr_entry != IP_NULL)
break;
}
}
if (addr_entry != IP_NULL)
addr_type = addr_entry->type;
}
/*
* Not my address.
*/
if (addr_type == IPNET_ADDR_TYPE_NOT_LOCAL)
return -IP_ERRNO_EADDRNOTAVAIL;
#if defined(IPNET_USE_RFC5227) || defined(IPNET_USE_RFC3927)
/* Address still in tentative state, not available */
if ((addr_entry != IP_NULL) && (IP_BIT_ISSET(addr_entry->flags, IPNET_IP4_ADDR_FLAG_TENTATIVE)))
return -IP_ERRNO_EADDRNOTAVAIL;
#endif
if (sock->ipcom.type == IP_SOCK_STREAM
&& addr_type != IPNET_ADDR_TYPE_UNICAST
&& addr_type != IPNET_ADDR_TYPE_ANY)
{
/*
* Can't bind stream socket to broadcast/multicast address.
*/
return -IP_ERRNO_EINVAL;
}
sock->ip4->saddr_n = name_in->sin_addr.s_addr;
#ifndef IPCOM_FORWARDER_NAE
/*
* SCTP can have many addresses, one is not enough, unbind need
* not modify
*/
if ((addr_entry != IP_NULL) && (IP_IPPROTO_SCTP != sock->proto))
{
ip_assert(sock->addr_next == IP_NULL);
ip_assert(sock->addr_prev == IP_NULL);
/*
* Add this socket to list of sockets using the address
*/
sock->addr_next = addr_entry->socket_list;
addr_entry->socket_list = sock;
if (sock->addr_next != IP_NULL)
sock->addr_next->addr_prev = sock;
sock->addr_prev = IP_NULL;
sock->addr_entry = addr_entry;
}
#endif /* !IPCOM_FORWARDER_NAE */
return 0;
}
/*
*===========================================================================
* ipnet_sock_ip4_getname
*===========================================================================
* Description: Returns the local name (or address) of the socket.
* Parameters: sock - The socket to return the name for.
* name - Buffer where the name will be stored.
* namelen - The length of the 'name' buffer.
* is_local_name - Is set to IP_TRUE of the local name of the
* socket should be returned, IP_FALSE means that the peer name
* should be returned.
* Returns: 0 = success, <0 = error code (-IPNET_ERRNO_xxx)
*
*/
IP_STATIC int
ipnet_sock_ip4_getname(struct Ipnet_socket_struct *sock,
struct Ip_sockaddr *name,
Ip_socklen_t *namelen,
Ip_bool is_local_name)
{
struct Ip_sockaddr_in *name_in;
int ret = 0;
if (*namelen < sizeof(struct Ip_sockaddr_in))
return -IP_ERRNO_ENOBUFS;
*namelen = sizeof(struct Ip_sockaddr_in);
name_in = (struct Ip_sockaddr_in *)name;
ipcom_memset(name_in->sin_zero, 0, sizeof(name_in->sin_zero));
IPCOM_SA_LEN_SET(name_in, sizeof(struct Ip_sockaddr_in));
name_in->sin_family = IP_AF_INET;
if (is_local_name)
{
name_in->sin_addr.s_addr = sock->ip4->saddr_n;
name_in->sin_port = ip_htons(sock->sport);
}
else
{
/*
* Copy the address before checking if the socket is
* connected. TCP may internally call this function when not
* connected to get the peer the socket used to be connected
* to.
*/
if (IP_BIT_ISFALSE(sock->flags, IPNET_SOCKET_FLAG_CONNECTED|IPNET_SOCKET_FLAG_CONNECTING))
ret = -IP_ERRNO_ENOTCONN;
name_in->sin_addr.s_addr = sock->ip4->daddr_n;
name_in->sin_port = ip_htons(sock->dport);
}
return ret;
}
/*
*===========================================================================
* ipnet_sock_ip4_mcast_remove_source
*===========================================================================
* Description: Callback to send a report for every source address
* blocked/allowed.
* Parameters: source - The source address to remove.
* md - The multicast address control block.
* Returns:
*/
#ifdef IPNET_USE_SOURCE_SPECIFIC_MCAST
IP_STATIC void
ipnet_sock_ip4_mcast_remove_source(struct Ip_in_addr *source,
Ipnet_ip4_sock_mcast_data *md)
{
(void)ipcom_set_remove(md->sources, source);
ipnet_igmpv3_report_change(md->netif, &md->maddr);
}
#endif /* IPNET_USE_SOURCE_SPECIFIC_MCAST */
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipnet_sock_ip4_get_mcast_data
*===========================================================================
* Description: Returns the pointer to where the multicast data for the
* specified multicast address is stored.
* Parameters: sock - The controlling socket for the multicast address.
* netif - The interface the multicast address will be assigned to.
* maddr - An multicast address.
* Returns: Always != IP_NULL, but the storage might hold IP_NULL which
* means that there was not match.
*/
IP_GLOBAL Ipnet_ip4_sock_mcast_data **
ipnet_sock_ip4_get_mcast_data(Ipnet_socket *sock,
Ipnet_netif *netif,
IP_CONST struct Ip_in_addr *maddr)
{
Ipnet_ip4_sock_mcast_data **mlt_it;
/* Try to find the multicast address in the socket multicast address list */
for (mlt_it = &sock->ip4->multicast_addr_list;
*mlt_it != IP_NULL;
mlt_it = &(*mlt_it)->next)
{
if (maddr->s_addr == (*mlt_it)->maddr.s_addr
&& netif == (*mlt_it)->netif)
break;
}
return mlt_it;
}
/*
*===========================================================================
* ipnet_sock_ip4_mcast_delete_data
*===========================================================================
* Description: Deletes a multicast data block for a specific address.
* Parameters: sock - The controlling socket for the multicast address.
* netif - The interface the multicast address will removed from.
* maddr - An multicast address.
* Returns: >=0 = success, <0 = error code.
*
*/
IP_GLOBAL int
ipnet_sock_ip4_mcast_delete_data(Ipnet_socket *sock,
Ipnet_netif *netif,
struct Ip_in_addr *maddr)
{
Ipnet_ip4_sock_mcast_data *mcast_data;
Ipnet_ip4_sock_mcast_data **pmcd;
#ifdef IPNET_USE_SOURCE_SPECIFIC_MCAST
Ipnet_ip4_addr_entry *addr_entry;
int filter_mode;
#endif
pmcd = ipnet_sock_ip4_get_mcast_data(sock, netif, maddr);
mcast_data = *pmcd;
if (mcast_data == IP_NULL)
/* This address has not been joined */
return -IP_ERRNO_EADDRNOTAVAIL;
#ifdef IPNET_USE_SOURCE_SPECIFIC_MCAST
/* Send IGMPv3 report if the interface filter changes */
ipcom_set_for_each(mcast_data->sources,
(Ipcom_set_foreach_cb_func) ipnet_sock_ip4_mcast_remove_source,
mcast_data);
filter_mode = mcast_data->sources->user;
ipcom_set_delete(mcast_data->sources);
addr_entry = ipnet_ip4_get_addr_entry(maddr->s_addr, sock->vr_index, netif);
if (addr_entry != IP_NULL)
(void)ipcom_set_remove(addr_entry->mcast.sockets, &sock);
/* else: This socket does not control this multicast address */
if (filter_mode == IPCOM_SET_IS_EXCLUDE)
ipnet_igmpv3_report_change(mcast_data->netif, &mcast_data->maddr);
#endif /* IPNET_USE_SOURCE_SPECIFIC_MCAST */
/* Unhook 'mcast_data' from the list */
*pmcd = mcast_data->next;
ipcom_free(mcast_data);
return ipnet_ip4_remove_addr(netif, maddr->s_addr);
}
/*
*===========================================================================
* ipnet_sock_ip4_lookup
*===========================================================================
* Description: Returns the IPv4 socket matching the parameters.
* Parameters: vr - The virtual router the socket must be bound to.
* proto - The protocol the returned socket should be using.
* local_addr_ptr - The IPv4 address in network order of the
* local address to match or IP_NULL if any address should match.
* local_port - The source port in HOST byte order or 0 if any
* source port should match.
* peer_addr_n - The IPv4 address in network order of the
* peer address to match or IP_NULL if any address should match.
* peer_port - The destination port in HOST byte order or 0 if any
* destination port should match.
* pfirst - [in] the socket descriptor to from where the scan should start
* [out] the socket descriptor to start the next search from.
* set to IP_NULL to start from 0.
* Returns: A pointer to the matching socket or IP_NULL if no socket match.
*
*/
IP_GLOBAL Ipnet_socket *
ipnet_sock_ip4_lookup(Ip_u16 vr, int proto,
IP_CONST Ip_u32 *local_addr_ptr, Ip_u16 local_port,
IP_CONST Ip_u32 *peer_addr_ptr, Ip_u16 peer_port)
{
Ipnet_socket *sock;
Ipnet_socket_lookup_key key;
key.domain = IP_AF_INET;
key.proto = (Ip_u16) proto;
key.vr = vr;
key.local_port = local_port;
key.peer_port = peer_port;
if (local_addr_ptr)
key.local_addr.in.s_addr = IP_GET_32ON16(local_addr_ptr);
else
key.local_addr.in.s_addr = 0;
if (peer_addr_ptr)
key.peer_addr.in.s_addr = IP_GET_32ON16(peer_addr_ptr);
else
key.peer_addr.in.s_addr = 0;
sock = ipnet_sock_get(&key, IP_NULL);
if (sock == IP_NULL)
{
key.peer_port = 0;
key.peer_addr.in.s_addr = 0;
sock = ipnet_sock_get(&key, IP_NULL);
if (sock == IP_NULL)
{
Ip_u32 local_addr = key.local_addr.in.s_addr;
key.local_addr.in.s_addr = 0;
sock = ipnet_sock_get(&key, IP_NULL);
/* If MCP is enabled, all multicast packets will be received. */
if (ipmcp_is_enabled == IP_TRUE)
return sock;
/* For multicast address the socket which has joined the related group could receive the data. */
if (IP_IN_CLASSD(local_addr) && local_addr != ip_htonl(0xe0000001))
{
while(sock != IP_NULL && sock->ipcom.type == IP_SOCK_DGRAM)
{
Ipnet_ip4_sock_mcast_data *mc_addr = sock->ip4->multicast_addr_list;
while (mc_addr != IP_NULL)
{
if (mc_addr->maddr.s_addr == local_addr)
return sock;
mc_addr = mc_addr->next;
}
/* search for next socket */
if (mc_addr == IP_NULL)
sock = ipnet_sock_next(sock);
}
}
}
}
#ifdef IPCOM_USE_INET6
if (sock == IP_NULL)
{
struct Ip_in6_addr local_in6;
struct Ip_in6_addr peer_in6;
if (local_addr_ptr)
key.local_addr.in.s_addr = IP_GET_32ON16(local_addr_ptr);
if (peer_addr_ptr)
key.peer_addr.in.s_addr = IP_GET_32ON16(peer_addr_ptr);
ipnet_ip6_create_mapped_addr(&key.local_addr.in, &local_in6);
ipnet_ip6_create_mapped_addr(&key.peer_addr.in, &peer_in6);
sock = ipnet_sock_ip6_lookup(vr, proto,
&local_in6, local_port,
&peer_in6, peer_port);
if (sock == IP_NULL || IP_BIT_ISSET(sock->ip6->flags, IPNET_SOCKET_FLAG_IP6_V6ONLY))
return IP_NULL;
}
#endif /* IPCOM_USE_INET6 */
return sock;
}
/*
*===========================================================================
* ipnet_sock_ip4_get_ops
*===========================================================================
* Description: Sets all members that are valid for IPv4.
* Parameters: ops - Socket operation structure.
* Returns:
*
*/
IP_GLOBAL void
ipnet_sock_ip4_get_ops(Ipnet_sock_inet_ops *ops)
{
ipnet_usr_sock_get_ops(&ops->sock);
ops->sock.domain = IP_AF_INET;
#ifdef IPIPSEC2
ops->sock.hdr_space = IPNET_IP_HDR_SIZE + IPIPSEC_IPSEC_HDR_MAX_SIZE;
#else
ops->sock.hdr_space = IPNET_IP_HDR_SIZE;
#endif
ops->sock.extra_sock_space = sizeof(Ipnet_ip4_socket);
ops->sock.init = ipnet_sock_ip4_init;
ops->sock.destroy = ipnet_sock_ip4_destroy;
ops->sock.bind = ipnet_sock_bind;
ops->sock.connect = ipnet_sock_ip4_connect;
ops->sock.lookup = (Ipnet_sock_lookup_f) ipnet_sock_ip4_lookup;
ops->sock.send = ipnet_ip4_sendto;
ops->sock.getname = ipnet_sock_ip4_getname;
ops->network_bind = ipnet_sock_ip4_bind;
ops->network_send = ipnet_ip4_sendto;
}
/*
*===========================================================================
* ipnet_sock_ip4_register
*===========================================================================
* Description: Registers the IP_SOCK_RAW type for the IP_AF_INET domain.
* Parameters:
* Returns: 0 = success, <0 = error code.
*
*/
IP_GLOBAL int
ipnet_sock_ip4_register(void)
{
Ipnet_sock_inet_ops *ops;
ops = ipcom_calloc(1, sizeof(*ops));
if (ops == IP_NULL)
{
IPCOM_LOG0(CRIT, "Could not register the IP_SOCK_RAW in IP_AF_INET domain, out of memory");
IP_PANIC();
return -IP_ERRNO_ENOMEM;
}
ipnet_sock_ip4_get_ops(ops);
ops->sock.type = IP_SOCK_RAW;
ops->sock.proto = -1;
ops->sock.connect = ipnet_sock_ip4_raw_connect;
ops->sock.send = ipnet_sock_ip4_raw_sendto;
ops->sock.extra_sock_space += sizeof(struct Ip_icmp_filter);
return ipnet_sock_register_ops(&ops->sock);
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
#endif /* IPCOM_USE_INET */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/