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

955 lines
28 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip_inet.c,v $ $Revision: 1.11.10.3 $
* $Source: /home/interpeak/CVSRoot/ipmip/src/ipmip_inet.c,v $
* $Author: jsheng $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip_inet.c,v $ $Revision: 1.11.10.3 $
* $Source: /home/interpeak/CVSRoot/ipmip/src/ipmip_inet.c,v $
* $Author: jsheng $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipmip_config.h"
#ifdef IPMIP_USE_INET
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_clib2.h>
#include <ipcom_err.h>
#include <ipcom_inet.h>
#include <ipcom_ipd.h>
#include <ipcom_list.h>
#include <ipcom_hash.h>
#include <ipcom_os.h>
#include <ipcom_sock.h>
#include <ipcom_sock.h>
#include <ipcom_sock2.h>
#include <ipcom_sysctl.h>
#include <ipcom_syslog.h>
#include <ipcom_sysvar.h>
#include <ipcom_cmd.h>
#include <ipcom_getopt.h>
#include <ipcom_netif.h>
#include <ipmip.h>
#include <private/ipmip_buffer.h>
#include <private/ipmip_context.h>
#include <private/ipmip_pktbuf.h>
#include <private/ipmip_cli.h>
#include <private/ipmip_util.h>
#include <private/ipmip_sysvar.h>
#include <private/ipmip_inet.h>
#include <private/ipmip_lladdr.h>
#include <private/ipmip_netlink.h>
#include <private/ipmip_if.h>
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
#define IPMIP_INET_PKT_CLEN 128
#define IPCOM_SYSLOG_PRIORITY IPCOM_LOG_DEBUG2
#define IPCOM_SYSLOG_FACILITY IPCOM_LOG_IPMIP
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
static Ip_u16 ipmip_pkt_ipid = 1;
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
IP_STATIC unsigned
ipmip_inet_arp_key_ifindex(Ip_u32 *ifindex)
{
return ipcom_hash_update(ifindex, sizeof(*ifindex), 0);
}
IP_STATIC unsigned
ipmip_inet_arp_obj_ifindex(Ipmip_arp_node_t *node)
{
return ipmip_inet_arp_key_ifindex(&node->ifindex);
}
IP_STATIC Ip_bool
ipmip_inet_arp_cmp_ifindex(Ipmip_arp_node_t *node, Ip_u32 *ifindex)
{
/* Compare */
return node->ifindex == *ifindex;
}
IP_STATIC void
ipmip_inet_arp_context_create(struct Ipmip_context *ctx,
struct Ipmip_proc *proc)
{
IPMIP_UNUSED_PARAMETER(proc);
if (ctx->arp != IP_NULL)
return;
ctx->arp = ipcom_calloc(1, sizeof(*ctx->arp));
if(IP_NULL == ctx->arp)
{
return;
}
ctx->arp->fd_arp_in = IP_INVALID_SOCKET;
ctx->arp->fd_arp_out = IP_INVALID_SOCKET;
(void)ipcom_mutex_create(&ctx->arp->mutex);
ctx->arp->ifindex_table = ipcom_hash_new((Ipcom_hash_obj_func) ipmip_inet_arp_obj_ifindex,
(Ipcom_hash_key_func) ipmip_inet_arp_key_ifindex,
(Ipcom_hash_cmp_func) ipmip_inet_arp_cmp_ifindex);
}
IP_STATIC Ipmip_pktbuf_t *
ipmip_inet_arp_recvmsg(Ipmip_context_t *ctx,
Ipmip_proc_t *proc,
Ip_size_t vlen,
Ip_fd fd)
{
int len;
struct Ip_sockaddr_ll ll;
struct Ip_msghdr msg;
struct Ip_iovec vec;
/* Set when the option is located */
Ipmip_pktbuf_t *pbuf = IP_NULL;
/* Allocate pktbuf */
pbuf = (Ipmip_pktbuf_t *)ipmip_pktbuf_alloc(ctx, proc, vlen);
/* Failed to allocate buffer? */
if (pbuf == IP_NULL)
return IP_NULL;
/* Initialize vector */
vec.iov_base = IPMIP_BUFFER_DATA(&pbuf->packet);
vec.iov_len = vlen;
/* Initialize name */
msg.msg_name = &ll;
msg.msg_namelen = sizeof(ll);
/* Initialize io */
msg.msg_iov = &vec;
msg.msg_iovlen = 1;
/* Initialize control */
msg.msg_control = IP_NULL;
msg.msg_controllen = 0;
/* Clear flags */
msg.msg_flags = 0;
/* Read and process a Mobile Header message */
if ((len = ipcom_recvmsg(fd, &msg, 0)) < 0)
{
/* Failure */
IPCOM_LOG2(ERR,
"%s: Failed to receive from ARP socket = %x",
ctx->name, ipcom_errno);
ipmip_util_sock_clear(fd);
goto error_out;
}
/* Sanity, must be atleast the mobility header */
if ((Ip_size_t)len < sizeof(Ipmip_arp_hdr_t))
{
/* Failure */
IPCOM_LOG1(INFO,
"%s: ARP Received packet was too short", ctx->name);
goto error_out;
}
/* We've gotten something */
if ((msg.msg_flags & (IP_MSG_TRUNC | IP_MSG_CTRUNC)) != 0)
{
/* Failure */
IPCOM_LOG1(INFO,
"%s: ARP TRUNC or CTRUNC set, not all data read. Discarding",
ctx->name);
goto error_out;
}
/* Store value */
ipmip_util_dup(&pbuf->srcinfo.ll, &ll, sizeof(ll));
/**/
pbuf->srcinfo.lladdr = ipmip_lladdr_ll_to_lladdr(pbuf->srcinfo.ll);
/* Move past the read length */
ipmip_buffer_append(&pbuf->packet, IP_NULL, len);
/* */
return pbuf;
error_out:
ipmip_pktbuf_release(ctx, proc, pbuf);
return IP_NULL;
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
IP_GLOBAL void
ipmip_inet_arp_write(Ipmip_context_t *ctx,
Ipmip_proc_t *proc,
Ip_u32 from,
Ip_u32 to,
Ipmip_if_t *iff,
Ipmip_lladdr_t *lladdr)
{
IPMIP_UNUSED_PARAMETER(proc);
/* Only do MAC */
if (lladdr->type == IPMIP_LLADDR_TYPE_MAC && iff->lladdr != IP_NULL && iff->lladdr->type == lladdr->type)
{
struct Ip_iovec iov;
struct Ip_msghdr m;
Ipmip_arp_hdr_t arp;
struct Ip_sockaddr_ll to_ll;
ipcom_memset(&m, 0, sizeof(m));
/* Set the base values */
arp.hrd = IPMIP_ARP_HRD_ETHER;
arp.pro = IPMIP_ARP_PRO_IP;
arp.hln_pln = IPMIP_ARP_HLN_PLN;
arp.op = IPMIP_ARP_OP_REPLY;
/* Setup the structures */
ipcom_memcpy(arp.eth_src, iff->lladdr->lla, IPMIP_ETH_ADDR_SIZE);
ipcom_memcpy(arp.eth_dst, lladdr->lla, IPMIP_ETH_ADDR_SIZE);
IP_SET_32ON8(arp.ip_src, from);
IP_SET_32ON8(arp.ip_dst, to);
IPCOM_SA_LEN_SET(&to_ll, sizeof(to_ll));
to_ll.sll_family = IP_AF_PACKET;
to_ll.sll_protocol = ip_htons(IPMIP_ETH_P_ARP);
to_ll.sll_ifindex = iff->ifindex;
to_ll.sll_halen = IPMIP_ETH_ADDR_SIZE;
ipcom_memcpy(to_ll.sll_addr, lladdr->lla, IPMIP_ETH_ADDR_SIZE);
iov.iov_base = &arp;
iov.iov_len = sizeof(arp);
m.msg_iov = &iov;
m.msg_iovlen = 1;
m.msg_name = &to_ll;
m.msg_namelen = sizeof(to_ll);
/* */
if (ipcom_sendmsg(ctx->arp->fd_arp_out, &m, 0) < 0)
ipmip_util_sock_clear(ctx->arp->fd_arp_out);
}
}
IP_GLOBAL void
ipmip_inet_arp_reply(Ipmip_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip_arp_hdr_t *arp_req,
Ipmip_if_t *iff)
{
IPMIP_UNUSED_PARAMETER(proc);
/* Only do MAC */
if (iff->lladdr != IP_NULL && iff->lladdr->type == IPMIP_LLADDR_TYPE_MAC)
{
Ipmip_lladdr_t *lla = ipmip_lladdr_build((Ipmip_lladdr_t *)proc->ntop.ntop_pbuf, iff->lladdr->type, iff->lladdr->type, &arp_req->eth_src[0], IPMIP_ETH_ADDR_SIZE);
ipmip_inet_arp_write(ctx, proc, IP_GET_32ON8(&arp_req->ip_dst), IP_GET_32ON8(&arp_req->ip_src), iff, lla);
}
}
IP_GLOBAL Ipmip_pktbuf_t *
ipmip_inet_udp_recvmsg(Ipmip_context_t *ctx,
Ipmip_proc_t *proc,
Ip_size_t vlen,
Ip_fd fd)
{
struct Ip_cmsghdr *cmsghdr;
int len;
/* Destination Option & Packet Info */
struct Ip_msghdr msg;
struct Ip_iovec vec;
Ipmip_pktbuf_t *pbuf = IP_NULL;
struct Ip_sockaddr_in src;
/* Allocate pktbuf */
pbuf = (Ipmip_pktbuf_t *)ipmip_pktbuf_alloc(ctx, proc, vlen + IPMIP_INET_PKT_CLEN);
/* Failed to allocate buffer? */
if (pbuf == IP_NULL)
return IP_NULL;
/* Initialize vector */
vec.iov_base = IPMIP_BUFFER_DATA(&pbuf->packet);
vec.iov_len = vlen;
/* Initialize name */
msg.msg_name = &src;
msg.msg_namelen = sizeof(src);
/* Initialize io */
msg.msg_iov = &vec;
msg.msg_iovlen = 1;
/* Initialize control */
msg.msg_control = ipmip_buffer_offset(&pbuf->packet, vlen);
msg.msg_controllen = IPMIP_INET_PKT_CLEN;
/* Clear flags */
msg.msg_flags = 0;
/* Read and process a Mobile Header message */
if ((len = ipcom_recvmsg(fd, &msg, 0)) <= 0)
{
ipmip_util_sock_clear(fd);
goto error_out;
}
/* We've gotten something */
if ((msg.msg_flags & (IP_MSG_TRUNC | IP_MSG_CTRUNC)) != 0)
goto error_out;
/* Store value */
ipmip_util_dup(&pbuf->srcinfo.src, &src, sizeof(src));
/* Move past the read length */
ipmip_buffer_append(&pbuf->packet, IP_NULL, len);
/* Did we get any ancillary data? */
if (msg.msg_controllen > 0)
{
/* Loop the ancillary data, see what we find */
for (cmsghdr = IP_CMSG_FIRSTHDR(&msg); cmsghdr != 0; cmsghdr = IP_CMSG_NXTHDR(&msg, cmsghdr))
{
/* Correct level? */
if (cmsghdr->cmsg_level == IP_IPPROTO_IP)
{
/* Type? */
switch (cmsghdr->cmsg_type)
{
case IP_IP_X_SENDERLINKADDR:
{
struct Ip_sockaddr_dl *dl = IP_CMSG_DATA(cmsghdr);
ipmip_util_dup(&pbuf->srcinfo.dl, dl, IPCOM_SA_LEN_GET(dl));
}
break;
case IP_IP_PKTINFO:
{
struct Ip_in_pktinfo *pktinfo = IP_CMSG_DATA(cmsghdr);
ipmip_pktbuf_srcinfo_dst_inet(pbuf, pktinfo);
}
break;
case IP_IP_TTL:
{
int *ttl = IP_CMSG_DATA(cmsghdr);
pbuf->srcinfo.ttl = IP_GET_32ON8(ttl);
}
break;
default:
break;
}
}
}
}
if (pbuf->srcinfo.dst == IP_NULL)
goto error_out;
pbuf->srcinfo.lladdr = ipmip_lladdr_dl_to_lladdr(pbuf->srcinfo.dl, pbuf->srcinfo.dst->ifindex);
return pbuf;
error_out:
ipmip_pktbuf_release(ctx, proc, pbuf);
return IP_NULL;
}
/*
*===========================================================================
* ipmip4_pkt_udp_write
*===========================================================================
* Description: Send a UDP message to a link local host with the
* indicated MAC address.
* Parameters: ctx - The context
* proc - Process context
* payload - The payload buffer
* from - The source address
* from_port - The source port in netwrok byte order
* to - The destination address
* to_port - The destination port in network byte order
* iff - Outgoing interface
* lla - MAC address
* Returns: The resulting return code.
*
*/
IP_GLOBAL int
ipmip_inet_udp_write(Ipmip_context_t *ctx,
Ipmip_proc_t *proc,
Ip_fd fd_pkt,
Ip_fd fd_raw,
Ipmip_buffer_t *payload,
Ip_u32 from,
Ip_u16 from_port,
Ip_u32 to,
Ip_u16 to_port,
Ipmip_if_t *iff,
Ipmip_lladdr_t *lladdr)
{
int ret = -IP_ERRNO_EINVAL;
Ip_u32 chk;
Ip_size_t tot_size = 0;
struct Ip_iovec iov[3];
Ipcom_ip_header iph;
Ipcom_udp_header udph;
struct Ip_msghdr m;
IPMIP_UNUSED_PARAMETER(proc);
/* */
if (fd_raw != IP_INVALID_SOCKET)
{
if (lladdr == IP_NULL || fd_pkt == IP_INVALID_SOCKET || lladdr->type != IPMIP_LLADDR_TYPE_MAC)
return ipmip_inet_udp_sendmsg(ctx, proc, fd_raw, payload, from, from_port, to, to_port, iff);
}
else if (lladdr == IP_NULL)
return -IP_ERRNO_EINVAL;
chk = 0;
/* Create the IO vector */
iov[0].iov_base = &iph;
iov[0].iov_len = sizeof(iph);
iov[1].iov_base = &udph;
iov[1].iov_len = sizeof(udph);
iov[2].iov_base = IPMIP_BUFFER_DATA(payload);
iov[2].iov_len = IPMIP_BUFFER_SIZE(payload);
/* Start with the payload as total size */
tot_size = IPMIP_BUFFER_SIZE(payload);
/* Zero the memory */
ipcom_memset(&iph, 0, sizeof(iph));
ipcom_memset(&udph, 0, sizeof(udph));
ipcom_memset(&m, 0, sizeof(m));
/* Include the UDP header */
tot_size += sizeof(udph);
if (to == 0)
/* Send to world wide broadcast */
to = IP_INADDR_BROADCAST;
/* Create the UDP packet */
udph.src_port = from_port;
udph.dst_port = to_port;
udph.length = ip_htons((Ip_u16) tot_size);
/* IPv4 header */
tot_size += sizeof(iph);
iph.vers_len = 0x45;
iph.id = ip_htons(ipmip_pkt_ipid);
iph.ttl = 255;
iph.protocol = IP_IPPROTO_UDP;
iph.src.addr32 = from;
iph.dst.addr32 = to;
ipmip_pkt_ipid++;
/* UDP checksum (including pseudo-header) */
chk = ((Ip_u16 *) &iph.src)[0];
chk += ((Ip_u16 *) &iph.src)[1];
chk += ((Ip_u16 *) &iph.dst)[0];
chk += ((Ip_u16 *) &iph.dst)[1];
chk += udph.length;
{
Ip_u16 tmp = iph.protocol;
chk += ip_htons(tmp);
}
chk += ipcom_in_checksum_update(&udph, sizeof(udph));
/* Do the checksum calculation */
chk += ipcom_in_checksum_update(iov[2].iov_base,
iov[2].iov_len);
udph.checksum = ipcom_in_checksum_finish(chk);
m.msg_iov = iov;
m.msg_iovlen = 3;
/* Is it a local packet or routed packet? */
iph.length = ip_htons(((Ip_u16)tot_size));
/* Local; build IP & UDP header */
chk = ipcom_in_checksum_update(&iph, sizeof(iph));
iph.checksum = ipcom_in_checksum_finish(chk);
/**/
if (fd_pkt != IP_INVALID_SOCKET)
{
/* Only deal with MAC's right now */
if (lladdr->type == IPMIP_LLADDR_TYPE_MAC)
{
struct Ip_sockaddr_ll to_ll;
IPCOM_SA_LEN_SET(&to_ll, sizeof(to_ll));
to_ll.sll_family = IP_AF_PACKET;
to_ll.sll_protocol = ip_htons(0x800);
to_ll.sll_ifindex = iff->ifindex;
to_ll.sll_halen = 6;
ipcom_memcpy(to_ll.sll_addr, lladdr->lla, IPMIP_ETH_ADDR_SIZE);
m.msg_name = &to_ll;
m.msg_namelen = sizeof(to_ll);
if ((ipcom_sendmsg(fd_pkt, &m, 0)) < 0)
{
ret = -ipcom_errno;
ipmip_util_sock_clear(fd_pkt);
}
else
{
ret = IPCOM_SUCCESS;
}
goto done_out;
}
}
/**/
done_out:
return ret;
}
IP_GLOBAL Ip_fd
ipmip_inet_udp_socket(struct Ip_sockaddr_in *s_in)
{
Ip_fd s;
int i = 1;
Ip_socklen_t slen;
/* Create raw IP socket for all IPv4 input on this interface */
if ((s = ipcom_socket(IP_AF_INET, IP_SOCK_DGRAM, IP_IPPROTO_UDP)) == IP_INVALID_SOCKET)
return IP_INVALID_SOCKET;
/* Allow reusage of address */
if (ipcom_setsockopt(s, IP_SOL_SOCKET, IP_SO_REUSEADDR, &i, sizeof(i)))
goto fail;
/* Allow reusage of ports */
if (ipcom_setsockopt(s, IP_SOL_SOCKET, IP_SO_REUSEPORT, &i, sizeof(i)))
goto fail;
/* I want to receive PACKET INFO as ancillary data */
if (ipcom_setsockopt(s, IP_IPPROTO_IP, IP_IP_PKTINFO, &i, sizeof(i)) < 0)
goto fail;
if (ipcom_setsockopt(s, IP_IPPROTO_IP, IP_IP_RECVTTL, &i, sizeof(i)))
goto fail;
/* Enable IP_X_SENDERLINKADDR to get source link address */
if (ipcom_setsockopt(s, IP_IPPROTO_IP, IP_IP_X_SENDERLINKADDR, &i, sizeof(i)) < 0)
goto fail;
if (s_in != IP_NULL)
{
/* */
if (ipcom_bind(s, (struct Ip_sockaddr *) s_in, sizeof(*s_in)) < 0)
goto fail;
slen = sizeof(*s_in);
if (ipcom_getsockname(s, (struct Ip_sockaddr *) s_in, &slen) < 0)
goto fail;
}
return s;
fail:
ipcom_socketclose(s);
return IP_INVALID_SOCKET;
}
/*
*===========================================================================
* ipmip_inet_udp_sendmsg
*===========================================================================
* Description: Send a UDP message to a remote host
* Parameters: ctx - The context
* proc - Process context
* payload - The payload buffer
* from - The source address
* from_port - The source port in network byte order
* to - The destination address
* to_port - The destination port in network byte order
* iff - If set; the interface to force the output on.
* Returns: The resulting return code.
*
*/
IP_GLOBAL int
ipmip_inet_udp_sendmsg(Ipmip_context_t *ctx,
Ipmip_proc_t *proc,
Ip_fd fd_raw,
Ipmip_buffer_t *payload,
Ip_u32 from,
Ip_u16 from_port,
Ip_u32 to,
Ip_u16 to_port,
Ipmip_if_t *iff)
{
int ret = IPCOM_SUCCESS;
Ip_u32 chk;
Ip_size_t tot_size = 0;
struct Ip_iovec iov[3];
Ipcom_ip_header iph;
Ipcom_udp_header udph;
struct Ip_msghdr m;
Ip_u8 cmsg_buf[IP_CMSG_SPACE(sizeof(struct Ip_in_pktinfo))];
struct Ip_cmsghdr *c;
struct Ip_in_pktinfo *pktinfo;
struct Ip_sockaddr_in sin4;
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
chk = 0;
/* Create the IO vector */
iov[0].iov_base = &iph;
iov[0].iov_len = sizeof(iph);
iov[1].iov_base = &udph;
iov[1].iov_len = sizeof(udph);
iov[2].iov_base = IPMIP_BUFFER_DATA(payload);
iov[2].iov_len = IPMIP_BUFFER_SIZE(payload);
/* Start with the payload as total size */
tot_size = IPMIP_BUFFER_SIZE(payload);
/* Zero the memory */
ipcom_memset(&iph, 0, sizeof(iph));
ipcom_memset(&udph, 0, sizeof(udph));
ipcom_memset(&m, 0, sizeof(m));
/* Include the UDP header */
tot_size += sizeof(udph);
if (to == 0)
to = IP_INADDR_BROADCAST;
/* Create the UDP packet */
udph.src_port = from_port;
udph.dst_port = to_port;
udph.length = ip_htons((Ip_u16) tot_size);
/* IPv4 header */
tot_size += sizeof(iph);
iph.vers_len = 0x45;
iph.id = ip_htons(ipmip_pkt_ipid);
iph.ttl = 255;
iph.protocol = IP_IPPROTO_UDP;
iph.src.addr32 = from;
iph.dst.addr32 = to;
ipcom_memset(&sin4, 0, sizeof(sin4));
sin4.sin_family = IP_AF_INET;
IPCOM_SA_LEN_SET(&sin4, sizeof(sin4));
sin4.sin_port = to_port;
sin4.sin_addr.s_addr = to;
ipmip_pkt_ipid++;
/* UDP checksum (including pseudo-header) */
chk = ((Ip_u16 *) &iph.src)[0];
chk += ((Ip_u16 *) &iph.src)[1];
chk += ((Ip_u16 *) &iph.dst)[0];
chk += ((Ip_u16 *) &iph.dst)[1];
chk += udph.length;
{
Ip_u16 tmp = iph.protocol;
chk += ip_htons(tmp);
}
chk += ipcom_in_checksum_update(&udph, sizeof(udph));
/* Do the checksum calculation */
chk += ipcom_in_checksum_update(iov[2].iov_base,
iov[2].iov_len);
udph.checksum = ipcom_in_checksum_finish(chk);
m.msg_iov = iov;
m.msg_iovlen = 3;
/* Is it a local packet or routed packet? */
iph.length = (Ip_u16) tot_size;
m.msg_name = &sin4;
m.msg_namelen = sizeof(sin4);
/* Force it out the indicated interface */
if (iff != IP_NULL)
{
/* Use ancillary data to specify outgoing interface and address. */
c = (struct Ip_cmsghdr *) cmsg_buf;
c->cmsg_len = IP_CMSG_LEN(sizeof(struct Ip_in_pktinfo));
c->cmsg_level = IP_IPPROTO_IP;
c->cmsg_type = IP_IP_PKTINFO;
pktinfo = IP_CMSG_DATA(c);
ipcom_memset(pktinfo, 0, sizeof(*pktinfo));
/* Bind to the correct interface */
pktinfo->ipi_ifindex = iff->ifindex;
m.msg_control = c;
m.msg_controllen = sizeof(cmsg_buf);
}
/* Do send */
if (ipcom_sendmsg(fd_raw, &m, 0) <0)
{
ret = -ipcom_errno;
ipmip_util_sock_clear(fd_raw);
}
/**/
return ret;
}
IP_GLOBAL void
ipmip_inet_arp_context_in_create(struct Ipmip_context *ctx,
struct Ipmip_proc *proc)
{
ipmip_inet_arp_context_create(ctx, proc);
if (ctx->arp->fd_arp_in == IP_INVALID_SOCKET)
{
ctx->arp->fd_arp_in = ipcom_socket(IP_AF_PACKET, IP_SOCK_DGRAM, ip_htons(0x0806));
ipcom_shutdown(ctx->arp->fd_arp_in, IP_SHUT_WR);
}
}
IP_GLOBAL void
ipmip_inet_arp_context_out_create(struct Ipmip_context *ctx,
struct Ipmip_proc *proc)
{
ipmip_inet_arp_context_create(ctx, proc);
if (ctx->arp->fd_arp_out == IP_INVALID_SOCKET)
{
ctx->arp->fd_arp_out = ipcom_socket(IP_AF_PACKET, IP_SOCK_DGRAM, ip_htons(0x0806));
ipcom_shutdown(ctx->arp->fd_arp_out, IP_SHUT_RD);
}
}
IP_GLOBAL void
ipmip_inet_arp_context_destroy(struct Ipmip_context *ctx,
struct Ipmip_proc *proc)
{
IPMIP_UNUSED_PARAMETER(proc);
if (ctx->arp != IP_NULL)
{
if (ctx->arp->fd_arp_in != IP_INVALID_SOCKET)
ipcom_socketclose(ctx->arp->fd_arp_in);
if (ctx->arp->fd_arp_out != IP_INVALID_SOCKET)
ipcom_socketclose(ctx->arp->fd_arp_out);
if (ctx->arp->ifindex_table)
ipcom_hash_delete(ctx->arp->ifindex_table);
ipcom_mutex_delete(&ctx->arp->mutex);
ipcom_free(ctx->arp);
ctx->arp = IP_NULL;
}
}
IP_GLOBAL void
ipmip_inet_arp_process(struct Ipmip_context *ctx,
struct Ipmip_proc *proc)
{
Ipmip_pktbuf_t *pbuf = ipmip_inet_arp_recvmsg(ctx, proc, 1024, ctx->arp->fd_arp_in);
/* Invoke callback */
if (pbuf)
{
Ipmip_arp_node_t *node = IP_NULL;
ipcom_mutex_lock(ctx->arp->mutex);
node = ipcom_hash_get(ctx->arp->ifindex_table, &pbuf->srcinfo.ll->sll_ifindex);
/* Time to invoke function */
if (node != IP_NULL)
ipmip_timer_request(ctx, proc, &pbuf->timeout, node->lock, node->process_func, node, pbuf, 0);
else
ipmip_pktbuf_release(ctx, proc, pbuf);
ipcom_mutex_unlock(ctx->arp->mutex);
}
}
IP_GLOBAL void
ipmip_inet_arp_register(struct Ipmip_context *ctx,
struct Ipmip_proc *proc,
Ipmip_arp_node_t *node)
{
IPMIP_UNUSED_PARAMETER(proc);
/* We're going to relay */
ipcom_mutex_lock(ctx->arp->mutex);
if (node->ifindex)
ipcom_hash_add(ctx->arp->ifindex_table, node);
ipcom_mutex_unlock(ctx->arp->mutex);
}
IP_GLOBAL void
ipmip_inet_arp_unregister(struct Ipmip_context *ctx,
struct Ipmip_proc *proc,
Ipmip_arp_node_t *node)
{
IPMIP_UNUSED_PARAMETER(proc);
/* We're going to relay */
ipcom_mutex_lock(ctx->arp->mutex);
if (node->ifindex)
ipcom_hash_remove(ctx->arp->ifindex_table, node);
ipcom_mutex_unlock(ctx->arp->mutex);
}
/*
*===========================================================================
* ipmip_inet_arp_proxy
*===========================================================================
* Description: This is run when initiating proxying for an address
* Sets(/deletes) a static, permanent, public and blackholed arp entry,
* plus sends out a gratuitous arp.
* Parameters:
* Returns: IP_TRUE on success.
*
*/
IP_GLOBAL Ip_bool
ipmip_inet_arp_proxy(Ipmip_context_t *ctx,
Ipmip_proc_t *proc,
Ip_u32 ifindex,
Ip_u32 address,
Ip_bool set)
{
return ipmip_netlink_inX_neigh(ctx, proc, IP_AF_INET, set? IP_RTM_NEWNEIGH : IP_RTM_DELNEIGH, IP_NLM_F_CREATE, ifindex, IP_NTF_PROXY|IP_NTF_GRAT, IP_NUD_PERMANENT|IP_NUD_REACHABLE, &address, IP_NULL) == 0;
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
#else
int ipmip_inet_empty_file = 0;
#endif
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/