Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / common / vera / niu_ippktgen / C / libnet / src / libnet_build_gre.c
/*
* libnet
* libnet_build_gre.c - GRE packet assembler
*
* Copyright (c) 2003 Frédéric Raynal <pappy@security-labs.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#if (HAVE_CONFIG_H)
#include "../include/config.h"
#endif
#if (!(_WIN32) || (__CYGWIN__))
#include "../include/libnet.h"
#else
#include "../include/win32/libnet.h"
#endif
/*
* Overall packet
*
* The entire encapsulated packet would then have the form:
*
* ---------------------------------
* | |
* | Delivery Header |
* | |
* ---------------------------------
* | |
* | GRE Header |
* | |
* ---------------------------------
* | |
* | Payload packet |
* | |
* ---------------------------------
*
* RFC 1701 defines a header.
* A new RFC (2784) has changed the header and proposed to remove the key
* and seqnum.
* A newer RFC (2890) has changed the header proposed in RFC 2784 by putting
* back key and seqnum.
* These will be supported the day IETF'guys stop this mess !
*
* FR
*/
/*
* Generic Routing Encapsulation (GRE)
* RFC 1701 http://www.faqs.org/rfcs/rfc1701.html
*
*
* Packet header
*
* The GRE packet header has the form:
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |C|R|K|S|s|Recur| Flags | Ver | Protocol Type |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Checksum (optional) | Offset (optional) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Key (optional) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Sequence Number (optional) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Routing (optional) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Enhanced GRE header
*
* See rfc 2637 for details. It is used for PPTP tunneling.
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |C|R|K|S|s|Recur|A| Flags | Ver | Protocol Type |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Key (HW) Payload Length | Key (LW) Call ID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Sequence Number (Optional) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Acknowledgment Number (Optional) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
static inline void
__libnet_print_gre_flags_ver(u_int16_t fv)
{
printf("version = %d (%d) -> ",
fv & GRE_VERSION_MASK, libnet_getgre_length(fv));
if (fv & GRE_CSUM)
{
printf("CSUM ");
}
if (fv & GRE_ROUTING)
{
printf("ROUTING ");
}
if (fv & GRE_KEY)
{
printf("KEY ");
}
if (fv & GRE_SEQ)
{
printf("SEQ ");
}
if (fv & GRE_ACK)
{
printf("ACK ");
}
printf("\n");
}
/* review: what is the portability of the "((struct libnet_gre_hdr*)0)->" ? */
inline u_int32_t
libnet_getgre_length(u_int16_t fv)
{
u_int32_t n = LIBNET_GRE_H;
/*
* If either the Checksum Present bit or the Routing Present bit are
* set, BOTH the Checksum and Offset fields are present in the GRE
* packet.
*/
if ((!(fv & GRE_VERSION_MASK) && (fv & (GRE_CSUM|GRE_ROUTING))) || /* v0 */
(fv & GRE_VERSION_MASK) ) /* v1 */
{
n += sizeof( ((struct libnet_gre_hdr *)0)->gre_sum) +
sizeof( ((struct libnet_gre_hdr *)0)->gre_offset);
}
if ((!(fv & GRE_VERSION_MASK) && (fv & GRE_KEY)) || /* v0 */
( (fv & GRE_VERSION_MASK) && (fv & GRE_SEQ)) ) /* v1 */
{
n += sizeof( ((struct libnet_gre_hdr *)0)->gre_key);
}
if ((!(fv & GRE_VERSION_MASK) && (fv & GRE_SEQ)) || /* v0 */
( (fv & GRE_VERSION_MASK) && (fv & GRE_ACK)) ) /* v1 */
{
n += sizeof( ((struct libnet_gre_hdr *)0)->gre_seq );
}
return (n);
}
libnet_ptag_t
libnet_build_gre(u_int16_t fv, u_int16_t type, u_int16_t sum,
u_int16_t offset, u_int32_t key, u_int32_t seq, u_int16_t len,
u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
{
u_int32_t n;
libnet_pblock_t *p;
struct libnet_gre_hdr gre_hdr;
if (l == NULL)
{
return (-1);
}
n = libnet_getgre_length(fv) + payload_s;
/*
* Find the existing protocol block if a ptag is specified, or create
* a new one.
*/
p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_GRE_H);
if (p == NULL)
{
return (-1);
}
gre_hdr.flags_ver = htons(fv);
gre_hdr.type = htons(type);
n = libnet_pblock_append(l, p, (u_int8_t *)&gre_hdr, LIBNET_GRE_H);
if (n == -1)
{
/* err msg set in libnet_pblock_append() */
goto bad;
}
if ((!(fv & GRE_VERSION_MASK) && (fv & (GRE_CSUM|GRE_ROUTING))) || /* v0 */
(fv & GRE_VERSION_MASK)) /* v1 */
{
sum = htons(sum);
n = libnet_pblock_append(l, p, (u_int8_t*)&sum,
sizeof(gre_hdr.gre_sum));
if (n == -1)
{
/* err msg set in libnet_pblock_append() */
goto bad;
}
offset = htons(offset);
n = libnet_pblock_append(l, p, (u_int8_t*)&offset,
sizeof(gre_hdr.gre_offset));
if (n == -1)
{
/* err msg set in libnet_pblock_append() */
goto bad;
}
}
if ((!(fv & GRE_VERSION_MASK) && (fv & GRE_KEY)) || /* v0 */
( (fv & GRE_VERSION_MASK) && (fv & GRE_SEQ)) ) /* v1 */
{
key = htonl(key);
n = libnet_pblock_append(l, p, (u_int8_t*)&key,
sizeof(gre_hdr.gre_key));
if (n == -1)
{
/* err msg set in libnet_pblock_append() */
goto bad;
}
}
if ((!(fv & GRE_VERSION_MASK) && (fv & GRE_SEQ)) || /* v0 */
( (fv & GRE_VERSION_MASK) && (fv & GRE_ACK)) ) /* v1 */
{
seq = htonl(seq);
n = libnet_pblock_append(l, p, (u_int8_t*)&seq,
sizeof(gre_hdr.gre_seq));
if (n == -1)
{
/* err msg set in libnet_pblock_append() */
goto bad;
}
}
if ((payload && !payload_s) || (!payload && payload_s))
{
sprintf(l->err_buf, "%s(): payload inconsistency\n", __func__);
goto bad;
}
if (payload && payload_s)
{
n = libnet_pblock_append(l, p, payload, payload_s);
if (n == -1)
{
/* err msg set in libnet_pblock_append() */
goto bad;
}
}
if ( (fv & GRE_CSUM) && (!sum) )
{
libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
}
return (ptag ? ptag : libnet_pblock_update(l, p, len, LIBNET_PBLOCK_GRE_H));
bad:
libnet_pblock_delete(l, p);
return (-1);
}
libnet_ptag_t
libnet_build_egre(u_int16_t fv, u_int16_t type, u_int16_t sum,
u_int16_t offset, u_int32_t key, u_int32_t seq, u_int16_t len,
u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
{
return (libnet_build_gre(fv, type, sum, offset, key, seq, len,
payload, payload_s, l, ptag));
}
/*
* Routing (variable)
*
* The Routing field is optional and is present only if the Routing
* Present bit is set to 1.
*
* The Routing field is a list of Source Route Entries (SREs). Each
* SRE has the form:
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Address Family | SRE Offset | SRE Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Routing Information ...
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
libnet_ptag_t
libnet_build_gre_sre(u_int16_t af, u_int8_t offset, u_int8_t length,
u_int8_t *routing, u_int8_t *payload, u_int32_t payload_s, libnet_t *l,
libnet_ptag_t ptag)
{
u_int32_t n;
libnet_pblock_t *p;
struct libnet_gre_sre_hdr sre_hdr;
if (l == NULL)
{
return (-1);
}
n = LIBNET_GRE_SRE_H + length + payload_s;
/*
* Find the existing protocol block if a ptag is specified, or create
* a new one.
*/
p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_GRE_SRE_H);
if (p == NULL)
{
return (-1);
}
sre_hdr.af = htons(af);
sre_hdr.sre_offset = offset;
sre_hdr.sre_length = length;
n = libnet_pblock_append(l, p, (u_int8_t *)&sre_hdr, LIBNET_GRE_SRE_H);
if (n == -1)
{
/* err msg set in libnet_pblock_append() */
goto bad;
}
if ((routing && !length) || (!routing && length))
{
sprintf(l->err_buf, "%s(): routing inconsistency\n", __func__);
goto bad;
}
if (routing && length)
{
n = libnet_pblock_append(l, p, routing, length);
if (n == -1)
{
/* err msg set in libnet_pblock_append() */
goto bad;
}
}
if ((payload && !payload_s) || (!payload && payload_s))
{
sprintf(l->err_buf, "%s(): payload inconsistency\n", __func__);
goto bad;
}
if (payload && payload_s)
{
n = libnet_pblock_append(l, p, payload, payload_s);
if (n == -1)
{
/* err msg set in libnet_pblock_append() */
goto bad;
}
}
return (ptag ? ptag : libnet_pblock_update(l, p, 0,
LIBNET_PBLOCK_GRE_SRE_H));
bad:
libnet_pblock_delete(l, p);
return (-1);
}
libnet_ptag_t
libnet_build_gre_last_sre(libnet_t *l, libnet_ptag_t ptag)
{
u_int32_t n, zero = 0;
libnet_pblock_t *p;
if (l == NULL)
{
return (-1);
}
n = LIBNET_GRE_SRE_H;
/*
* Find the existing protocol block if a ptag is specified, or create
* a new one.
*/
p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_GRE_H);
if (p == NULL)
{
return (-1);
}
n = libnet_pblock_append(l, p, (u_int8_t *)&zero, LIBNET_GRE_SRE_H);
if (n == -1)
{
/* err msg set in libnet_pblock_append() */
goto bad;
}
return (ptag ? ptag : libnet_pblock_update(l, p, 0,
LIBNET_PBLOCK_GRE_SRE_H));
bad:
libnet_pblock_delete(l, p);
return (-1);
}
/* EOF */