632 lines
21 KiB
C
632 lines
21 KiB
C
/*
|
|
******************************************************************************
|
|
* 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
|
|
****************************************************************************
|
|
*/
|