diff options
-rw-r--r-- | proto/babel/babel.c | 156 | ||||
-rw-r--r-- | proto/babel/babel.h | 12 | ||||
-rw-r--r-- | proto/babel/config.Y | 6 | ||||
-rw-r--r-- | proto/babel/packets.c | 199 |
4 files changed, 307 insertions, 66 deletions
diff --git a/proto/babel/babel.c b/proto/babel/babel.c index 1b1d9f62..67a59df6 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -78,13 +78,15 @@ babel_init_entry(void *E) static inline struct babel_entry * babel_find_entry(struct babel_proto *p, const net_addr *n) { - return fib_find(&p->rtable, n); + struct fib *rtable = (n->type == NET_IP4) ? &p->ip4_rtable : &p->ip6_rtable; + return fib_find(rtable, n); } static struct babel_entry * babel_get_entry(struct babel_proto *p, const net_addr *n) { - struct babel_entry *e = fib_get(&p->rtable, n); + struct fib *rtable = (n->type == NET_IP4) ? &p->ip4_rtable : &p->ip6_rtable; + struct babel_entry *e = fib_get(rtable, n); e->proto = p; return e; } @@ -224,15 +226,15 @@ babel_refresh_route(struct babel_route *r) } static void -babel_expire_routes(struct babel_proto *p) +babel_expire_routes_(struct babel_proto *p UNUSED, struct fib *rtable) { struct babel_route *r, *rx; struct fib_iterator fit; - FIB_ITERATE_INIT(&fit, &p->rtable); + FIB_ITERATE_INIT(&fit, rtable); loop: - FIB_ITERATE_START(&p->rtable, &fit, struct babel_entry, e) + FIB_ITERATE_START(rtable, &fit, struct babel_entry, e) { int changed = 0; @@ -253,7 +255,7 @@ loop: /* * We have to restart the iteration because there may be a cascade of * synchronous events babel_select_route() -> nest table change -> - * babel_rt_notify() -> p->rtable change, invalidating hidden variables. + * babel_rt_notify() -> rtable change, invalidating hidden variables. */ FIB_ITERATE_PUT(&fit); @@ -267,13 +269,20 @@ loop: if (EMPTY_LIST(e->sources) && EMPTY_LIST(e->routes)) { FIB_ITERATE_PUT(&fit); - fib_delete(&p->rtable, e); + fib_delete(rtable, e); goto loop; } } FIB_ITERATE_END; } +static void +babel_expire_routes(struct babel_proto *p) +{ + babel_expire_routes_(p, &p->ip4_rtable); + babel_expire_routes_(p, &p->ip6_rtable); +} + static struct babel_neighbor * babel_find_neighbor(struct babel_iface *ifa, ip_addr addr) { @@ -468,6 +477,7 @@ static void babel_announce_rte(struct babel_proto *p, struct babel_entry *e) { struct babel_route *r = e->selected_in; + struct channel *c = (e->n.addr->type == NET_IP4) ? p->ip4_channel : p->ip6_channel; if (r) { @@ -490,12 +500,12 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e) rte->u.babel.router_id = r->router_id; rte->pflags = 0; - rte_update(&p->p, e->n.addr, rte); + rte_update2(c, e->n.addr, rte, p->p.main_source); } else { /* Retraction */ - rte_update(&p->p, e->n.addr, NULL); + rte_update2(c, e->n.addr, NULL, p->p.main_source); } } @@ -740,11 +750,11 @@ babel_unicast_seqno_request(struct babel_route *r) * transmitted entry is updated. */ static void -babel_send_update(struct babel_iface *ifa, bird_clock_t changed) +babel_send_update_(struct babel_iface *ifa, bird_clock_t changed, struct fib *rtable) { struct babel_proto *p = ifa->proto; - FIB_WALK(&p->rtable, struct babel_entry, e) + FIB_WALK(rtable, struct babel_entry, e) { struct babel_route *r = e->selected_out; @@ -774,6 +784,9 @@ babel_send_update(struct babel_iface *ifa, bird_clock_t changed) msg.update.router_id = r->router_id; net_copy(&msg.update.net, e->n.addr); + msg.update.next_hop = ((e->n.addr->type == NET_IP4) ? + ifa->next_hop_ip4 : ifa->next_hop_ip6); + babel_enqueue(&msg, ifa); /* Update feasibility distance for redistributed routes */ @@ -794,6 +807,15 @@ babel_send_update(struct babel_iface *ifa, bird_clock_t changed) } static void +babel_send_update(struct babel_iface *ifa, bird_clock_t changed) +{ + struct babel_proto *p = ifa->proto; + + babel_send_update_(ifa, changed, &p->ip4_rtable); + babel_send_update_(ifa, changed, &p->ip6_rtable); +} + +static void babel_trigger_iface_update(struct babel_iface *ifa) { struct babel_proto *p = ifa->proto; @@ -1073,6 +1095,13 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa) return; } + struct channel *c = (msg->net.type == NET_IP4) ? p->ip4_channel : p->ip6_channel; + if (!c || (c->channel_state != CS_UP)) + { + DBG("Babel: Ignoring update for inactive address family.\n"); + return; + } + /* * RFC section 3.5.4: * @@ -1475,14 +1504,26 @@ babel_add_iface(struct babel_proto *p, struct iface *new, struct babel_iface_con add_tail(&p->interfaces, NODE ifa); + ip_addr addr4 = IPA_NONE; struct ifa *addr; WALK_LIST(addr, new->addrs) + { if (ipa_is_link_local(addr->ip)) ifa->addr = addr->ip; + if (ipa_zero(addr4) && ipa_is_ip4(addr->ip)) + addr4 = addr->ip; + } + + ifa->next_hop_ip4 = ipa_nonzero(ic->next_hop_ip4) ? ic->next_hop_ip4 : addr4; + ifa->next_hop_ip6 = ipa_nonzero(ic->next_hop_ip6) ? ic->next_hop_ip6 : ifa->addr; + if (ipa_zero(ifa->addr)) log(L_WARN "%s: Cannot find link-local addr on %s", p->p.name, new->name); + if (ipa_zero(ifa->next_hop_ip4) && p->ip4_channel) + log(L_WARN "%s: Cannot find IPv4 next hop addr on %s", p->p.name, new->name); + init_list(&ifa->neigh_list); ifa->hello_seqno = 1; @@ -1574,6 +1615,26 @@ babel_reconfigure_iface(struct babel_proto *p, struct babel_iface *ifa, struct b ifa->cf = new; + if (ipa_nonzero(new->next_hop_ip4)) + ifa->next_hop_ip4 = new->next_hop_ip4; + else + { + ifa->next_hop_ip4 = IPA_NONE; + + struct ifa *addr; + WALK_LIST(addr, ifa->iface->addrs) + if (ipa_is_ip4(addr->ip)) + { + ifa->next_hop_ip4 = addr->ip; + break; + } + } + + ifa->next_hop_ip6 = ipa_nonzero(new->next_hop_ip6) ? new->next_hop_ip6 : ifa->addr; + + if (ipa_zero(ifa->next_hop_ip4) && p->ip4_channel) + log(L_WARN "%s: Cannot find IPv4 next hop addr on %s", p->p.name, ifa->ifname); + if (ifa->next_hello > (now + new->hello_interval)) ifa->next_hello = now + (random() % new->hello_interval) + 1; @@ -1680,9 +1741,10 @@ babel_dump_iface(struct babel_iface *ifa) { struct babel_neighbor *n; - debug("Babel: Interface %s addr %I rxcost %d type %d hello seqno %d intervals %d %d\n", + debug("Babel: Interface %s addr %I rxcost %d type %d hello seqno %d intervals %d %d", ifa->ifname, ifa->addr, ifa->cf->rxcost, ifa->cf->type, ifa->hello_seqno, ifa->cf->hello_interval, ifa->cf->update_interval); + debug(" next hop v4 %I next hop v6 %I\n", ifa->next_hop_ip4, ifa->next_hop_ip6); WALK_LIST(n, ifa->neigh_list) { debug(" "); babel_dump_neighbor(n); } @@ -1699,7 +1761,12 @@ babel_dump(struct proto *P) WALK_LIST(ifa, p->interfaces) babel_dump_iface(ifa); - FIB_WALK(&p->rtable, struct babel_entry, e) + FIB_WALK(&p->ip4_rtable, struct babel_entry, e) + { + babel_dump_entry(e); + } + FIB_WALK_END; + FIB_WALK(&p->ip6_rtable, struct babel_entry, e) { babel_dump_entry(e); } @@ -1749,8 +1816,9 @@ babel_show_interfaces(struct proto *P, char *iff) } cli_msg(-1023, "%s:", p->p.name); - cli_msg(-1023, "%-10s %-6s %7s %6s %6s", - "Interface", "State", "RX cost", "Nbrs", "Timer"); + cli_msg(-1023, "%-10s %-6s %7s %6s %6s %-15s %s", + "Interface", "State", "RX cost", "Nbrs", "Timer", + "Next hop (v4)", "Next hop (v6)"); WALK_LIST(ifa, p->interfaces) { @@ -1762,8 +1830,10 @@ babel_show_interfaces(struct proto *P, char *iff) nbrs++; int timer = MIN(ifa->next_regular, ifa->next_hello) - now; - cli_msg(-1023, "%-10s %-6s %7u %6u %6u", - ifa->iface->name, (ifa->up ? "Up" : "Down"), ifa->cf->rxcost, nbrs, MAX(timer, 0)); + cli_msg(-1023, "%-10s %-6s %7u %6u %6u %-15I %I", + ifa->iface->name, (ifa->up ? "Up" : "Down"), + ifa->cf->rxcost, nbrs, MAX(timer, 0), + ifa->next_hop_ip4, ifa->next_hop_ip6); } cli_msg(0, ""); @@ -1808,27 +1878,15 @@ babel_show_neighbors(struct proto *P, char *iff) cli_msg(0, ""); } -void -babel_show_entries(struct proto *P) +static void +babel_show_entries_(struct babel_proto *p, struct fib *rtable) { - struct babel_proto *p = (void *) P; struct babel_source *s = NULL; struct babel_route *r = NULL; char ridbuf[ROUTER_ID_64_LENGTH+1]; - if (p->p.proto_state != PS_UP) - { - cli_msg(-1025, "%s: is not up", p->p.name); - cli_msg(0, ""); - return; - } - - cli_msg(-1025, "%s:", p->p.name); - cli_msg(-1025, "%-29s %-23s %6s %5s %7s %7s", - "Prefix", "Router ID", "Metric", "Seqno", "Expires", "Sources"); - - FIB_WALK(&p->rtable, struct babel_entry, e) + FIB_WALK(rtable, struct babel_entry, e) { r = e->selected_in ? e->selected_in : e->selected_out; @@ -1853,6 +1911,26 @@ babel_show_entries(struct proto *P) } } FIB_WALK_END; +} + +void +babel_show_entries(struct proto *P) +{ + struct babel_proto *p = (void *) P; + + if (p->p.proto_state != PS_UP) + { + cli_msg(-1025, "%s: is not up", p->p.name); + cli_msg(0, ""); + return; + } + + cli_msg(-1025, "%s:", p->p.name); + cli_msg(-1025, "%-29s %-23s %6s %5s %7s %7s", + "Prefix", "Router ID", "Metric", "Seqno", "Expires", "Sources"); + + babel_show_entries_(p, &p->ip4_rtable); + babel_show_entries_(p, &p->ip6_rtable); cli_msg(0, ""); } @@ -2028,8 +2106,10 @@ static struct proto * babel_init(struct proto_config *CF) { struct proto *P = proto_new(CF); + struct babel_proto *p = (void *) P; - P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF)); + proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4)); + proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6)); P->if_notify = babel_if_notify; P->rt_notify = babel_rt_notify; @@ -2048,8 +2128,11 @@ babel_start(struct proto *P) struct babel_proto *p = (void *) P; struct babel_config *cf = (void *) P->cf; - fib_init(&p->rtable, P->pool, NET_IP6, sizeof(struct babel_entry), + fib_init(&p->ip4_rtable, P->pool, NET_IP4, sizeof(struct babel_entry), OFFSETOF(struct babel_entry, n), 0, babel_init_entry); + fib_init(&p->ip6_rtable, P->pool, NET_IP6, sizeof(struct babel_entry), + OFFSETOF(struct babel_entry, n), 0, babel_init_entry); + init_list(&p->interfaces); p->timer = tm_new_set(P->pool, babel_timer, p, 0, 1); tm_start(p->timer, 2); @@ -2099,7 +2182,8 @@ babel_reconfigure(struct proto *P, struct proto_config *CF) TRACE(D_EVENTS, "Reconfiguring"); - if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF))) + if (!proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4)) || + !proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6))) return 0; p->p.cf = CF; @@ -2117,7 +2201,7 @@ struct protocol proto_babel = { .template = "babel%d", .attr_class = EAP_BABEL, .preference = DEF_PREF_BABEL, - .channel_mask = NB_IP6, + .channel_mask = NB_IP, .proto_size = sizeof(struct babel_proto), .config_size = sizeof(struct babel_config), .init = babel_init, diff --git a/proto/babel/babel.h b/proto/babel/babel.h index 792c9d60..26f52455 100644 --- a/proto/babel/babel.h +++ b/proto/babel/babel.h @@ -116,12 +116,20 @@ struct babel_iface_config { u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */ int tx_tos; int tx_priority; + + ip_addr next_hop_ip4; + ip_addr next_hop_ip6; }; struct babel_proto { struct proto p; timer *timer; - struct fib rtable; + struct fib ip4_rtable; + struct fib ip6_rtable; + + struct channel *ip4_channel; + struct channel *ip6_channel; + list interfaces; /* Interfaces we really know about (struct babel_iface) */ u64 router_id; u16 update_seqno; /* To be increased on request */ @@ -151,6 +159,8 @@ struct babel_iface { char *ifname; sock *sk; ip_addr addr; + ip_addr next_hop_ip4; + ip_addr next_hop_ip6; int tx_length; list neigh_list; /* List of neighbors seen on this iface (struct babel_neighbor) */ list msg_queue; diff --git a/proto/babel/config.Y b/proto/babel/config.Y index cf8983fa..93c92790 100644 --- a/proto/babel/config.Y +++ b/proto/babel/config.Y @@ -21,7 +21,8 @@ CF_DEFINES CF_DECLS CF_KEYWORDS(BABEL, METRIC, RXCOST, HELLO, UPDATE, INTERVAL, PORT, WIRED, -WIRELESS, RX, TX, BUFFER, LENGTH, CHECK, LINK, BABEL_METRIC) + WIRELESS, RX, TX, BUFFER, LENGTH, CHECK, LINK, BABEL_METRIC, NEXT, HOP, + IPV4, IPV6) CF_GRAMMAR @@ -30,7 +31,6 @@ CF_ADDTO(proto, babel_proto) babel_proto_start: proto_start BABEL { this_proto = proto_config_new(&proto_babel, $1); - this_proto->net_type = NET_IP6; init_list(&BABEL_CFG->iface_list); }; @@ -98,6 +98,8 @@ babel_iface_item: | TX tos { BABEL_IFACE->tx_tos = $2; } | TX PRIORITY expr { BABEL_IFACE->tx_priority = $3; } | CHECK LINK bool { BABEL_IFACE->check_link = $3; } + | NEXT HOP IPV4 ipa { BABEL_IFACE->next_hop_ip4 = $4; if (!ipa_is_ip4($4)) cf_error("Must be an IPv4 address"); } + | NEXT HOP IPV6 ipa { BABEL_IFACE->next_hop_ip6 = $4; if (!ipa_is_ip6($4)) cf_error("Must be an IPv6 address"); } ; babel_iface_opts: diff --git a/proto/babel/packets.c b/proto/babel/packets.c index 70cfc196..b52c2ddf 100644 --- a/proto/babel/packets.c +++ b/proto/babel/packets.c @@ -112,7 +112,8 @@ struct babel_parse_state { struct babel_proto *proto; struct babel_iface *ifa; ip_addr saddr; - ip_addr next_hop; + ip_addr next_hop_ip4; + ip_addr next_hop_ip6; u64 router_id; /* Router ID used in subsequent updates */ u8 def_ip6_prefix[16]; /* Implicit IPv6 prefix in network order */ u8 def_ip4_prefix[4]; /* Implicit IPv4 prefix in network order */ @@ -130,7 +131,8 @@ enum parse_result { struct babel_write_state { u64 router_id; u8 router_id_seen; -// ip_addr next_hop; + ip_addr next_hop_ip4; + ip_addr next_hop_ip6; }; @@ -163,6 +165,21 @@ put_time16(void *p, u16 v) } static inline void +read_ip4_px(net_addr *n, const void *p, uint plen) +{ + ip4_addr addr = {0}; + memcpy(&addr, p, BYTES(plen)); + net_fill_ip4(n, ip4_ntoh(addr), plen); +} + +static inline void +put_ip4_px(void *p, net_addr *n) +{ + ip4_addr addr = ip4_hton(net4_prefix(n)); + memcpy(p, &addr, NET_SIZE(n)); +} + +static inline void read_ip6_px(net_addr *n, const void *p, uint plen) { ip6_addr addr = IPA_NONE; @@ -432,21 +449,24 @@ babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED, return PARSE_ERROR; case BABEL_AE_IP4: - /* TODO */ + if (TLV_OPT_LENGTH(tlv) < sizeof(ip4_addr)) + return PARSE_ERROR; + + state->next_hop_ip4 = ipa_from_ip4(get_ip4(&tlv->addr)); return PARSE_IGNORE; case BABEL_AE_IP6: if (TLV_OPT_LENGTH(tlv) < sizeof(ip6_addr)) return PARSE_ERROR; - state->next_hop = ipa_from_ip6(get_ip6(&tlv->addr)); + state->next_hop_ip6 = ipa_from_ip6(get_ip6(&tlv->addr)); return PARSE_IGNORE; case BABEL_AE_IP6_LL: if (TLV_OPT_LENGTH(tlv) < 8) return PARSE_ERROR; - state->next_hop = ipa_from_ip6(get_ip6_ll(&tlv->addr)); + state->next_hop_ip6 = ipa_from_ip6(get_ip6_ll(&tlv->addr)); return PARSE_IGNORE; default: @@ -456,6 +476,51 @@ babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED, return PARSE_IGNORE; } +/* This is called directly from babel_write_update() and returns -1 if a next + hop should be written but there is not enough space. */ +static int +babel_write_next_hop(struct babel_tlv *hdr, ip_addr addr, + struct babel_write_state *state, uint max_len) +{ + struct babel_tlv_next_hop *tlv = (void *) hdr; + + if (ipa_zero(addr)) + { + /* Should not happen */ + return 0; + } + else if (ipa_is_ip4(addr) && !ipa_equal(addr, state->next_hop_ip4)) + { + uint len = sizeof(struct babel_tlv_next_hop) + sizeof(ip4_addr); + if (len > max_len) + return -1; + + TLV_HDR(tlv, BABEL_TLV_NEXT_HOP, len); + + tlv->ae = BABEL_AE_IP4; + put_ip4(&tlv->addr, ipa_to_ip4(addr)); + state->next_hop_ip4 = addr; + + return len; + } + else if (ipa_is_ip6(addr) && !ipa_equal(addr, state->next_hop_ip6)) + { + uint len = sizeof(struct babel_tlv_next_hop) + sizeof(ip6_addr); + if (len > max_len) + return -1; + + TLV_HDR(tlv, BABEL_TLV_NEXT_HOP, len); + + tlv->ae = BABEL_AE_IP6; + put_ip6(&tlv->addr, ipa_to_ip6(addr)); + state->next_hop_ip6 = addr; + + return len; + } + + return 0; +} + static int babel_read_update(struct babel_tlv *hdr, union babel_msg *m, struct babel_parse_state *state) @@ -488,8 +553,33 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m, break; case BABEL_AE_IP4: - /* TODO */ - return PARSE_IGNORE; + if (tlv->plen > IP4_MAX_PREFIX_LENGTH) + return PARSE_ERROR; + + /* Cannot omit data if there is no saved prefix */ + if (tlv->omitted && !state->def_ip4_prefix_seen) + return PARSE_ERROR; + + /* Need next hop for v4 routes */ + if (ipa_zero(state->next_hop_ip4)) + return PARSE_ERROR; + + /* Merge saved prefix and received prefix parts */ + memcpy(buf, state->def_ip4_prefix, tlv->omitted); + memcpy(buf + tlv->omitted, tlv->addr, len); + + ip4_addr prefix4 = get_ip4(buf); + net_fill_ip4(&msg->net, prefix4, tlv->plen); + + if (tlv->flags & BABEL_FLAG_DEF_PREFIX) + { + put_ip4(state->def_ip4_prefix, prefix4); + state->def_ip4_prefix_seen = 1; + } + + msg->next_hop = state->next_hop_ip4; + + break; case BABEL_AE_IP6: if (tlv->plen > IP6_MAX_PREFIX_LENGTH) @@ -503,20 +593,23 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m, memcpy(buf, state->def_ip6_prefix, tlv->omitted); memcpy(buf + tlv->omitted, tlv->addr, len); - ip6_addr prefix = get_ip6(buf); - net_fill_ip6(&msg->net, prefix, tlv->plen); + ip6_addr prefix6 = get_ip6(buf); + net_fill_ip6(&msg->net, prefix6, tlv->plen); if (tlv->flags & BABEL_FLAG_DEF_PREFIX) { - put_ip6(state->def_ip6_prefix, prefix); + put_ip6(state->def_ip6_prefix, prefix6); state->def_ip6_prefix_seen = 1; } if (tlv->flags & BABEL_FLAG_ROUTER_ID) { - state->router_id = ((u64) _I2(prefix)) << 32 | _I3(prefix); + state->router_id = ((u64) _I2(prefix6)) << 32 | _I3(prefix6); state->router_id_seen = 1; } + + msg->next_hop = state->next_hop_ip6; + break; case BABEL_AE_IP6_LL: @@ -535,7 +628,6 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m, } msg->router_id = state->router_id; - msg->next_hop = state->next_hop; msg->sender = state->saddr; return PARSE_SUCCESS; @@ -545,7 +637,6 @@ static uint babel_write_update(struct babel_tlv *hdr, union babel_msg *m, struct babel_write_state *state, uint max_len) { - struct babel_tlv_update *tlv = (void *) hdr; struct babel_msg_update *msg = &m->update; uint len0 = 0; @@ -554,15 +645,34 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m, * both of them. There is enough space for the Router-ID TLV, because * sizeof(struct babel_tlv_router_id) == sizeof(struct babel_tlv_update). * - * Router ID is not used for retractions, so do not us it in such case. + * Router ID is not used for retractions, so do not use it in such case. */ if ((msg->metric < BABEL_INFINITY) && (!state->router_id_seen || (msg->router_id != state->router_id))) { len0 = babel_write_router_id(hdr, msg->router_id, state, max_len); - tlv = (struct babel_tlv_update *) NEXT_TLV(tlv); + hdr = NEXT_TLV(hdr); } + /* + * We also may add Next Hop TLV for regular updates. It may fail for not + * enough space or it may be unnecessary as the next hop is the same as the + * last one already announced. So we handle all three cases. + */ + if (msg->metric < BABEL_INFINITY) + { + int l = babel_write_next_hop(hdr, msg->next_hop, state, max_len - len0); + if (l < 0) + return 0; + + if (l) + { + len0 += l; + hdr = NEXT_TLV(hdr); + } + } + + struct babel_tlv_update *tlv = (void *) hdr; uint len = sizeof(struct babel_tlv_update) + NET_SIZE(&msg->net); if (len0 + len > max_len) @@ -576,6 +686,12 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m, tlv->ae = BABEL_AE_WILDCARD; tlv->plen = 0; } + else if (msg->net.type == NET_IP4) + { + tlv->ae = BABEL_AE_IP4; + tlv->plen = net4_pxlen(&msg->net); + put_ip4_px(tlv->addr, &msg->net); + } else { tlv->ae = BABEL_AE_IP6; @@ -610,8 +726,14 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m, return PARSE_SUCCESS; case BABEL_AE_IP4: - /* TODO */ - return PARSE_IGNORE; + if (tlv->plen > IP4_MAX_PREFIX_LENGTH) + return PARSE_ERROR; + + if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen)) + return PARSE_ERROR; + + read_ip4_px(&msg->net, tlv->addr, tlv->plen); + return PARSE_SUCCESS; case BABEL_AE_IP6: if (tlv->plen > IP6_MAX_PREFIX_LENGTH) @@ -652,6 +774,12 @@ babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m, tlv->ae = BABEL_AE_WILDCARD; tlv->plen = 0; } + else if (msg->net.type == NET_IP4) + { + tlv->ae = BABEL_AE_IP4; + tlv->plen = net4_pxlen(&msg->net); + put_ip4_px(tlv->addr, &msg->net); + } else { tlv->ae = BABEL_AE_IP6; @@ -684,8 +812,14 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m, return PARSE_ERROR; case BABEL_AE_IP4: - /* TODO */ - return PARSE_IGNORE; + if (tlv->plen > IP4_MAX_PREFIX_LENGTH) + return PARSE_ERROR; + + if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen)) + return PARSE_ERROR; + + read_ip4_px(&msg->net, tlv->addr, tlv->plen); + return PARSE_SUCCESS; case BABEL_AE_IP6: if (tlv->plen > IP6_MAX_PREFIX_LENGTH) @@ -720,12 +854,23 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m, return 0; TLV_HDR(tlv, BABEL_TLV_SEQNO_REQUEST, len); - tlv->ae = BABEL_AE_IP6; - tlv->plen = net6_pxlen(&msg->net); + + if (msg->net.type == NET_IP4) + { + tlv->ae = BABEL_AE_IP4; + tlv->plen = net4_pxlen(&msg->net); + put_ip4_px(tlv->addr, &msg->net); + } + else + { + tlv->ae = BABEL_AE_IP6; + tlv->plen = net6_pxlen(&msg->net); + put_ip6_px(tlv->addr, &msg->net); + } + put_u16(&tlv->seqno, msg->seqno); tlv->hop_count = msg->hop_count; put_u64(&tlv->router_id, msg->router_id); - put_ip6_px(tlv->addr, &msg->net); return len; } @@ -799,7 +944,7 @@ static uint babel_write_queue(struct babel_iface *ifa, list *queue) { struct babel_proto *p = ifa->proto; - struct babel_write_state state = {}; + struct babel_write_state state = { .next_hop_ip6 = ifa->addr }; if (EMPTY_LIST(*queue)) return 0; @@ -935,10 +1080,10 @@ babel_process_packet(struct babel_pkt_header *pkt, int len, byte *end = (byte *)pkt + plen; struct babel_parse_state state = { - .proto = p, - .ifa = ifa, - .saddr = saddr, - .next_hop = saddr, + .proto = p, + .ifa = ifa, + .saddr = saddr, + .next_hop_ip6 = saddr, }; if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION)) |