summaryrefslogtreecommitdiff
path: root/proto/babel
diff options
context:
space:
mode:
Diffstat (limited to 'proto/babel')
-rw-r--r--proto/babel/babel.h5
-rw-r--r--proto/babel/packets.c78
2 files changed, 79 insertions, 4 deletions
diff --git a/proto/babel/babel.h b/proto/babel/babel.h
index 26f52455..fccb60c9 100644
--- a/proto/babel/babel.h
+++ b/proto/babel/babel.h
@@ -78,6 +78,11 @@ enum babel_tlv_type {
BABEL_TLV_MAX
};
+enum babel_subtlv_type {
+ BABEL_SUBTLV_PAD1 = 0,
+ BABEL_SUBTLV_PADN = 1
+};
+
enum babel_iface_type {
/* In practice, UNDEF and WIRED give equivalent behaviour */
BABEL_IFACE_TYPE_UNDEF = 0,
diff --git a/proto/babel/packets.c b/proto/babel/packets.c
index 72ac4f29..3564c703 100644
--- a/proto/babel/packets.c
+++ b/proto/babel/packets.c
@@ -120,6 +120,7 @@ struct babel_parse_state {
u8 router_id_seen; /* router_id field is valid */
u8 def_ip6_prefix_seen; /* def_ip6_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 {
@@ -379,14 +380,33 @@ babel_read_ihu(struct babel_tlv *hdr, union babel_msg *m,
if (msg->ae >= BABEL_AE_MAX)
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.
- if (msg->ae == BABEL_AE_IP6_LL)
+ /*
+ * We only actually read 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 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)
return PARSE_ERROR;
msg->addr = ipa_from_ip6(get_ip6_ll(&tlv->addr));
+ state->current_tlv_endpos += 8;
+ break;
}
return PARSE_SUCCESS;
@@ -463,6 +483,7 @@ babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED,
return PARSE_ERROR;
state->next_hop_ip4 = ipa_from_ip4(get_ip4(&tlv->addr));
+ state->current_tlv_endpos += sizeof(ip4_addr);
return PARSE_IGNORE;
case BABEL_AE_IP6:
@@ -470,6 +491,7 @@ babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED,
return PARSE_ERROR;
state->next_hop_ip6 = ipa_from_ip6(get_ip6(&tlv->addr));
+ state->current_tlv_endpos += sizeof(ip6_addr);
return PARSE_IGNORE;
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;
state->next_hop_ip6 = ipa_from_ip6(get_ip6_ll(&tlv->addr));
+ state->current_tlv_endpos += 8;
return PARSE_IGNORE;
default:
@@ -639,6 +662,7 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
msg->router_id = state->router_id;
msg->sender = state->saddr;
+ state->current_tlv_endpos += len;
return PARSE_SUCCESS;
}
@@ -765,6 +789,7 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
return PARSE_ERROR;
read_ip4_px(&msg->net, tlv->addr, tlv->plen);
+ state->current_tlv_endpos += BYTES(tlv->plen);
return PARSE_SUCCESS;
case BABEL_AE_IP6:
@@ -775,6 +800,7 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
return PARSE_ERROR;
read_ip6_px(&msg->net, tlv->addr, tlv->plen);
+ state->current_tlv_endpos += BYTES(tlv->plen);
return PARSE_SUCCESS;
case BABEL_AE_IP6_LL:
@@ -851,6 +877,7 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
return PARSE_ERROR;
read_ip4_px(&msg->net, tlv->addr, tlv->plen);
+ state->current_tlv_endpos += BYTES(tlv->plen);
return PARSE_SUCCESS;
case BABEL_AE_IP6:
@@ -861,6 +888,7 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
return PARSE_ERROR;
read_ip6_px(&msg->net, tlv->addr, tlv->plen);
+ state->current_tlv_endpos += BYTES(tlv->plen);
return PARSE_SUCCESS;
case BABEL_AE_IP6_LL:
@@ -908,6 +936,42 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
}
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
babel_read_tlv(struct babel_tlv *hdr,
union babel_msg *msg,
struct babel_parse_state *state)
@@ -920,8 +984,14 @@ babel_read_tlv(struct babel_tlv *hdr,
if (TLV_LENGTH(hdr) < tlv_data[hdr->type].min_length)
return PARSE_ERROR;
+ state->current_tlv_endpos = tlv_data[hdr->type].min_length;
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