mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-12 22:28:44 +00:00
Babel: Parse sub-TLVs and skip TLVs with mandatory sub-TLV
RFC6126bis formally introduces sub-TLVs to the Babel protocol, including mandatory sub-TLVs. This adds support for parsing sub-TLVs to the Babel protocol and skips TLVs that contain mandatory sub-TLVs, as per the spec. For details, see section 4.4 of https://tools.ietf.org/html/draft-ietf-babel-rfc6126bis-02 Thanks to Toke Høiland-Jørgensen <toke@toke.dk> for the patch.
This commit is contained in:
parent
b3c6273efa
commit
145ebfa1df
@ -78,6 +78,11 @@ enum babel_tlv_type {
|
|||||||
BABEL_TLV_MAX
|
BABEL_TLV_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum babel_subtlv_type {
|
||||||
|
BABEL_SUBTLV_PAD1 = 0,
|
||||||
|
BABEL_SUBTLV_PADN = 1
|
||||||
|
};
|
||||||
|
|
||||||
enum babel_iface_type {
|
enum babel_iface_type {
|
||||||
/* In practice, UNDEF and WIRED give equivalent behaviour */
|
/* In practice, UNDEF and WIRED give equivalent behaviour */
|
||||||
BABEL_IFACE_TYPE_UNDEF = 0,
|
BABEL_IFACE_TYPE_UNDEF = 0,
|
||||||
|
@ -120,6 +120,7 @@ struct babel_parse_state {
|
|||||||
u8 router_id_seen; /* router_id field is valid */
|
u8 router_id_seen; /* router_id field is valid */
|
||||||
u8 def_ip6_prefix_seen; /* def_ip6_prefix is valid */
|
u8 def_ip6_prefix_seen; /* def_ip6_prefix is valid */
|
||||||
u8 def_ip4_prefix_seen; /* def_ip4_prefix is valid */
|
u8 def_ip4_prefix_seen; /* def_ip4_prefix is valid */
|
||||||
|
u8 current_tlv_endpos; /* End of self-terminating TLVs (offset from start) */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum parse_result {
|
enum parse_result {
|
||||||
@ -379,14 +380,33 @@ babel_read_ihu(struct babel_tlv *hdr, union babel_msg *m,
|
|||||||
if (msg->ae >= BABEL_AE_MAX)
|
if (msg->ae >= BABEL_AE_MAX)
|
||||||
return PARSE_IGNORE;
|
return PARSE_IGNORE;
|
||||||
|
|
||||||
// We handle link-local IPs. In every other case, the addr field will be 0 but
|
/*
|
||||||
// validation will succeed. The handler takes care of these cases.
|
* We only actually read link-local IPs. In every other case, the addr field
|
||||||
if (msg->ae == BABEL_AE_IP6_LL)
|
* will be 0 but validation will succeed. The handler takes care of these
|
||||||
|
* cases. We handle them here anyway because we need the length for parsing
|
||||||
|
* subtlvs.
|
||||||
|
*/
|
||||||
|
switch (msg->ae)
|
||||||
{
|
{
|
||||||
|
case BABEL_AE_IP4:
|
||||||
|
if (TLV_OPT_LENGTH(tlv) < 4)
|
||||||
|
return PARSE_ERROR;
|
||||||
|
state->current_tlv_endpos += 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BABEL_AE_IP6:
|
||||||
|
if (TLV_OPT_LENGTH(tlv) < 16)
|
||||||
|
return PARSE_ERROR;
|
||||||
|
state->current_tlv_endpos += 16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BABEL_AE_IP6_LL:
|
||||||
if (TLV_OPT_LENGTH(tlv) < 8)
|
if (TLV_OPT_LENGTH(tlv) < 8)
|
||||||
return PARSE_ERROR;
|
return PARSE_ERROR;
|
||||||
|
|
||||||
msg->addr = ipa_from_ip6(get_ip6_ll(&tlv->addr));
|
msg->addr = ipa_from_ip6(get_ip6_ll(&tlv->addr));
|
||||||
|
state->current_tlv_endpos += 8;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return PARSE_SUCCESS;
|
return PARSE_SUCCESS;
|
||||||
@ -463,6 +483,7 @@ babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED,
|
|||||||
return PARSE_ERROR;
|
return PARSE_ERROR;
|
||||||
|
|
||||||
state->next_hop_ip4 = ipa_from_ip4(get_ip4(&tlv->addr));
|
state->next_hop_ip4 = ipa_from_ip4(get_ip4(&tlv->addr));
|
||||||
|
state->current_tlv_endpos += sizeof(ip4_addr);
|
||||||
return PARSE_IGNORE;
|
return PARSE_IGNORE;
|
||||||
|
|
||||||
case BABEL_AE_IP6:
|
case BABEL_AE_IP6:
|
||||||
@ -470,6 +491,7 @@ babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED,
|
|||||||
return PARSE_ERROR;
|
return PARSE_ERROR;
|
||||||
|
|
||||||
state->next_hop_ip6 = ipa_from_ip6(get_ip6(&tlv->addr));
|
state->next_hop_ip6 = ipa_from_ip6(get_ip6(&tlv->addr));
|
||||||
|
state->current_tlv_endpos += sizeof(ip6_addr);
|
||||||
return PARSE_IGNORE;
|
return PARSE_IGNORE;
|
||||||
|
|
||||||
case BABEL_AE_IP6_LL:
|
case BABEL_AE_IP6_LL:
|
||||||
@ -477,6 +499,7 @@ babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED,
|
|||||||
return PARSE_ERROR;
|
return PARSE_ERROR;
|
||||||
|
|
||||||
state->next_hop_ip6 = ipa_from_ip6(get_ip6_ll(&tlv->addr));
|
state->next_hop_ip6 = ipa_from_ip6(get_ip6_ll(&tlv->addr));
|
||||||
|
state->current_tlv_endpos += 8;
|
||||||
return PARSE_IGNORE;
|
return PARSE_IGNORE;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -639,6 +662,7 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
|
|||||||
|
|
||||||
msg->router_id = state->router_id;
|
msg->router_id = state->router_id;
|
||||||
msg->sender = state->saddr;
|
msg->sender = state->saddr;
|
||||||
|
state->current_tlv_endpos += len;
|
||||||
|
|
||||||
return PARSE_SUCCESS;
|
return PARSE_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -765,6 +789,7 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
|
|||||||
return PARSE_ERROR;
|
return PARSE_ERROR;
|
||||||
|
|
||||||
read_ip4_px(&msg->net, tlv->addr, tlv->plen);
|
read_ip4_px(&msg->net, tlv->addr, tlv->plen);
|
||||||
|
state->current_tlv_endpos += BYTES(tlv->plen);
|
||||||
return PARSE_SUCCESS;
|
return PARSE_SUCCESS;
|
||||||
|
|
||||||
case BABEL_AE_IP6:
|
case BABEL_AE_IP6:
|
||||||
@ -775,6 +800,7 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
|
|||||||
return PARSE_ERROR;
|
return PARSE_ERROR;
|
||||||
|
|
||||||
read_ip6_px(&msg->net, tlv->addr, tlv->plen);
|
read_ip6_px(&msg->net, tlv->addr, tlv->plen);
|
||||||
|
state->current_tlv_endpos += BYTES(tlv->plen);
|
||||||
return PARSE_SUCCESS;
|
return PARSE_SUCCESS;
|
||||||
|
|
||||||
case BABEL_AE_IP6_LL:
|
case BABEL_AE_IP6_LL:
|
||||||
@ -851,6 +877,7 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
|
|||||||
return PARSE_ERROR;
|
return PARSE_ERROR;
|
||||||
|
|
||||||
read_ip4_px(&msg->net, tlv->addr, tlv->plen);
|
read_ip4_px(&msg->net, tlv->addr, tlv->plen);
|
||||||
|
state->current_tlv_endpos += BYTES(tlv->plen);
|
||||||
return PARSE_SUCCESS;
|
return PARSE_SUCCESS;
|
||||||
|
|
||||||
case BABEL_AE_IP6:
|
case BABEL_AE_IP6:
|
||||||
@ -861,6 +888,7 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
|
|||||||
return PARSE_ERROR;
|
return PARSE_ERROR;
|
||||||
|
|
||||||
read_ip6_px(&msg->net, tlv->addr, tlv->plen);
|
read_ip6_px(&msg->net, tlv->addr, tlv->plen);
|
||||||
|
state->current_tlv_endpos += BYTES(tlv->plen);
|
||||||
return PARSE_SUCCESS;
|
return PARSE_SUCCESS;
|
||||||
|
|
||||||
case BABEL_AE_IP6_LL:
|
case BABEL_AE_IP6_LL:
|
||||||
@ -907,6 +935,42 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
babel_read_subtlvs(struct babel_tlv *hdr,
|
||||||
|
union babel_msg *msg UNUSED,
|
||||||
|
struct babel_parse_state *state)
|
||||||
|
{
|
||||||
|
struct babel_tlv *tlv;
|
||||||
|
|
||||||
|
for (tlv = (void *) hdr + state->current_tlv_endpos;
|
||||||
|
tlv < hdr + TLV_LENGTH(hdr);
|
||||||
|
tlv = NEXT_TLV(tlv))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The subtlv type space is non-contiguous (due to the mandatory bit), so
|
||||||
|
* use a switch for dispatch instead of the mapping array we use for TLVs
|
||||||
|
*/
|
||||||
|
switch (tlv->type)
|
||||||
|
{
|
||||||
|
case BABEL_SUBTLV_PAD1:
|
||||||
|
case BABEL_SUBTLV_PADN:
|
||||||
|
/* FIXME: Framing errors in PADN are silently ignored, see babel_process_packet() */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Unknown mandatory subtlv; PARSE_IGNORE ignores the whole TLV */
|
||||||
|
if (tlv->type > 128)
|
||||||
|
{
|
||||||
|
DBG("Babel: Mandatory subtlv %d found; skipping TLV\n", tlv->type);
|
||||||
|
return PARSE_IGNORE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PARSE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
babel_read_tlv(struct babel_tlv *hdr,
|
babel_read_tlv(struct babel_tlv *hdr,
|
||||||
union babel_msg *msg,
|
union babel_msg *msg,
|
||||||
@ -920,8 +984,14 @@ babel_read_tlv(struct babel_tlv *hdr,
|
|||||||
if (TLV_LENGTH(hdr) < tlv_data[hdr->type].min_length)
|
if (TLV_LENGTH(hdr) < tlv_data[hdr->type].min_length)
|
||||||
return PARSE_ERROR;
|
return PARSE_ERROR;
|
||||||
|
|
||||||
|
state->current_tlv_endpos = tlv_data[hdr->type].min_length;
|
||||||
memset(msg, 0, sizeof(*msg));
|
memset(msg, 0, sizeof(*msg));
|
||||||
return tlv_data[hdr->type].read_tlv(hdr, msg, state);
|
|
||||||
|
int res = tlv_data[hdr->type].read_tlv(hdr, msg, state);
|
||||||
|
if (res != PARSE_SUCCESS)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
return babel_read_subtlvs(hdr, msg, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint
|
static uint
|
||||||
|
Loading…
Reference in New Issue
Block a user