diff options
Diffstat (limited to 'filter/filter.c')
-rw-r--r-- | filter/filter.c | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/filter/filter.c b/filter/filter.c index e505d570..90673865 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -141,6 +141,178 @@ f_rta_cow(struct filter_state *fs) static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; +int +calc_tunnel_encap(const struct f_tree *t, int *type) +{ + if (t == NULL) + return 0; + + if (t->from.type == 0) { + return 0; + } + + if (t->from.type != T_SUB_TLV) { + DBG("Not tlv %d\n", t->from.type); + return -1; + } + + const struct tlv *tlv = &t->from.val.tlv; + int len = 0; + switch (tlv->type) { + case TLV_ENCAPSULATION: + /* + Header: + Tunnel Type (2 Octets) + Length (2 Octets) + Value (Variable) + + TLV: + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (Variable) + */ + if (tlv->u.tunnel_encap.length > 0) + len = 4 + 2 + tlv->u.tunnel_encap.length; + else + len = 0; + *type = tlv->u.tunnel_encap.type; + break; + case TLV_COLOR: + /* + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (8 Octets) + */ + len = 10; + break; + case TLV_UDP_DEST_PORT: + /* + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (2 Octets) + */ + len = 4; + break; + case TLV_TUNNEL_ENDPOINT: + /* + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (10 or 22 Octets) + */ + if (ipa_is_ip4(tlv->u.tunnel_endpoint.ip)) + len = 2 + 10; + else + len = 2 + 22; + break; + default: + /* Ignore unknown */ + len = 0; + break; + } + + return len + calc_tunnel_encap(t->left, type) + calc_tunnel_encap(t->right, type); +} + +static void * +build_tunnel_encap_rec(void *p, const struct f_tree *t) +{ + if (t == NULL) + return p; + + if (t->from.type != T_SUB_TLV) { + DBG("Not tlv %d\n", t->from.type); + return p; + } + + const struct tlv *tlv = &t->from.val.tlv; + switch (tlv->type) { + case TLV_ENCAPSULATION: + { + /* + TLV: + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (Variable) + */ + int len = tlv->u.tunnel_encap.length; + if (len <= 0) + break; + put_u8(p, tlv->type); p++; + put_u8(p, len); p++; + memcpy(p, tlv->u.tunnel_encap.data, len); p+=len; + break; + } + case TLV_COLOR: + /* + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (8 Octets) + */ + put_u8(p, tlv->type); p++; + put_u8(p, 8); p++; + put_u8(p, 0x03); p++; + put_u8(p, 0x0b); p++; + put_u16(p, 0x0); p+=2; + put_u32(p, tlv->u.color); p+=4; + break; + case TLV_UDP_DEST_PORT: + /* + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (2 Octets) + */ + put_u8(p, tlv->type); p++; + put_u8(p, 2); p++; + put_u16(p, tlv->u.udp_dest_port); p+=2; + break; + case TLV_TUNNEL_ENDPOINT: + /* + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (10 or 22 Octets) + */ + put_u8(p, tlv->type); p++; + if (ipa_is_ip4(tlv->u.tunnel_endpoint.ip)) { + put_u8(p, 10); p++; + put_u32(p, tlv->u.tunnel_endpoint.asn); p+=4; + put_u16(p, NET_IP4); p+=2; + put_ip4(p, ipa_to_ip4(tlv->u.tunnel_endpoint.ip)); p+=4; + } else { + put_u8(p, 22); p++; + put_u32(p, tlv->u.tunnel_endpoint.asn); p+=4; + put_u16(p, NET_IP6); p+=2; + put_ip6(p, ipa_to_ip6(tlv->u.tunnel_endpoint.ip)); p+=16; + } + break; + default: + /* Ignore unknown */ + break; + } + + return build_tunnel_encap_rec(build_tunnel_encap_rec(p, t->left), t->right); +} + +struct adata * +build_tunnel_encap(struct linpool *pool, const struct f_tree *t, int type, int len) +{ + struct adata *ad = lp_alloc(pool, sizeof(struct adata) + len); + ad->length = len; + void *p = ad->data; + + /* + Header: + Tunnel Type (2 Octets) + Length (2 Octets) + Value (Variable) + */ + + put_u16(p, type); p += 2; + put_u16(p, len - 4); p += 2; + build_tunnel_encap_rec(p, t); + return ad; +} + + /** * interpret * @fs: filter state |