original files of m241
This commit is contained in:
@@ -0,0 +1,631 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
* INTERPEAK SOURCE FILE
|
||||
*
|
||||
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_gre.c,v $ $Revision: 1.23.54.3 $
|
||||
* $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_gre.c,v $
|
||||
* $Author: hxie $
|
||||
* $State: Exp $ $Locker: $
|
||||
*
|
||||
* INTERPEAK_COPYRIGHT_STRING
|
||||
* Design and implementation by Lennart Bang <lob@interpeak.se>
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 1 DESCRIPTION
|
||||
****************************************************************************
|
||||
* GRE Tunneling Interface based on the following RFC:
|
||||
* ==========================================================
|
||||
* RFC 2784 - Generic Routing Encapsulation (GRE).
|
||||
* RFC 2890 - Key and Sequence Number Extensions to GRE
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* IPNET (10.1.2.100/16):
|
||||
* > tunnel add gre0 -mode gre -local 10.1.2.100 -remote 10.1.2.64 -ttl 64 -ocsum
|
||||
* > ifconfig gre0 inet add 14.0.0.100
|
||||
* > ifconfig gre0 up
|
||||
* > route add -net -netmask 255.0.0.0 14.0.0.0 gre0
|
||||
*
|
||||
* LINUX (10.1.2.64/16):
|
||||
* > ip tunnel add gre1 mode gre remote 10.1.2.100 local 10.1.2.64 ttl 255 ocsum
|
||||
* > ip addr add 14.0.0.64 dev gre1
|
||||
* > ip link set gre1 up
|
||||
* > ip route add 14.0.0.0/8 dev gre3
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 2 CONFIGURATION
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef IPCOM_KERNEL
|
||||
#define IPCOM_KERNEL
|
||||
#endif
|
||||
#include "ipnet_config.h"
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 3 INCLUDE FILES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#ifdef IPNET_USE_GRE
|
||||
|
||||
#ifndef IPCOM_USE_INET
|
||||
#error "IPCOM_USE_INET must be defined to make GRE work"
|
||||
#endif
|
||||
|
||||
#define IPCOM_USE_CLIB_PROTO
|
||||
#include <ipcom_clib.h>
|
||||
#include <ipcom_cstyle.h>
|
||||
#include <ipcom_err.h>
|
||||
#include <ipcom_syslog.h>
|
||||
#include <ipcom_pqueue.h>
|
||||
#include <ipcom_type.h>
|
||||
|
||||
#include "ipnet_h.h"
|
||||
#include "ipnet_netif.h"
|
||||
#include "ipnet_timeout.h"
|
||||
#include "ipnet_tunnel.h"
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 4 DEFINES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/* Supported GRE protocol types, in network byte order */
|
||||
#define IPNET_GRE_PROTOCOL_TYPE_IPV4 ip_htons(0x0800)
|
||||
#define IPNET_GRE_PROTOCOL_TYPE_IPV6 ip_htons(0x86DD)
|
||||
|
||||
|
||||
/* RFC 2784 flags: (rfc1701 options all depreceated except checksum). */
|
||||
#define IPNET_GRE_FLAG_CHECKSUM ip_htons(0x8000) /* Checksum Present */
|
||||
#define IPNET_GRE_FLAG_KEY ip_htons(0x2000) /* Key Present */
|
||||
#define IPNET_GRE_FLAG_SEQNUM ip_htons(0x1000) /* Sequence Number Present */
|
||||
#define IPNET_GRE_FLAG_RESERVED ip_htons(0x03f8) /* bits 6-12 = Reserved */
|
||||
#define IPNET_GRE_FLAG_VERSION ip_htons(0x0007) /* bits 13-15 = Version Number */
|
||||
#ifdef IPNET_USE_RFC2890
|
||||
#define IPNET_GRE_FLAG_MUSTBE0 ip_htons(0x4c00) /* bits 1,4-5 must be 0 */
|
||||
#else
|
||||
#define IPNET_GRE_FLAG_MUSTBE0 ip_htons(0x7c00) /* bits 1-5 must be 0 */
|
||||
#endif
|
||||
|
||||
#define IPNET_GRE_CHECKSUM_PRESENT(gre) \
|
||||
IP_BIT_ISSET((gre)->flags_reserved0_ver, IPNET_GRE_FLAG_CHECKSUM)
|
||||
#define IPNET_GRE_KEY_PRESENT(gre) \
|
||||
IP_BIT_ISSET((gre)->flags_reserved0_ver, IPNET_GRE_FLAG_KEY)
|
||||
#define IPNET_GRE_SEQNUM_PRESENT(gre) \
|
||||
IP_BIT_ISSET((gre)->flags_reserved0_ver, IPNET_GRE_FLAG_SEQNUM)
|
||||
|
||||
#define IPNET_GRE_HDR_SIZE 4
|
||||
#define IPNET_GRE_OPT_CSUM_SIZE 4
|
||||
#define IPNET_GRE_OPT_KEY_SIZE 4
|
||||
#define IPNET_GRE_OPT_SEQNUM_SIZE 4
|
||||
|
||||
|
||||
/* */
|
||||
#define IPNET_GRE_PKT_SET_KEY(pkt, key) ((pkt)->link_cookie = key)
|
||||
|
||||
#define IPNET_GRE_PKT_GET_SEQNUM(pkt, seqnum) (Ip_u32) ((pkt)->link_cookie)
|
||||
#define IPNET_GRE_PKT_SET_SEQNUM(pkt, seqnum) ((pkt)->link_cookie = seqnum)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 5 TYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* Ipnet_pkt_gre
|
||||
*===========================================================================
|
||||
*/
|
||||
#include "ipcom_align16.h"
|
||||
typedef IP_PACKED1 struct Ipnet_pkt_gre_struct
|
||||
{
|
||||
Ip_u16 flags_reserved0_ver;
|
||||
Ip_u16 protocol_type;
|
||||
Ip_u8 options[1];
|
||||
}
|
||||
IP_PACKED2 Ipnet_pkt_gre;
|
||||
|
||||
typedef IP_PACKED1 struct Ipnet_pkt_gre_opt_csum_struct
|
||||
{
|
||||
Ip_u16 checksum;
|
||||
Ip_u16 reserved1;
|
||||
}
|
||||
IP_PACKED2 Ipnet_pkt_gre_opt_csum;
|
||||
#include "ipcom_align16.h"
|
||||
|
||||
#ifdef IPNET_USE_RFC2890
|
||||
typedef struct Ipnet_gre_struct
|
||||
{
|
||||
Ipcom_pqueue *reassembly_queue;
|
||||
Ipnet_timeout *reassembly_tmo;
|
||||
Ip_u32 recv_seqnum;
|
||||
Ip_u32 send_seqnum;
|
||||
}
|
||||
Ipnet_gre_t;
|
||||
#endif /* IPNET_USE_RFC2890 */
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 6 EXTERN PROTOTYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 7 LOCAL PROTOTYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 8 DATA
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 9 STATIC FUNCTIONS
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#ifdef IPNET_USE_RFC2890
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_gre_seq_cmp
|
||||
*===========================================================================
|
||||
* Description: Compares the sequence number of two packets.
|
||||
* Parameters: netif - A GRE tunnel interface.
|
||||
* Returns: 0 = success, <0 = error code.
|
||||
*
|
||||
*/
|
||||
IP_STATIC int
|
||||
ipnet_gre_seq_cmp(IP_CONST Ipcom_pkt *pkt1, IP_CONST Ipcom_pkt *pkt2)
|
||||
{
|
||||
void *pkt1_data = ipcom_pkt_get_data(pkt1, 0);
|
||||
Ip_u32 seqnum1 = IP_GET_NTOHL(pkt1_data);
|
||||
void *pkt2_data = ipcom_pkt_get_data(pkt2, 0);
|
||||
Ip_u32 seqnum2 = IP_GET_NTOHL(pkt2_data);
|
||||
|
||||
if (IPCOM_IS_LT(seqnum1, seqnum2))
|
||||
return 1;
|
||||
|
||||
if (IPCOM_IS_GT(seqnum1, seqnum2))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_gre_tmo
|
||||
*===========================================================================
|
||||
* Description: Reassembly timeout handler.
|
||||
* Parameters: netif - A GRE tunnel interface.
|
||||
* Returns: 0 = success, <0 = error code.
|
||||
*
|
||||
*/
|
||||
IP_STATIC void
|
||||
ipnet_gre_seq_tmo(Ipnet_netif *netif)
|
||||
{
|
||||
Ipnet_pkt_gre *gre_hdr;
|
||||
Ipcom_pkt *pkt;
|
||||
Ipnet_gre_t *gre = netif->ipcom.pdrv;
|
||||
|
||||
/* RFC 2890, chapter 2.2
|
||||
...
|
||||
Under no circumstances should a packet wait more that
|
||||
OUTOFORDER_TIMER milliseconds in the buffer. If a packet has been
|
||||
waiting that long, the receiver MUST immediately traverse the buffer
|
||||
in sorted order, decapsulating packets (and ignoring any sequence
|
||||
number gaps) until there are no more packets in the buffer that have
|
||||
been waiting longer than OUTOFORDER_TIMER milliseconds. The "last
|
||||
successfully decapsulated sequence number" should then be set to the
|
||||
last packet so decapsulated.
|
||||
...
|
||||
*/
|
||||
pkt = ipcom_pqueue_get_next(gre->reassembly_queue);
|
||||
ip_assert(pkt != IP_NULL);
|
||||
gre->recv_seqnum = IP_GET_NTOHL(ipcom_pkt_get_data(pkt, 0));
|
||||
|
||||
do
|
||||
{
|
||||
pkt = ipcom_pqueue_remove_next(gre->reassembly_queue);
|
||||
ip_assert(pkt != IP_NULL);
|
||||
/*
|
||||
* Discard the sequence number option and make place for a GRE
|
||||
* header
|
||||
*/
|
||||
(void) ipcom_pkt_pop_front(pkt, IPNET_GRE_OPT_SEQNUM_SIZE - IPNET_GRE_HDR_SIZE);
|
||||
|
||||
gre_hdr = ipcom_pkt_get_data(pkt, 0);
|
||||
gre_hdr->flags_reserved0_ver = 0;
|
||||
if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_IPV4))
|
||||
gre_hdr->protocol_type = ip_htons(0x0800);
|
||||
else if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_IPV6))
|
||||
gre_hdr->protocol_type = ip_htons(0x86DD);
|
||||
|
||||
(void) ipnet_gre_input(netif, pkt);
|
||||
++gre->recv_seqnum;
|
||||
} while (IP_NULL != (pkt = ipcom_pqueue_get_next(gre->reassembly_queue))
|
||||
&& gre->recv_seqnum == IP_GET_NTOHL(ipcom_pkt_get_data(pkt, 0)));
|
||||
|
||||
if (pkt != IP_NULL)
|
||||
{
|
||||
Ip_s64 timeout = IPNET_PKT_GET_TIMEOUT_ABS(pkt);
|
||||
|
||||
/*
|
||||
* More out of order packets waiting, schedule a timeout of
|
||||
* the time remaining until this packet sequence timer
|
||||
* timeouts
|
||||
*/
|
||||
(void) ipnet_timeout_schedule((timeout < ipnet->msec_now
|
||||
? 0
|
||||
: timeout - ipnet->msec_now),
|
||||
(Ipnet_timeout_handler) ipnet_gre_seq_tmo,
|
||||
netif,
|
||||
&gre->reassembly_tmo);
|
||||
}
|
||||
}
|
||||
#endif /* IPNET_USE_RFC2890 */
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 10 GLOBAL FUNCTIONS
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_gre_setup
|
||||
*===========================================================================
|
||||
* Description: Setup the GRE tunnel.
|
||||
* Parameters: netif - A GRE tunnel interface.
|
||||
* Returns: 0 = success, <0 = error code.
|
||||
*
|
||||
*/
|
||||
IP_GLOBAL int
|
||||
ipnet_gre_setup(Ipnet_netif *netif)
|
||||
{
|
||||
#ifdef IPNET_USE_RFC2890
|
||||
Ipnet_gre_t *gre;
|
||||
|
||||
gre = netif->ipcom.pdrv = ipcom_calloc(1, sizeof(Ipnet_gre_t));
|
||||
if (gre == IP_NULL)
|
||||
goto errout;
|
||||
|
||||
gre->reassembly_queue
|
||||
= ipcom_pqueue_new((Ipcom_pqueue_cmp_func) ipnet_gre_seq_cmp,
|
||||
ipcom_pqueue_nop_store_index);
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
ipnet_gre_destroy(netif);
|
||||
IPCOM_LOG0(CRIT, "Failed to create GRE tunnel due to unsifficient memory");
|
||||
return -IP_ERRNO_ENOMEM;
|
||||
#else
|
||||
IPCOM_UNUSED_ARG(netif);
|
||||
return 0;
|
||||
#endif /* IPNET_USE_RFC2890 */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_gre_destroy
|
||||
*===========================================================================
|
||||
* Description: Destroy the GRE tunnel.
|
||||
* Parameters: netif - A GRE tunnel interface.
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_GLOBAL void
|
||||
ipnet_gre_destroy(Ipnet_netif *netif)
|
||||
{
|
||||
#ifdef IPNET_USE_RFC2890
|
||||
Ipnet_gre_t *gre = netif->ipcom.pdrv;
|
||||
Ipcom_pkt *pkt;
|
||||
|
||||
if (gre != IP_NULL)
|
||||
{
|
||||
if (gre->reassembly_queue != IP_NULL)
|
||||
{
|
||||
while (IP_NULL != (pkt = ipcom_pqueue_remove_next(gre->reassembly_queue)))
|
||||
ipcom_pkt_free(pkt);
|
||||
ipcom_pqueue_delete(gre->reassembly_queue);
|
||||
}
|
||||
ipnet_timeout_cancel(gre->reassembly_tmo);
|
||||
ipcom_free(gre);
|
||||
}
|
||||
#endif /* IPNET_USE_RFC2890 */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_gre_input
|
||||
*===========================================================================
|
||||
* Description: Handler for received GRE packets.
|
||||
* Parameters: pkt - Received GRE packet.
|
||||
* Returns: 0 = success, <0 = error code.
|
||||
*
|
||||
*/
|
||||
IP_GLOBAL int
|
||||
ipnet_gre_input(Ipnet_netif *netif, Ipcom_pkt *pkt)
|
||||
{
|
||||
Ipnet_pkt_gre *gre_hdr;
|
||||
int initial_pkt_len = ipcom_pkt_get_length(pkt);
|
||||
|
||||
IP_BIT_CLR(pkt->flags, IPCOM_PKT_FLAG_IPV4 | IPCOM_PKT_FLAG_IPV6);
|
||||
gre_hdr = ipcom_pkt_pop_front(pkt, IPNET_GRE_HDR_SIZE);
|
||||
|
||||
/* First 16-bits non-null, verify bits and version. */
|
||||
if (gre_hdr->flags_reserved0_ver)
|
||||
{
|
||||
/* RFC 2784: 2.3. Reserved0 (bits 1-12)
|
||||
A receiver MUST discard a packet where any of bits 1-5 are non-zero,
|
||||
unless that receiver implements RFC 1701. Bits 6-12 are reserved for
|
||||
future use. These bits MUST be sent as zero and MUST be ignored on
|
||||
receipt.
|
||||
|
||||
RFC 2890: 2. Extensions to GRE Header
|
||||
Key present (bit 2)
|
||||
Sequence Number Present (bit 3)
|
||||
*/
|
||||
if (IP_BIT_ISSET(gre_hdr->flags_reserved0_ver, IPNET_GRE_FLAG_MUSTBE0))
|
||||
goto cleanup;
|
||||
|
||||
/* RFC 2784: 2.3.1. Version Number (bits 13-15)
|
||||
The Version Number field MUST contain the value zero.
|
||||
*/
|
||||
if (IP_BIT_ISSET(gre_hdr->flags_reserved0_ver, IPNET_GRE_FLAG_VERSION))
|
||||
goto cleanup;
|
||||
|
||||
/* RFC 2784: 2.5. Checksum (2 octets)
|
||||
The Checksum field contains the IP (one's complement) checksum sum of
|
||||
the all the 16 bit words in the GRE header and the payload packet.
|
||||
For purposes of computing the checksum, the value of the checksum
|
||||
field is zero. This field is present only if the Checksum Present bit
|
||||
is set to one.
|
||||
*/
|
||||
if (IPNET_GRE_CHECKSUM_PRESENT(gre_hdr))
|
||||
{
|
||||
(void)ipcom_pkt_pop_front(pkt, IPNET_GRE_OPT_CSUM_SIZE);
|
||||
|
||||
/* IP checksum must be ok. */
|
||||
if (ipcom_in_checksum(&gre_hdr->flags_reserved0_ver, (Ip_size_t)initial_pkt_len) != 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#ifdef IPNET_USE_RFC2890
|
||||
/* RFC 2890: 2.1. Key Field (4 octets)
|
||||
The Key field contains a four octet number which was inserted by the
|
||||
encapsulator. The actual method by which this Key is obtained is
|
||||
beyond the scope of the document. The Key field is intended to be
|
||||
used for identifying an individual traffic flow within a tunnel. For
|
||||
example, packets may need to be routed based on context information
|
||||
not present in the encapsulated data. The Key field provides this
|
||||
context and defines a logical traffic flow between encapsulator and
|
||||
decapsulator. Packets belonging to a traffic flow are encapsulated
|
||||
using the same Key value and the decapsulating tunnel endpoint
|
||||
identifies packets belonging to a traffic flow based on the Key Field
|
||||
value.
|
||||
*/
|
||||
if (IPNET_GRE_KEY_PRESENT(gre_hdr))
|
||||
{
|
||||
Ip_u32 key;
|
||||
void *pkt_data = ipcom_pkt_pop_front(pkt, IPNET_GRE_OPT_KEY_SIZE);
|
||||
|
||||
key = IP_GET_NTOHL(pkt_data);
|
||||
IPNET_GRE_PKT_SET_KEY(pkt, key);
|
||||
}
|
||||
|
||||
/* RFC 2890: 2.2. Sequence Number (4 octets)
|
||||
The Sequence Number field is a four byte field and is inserted by the
|
||||
encapsulator when Sequence Number Present Bit is set. The Sequence
|
||||
Number MUST be used by the receiver to establish the order in which
|
||||
packets have been transmitted from the encapsulator to the receiver.
|
||||
The intended use of the Sequence Field is to provide unreliable but
|
||||
in-order delivery. If the Key present bit (bit 2) is set, the
|
||||
sequence number is specific to the traffic flow identified by the Key
|
||||
field. Note that packets without the sequence bit set can be
|
||||
interleaved with packets with the sequence bit set.
|
||||
*/
|
||||
if (IPNET_GRE_SEQNUM_PRESENT(gre_hdr))
|
||||
{
|
||||
Ipnet_gre_t *gre = netif->ipcom.pdrv;
|
||||
Ip_u32 seqnum;
|
||||
void *pkt_data = ipcom_pkt_get_data(pkt, 0);
|
||||
|
||||
seqnum = IP_GET_NTOHL(pkt_data);
|
||||
if (seqnum == gre->recv_seqnum)
|
||||
/* In order segment */
|
||||
++gre->recv_seqnum;
|
||||
else if (IPCOM_IS_LT(seqnum, gre->recv_seqnum))
|
||||
/* Out of order */
|
||||
goto cleanup;
|
||||
else
|
||||
{
|
||||
Ip_u32 outoforder_timer;
|
||||
int max_perflow_buffer;
|
||||
|
||||
max_perflow_buffer = ipcom_sysvar_get_as_int0("ipnet.gre.MAX_PERFLOW_BUFFER", 3);
|
||||
outoforder_timer = (Ip_u32) ipcom_sysvar_get_as_int0("ipnet.gre.OUTOFORDER_TIMER", 1000);
|
||||
|
||||
if (max_perflow_buffer <= 0)
|
||||
/* No buffering allowed */
|
||||
goto cleanup;
|
||||
|
||||
while (ipcom_pqueue_size(gre->reassembly_queue) >= max_perflow_buffer)
|
||||
{
|
||||
ipnet_timeout_cancel(gre->reassembly_tmo);
|
||||
/*
|
||||
* Call the timeout handler to force the oldest packet(s)
|
||||
* to be inputted to the stack and the receive sequence
|
||||
* number to advanced
|
||||
*/
|
||||
ipnet_gre_seq_tmo(netif);
|
||||
}
|
||||
|
||||
if (gre_hdr->protocol_type == ip_htons(0x0800))
|
||||
IP_BIT_SET(pkt->flags, IPCOM_PKT_FLAG_IPV4);
|
||||
else if (gre_hdr->protocol_type == ip_htons(0x86DD))
|
||||
IP_BIT_SET(pkt->flags, IPCOM_PKT_FLAG_IPV6);
|
||||
|
||||
IPNET_PKT_SET_TIMEOUT_ABS(pkt, ipnet->msec_now + outoforder_timer);
|
||||
if (gre->reassembly_tmo == IP_NULL)
|
||||
if (ipnet_timeout_schedule(outoforder_timer,
|
||||
(Ipnet_timeout_handler) ipnet_gre_seq_tmo,
|
||||
netif,
|
||||
&gre->reassembly_tmo) < 0)
|
||||
goto cleanup;
|
||||
if (ipcom_pqueue_insert(gre->reassembly_queue, pkt) != IPCOM_SUCCESS)
|
||||
{
|
||||
ipnet_timeout_cancel(gre->reassembly_tmo);
|
||||
goto cleanup;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
pkt->start += IPNET_GRE_OPT_SEQNUM_SIZE;
|
||||
}
|
||||
#endif /* IPNET_USE_RFC2890 */
|
||||
}
|
||||
|
||||
/**/
|
||||
if (netif->ipcom.link_tap)
|
||||
/* start is PAYLOAD == the inner IP header; ipstart points to the PREVIOUS
|
||||
* IP header */
|
||||
netif->ipcom.link_tap(&netif->ipcom, pkt, IP_PACKET_HOST, gre_hdr->protocol_type, pkt->start, pkt->start);
|
||||
|
||||
#ifdef IPCOM_USE_INET
|
||||
/* IPv4 in GRE. */
|
||||
if (gre_hdr->protocol_type == ip_htons(0x0800))
|
||||
return ipnet_ip4_input(netif, pkt);
|
||||
#endif
|
||||
|
||||
#ifdef IPCOM_USE_INET6
|
||||
/* IPv6 in GRE. */
|
||||
if (gre_hdr->protocol_type == ip_htons(0x86DD))
|
||||
return ipnet_ip6_input(netif, pkt);
|
||||
#endif
|
||||
|
||||
/* Unsupported Protocol Type, drop. */
|
||||
|
||||
cleanup:
|
||||
ipcom_pkt_free(pkt);
|
||||
return -IP_ERRNO_EINVAL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_gre_output_append
|
||||
*===========================================================================
|
||||
* Description: Handler for packets to send.
|
||||
* Parameters: pkt - Packet to send and append GRE header to.
|
||||
* Returns: 0 = success, <0 = error code.
|
||||
*
|
||||
*/
|
||||
IP_GLOBAL int
|
||||
ipnet_gre_output_append(Ipnet_netif *netif, struct Ip_ip_tunnel_param *tunnel_param, Ipcom_pkt *pkt)
|
||||
{
|
||||
Ipnet_pkt_gre *gre_hdr;
|
||||
Ipnet_pkt_gre_opt_csum *csum_opt = IP_NULL;
|
||||
#ifdef IPNET_USE_RFC2890
|
||||
Ip_u32 *key_opt = IP_NULL;
|
||||
Ip_u32 *key_opt_info;
|
||||
Ip_u32 *seqnum_opt = IP_NULL;
|
||||
Ipnet_gre_t *gre = netif->ipcom.pdrv;
|
||||
#endif
|
||||
|
||||
ip_assert(pkt->start >= (IPNET_GRE_MAX_HDR_SIZE + IPNET_IP_HDR_SIZE));
|
||||
|
||||
#ifdef IPNET_USE_RFC2890
|
||||
if (IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_LINK1))
|
||||
{
|
||||
seqnum_opt = ipcom_pkt_push_front(pkt, IPNET_GRE_OPT_SEQNUM_SIZE);
|
||||
IP_SET_HTONL(seqnum_opt, gre->send_seqnum);
|
||||
++gre->send_seqnum;
|
||||
}
|
||||
|
||||
if ((key_opt_info = ipcom_pkt_get_info(pkt, IPNET_PKT_INFO_GRE_KEY_OUTPUT)) != IP_NULL)
|
||||
{
|
||||
key_opt = ipcom_pkt_push_front(pkt, IPNET_GRE_OPT_KEY_SIZE);
|
||||
IP_SET_HTONL(key_opt, *key_opt_info);
|
||||
}
|
||||
#endif /* IPNET_USE_RFC2890 */
|
||||
|
||||
if (IP_BIT_ISTRUE(tunnel_param->o_flags, IPCOM_TUNNEL_FLAG_GRE_CHECKSUM)
|
||||
|| IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_LINK2))
|
||||
{
|
||||
/* GRE output checksum enabled. */
|
||||
csum_opt = ipcom_pkt_push_front(pkt, IPNET_GRE_OPT_CSUM_SIZE);
|
||||
csum_opt->checksum = 0;
|
||||
csum_opt->reserved1 = 0;
|
||||
}
|
||||
|
||||
/* Add GRE header. */
|
||||
gre_hdr = ipcom_pkt_push_front(pkt, IPNET_GRE_HDR_SIZE);
|
||||
gre_hdr->flags_reserved0_ver = 0;
|
||||
switch (pkt->data[pkt->ipstart] & 0xf0)
|
||||
{
|
||||
#ifdef IPCOM_USE_INET
|
||||
case 0x40:
|
||||
gre_hdr->protocol_type = IPNET_GRE_PROTOCOL_TYPE_IPV4;
|
||||
break;
|
||||
#endif
|
||||
#ifdef IPCOM_USE_INET6
|
||||
case 0x60:
|
||||
gre_hdr->protocol_type = IPNET_GRE_PROTOCOL_TYPE_IPV6;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return -IP_ERRNO_EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
#ifdef IPNET_USE_RFC2890
|
||||
if (key_opt != IP_NULL)
|
||||
IP_BIT_SET(gre_hdr->flags_reserved0_ver, IPNET_GRE_FLAG_KEY);
|
||||
|
||||
if (seqnum_opt != IP_NULL)
|
||||
IP_BIT_SET(gre_hdr->flags_reserved0_ver, IPNET_GRE_FLAG_SEQNUM);
|
||||
#endif /* IPNET_USE_RFC2890 */
|
||||
|
||||
if (csum_opt != IP_NULL)
|
||||
{
|
||||
/* The whole GRE header is written, time to calculate the checksum */
|
||||
IP_BIT_SET(gre_hdr->flags_reserved0_ver, IPNET_GRE_FLAG_CHECKSUM);
|
||||
csum_opt->checksum = ipcom_in_checksum(gre_hdr, ipcom_pkt_get_length(pkt));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 11 PUBLIC FUNCTIONS
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#endif /* IPNET_USE_GRE */
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* END OF FILE
|
||||
****************************************************************************
|
||||
*/
|
||||
Reference in New Issue
Block a user