|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Exthdr expression protocol and type definitions and related functions.
|
|
Packit |
c5a612 |
*
|
|
Packit |
c5a612 |
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
|
Packit |
c5a612 |
*
|
|
Packit |
c5a612 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
c5a612 |
* it under the terms of the GNU General Public License version 2 as
|
|
Packit |
c5a612 |
* published by the Free Software Foundation.
|
|
Packit |
c5a612 |
*
|
|
Packit |
c5a612 |
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <stddef.h>
|
|
Packit |
c5a612 |
#include <stdlib.h>
|
|
Packit |
c5a612 |
#include <stdio.h>
|
|
Packit |
c5a612 |
#include <stdint.h>
|
|
Packit |
c5a612 |
#include <string.h>
|
|
Packit |
c5a612 |
#include <netinet/in.h>
|
|
Packit |
c5a612 |
#include <netinet/ip6.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <utils.h>
|
|
Packit |
c5a612 |
#include <headers.h>
|
|
Packit |
c5a612 |
#include <expression.h>
|
|
Packit |
c5a612 |
#include <statement.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void exthdr_expr_print(const struct expr *expr, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (expr->exthdr.op == NFT_EXTHDR_OP_TCPOPT) {
|
|
Packit |
c5a612 |
/* Offset calculation is a bit hacky at this point.
|
|
Packit |
c5a612 |
* There might be a tcp option one day with another
|
|
Packit |
c5a612 |
* multiplicator
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
unsigned int offset = expr->exthdr.offset / 64;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nft_print(octx, "tcp option %s", expr->exthdr.desc->name);
|
|
Packit |
c5a612 |
if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
if (offset)
|
|
Packit |
c5a612 |
nft_print(octx, "%d", offset);
|
|
Packit |
c5a612 |
nft_print(octx, " %s", expr->exthdr.tmpl->token);
|
|
Packit |
c5a612 |
} else if (expr->exthdr.op == NFT_EXTHDR_OP_IPV4) {
|
|
Packit |
c5a612 |
nft_print(octx, "ip option %s", expr->exthdr.desc->name);
|
|
Packit |
c5a612 |
if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
nft_print(octx, " %s", expr->exthdr.tmpl->token);
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
|
|
Packit |
c5a612 |
nft_print(octx, "exthdr %s", expr->exthdr.desc->name);
|
|
Packit |
c5a612 |
else {
|
|
Packit |
c5a612 |
nft_print(octx, "%s %s",
|
|
Packit |
c5a612 |
expr->exthdr.desc ? expr->exthdr.desc->name : "unknown-exthdr",
|
|
Packit |
c5a612 |
expr->exthdr.tmpl->token);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static bool exthdr_expr_cmp(const struct expr *e1, const struct expr *e2)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return e1->exthdr.desc == e2->exthdr.desc &&
|
|
Packit |
c5a612 |
e1->exthdr.tmpl == e2->exthdr.tmpl &&
|
|
Packit |
c5a612 |
e1->exthdr.op == e2->exthdr.op &&
|
|
Packit |
c5a612 |
e1->exthdr.flags == e2->exthdr.flags;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void exthdr_expr_clone(struct expr *new, const struct expr *expr)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
new->exthdr.desc = expr->exthdr.desc;
|
|
Packit |
c5a612 |
new->exthdr.tmpl = expr->exthdr.tmpl;
|
|
Packit |
c5a612 |
new->exthdr.offset = expr->exthdr.offset;
|
|
Packit |
c5a612 |
new->exthdr.op = expr->exthdr.op;
|
|
Packit |
c5a612 |
new->exthdr.flags = expr->exthdr.flags;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct expr_ops exthdr_expr_ops = {
|
|
Packit |
c5a612 |
.type = EXPR_EXTHDR,
|
|
Packit |
c5a612 |
.name = "exthdr",
|
|
Packit |
c5a612 |
.print = exthdr_expr_print,
|
|
Packit |
c5a612 |
.json = exthdr_expr_json,
|
|
Packit |
c5a612 |
.cmp = exthdr_expr_cmp,
|
|
Packit |
c5a612 |
.clone = exthdr_expr_clone,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct proto_hdr_template exthdr_unknown_template =
|
|
Packit |
c5a612 |
PROTO_HDR_TEMPLATE("unknown", &invalid_type, BYTEORDER_INVALID, 0, 0);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct expr *exthdr_expr_alloc(const struct location *loc,
|
|
Packit |
c5a612 |
const struct exthdr_desc *desc,
|
|
Packit |
c5a612 |
uint8_t type)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct proto_hdr_template *tmpl;
|
|
Packit |
c5a612 |
struct expr *expr;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (desc != NULL)
|
|
Packit |
c5a612 |
tmpl = &desc->templates[type];
|
|
Packit |
c5a612 |
else
|
|
Packit |
c5a612 |
tmpl = &exthdr_unknown_template;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype,
|
|
Packit |
c5a612 |
BYTEORDER_BIG_ENDIAN, tmpl->len);
|
|
Packit |
c5a612 |
expr->exthdr.desc = desc;
|
|
Packit |
c5a612 |
expr->exthdr.tmpl = tmpl;
|
|
Packit |
c5a612 |
return expr;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void exthdr_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
expr_print(stmt->exthdr.expr, octx);
|
|
Packit |
c5a612 |
nft_print(octx, " set ");
|
|
Packit |
c5a612 |
expr_print(stmt->exthdr.val, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void exthdr_stmt_destroy(struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
expr_free(stmt->exthdr.expr);
|
|
Packit |
c5a612 |
expr_free(stmt->exthdr.val);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops exthdr_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_EXTHDR,
|
|
Packit |
c5a612 |
.name = "exthdr",
|
|
Packit |
c5a612 |
.print = exthdr_stmt_print,
|
|
Packit |
c5a612 |
.json = exthdr_stmt_json,
|
|
Packit |
c5a612 |
.destroy = exthdr_stmt_destroy,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *exthdr_stmt_alloc(const struct location *loc,
|
|
Packit |
c5a612 |
struct expr *expr, struct expr *val)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct stmt *stmt;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
stmt = stmt_alloc(loc, &exthdr_stmt_ops);
|
|
Packit |
c5a612 |
stmt->exthdr.expr = expr;
|
|
Packit |
c5a612 |
stmt->exthdr.val = val;
|
|
Packit |
c5a612 |
return stmt;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct exthdr_desc *exthdr_protocols[IPPROTO_MAX] = {
|
|
Packit |
c5a612 |
[IPPROTO_HOPOPTS] = &exthdr_hbh,
|
|
Packit |
c5a612 |
[IPPROTO_ROUTING] = &exthdr_rt,
|
|
Packit |
c5a612 |
[IPPROTO_FRAGMENT] = &exthdr_frag,
|
|
Packit |
c5a612 |
[IPPROTO_DSTOPTS] = &exthdr_dst,
|
|
Packit |
c5a612 |
[IPPROTO_MH] = &exthdr_mh,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct exthdr_desc *exthdr_find_proto(uint8_t proto)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
assert(exthdr_protocols[proto]);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return exthdr_protocols[proto];
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct proto_hdr_template *
|
|
Packit |
c5a612 |
exthdr_rt_find(struct expr *expr, const struct exthdr_desc *desc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct proto_hdr_template *tmpl;
|
|
Packit |
c5a612 |
unsigned int i;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
for (i = 0; i < array_size(desc->templates); i++) {
|
|
Packit |
c5a612 |
tmpl = &desc->templates[i];
|
|
Packit |
c5a612 |
if (tmpl->offset == expr->exthdr.offset &&
|
|
Packit |
c5a612 |
tmpl->len == expr->len) {
|
|
Packit |
c5a612 |
expr->exthdr.desc = desc;
|
|
Packit |
c5a612 |
return tmpl;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void exthdr_init_raw(struct expr *expr, uint8_t type,
|
|
Packit |
c5a612 |
unsigned int offset, unsigned int len,
|
|
Packit |
c5a612 |
enum nft_exthdr_op op, uint32_t flags)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct proto_hdr_template *tmpl = &exthdr_unknown_template;
|
|
Packit |
c5a612 |
unsigned int i;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
assert(expr->etype == EXPR_EXTHDR);
|
|
Packit |
c5a612 |
if (op == NFT_EXTHDR_OP_TCPOPT)
|
|
Packit |
c5a612 |
return tcpopt_init_raw(expr, type, offset, len, flags);
|
|
Packit |
c5a612 |
if (op == NFT_EXTHDR_OP_IPV4)
|
|
Packit |
c5a612 |
return ipopt_init_raw(expr, type, offset, len, flags, true);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
expr->len = len;
|
|
Packit |
c5a612 |
expr->exthdr.flags = flags;
|
|
Packit |
c5a612 |
expr->exthdr.offset = offset;
|
|
Packit |
c5a612 |
expr->exthdr.desc = NULL;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (type < array_size(exthdr_protocols))
|
|
Packit |
c5a612 |
expr->exthdr.desc = exthdr_protocols[type];
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (expr->exthdr.desc == NULL)
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
for (i = 0; i < array_size(expr->exthdr.desc->templates); i++) {
|
|
Packit |
c5a612 |
tmpl = &expr->exthdr.desc->templates[i];
|
|
Packit |
c5a612 |
if (tmpl->offset == offset && tmpl->len == len)
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (expr->exthdr.desc == &exthdr_rt) {
|
|
Packit |
c5a612 |
tmpl = exthdr_rt_find(expr, &exthdr_rt4);
|
|
Packit |
c5a612 |
if (tmpl)
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
tmpl = exthdr_rt_find(expr, &exthdr_rt0);
|
|
Packit |
c5a612 |
if (tmpl)
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
tmpl = exthdr_rt_find(expr, &exthdr_rt2);
|
|
Packit |
c5a612 |
if (tmpl)
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
tmpl = &exthdr_unknown_template;
|
|
Packit |
c5a612 |
out:
|
|
Packit |
c5a612 |
expr->exthdr.tmpl = tmpl;
|
|
Packit |
c5a612 |
if (flags & NFT_EXTHDR_F_PRESENT)
|
|
Packit |
c5a612 |
datatype_set(expr, &boolean_type);
|
|
Packit |
c5a612 |
else
|
|
Packit |
c5a612 |
datatype_set(expr, tmpl->dtype);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static unsigned int mask_length(const struct expr *mask)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
unsigned long off = mpz_scan1(mask->value, 0);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return mpz_scan0(mask->value, off + 1);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
bool exthdr_find_template(struct expr *expr, const struct expr *mask, unsigned int *shift)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
unsigned int off, mask_offset, mask_len;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (expr->exthdr.op != NFT_EXTHDR_OP_IPV4 &&
|
|
Packit |
c5a612 |
expr->exthdr.tmpl != &exthdr_unknown_template)
|
|
Packit |
c5a612 |
return false;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* In case we are handling tcp options instead of the default ipv6
|
|
Packit |
c5a612 |
* extension headers.
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
if (expr->exthdr.op == NFT_EXTHDR_OP_TCPOPT)
|
|
Packit |
c5a612 |
return tcpopt_find_template(expr, mask, shift);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mask_offset = mpz_scan1(mask->value, 0);
|
|
Packit |
c5a612 |
mask_len = mask_length(mask);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
off = expr->exthdr.offset;
|
|
Packit |
c5a612 |
off += round_up(mask->len, BITS_PER_BYTE) - mask_len;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* Handle ip options after the offset and mask have been calculated. */
|
|
Packit |
c5a612 |
if (expr->exthdr.op == NFT_EXTHDR_OP_IPV4) {
|
|
Packit |
c5a612 |
if (ipopt_find_template(expr, off, mask_len - mask_offset)) {
|
|
Packit |
c5a612 |
*shift = mask_offset;
|
|
Packit |
c5a612 |
return true;
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
return false;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
exthdr_init_raw(expr, expr->exthdr.desc->type,
|
|
Packit |
c5a612 |
off, mask_len - mask_offset, expr->exthdr.op, 0);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* still failed to find a template... Bug. */
|
|
Packit |
c5a612 |
if (expr->exthdr.tmpl == &exthdr_unknown_template)
|
|
Packit |
c5a612 |
return false;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
*shift = mask_offset;
|
|
Packit |
c5a612 |
return true;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#define HDR_TEMPLATE(__name, __dtype, __type, __member) \
|
|
Packit |
c5a612 |
PROTO_HDR_TEMPLATE(__name, __dtype, \
|
|
Packit |
c5a612 |
BYTEORDER_BIG_ENDIAN, \
|
|
Packit |
c5a612 |
offsetof(__type, __member) * 8, \
|
|
Packit |
c5a612 |
field_sizeof(__type, __member) * 8)
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Hop-by-hop options
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#define HBH_FIELD(__name, __member, __dtype) \
|
|
Packit |
c5a612 |
HDR_TEMPLATE(__name, __dtype, struct ip6_hbh, __member)
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct exthdr_desc exthdr_hbh = {
|
|
Packit |
c5a612 |
.name = "hbh",
|
|
Packit |
c5a612 |
.type = IPPROTO_HOPOPTS,
|
|
Packit |
c5a612 |
.templates = {
|
|
Packit |
c5a612 |
[HBHHDR_NEXTHDR] = HBH_FIELD("nexthdr", ip6h_nxt, &inet_protocol_type),
|
|
Packit |
c5a612 |
[HBHHDR_HDRLENGTH] = HBH_FIELD("hdrlength", ip6h_len, &integer_type),
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Routing header
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct exthdr_desc exthdr_rt2 = {
|
|
Packit |
c5a612 |
.name = "rt2",
|
|
Packit |
c5a612 |
.type = IPPROTO_ROUTING,
|
|
Packit |
c5a612 |
.proto_key = 2,
|
|
Packit |
c5a612 |
.templates = {
|
|
Packit |
c5a612 |
[RT2HDR_RESERVED] = {},
|
|
Packit |
c5a612 |
[RT2HDR_ADDR] = {},
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#define RT0_FIELD(__name, __member, __dtype) \
|
|
Packit |
c5a612 |
HDR_TEMPLATE(__name, __dtype, struct ip6_rthdr0, __member)
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct exthdr_desc exthdr_rt0 = {
|
|
Packit |
c5a612 |
.name = "rt0",
|
|
Packit |
c5a612 |
.type = IPPROTO_ROUTING,
|
|
Packit |
c5a612 |
.proto_key = 0,
|
|
Packit |
c5a612 |
.templates = {
|
|
Packit |
c5a612 |
[RT0HDR_RESERVED] = RT0_FIELD("reserved", ip6r0_reserved, &integer_type),
|
|
Packit |
c5a612 |
[RT0HDR_ADDR_1] = RT0_FIELD("addr[1]", ip6r0_addr[0], &ip6addr_type),
|
|
Packit |
c5a612 |
[RT0HDR_ADDR_1 + 1] = RT0_FIELD("addr[2]", ip6r0_addr[1], &ip6addr_type),
|
|
Packit |
c5a612 |
// ...
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#define RT4_FIELD(__name, __member, __dtype) \
|
|
Packit |
c5a612 |
HDR_TEMPLATE(__name, __dtype, struct ip6_rt4, __member)
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct exthdr_desc exthdr_rt4 = {
|
|
Packit |
c5a612 |
.name = "srh",
|
|
Packit |
c5a612 |
.type = IPPROTO_ROUTING,
|
|
Packit |
c5a612 |
.proto_key = 4,
|
|
Packit |
c5a612 |
.templates = {
|
|
Packit |
c5a612 |
[RT4HDR_LASTENT] = RT4_FIELD("last-entry", ip6r4_last_entry, &integer_type),
|
|
Packit |
c5a612 |
[RT4HDR_FLAGS] = RT4_FIELD("flags", ip6r4_flags, &integer_type),
|
|
Packit |
c5a612 |
[RT4HDR_TAG] = RT4_FIELD("tag", ip6r4_tag, &integer_type),
|
|
Packit |
c5a612 |
[RT4HDR_SID_1] = RT4_FIELD("sid[1]", ip6r4_segments[0], &ip6addr_type),
|
|
Packit |
c5a612 |
[RT4HDR_SID_1 + 1] = RT4_FIELD("sid[2]", ip6r4_segments[1], &ip6addr_type),
|
|
Packit |
c5a612 |
// ...
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#define RT_FIELD(__name, __member, __dtype) \
|
|
Packit |
c5a612 |
HDR_TEMPLATE(__name, __dtype, struct ip6_rthdr, __member)
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct exthdr_desc exthdr_rt = {
|
|
Packit |
c5a612 |
.name = "rt",
|
|
Packit |
c5a612 |
.type = IPPROTO_ROUTING,
|
|
Packit |
c5a612 |
.proto_key = -1,
|
|
Packit |
c5a612 |
#if 0
|
|
Packit |
c5a612 |
.protocol_key = RTHDR_TYPE,
|
|
Packit |
c5a612 |
.protocols = {
|
|
Packit |
c5a612 |
[0] = &exthdr_rt0,
|
|
Packit |
c5a612 |
[2] = &exthdr_rt2,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
#endif
|
|
Packit |
c5a612 |
.templates = {
|
|
Packit |
c5a612 |
[RTHDR_NEXTHDR] = RT_FIELD("nexthdr", ip6r_nxt, &inet_protocol_type),
|
|
Packit |
c5a612 |
[RTHDR_HDRLENGTH] = RT_FIELD("hdrlength", ip6r_len, &integer_type),
|
|
Packit |
c5a612 |
[RTHDR_TYPE] = RT_FIELD("type", ip6r_type, &integer_type),
|
|
Packit |
c5a612 |
[RTHDR_SEG_LEFT] = RT_FIELD("seg-left", ip6r_segleft, &integer_type),
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Fragment header
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#define FRAG_FIELD(__name, __member, __dtype) \
|
|
Packit |
c5a612 |
HDR_TEMPLATE(__name, __dtype, struct ip6_frag, __member)
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct exthdr_desc exthdr_frag = {
|
|
Packit |
c5a612 |
.name = "frag",
|
|
Packit |
c5a612 |
.type = IPPROTO_FRAGMENT,
|
|
Packit |
c5a612 |
.templates = {
|
|
Packit |
c5a612 |
[FRAGHDR_NEXTHDR] = FRAG_FIELD("nexthdr", ip6f_nxt, &inet_protocol_type),
|
|
Packit |
c5a612 |
[FRAGHDR_RESERVED] = FRAG_FIELD("reserved", ip6f_reserved, &integer_type),
|
|
Packit |
c5a612 |
[FRAGHDR_FRAG_OFF] = PROTO_HDR_TEMPLATE("frag-off", &integer_type,
|
|
Packit |
c5a612 |
BYTEORDER_BIG_ENDIAN,
|
|
Packit |
c5a612 |
16, 13),
|
|
Packit |
c5a612 |
[FRAGHDR_RESERVED2] = PROTO_HDR_TEMPLATE("reserved2", &integer_type,
|
|
Packit |
c5a612 |
BYTEORDER_BIG_ENDIAN,
|
|
Packit |
c5a612 |
29, 2),
|
|
Packit |
c5a612 |
[FRAGHDR_MFRAGS] = PROTO_HDR_TEMPLATE("more-fragments", &integer_type,
|
|
Packit |
c5a612 |
BYTEORDER_BIG_ENDIAN,
|
|
Packit |
c5a612 |
31, 1),
|
|
Packit |
c5a612 |
[FRAGHDR_ID] = FRAG_FIELD("id", ip6f_ident, &integer_type),
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* DST options
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#define DST_FIELD(__name, __member, __dtype) \
|
|
Packit |
c5a612 |
HDR_TEMPLATE(__name, __dtype, struct ip6_dest, __member)
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct exthdr_desc exthdr_dst = {
|
|
Packit |
c5a612 |
.name = "dst",
|
|
Packit |
c5a612 |
.type = IPPROTO_DSTOPTS,
|
|
Packit |
c5a612 |
.templates = {
|
|
Packit |
c5a612 |
[DSTHDR_NEXTHDR] = DST_FIELD("nexthdr", ip6d_nxt, &inet_protocol_type),
|
|
Packit |
c5a612 |
[DSTHDR_HDRLENGTH] = DST_FIELD("hdrlength", ip6d_len, &integer_type),
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Mobility header
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#define MH_FIELD(__name, __member, __dtype) \
|
|
Packit |
c5a612 |
HDR_TEMPLATE(__name, __dtype, struct ip6_mh, __member)
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct symbol_table mh_type_tbl = {
|
|
Packit |
c5a612 |
.base = BASE_DECIMAL,
|
|
Packit |
c5a612 |
.symbols = {
|
|
Packit |
c5a612 |
SYMBOL("binding-refresh-request", IP6_MH_TYPE_BRR),
|
|
Packit |
c5a612 |
SYMBOL("home-test-init", IP6_MH_TYPE_HOTI),
|
|
Packit |
c5a612 |
SYMBOL("careof-test-init", IP6_MH_TYPE_COTI),
|
|
Packit |
c5a612 |
SYMBOL("home-test", IP6_MH_TYPE_HOT),
|
|
Packit |
c5a612 |
SYMBOL("careof-test", IP6_MH_TYPE_COT),
|
|
Packit |
c5a612 |
SYMBOL("binding-update", IP6_MH_TYPE_BU),
|
|
Packit |
c5a612 |
SYMBOL("binding-acknowledgement", IP6_MH_TYPE_BACK),
|
|
Packit |
c5a612 |
SYMBOL("binding-error", IP6_MH_TYPE_BERROR),
|
|
Packit |
c5a612 |
SYMBOL("fast-binding-update", IP6_MH_TYPE_FBU),
|
|
Packit |
c5a612 |
SYMBOL("fast-binding-acknowledgement", IP6_MH_TYPE_FBACK),
|
|
Packit |
c5a612 |
SYMBOL("fast-binding-advertisement", IP6_MH_TYPE_FNA),
|
|
Packit |
c5a612 |
SYMBOL("experimental-mobility-header", IP6_MH_TYPE_EMH),
|
|
Packit |
c5a612 |
SYMBOL("home-agent-switch-message", IP6_MH_TYPE_HASM),
|
|
Packit |
c5a612 |
SYMBOL_LIST_END
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype mh_type_type = {
|
|
Packit |
c5a612 |
.type = TYPE_MH_TYPE,
|
|
Packit |
c5a612 |
.name = "mh_type",
|
|
Packit |
c5a612 |
.desc = "Mobility Header Type",
|
|
Packit |
c5a612 |
.byteorder = BYTEORDER_BIG_ENDIAN,
|
|
Packit |
c5a612 |
.size = BITS_PER_BYTE,
|
|
Packit |
c5a612 |
.basetype = &integer_type,
|
|
Packit |
c5a612 |
.sym_tbl = &mh_type_tbl,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct exthdr_desc exthdr_mh = {
|
|
Packit |
c5a612 |
.name = "mh",
|
|
Packit |
c5a612 |
.type = IPPROTO_MH,
|
|
Packit |
c5a612 |
.templates = {
|
|
Packit |
c5a612 |
[MHHDR_NEXTHDR] = MH_FIELD("nexthdr", ip6mh_proto, &inet_protocol_type),
|
|
Packit |
c5a612 |
[MHHDR_HDRLENGTH] = MH_FIELD("hdrlength", ip6mh_hdrlen, &integer_type),
|
|
Packit |
c5a612 |
[MHHDR_TYPE] = MH_FIELD("type", ip6mh_type, &mh_type_type),
|
|
Packit |
c5a612 |
[MHHDR_RESERVED] = MH_FIELD("reserved", ip6mh_reserved, &integer_type),
|
|
Packit |
c5a612 |
[MHHDR_CHECKSUM] = MH_FIELD("checksum", ip6mh_cksum, &integer_type),
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
};
|