Commit 185a0a51 authored by Ondrej Zajicek (work)'s avatar Ondrej Zajicek (work)
Browse files

Babel: Add source-specific routing support

This patch adds support for source-specific routing to the Babel protocol.
It changes the protocol to support both NET_IP6 and NET_IP6_SADR channels
for IPv6 addresses. If only a NET_IP6 channel is configured,
source-specific updates are ignored. Otherwise, non-source-specific
routes are simply treated as source-specific routes with SADR prefix 0.

Thanks to Toke Hoiland-Jorgensen for the original patch.
Minor changes by Ondrej Santiago Zajicek.
parent be17805c
Loading
Loading
Loading
Loading
+44 −14
Original line number Original line Diff line number Diff line
@@ -1935,8 +1935,10 @@ babel_show_neighbors(struct proto *P, char *iff)
}
}


static void
static void
babel_show_entries_(struct babel_proto *p UNUSED, struct fib *rtable)
babel_show_entries_(struct babel_proto *p, struct fib *rtable)
{
{
  int width = babel_sadr_enabled(p) ? -54 : -24;

  FIB_WALK(rtable, struct babel_entry, e)
  FIB_WALK(rtable, struct babel_entry, e)
  {
  {
    struct babel_route *r = NULL;
    struct babel_route *r = NULL;
@@ -1950,13 +1952,13 @@ babel_show_entries_(struct babel_proto *p UNUSED, struct fib *rtable)
      srcs++;
      srcs++;


    if (e->valid)
    if (e->valid)
      cli_msg(-1025, "%-24N %-23lR %6u %5u %7u %7u",
      cli_msg(-1025, "%-*N %-23lR %6u %5u %7u %7u", width,
	      e->n.addr, e->router_id, e->metric, e->seqno, rts, srcs);
	      e->n.addr, e->router_id, e->metric, e->seqno, rts, srcs);
    else if (r = e->selected)
    else if (r = e->selected)
      cli_msg(-1025, "%-24N %-23lR %6u %5u %7u %7u",
      cli_msg(-1025, "%-*N %-23lR %6u %5u %7u %7u", width,
	      e->n.addr, r->router_id, r->metric, r->seqno, rts, srcs);
	      e->n.addr, r->router_id, r->metric, r->seqno, rts, srcs);
    else
    else
      cli_msg(-1025, "%-24N %-23s %6s %5s %7u %7u",
      cli_msg(-1025, "%-*N %-23s %6s %5s %7u %7u", width,
	      e->n.addr, "<none>", "-", "-", rts, srcs);
	      e->n.addr, "<none>", "-", "-", rts, srcs);
  }
  }
  FIB_WALK_END;
  FIB_WALK_END;
@@ -1966,6 +1968,7 @@ void
babel_show_entries(struct proto *P)
babel_show_entries(struct proto *P)
{
{
  struct babel_proto *p = (void *) P;
  struct babel_proto *p = (void *) P;
  int width = babel_sadr_enabled(p) ? -54 : -24;


  if (p->p.proto_state != PS_UP)
  if (p->p.proto_state != PS_UP)
  {
  {
@@ -1975,7 +1978,7 @@ babel_show_entries(struct proto *P)
  }
  }


  cli_msg(-1025, "%s:", p->p.name);
  cli_msg(-1025, "%s:", p->p.name);
  cli_msg(-1025, "%-24s %-23s %6s %5s %7s %7s",
  cli_msg(-1025, "%-*s %-23s %6s %5s %7s %7s", width,
	  "Prefix", "Router ID", "Metric", "Seqno", "Routes", "Sources");
	  "Prefix", "Router ID", "Metric", "Seqno", "Routes", "Sources");


  babel_show_entries_(p, &p->ip4_rtable);
  babel_show_entries_(p, &p->ip4_rtable);
@@ -1985,8 +1988,10 @@ babel_show_entries(struct proto *P)
}
}


static void
static void
babel_show_routes_(struct babel_proto *p UNUSED, struct fib *rtable)
babel_show_routes_(struct babel_proto *p, struct fib *rtable)
{
{
  int width = babel_sadr_enabled(p) ? -54 : -24;

  FIB_WALK(rtable, struct babel_entry, e)
  FIB_WALK(rtable, struct babel_entry, e)
  {
  {
    struct babel_route *r;
    struct babel_route *r;
@@ -1994,7 +1999,7 @@ babel_show_routes_(struct babel_proto *p UNUSED, struct fib *rtable)
    {
    {
      char c = (r == e->selected) ? '*' : (r->feasible ? '+' : ' ');
      char c = (r == e->selected) ? '*' : (r->feasible ? '+' : ' ');
      btime time = r->expires ? r->expires - current_time() : 0;
      btime time = r->expires ? r->expires - current_time() : 0;
      cli_msg(-1025, "%-24N %-25I %-10s %5u %c %5u %7t",
      cli_msg(-1025, "%-*N %-25I %-10s %5u %c %5u %7t", width,
	      e->n.addr, r->next_hop, r->neigh->ifa->ifname,
	      e->n.addr, r->next_hop, r->neigh->ifa->ifname,
	      r->metric, c, r->seqno, MAX(time, 0));
	      r->metric, c, r->seqno, MAX(time, 0));
    }
    }
@@ -2006,6 +2011,7 @@ void
babel_show_routes(struct proto *P)
babel_show_routes(struct proto *P)
{
{
  struct babel_proto *p = (void *) P;
  struct babel_proto *p = (void *) P;
  int width = babel_sadr_enabled(p) ? -54 : -24;


  if (p->p.proto_state != PS_UP)
  if (p->p.proto_state != PS_UP)
  {
  {
@@ -2015,7 +2021,7 @@ babel_show_routes(struct proto *P)
  }
  }


  cli_msg(-1025, "%s:", p->p.name);
  cli_msg(-1025, "%s:", p->p.name);
  cli_msg(-1025, "%-24s %-25s %-9s %6s F %5s %7s",
  cli_msg(-1025, "%-*s %-25s %-9s %6s F %5s %7s", width,
	  "Prefix", "Nexthop", "Interface", "Metric", "Seqno", "Expires");
	  "Prefix", "Nexthop", "Interface", "Metric", "Seqno", "Expires");


  babel_show_routes_(p, &p->ip4_rtable);
  babel_show_routes_(p, &p->ip4_rtable);
@@ -2182,14 +2188,32 @@ babel_rte_same(struct rte *new, struct rte *old)
}
}




static void
babel_postconfig(struct proto_config *CF)
{
  struct babel_config *cf = (void *) CF;
  struct channel_config *ip4, *ip6, *ip6_sadr;

  ip4 = proto_cf_find_channel(CF, NET_IP4);
  ip6 = proto_cf_find_channel(CF, NET_IP6);
  ip6_sadr = proto_cf_find_channel(CF, NET_IP6_SADR);

  if (ip6 && ip6_sadr)
    cf_error("Both ipv6 and ipv6-sadr channels");

  cf->ip4_channel = ip4;
  cf->ip6_channel = ip6 ?: ip6_sadr;
}

static struct proto *
static struct proto *
babel_init(struct proto_config *CF)
babel_init(struct proto_config *CF)
{
{
  struct proto *P = proto_new(CF);
  struct proto *P = proto_new(CF);
  struct babel_proto *p = (void *) P;
  struct babel_proto *p = (void *) P;
  struct babel_config *cf = (void *) CF;


  proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4));
  proto_configure_channel(P, &p->ip4_channel, cf->ip4_channel);
  proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6));
  proto_configure_channel(P, &p->ip6_channel, cf->ip6_channel);


  P->if_notify = babel_if_notify;
  P->if_notify = babel_if_notify;
  P->rt_notify = babel_rt_notify;
  P->rt_notify = babel_rt_notify;
@@ -2207,10 +2231,11 @@ babel_start(struct proto *P)
{
{
  struct babel_proto *p = (void *) P;
  struct babel_proto *p = (void *) P;
  struct babel_config *cf = (void *) P->cf;
  struct babel_config *cf = (void *) P->cf;
  u8 ip6_type = cf->ip6_channel ? cf->ip6_channel->net_type : NET_IP6;


  fib_init(&p->ip4_rtable, P->pool, NET_IP4, 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);
	   OFFSETOF(struct babel_entry, n), 0, babel_init_entry);
  fib_init(&p->ip6_rtable, P->pool, NET_IP6, sizeof(struct babel_entry),
  fib_init(&p->ip6_rtable, P->pool, ip6_type, sizeof(struct babel_entry),
	   OFFSETOF(struct babel_entry, n), 0, babel_init_entry);
	   OFFSETOF(struct babel_entry, n), 0, babel_init_entry);


  init_list(&p->interfaces);
  init_list(&p->interfaces);
@@ -2258,11 +2283,15 @@ babel_reconfigure(struct proto *P, struct proto_config *CF)
{
{
  struct babel_proto *p = (void *) P;
  struct babel_proto *p = (void *) P;
  struct babel_config *new = (void *) CF;
  struct babel_config *new = (void *) CF;
  u8 ip6_type = new->ip6_channel ? new->ip6_channel->net_type : NET_IP6;


  TRACE(D_EVENTS, "Reconfiguring");
  TRACE(D_EVENTS, "Reconfiguring");


  if (!proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4)) ||
  if (p->ip6_rtable.addr_type != ip6_type)
      !proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6)))
    return 0;

  if (!proto_configure_channel(P, &p->ip4_channel, new->ip4_channel) ||
      !proto_configure_channel(P, &p->ip6_channel, new->ip6_channel))
    return 0;
    return 0;


  p->p.cf = CF;
  p->p.cf = CF;
@@ -2280,9 +2309,10 @@ struct protocol proto_babel = {
  .template =		"babel%d",
  .template =		"babel%d",
  .attr_class =		EAP_BABEL,
  .attr_class =		EAP_BABEL,
  .preference =		DEF_PREF_BABEL,
  .preference =		DEF_PREF_BABEL,
  .channel_mask =	NB_IP,
  .channel_mask =	NB_IP | NB_IP6_SADR,
  .proto_size =		sizeof(struct babel_proto),
  .proto_size =		sizeof(struct babel_proto),
  .config_size =	sizeof(struct babel_config),
  .config_size =	sizeof(struct babel_config),
  .postconfig =		babel_postconfig,
  .init =		babel_init,
  .init =		babel_init,
  .dump =		babel_dump,
  .dump =		babel_dump,
  .start =		babel_start,
  .start =		babel_start,
+21 −4
Original line number Original line Diff line number Diff line
@@ -85,7 +85,10 @@ enum babel_tlv_type {


enum babel_subtlv_type {
enum babel_subtlv_type {
  BABEL_SUBTLV_PAD1		= 0,
  BABEL_SUBTLV_PAD1		= 0,
  BABEL_SUBTLV_PADN		= 1
  BABEL_SUBTLV_PADN		= 1,

  /* Mandatory subtlvs */
  BABEL_SUBTLV_SOURCE_PREFIX    = 128,
};
};


enum babel_iface_type {
enum babel_iface_type {
@@ -109,6 +112,9 @@ struct babel_config {
  struct proto_config c;
  struct proto_config c;
  list iface_list;			/* List of iface configs (struct babel_iface_config) */
  list iface_list;			/* List of iface configs (struct babel_iface_config) */
  uint hold_time;			/* Time to hold stale entries and unreachable routes */
  uint hold_time;			/* Time to hold stale entries and unreachable routes */

  struct channel_config *ip4_channel;
  struct channel_config *ip6_channel;
};
};


struct babel_iface_config {
struct babel_iface_config {
@@ -303,7 +309,10 @@ struct babel_msg_update {
  u16 seqno;
  u16 seqno;
  u16 metric;
  u16 metric;
  u64 router_id;
  u64 router_id;
  union {
    net_addr net;
    net_addr net;
    net_addr_ip6_sadr net_sadr;
  };
  ip_addr next_hop;
  ip_addr next_hop;
  ip_addr sender;
  ip_addr sender;
};
};
@@ -311,7 +320,10 @@ struct babel_msg_update {
struct babel_msg_route_request {
struct babel_msg_route_request {
  u8 type;
  u8 type;
  u8 full;
  u8 full;
  union {
    net_addr net;
    net_addr net;
    net_addr_ip6_sadr net_sadr;
  };
};
};


struct babel_msg_seqno_request {
struct babel_msg_seqno_request {
@@ -319,7 +331,10 @@ struct babel_msg_seqno_request {
  u8 hop_count;
  u8 hop_count;
  u16 seqno;
  u16 seqno;
  u64 router_id;
  u64 router_id;
  union {
    net_addr net;
    net_addr net;
    net_addr_ip6_sadr net_sadr;
  };
  ip_addr sender;
  ip_addr sender;
};
};


@@ -339,6 +354,8 @@ struct babel_msg_node {
  union babel_msg msg;
  union babel_msg msg;
};
};


static inline int babel_sadr_enabled(struct babel_proto *p)
{ return p->ip6_rtable.addr_type == NET_IP6_SADR; }


/* babel.c */
/* babel.c */
void babel_handle_ack_req(union babel_msg *msg, struct babel_iface *ifa);
void babel_handle_ack_req(union babel_msg *msg, struct babel_iface *ifa);
+159 −10
Original line number Original line Diff line number Diff line
@@ -105,6 +105,13 @@ struct babel_tlv_seqno_request {
  u8 addr[0];
  u8 addr[0];
} PACKED;
} PACKED;


struct babel_subtlv_source_prefix {
  u8 type;
  u8 length;
  u8 plen;
  u8 addr[0];
} PACKED;



/* Hello flags */
/* Hello flags */
#define BABEL_HF_UNICAST	0x8000
#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_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) */
  u8 current_tlv_endpos;	/* End of self-terminating TLVs (offset from start) */
  u8 sadr_enabled;
};
};


enum parse_result {
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_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_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_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_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);
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_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_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 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 {
struct babel_tlv_data {
  u8 min_length;
  u8 min_length;
@@ -640,6 +650,9 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
    ip6_addr prefix6 = get_ip6(buf);
    ip6_addr prefix6 = get_ip6(buf);
    net_fill_ip6(&msg->net, prefix6, tlv->plen);
    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)
    if (tlv->flags & BABEL_UF_DEF_PREFIX)
    {
    {
      put_ip6(state->def_ip6_prefix, prefix6);
      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->seqno, msg->seqno);
  put_u16(&tlv->metric, msg->metric);
  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;
  return len0 + len;
}
}


static int
static int
babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
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_tlv_route_request *tlv = (void *) hdr;
  struct babel_msg_route_request *msg = &m->route_request;
  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);
    read_ip6_px(&msg->net, tlv->addr, tlv->plen);
    state->current_tlv_endpos += BYTES(tlv->plen);
    state->current_tlv_endpos += BYTES(tlv->plen);

    if (state->sadr_enabled)
      net_make_ip6_sadr(&msg->net);

    return PARSE_SUCCESS;
    return PARSE_SUCCESS;


  case BABEL_AE_IP6_LL:
  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);
    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;
  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);
    read_ip6_px(&msg->net, tlv->addr, tlv->plen);
    state->current_tlv_endpos += BYTES(tlv->plen);
    state->current_tlv_endpos += BYTES(tlv->plen);

    if (state->sadr_enabled)
      net_make_ip6_sadr(&msg->net);

    return PARSE_SUCCESS;
    return PARSE_SUCCESS;


  case BABEL_AE_IP6_LL:
  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;
  tlv->hop_count = msg->hop_count;
  put_u64(&tlv->router_id, msg->router_id);
  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;
  return len;
}
}



