bgp_read_capabilities(struct bgp_conn *conn, byte *pos, int len)
{
  struct bgp_proto *p = conn->bgp;
  struct bgp_caps *caps;
  struct bgp_af_caps *ac;
  int i, cl;
  u32 af;

  if (!conn->remote_caps)
    caps = mb_allocz(p->p.pool, sizeof(struct bgp_caps) + sizeof(struct bgp_af_caps));
  else
  {
    caps = conn->remote_caps;
    conn->remote_caps = NULL;
  }

  caps->length += len;

  while (len > 0)
  {
    if (len < 2 || len < (2 + pos[1]))
      goto err;

    /* Capability length */
    cl = pos[1];

    /* Capability type */
    switch (pos[0])
    {
    case  1: /* Multiprotocol capability, RFC 4760 */
      if (cl != 4)
	goto err;

      af = get_af4(pos+2);
      ac = bgp_get_af_caps(&caps, af);
      ac->ready = 1;
      break;

    case  2: /* Route refresh capability, RFC 2918 */
      if (cl != 0)
	goto err;

      caps->route_refresh = 1;
      break;

    case  5: /* Extended next hop encoding capability, RFC 5549 */
      if (cl % 6)
	goto err;

      for (i = 0; i < cl; i += 6)
      {
	/* Specified only for IPv4 prefixes with IPv6 next hops */
	if ((get_u16(pos+2+i+0) != BGP_AFI_IPV4) ||
	    (get_u16(pos+2+i+4) != BGP_AFI_IPV6))
	  continue;

	af = get_af4(pos+2+i);
	ac = bgp_get_af_caps(&caps, af);
	ac->ext_next_hop = 1;
      }
      break;

    case  6: /* Extended message length capability, RFC draft */
      if (cl != 0)
	goto err;

      caps->ext_messages = 1;
      break;

    case 64: /* Graceful restart capability, RFC 4724 */
      if (cl % 4 != 2)
	goto err;

      /* Only the last instance is valid */
      WALK_AF_CAPS(caps, ac)
      {
	ac->gr_able = 0;
	ac->gr_af_flags = 0;
      }

      caps->gr_aware = 1;
      caps->gr_flags = pos[2] & 0xf0;
      caps->gr_time = get_u16(pos + 2) & 0x0fff;

      for (i = 2; i < cl; i += 4)
      {
	af = get_af3(pos+2+i);
	ac = bgp_get_af_caps(&caps, af);
	ac->gr_able = 1;
	ac->gr_af_flags = pos[2+i+3];
      }
      break;

    case 65: /* AS4 capability, RFC 6793 */
      if (cl != 4)
	goto err;

      caps->as4_support = 1;
      caps->as4_number = get_u32(pos + 2);
      break;

    case 69: /* ADD-PATH capability, RFC 7911 */
      if (cl % 4)
	goto err;

      for (i = 0; i < cl; i += 4)
      {
	byte val = pos[2+i+3];
	if (!val || (val > BGP_ADD_PATH_FULL))
	{
	  log(L_WARN "%s: Got ADD-PATH capability with unknown value %u, ignoring",
	      p->p.name, val);
	  break;
	}
      }

      for (i = 0; i < cl; i += 4)
      {
	af = get_af3(pos+2+i);
	ac = bgp_get_af_caps(&caps, af);
	ac->add_path = pos[2+i+3];
      }
      break;

    case 70: /* Enhanced route refresh capability, RFC 7313 */
      if (cl != 0)
	goto err;

      caps->enhanced_refresh = 1;
      break;

    case 71: /* Long lived graceful restart capability, RFC draft */
      if (cl % 7)
	goto err;

      /* Presumably, only the last instance is valid */
      WALK_AF_CAPS(caps, ac)
      {
	ac->llgr_able = 0;
	ac->llgr_flags = 0;
	ac->llgr_time = 0;
      }

      caps->llgr_aware = 1;

      for (i = 0; i < cl; i += 7)
      {
	af = get_af3(pos+2+i);
	ac = bgp_get_af_caps(&caps, af);
	ac->llgr_able = 1;
	ac->llgr_flags = pos[2+i+3];
	ac->llgr_time = get_u24(pos + 2+i+4);
      }
      break;

      /* We can safely ignore all other capabilities */
    }

    ADVANCE(pos, len, 2 + cl);
  }

  /* The LLGR capability must be advertised together with the GR capability,
     otherwise it must be disregarded */
  if (!caps->gr_aware && caps->llgr_aware)
  {
    caps->llgr_aware = 0;
    WALK_AF_CAPS(caps, ac)
    {
      ac->llgr_able = 0;
      ac->llgr_flags = 0;
      ac->llgr_time = 0;
    }
  }

  conn->remote_caps = caps;
  return 0;

err:
  mb_free(caps);
  bgp_error(conn, 2, 0, NULL, 0);
  return -1;
}