diff options
Diffstat (limited to 'proto/babel/packets.c')
-rw-r--r-- | proto/babel/packets.c | 169 |
1 files changed, 159 insertions, 10 deletions
diff --git a/proto/babel/packets.c b/proto/babel/packets.c index dd86222a..59678678 100644 --- a/proto/babel/packets.c +++ b/proto/babel/packets.c @@ -105,6 +105,13 @@ struct babel_tlv_seqno_request { u8 addr[0]; } PACKED; +struct babel_subtlv_source_prefix { + u8 type; + u8 length; + u8 plen; + u8 addr[0]; +} PACKED; + /* Hello flags */ #define BABEL_HF_UNICAST 0x8000 @@ -127,6 +134,7 @@ struct babel_parse_state { 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) */ + u8 sadr_enabled; }; enum parse_result { @@ -237,6 +245,7 @@ static int babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *msg, stru static int babel_read_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state); static int babel_read_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state); static int babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state); +static int babel_read_source_prefix(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state); static uint babel_write_ack(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); static uint babel_write_hello(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); @@ -244,6 +253,7 @@ static uint babel_write_ihu(struct babel_tlv *hdr, union babel_msg *msg, struct static uint babel_write_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); static uint babel_write_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); static uint babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); +static int babel_write_source_prefix(struct babel_tlv *hdr, net_addr *net, uint max_len); struct babel_tlv_data { u8 min_length; @@ -640,6 +650,9 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m, ip6_addr prefix6 = get_ip6(buf); net_fill_ip6(&msg->net, prefix6, tlv->plen); + if (state->sadr_enabled) + net_make_ip6_sadr(&msg->net); + if (tlv->flags & BABEL_UF_DEF_PREFIX) { put_ip6(state->def_ip6_prefix, prefix6); @@ -770,12 +783,21 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m, put_u16(&tlv->seqno, msg->seqno); put_u16(&tlv->metric, msg->metric); + if (msg->net.type == NET_IP6_SADR) + { + int l = babel_write_source_prefix(hdr, &msg->net, max_len - (len0 + len)); + if (l < 0) + return 0; + + len += l; + } + return len0 + len; } static int babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m, - struct babel_parse_state *state UNUSED) + struct babel_parse_state *state) { struct babel_tlv_route_request *tlv = (void *) hdr; struct babel_msg_route_request *msg = &m->route_request; @@ -812,6 +834,10 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m, read_ip6_px(&msg->net, tlv->addr, tlv->plen); state->current_tlv_endpos += BYTES(tlv->plen); + + if (state->sadr_enabled) + net_make_ip6_sadr(&msg->net); + return PARSE_SUCCESS; case BABEL_AE_IP6_LL: @@ -856,6 +882,15 @@ babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m, put_ip6_px(tlv->addr, &msg->net); } + if (msg->net.type == NET_IP6_SADR) + { + int l = babel_write_source_prefix(hdr, &msg->net, max_len - len); + if (l < 0) + return 0; + + len += l; + } + return len; } @@ -900,6 +935,10 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m, read_ip6_px(&msg->net, tlv->addr, tlv->plen); state->current_tlv_endpos += BYTES(tlv->plen); + + if (state->sadr_enabled) + net_make_ip6_sadr(&msg->net); + return PARSE_SUCCESS; case BABEL_AE_IP6_LL: @@ -943,38 +982,147 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m, tlv->hop_count = msg->hop_count; put_u64(&tlv->router_id, msg->router_id); + if (msg->net.type == NET_IP6_SADR) + { + int l = babel_write_source_prefix(hdr, &msg->net, max_len - len); + if (l < 0) + return 0; + + len += l; + } + return len; } +static int +babel_read_source_prefix(struct babel_tlv *hdr, union babel_msg *msg, + struct babel_parse_state *state UNUSED) +{ + struct babel_subtlv_source_prefix *tlv = (void *) hdr; + net_addr_ip6_sadr *net; + + /* + * We would like to skip the sub-TLV if SADR is not enabled, but we do not + * know AF of the enclosing TLV yet. We will do that later. + */ + + /* Check internal consistency */ + if ((tlv->length < 1) || + (tlv->plen > IP6_MAX_PREFIX_LENGTH) || + (tlv->length < (1 + BYTES(tlv->plen)))) + return PARSE_ERROR; + + /* Plen MUST NOT be 0 */ + if (tlv->plen == 0) + return PARSE_ERROR; + + switch(msg->type) + { + case BABEL_TLV_UPDATE: + /* Wildcard updates with source prefix MUST be silently ignored */ + if (msg->update.wildcard) + return PARSE_IGNORE; + + net = (void *) &msg->update.net; + break; + + case BABEL_TLV_ROUTE_REQUEST: + /* Wildcard requests with source addresses MUST be silently ignored */ + if (msg->route_request.full) + return PARSE_IGNORE; + + net = (void *) &msg->route_request.net; + break; + + case BABEL_TLV_SEQNO_REQUEST: + net = (void *) &msg->seqno_request.net; + break; + + default: + return PARSE_ERROR; + } + + /* If SADR is active, the net has appropriate type */ + if (net->type != NET_IP6_SADR) + return PARSE_IGNORE; + + /* Duplicate Source Prefix sub-TLV; SHOULD ignore whole TLV */ + if (net->src_pxlen > 0) + return PARSE_IGNORE; + + net_addr_ip6 src; + read_ip6_px((void *) &src, tlv->addr, tlv->plen); + net->src_prefix = src.prefix; + net->src_pxlen = src.pxlen; + + return PARSE_SUCCESS; +} + +static int +babel_write_source_prefix(struct babel_tlv *hdr, net_addr *n, uint max_len) +{ + struct babel_subtlv_source_prefix *tlv = (void *) NEXT_TLV(hdr); + net_addr_ip6_sadr *net = (void *) n; + + /* Do not use this sub-TLV for default prefix */ + if (net->src_pxlen == 0) + return 0; + + uint len = sizeof(*tlv) + BYTES(net->src_pxlen); + + if (len > max_len) + return -1; + + TLV_HDR(tlv, BABEL_SUBTLV_SOURCE_PREFIX, len); + hdr->length += len; + + net_addr_ip6 src = NET_ADDR_IP6(net->src_prefix, net->src_pxlen); + tlv->plen = src.pxlen; + put_ip6_px(tlv->addr, (void *) &src); + + return len; +} + + static inline int babel_read_subtlvs(struct babel_tlv *hdr, - union babel_msg *msg UNUSED, + union babel_msg *msg, struct babel_parse_state *state) { struct babel_tlv *tlv; + byte *pos, *end = (byte *) hdr + TLV_LENGTH(hdr); + int res; for (tlv = (void *) hdr + state->current_tlv_endpos; - (void *) tlv < (void *) hdr + TLV_LENGTH(hdr); + (byte *) tlv < end; tlv = NEXT_TLV(tlv)) { + /* Ugly special case */ + if (tlv->type == BABEL_TLV_PAD1) + continue; + + /* The end of the common TLV header */ + pos = (byte *)tlv + sizeof(struct babel_tlv); + if ((pos > end) || (pos + tlv->length > end)) + return PARSE_ERROR; + /* * 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() */ + case BABEL_SUBTLV_SOURCE_PREFIX: + res = babel_read_source_prefix(tlv, msg, state); + if (res != PARSE_SUCCESS) + return res; break; + case BABEL_SUBTLV_PADN: 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); + if (tlv->type >= 128) return PARSE_IGNORE; - } break; } } @@ -1197,6 +1345,7 @@ babel_process_packet(struct babel_pkt_header *pkt, int len, .ifa = ifa, .saddr = saddr, .next_hop_ip6 = saddr, + .sadr_enabled = babel_sadr_enabled(p), }; if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION)) |