static inline int
static inline int
babel_read_subtlvs(struct babel_tlv *hdr,
babel_read_subtlvs(struct babel_tlv *hdr,
		   union babel_msg *msg UNUSED,
		   union babel_msg *msg,
		   struct babel_parse_state *state)
		   struct babel_parse_state *state)
{
{
  struct babel_tlv *tlv;
  struct babel_tlv *tlv;
  byte *pos, *end = (byte *) hdr + TLV_LENGTH(hdr);
  int res;


  for (tlv = (void *) hdr + state->current_tlv_endpos;
  for (tlv = (void *) hdr + state->current_tlv_endpos;
       (void *) tlv < (void *) hdr + TLV_LENGTH(hdr);
       (byte *) tlv < end;
       tlv = NEXT_TLV(tlv))
       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
     * 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
     * use a switch for dispatch instead of the mapping array we use for TLVs
     */
     */
    switch (tlv->type)
    switch (tlv->type)
    {
    {
    case BABEL_SUBTLV_PAD1:
    case BABEL_SUBTLV_SOURCE_PREFIX:
    case BABEL_SUBTLV_PADN:
      res = babel_read_source_prefix(tlv, msg, state);
      /* FIXME: Framing errors in PADN are silently ignored, see babel_process_packet() */
      if (res != PARSE_SUCCESS)
	return res;
      break;
      break;


    case BABEL_SUBTLV_PADN:
    default:
    default:
      /* Unknown mandatory subtlv; PARSE_IGNORE ignores the whole TLV */
      /* Unknown mandatory subtlv; PARSE_IGNORE ignores the whole TLV */
      if (tlv->type > 128)
      if (tlv->type >= 128)
      {
	DBG("Babel: Mandatory subtlv %d found; skipping TLV\n", tlv->type);
	return PARSE_IGNORE;
	return PARSE_IGNORE;
      }
      break;
      break;
    }
    }
  }
  }
@@ -1197,6 +1345,7 @@ babel_process_packet(struct babel_pkt_header *pkt, int len,
    .ifa	  = ifa,
    .ifa	  = ifa,
    .saddr	  = saddr,
    .saddr	  = saddr,
    .next_hop_ip6 = saddr,
    .next_hop_ip6 = saddr,
    .sadr_enabled = babel_sadr_enabled(p),
  };
  };


  if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION))
  if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION))