text: // Copyright 2019 The Fuchsia Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef SRC_DEVICES_BLOCK_DRIVERS_ZXCRYPT_DEVICE_MANAGER_H_
  #define SRC_DEVICES_BLOCK_DRIVERS_ZXCRYPT_DEVICE_MANAGER_H_
  
  #include <stddef.h>
  #include <stdint.h>
  #include <zircon/compiler.h>
  #include <zircon/types.h>
  
  #include <ddk/device.h>
  #include <ddktl/device.h>
  #include <fbl/macros.h>
  #include <fbl/mutex.h>
  #include <zxcrypt/volume.h>
  
  namespace zxcrypt {
  
  // |zxcrypt::DeviceManager| is a "wrapper" driver for zxcrypt volumes.  Each block device with valid
  // zxcrypt metadata will result in a wrapper being created, but the wrapper cannot perform any block
  // operations.  To perform block operations, |Unseal| must first be called with a valid key and
  // slot, which will cause an unsealed |zxcrypt::Device| to be added to the device tree.
  class DeviceManager;
  using DeviceManagerType = ddk::Device<DeviceManager, ddk::Unbindable, ddk::Messageable>;
  class DeviceManager final : public DeviceManagerType {
   public:
    explicit DeviceManager(zx_device_t* parent) : DeviceManagerType(parent), state_(kBinding) {}
    ~DeviceManager() = default;
    DISALLOW_COPY_ASSIGN_AND_MOVE(DeviceManager);
  
    static zx_status_t Create(void* ctx, zx_device_t* parent);
  
    // Adds the device
    zx_status_t Bind();
  
    // ddk::Device methods; see ddktl/device.h
    void DdkUnbind(ddk::UnbindTxn txn) __TA_EXCLUDES(mtx_);
    void DdkRelease();
  
    // ddk::Messageable methods
    zx_status_t DdkMessage(fidl_incoming_msg_t* msg, fidl_txn_t* txn) __TA_EXCLUDES(mtx_);
  
    // Unseals the zxcrypt volume and adds it as a |zxcrypt::Device| to the device tree.
    zx_status_t Unseal(const uint8_t* ikm, size_t ikm_len, key_slot_t slot) __TA_EXCLUDES(mtx_);
  
    // Removes the unsealed |zxcrypt::Device|, if present.
    zx_status_t Seal() __TA_EXCLUDES(mtx_);
  
    // Clobbers the superblock (and any backup superblocks), preventing future
    // Unseal operations from succeeding (provided no other program is
    // manipulating the underlying block device).
    zx_status_t Shred() __TA_EXCLUDES(mtx_);
  
   private:
    // Represents the state of this device.
    enum State {
      kBinding,
      kSealed,
      kUnsealed,
      kShredded,
      kRemoved,
    };
  
    // Unseals the zxcrypt volume and adds it as a |zxcrypt::Device| to the device tree.
    zx_status_t UnsealLocked(const uint8_t* ikm, size_t ikm_len, key_slot_t slot) __TA_REQUIRES(mtx_);
  
    // Used to ensure calls to |Unseal|, |Seal|, and |Unbind| are exclusive to each
    // other, and protects access to |state_|.
    fbl::Mutex mtx_;
  
    State state_ __TA_GUARDED(mtx_);
  };
  
  }  // namespace zxcrypt
  
  #endif  // SRC_DEVICES_BLOCK_DRIVERS_ZXCRYPT_DEVICE_MANAGER_H_
  