955 lines
28 KiB
C
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 = ≪
|
|
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
|
|
****************************************************************************
|
|
*/
|