Commit 145ebfa1 authored by Ondrej Zajicek (work)'s avatar Ondrej Zajicek (work)
Browse files

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.
parent b3c6273e
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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,
+74 −4
Original line number Diff line number Diff line
@@ -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:
@@ -907,6 +935,42 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
  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
babel_read_tlv(struct babel_tlv *hdr,
               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)
    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