aboutsummaryrefslogtreecommitdiff
path: root/ks_volatile.c
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2017-05-25 11:18:39 -0400
committerRob Austein <sra@hactrn.net>2017-05-25 11:18:39 -0400
commit5eccb3e6d7c27149a0092de48eb21baa495879cb (patch)
tree6968884adb4864c293943be3f43a05464ce0f383 /ks_volatile.c
parentb9565626187cca926c21120786ec575c59f06a05 (diff)
Checkpoint while refactoring. Almost certainly will not compile.
Diffstat (limited to 'ks_volatile.c')
-rw-r--r--ks_volatile.c607
1 files changed, 99 insertions, 508 deletions
diff --git a/ks_volatile.c b/ks_volatile.c
index 515a8e8..e9a0ef4 100644
--- a/ks_volatile.c
+++ b/ks_volatile.c
@@ -41,591 +41,182 @@
#include "hal.h"
#include "hal_internal.h"
-
-#define KEK_LENGTH (bitsToBytes(256))
+#include "ks.h"
#ifndef STATIC_KS_VOLATILE_SLOTS
#define STATIC_KS_VOLATILE_SLOTS HAL_STATIC_PKEY_STATE_BLOCKS
#endif
-#ifndef STATIC_KS_VOLATILE_ATTRIBUTE_SPACE
-#define STATIC_KS_VOLATILE_ATTRIBUTE_SPACE 4096
+#ifndef KS_VOLATILE_CACHE_SIZE
+#define KS_VOLATILE_CACHE_SIZE 4
#endif
-/*
- * In-memory keystore database. This is a bit more complicated than
- * necessary because originally I though we would want to continue
- * supporting an mmap()-based keystore as well. Needs cleaning up.
- */
-
typedef struct {
- hal_key_type_t type;
- hal_curve_name_t curve;
- hal_key_flags_t flags;
hal_client_handle_t client;
hal_session_handle_t session;
- size_t der_len;
- unsigned attributes_len;
- uint8_t der[HAL_KS_WRAPPED_KEYSIZE + STATIC_KS_VOLATILE_ATTRIBUTE_SPACE];
-} ks_key_t;
+ hal_ks_block_t block;
+} volatile_key_t;
-typedef struct {
- hal_ks_index_t ksi;
- ks_key_t *keys;
-} db_t;
-
-/*
- * "Subclass" (well, what one can do in C) of hal_ks_t. This is
- * separate from db_t primarily to simplify things like rewriting the
- * old ks_mmap driver to piggy-back on the ks_volatile driver: we
- * wouldn't want the hal_ks_t into the mmap()ed file.
- */
-
-typedef struct {
+static struct db {
hal_ks_t ks; /* Must be first */
- db_t *db; /* Which memory-based keystore database */
- int per_session; /* Whether objects are per-session */
-} ks_t;
+ volatile_key_t *keys;
+} db;
/*
- * If we also supported mmap, there would be a separate definition for
- * HAL_KS_MMAP_SLOTS above, and the bulk of the code would be under a
- * conditional testing whether either HAL_KS_*_SLOTS were nonzero.
+ * Read a block. CRC probably not necessary for RAM.
*/
-#if STATIC_KS_VOLATILE_SLOTS > 0
+static hal_error_t block_read(hal_k_t *ks, const unsigned blockno, ks_block_t *block)
+{
+ if (ks != &db.ks || db.keys == NULL || block == NULL || blockno >= ks->size)
+ return HAL_ERROR_IMPOSSIBLE;
-static ks_t volatile_ks;
+ memcpy(block, &db.keys[blockno].block, sizeof(*block));
-static inline ks_t *ks_to_ksv(hal_ks_t *ks)
-{
- return (ks_t *) ks;
+ return HAL_OK;
}
/*
- * Check whether the current session can see a particular key. One
- * might expect this to be based on whether the session matches, and
- * indeed it would be in a sane world, but in the world of PKCS #11,
- * keys belong to sessions, are visible to other sessions, and may
- * even be modifiable by other sessions, but softly and silently
- * vanish away when the original creating session is destroyed.
- *
- * In our terms, this means that visibility of session objects is
- * determined only by the client handle, so taking the session handle
- * as an argument here isn't really necessary, but we've flipflopped
- * on that enough times that at least for now I'd prefer to leave the
- * session handle here and not have to revise all the RPC calls again.
- * Remove it at some later date and redo the RPC calls if we manage to
- * avoid revising this yet again.
+ * Convert a live block into a tombstone.
*/
-static inline int key_visible_to_session(const ks_t * const ksv,
- const hal_client_handle_t client,
- const hal_session_handle_t session,
- const ks_key_t * const k)
+static hal_error_t block_deprecate(hal_k_t *ks, const unsigned blockno)
{
- return (!ksv->per_session ||
- client.handle == HAL_HANDLE_NONE ||
- k->client.handle == client.handle ||
- hal_rpc_is_logged_in(client, HAL_USER_WHEEL) == HAL_OK);
-}
-
-static inline void *gnaw(uint8_t **mem, size_t *len, const size_t size)
-{
- if (mem == NULL || *mem == NULL || len == NULL || size > *len)
- return NULL;
- void *ret = *mem;
- *mem += size;
- *len -= size;
- return ret;
-}
-
-static hal_error_t ks_init(const hal_ks_driver_t * const driver,
- const int per_session,
- ks_t *ksv,
- uint8_t *mem,
- size_t len)
-{
- if (ksv == NULL)
- return HAL_ERROR_IMPOSSIBLE;
-
- if (mem != NULL) {
- memset(ksv, 0, sizeof(*ksv));
- memset(mem, 0, len);
-
- ksv->db = gnaw(&mem, &len, sizeof(*ksv->db));
- ksv->db->ksi.index = gnaw(&mem, &len, sizeof(*ksv->db->ksi.index) * STATIC_KS_VOLATILE_SLOTS);
- ksv->db->ksi.names = gnaw(&mem, &len, sizeof(*ksv->db->ksi.names) * STATIC_KS_VOLATILE_SLOTS);
- ksv->db->keys = gnaw(&mem, &len, sizeof(*ksv->db->keys) * STATIC_KS_VOLATILE_SLOTS);
- ksv->db->ksi.size = STATIC_KS_VOLATILE_SLOTS;
- }
-
- if (ksv->db == NULL ||
- ksv->db->ksi.index == NULL ||
- ksv->db->ksi.names == NULL ||
- ksv->db->keys == NULL)
+ if (ks != &db.ks || db.keys == NULL || blockno >= ks->size)
return HAL_ERROR_IMPOSSIBLE;
- if (mem == NULL) {
- memset(ksv->db->ksi.index, 0, sizeof(*ksv->db->ksi.index) * STATIC_KS_VOLATILE_SLOTS);
- memset(ksv->db->ksi.names, 0, sizeof(*ksv->db->ksi.names) * STATIC_KS_VOLATILE_SLOTS);
- memset(ksv->db->keys, 0, sizeof(*ksv->db->keys) * STATIC_KS_VOLATILE_SLOTS);
- }
-
- ksv->ks.driver = driver;
- ksv->per_session = per_session;
- ksv->db->ksi.used = 0;
-
- /*
- * Set up keystore with empty index and full free list.
- * Since this driver doesn't care about wear leveling,
- * just populate the free list in block numerical order.
- */
-
- for (int i = 0; i < STATIC_KS_VOLATILE_SLOTS; i++)
- ksv->db->ksi.index[i] = i;
+ db.keys[blockno].block.header->block_status = BLOCK_STATUS_TOMBSTONE;
- return hal_ks_index_setup(&ksv->db->ksi);
+ return HAL_OK;
}
-static hal_error_t ks_volatile_init(const hal_ks_driver_t * const driver, const int alloc)
-{
- hal_error_t err = HAL_OK;
-
- hal_ks_lock();
-
- const size_t len = (sizeof(*volatile_ks.db) +
- sizeof(*volatile_ks.db->ksi.index) * STATIC_KS_VOLATILE_SLOTS +
- sizeof(*volatile_ks.db->ksi.names) * STATIC_KS_VOLATILE_SLOTS +
- sizeof(*volatile_ks.db->keys) * STATIC_KS_VOLATILE_SLOTS);
-
- uint8_t *mem = NULL;
+/*
+ * Zero (not erase) a flash block.
+ */
- if (alloc && (mem = hal_allocate_static_memory(len)) == NULL)
- err = HAL_ERROR_ALLOCATION_FAILURE;
- else
- err = ks_init(driver, 1, &volatile_ks, mem, len);
+static hal_error_t block_zero(hal_k_t *ks, const unsigned blockno)
+{
+ if (ks != &db.ks || db.keys == NULL || blockno >= ks->size)
+ return HAL_ERROR_IMPOSSIBLE;
- hal_ks_unlock();
- return err;
-}
+ memset(db.keys[blockno].block, 0x00, sizeof(db.keys[blockno].block));
+ db.keys[blockno].client.handle = HAL_HANDLE_NONE;
+ db.keys[blockno].session.handle = HAL_HANDLE_NONE;
-static hal_error_t ks_volatile_shutdown(const hal_ks_driver_t * const driver)
-{
- if (volatile_ks.ks.driver != driver)
- return HAL_ERROR_KEYSTORE_ACCESS;
return HAL_OK;
}
-static hal_error_t ks_volatile_open(const hal_ks_driver_t * const driver,
- hal_ks_t **ks)
-{
- assert(driver != NULL && ks != NULL);
- *ks = &volatile_ks.ks;
- return HAL_OK;
-}
+/*
+ * Erase a flash block.
+ */
-static hal_error_t ks_volatile_close(hal_ks_t *ks)
+static hal_error_t block_erase(hal_k_t *ks, const unsigned blockno)
{
+ if (ks != &db.ks || db.keys == NULL || blockno >= ks->size)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ memset(db.keys[blockno].block, 0xFF, sizeof(db.keys[blockno].block));
+ db.keys[blockno].client.handle = HAL_HANDLE_NONE;
+ db.keys[blockno].session.handle = HAL_HANDLE_NONE;
+
return HAL_OK;
}
-static inline int acceptable_key_type(const hal_key_type_t type)
-{
- switch (type) {
- case HAL_KEY_TYPE_RSA_PRIVATE:
- case HAL_KEY_TYPE_EC_PRIVATE:
- case HAL_KEY_TYPE_RSA_PUBLIC:
- case HAL_KEY_TYPE_EC_PUBLIC:
- return 1;
- default:
- return 0;
- }
-}
+/*
+ * Write a flash block. CRC probably not necessary for RAM.
+ */
-static hal_error_t ks_store(hal_ks_t *ks,
- hal_pkey_slot_t *slot,
- const uint8_t * const der, const size_t der_len)
+static hal_error_t block_write(hal_k_t *ks, const unsigned blockno, ks_block_t *block)
{
- if (ks == NULL || slot == NULL || der == NULL || der_len == 0 || !acceptable_key_type(slot->type))
- return HAL_ERROR_BAD_ARGUMENTS;
+ if (ks != &db.ks || db.keys == NULL || block == NULL || blockno >= ks->size)
+ return HAL_ERROR_IMPOSSIBLE;
- ks_t *ksv = ks_to_ksv(ks);
- hal_error_t err = HAL_OK;
- unsigned b;
+ memcpy(&db.keys[blockno].block, block, sizeof(*block));
- hal_ks_lock();
+ return HAL_OK;
+}
- if (ksv->db == NULL) {
- err = HAL_ERROR_KEYSTORE_ACCESS;
- goto done;
- }
+/*
+ * Set key ownership.
+ */
- if ((err = hal_ks_index_add(&ksv->db->ksi, &slot->name, &b, &slot->hint)) != HAL_OK)
- goto done;
+static hal_error_t block_set_owner(hal_ks_t *ks,
+ const unsigned blockno,
+ const hal_client_handle_t client,
+ const hal_session_handle_t session)
+{
+ if (ks != &db.ks || db.keys == NULL || blockno >= ks->size)
+ return HAL_ERROR_IMPOSSIBLE;
- uint8_t kek[KEK_LENGTH];
- size_t kek_len;
- ks_key_t k;
+ db.keys[blockno].client = client;
+ db.keys[blockno].session = session;
- memset(&k, 0, sizeof(k));
- k.der_len = sizeof(k.der);
- k.type = slot->type;
- k.curve = slot->curve;
- k.flags = slot->flags;
- k.client = slot->client_handle;
- k.session = slot->session_handle;
+ return HAL_OK;
+}
- if ((err = hal_mkm_get_kek(kek, &kek_len, sizeof(kek))) == HAL_OK)
- err = hal_aes_keywrap(NULL, kek, kek_len, der, der_len, k.der, &k.der_len);
+/*
+ * Test key ownership.
+ */
- memset(kek, 0, sizeof(kek));
+static hal_error_t block_test_owner(hal_ks_t *ks, const
+ unsigned blockno,
+ const hal_client_handle_t client,
+ const hal_session_handle_t session)
+{
+ if (ks != &db.ks || db.keys == NULL || blockno >= ks->size)
+ return HAL_ERROR_IMPOSSIBLE;
- if (err == HAL_OK)
- ksv->db->keys[b] = k;
+ if (db.keys[blockno].client.handle == client.handle &&
+ db.keys[blockno].session.handle == session.handle)
+ return HAL_OK;
else
- (void) hal_ks_index_delete(&ksv->db->ksi, &slot->name, NULL, &slot->hint);
-
- done:
- hal_ks_unlock();
- return err;
+ return HAL_ERROR_KEY_NOT_FOUND;
}
-static hal_error_t ks_fetch(hal_ks_t *ks,
- hal_pkey_slot_t *slot,
- uint8_t *der, size_t *der_len, const size_t der_max)
-{
- if (ks == NULL || slot == NULL)
- return HAL_ERROR_BAD_ARGUMENTS;
-
- ks_t *ksv = ks_to_ksv(ks);
- hal_error_t err = HAL_OK;
- unsigned b;
-
- hal_ks_lock();
-
- if (ksv->db == NULL) {
- err = HAL_ERROR_KEYSTORE_ACCESS;
- goto done;
- }
-
- if ((err = hal_ks_index_find(&ksv->db->ksi, &slot->name, &b, &slot->hint)) != HAL_OK)
- goto done;
-
- const ks_key_t * const k = &ksv->db->keys[b];
-
- if (!key_visible_to_session(ksv, slot->client_handle, slot->session_handle, k)) {
- err = HAL_ERROR_KEY_NOT_FOUND;
- goto done;
- }
-
- slot->type = k->type;
- slot->curve = k->curve;
- slot->flags = k->flags;
-
- if (der == NULL && der_len != NULL)
- *der_len = k->der_len;
-
- if (der != NULL) {
-
- uint8_t kek[KEK_LENGTH];
- size_t kek_len, der_len_;
-
- if (der_len == NULL)
- der_len = &der_len_;
-
- *der_len = der_max;
-
- if ((err = hal_mkm_get_kek(kek, &kek_len, sizeof(kek))) == HAL_OK)
- err = hal_aes_keyunwrap(NULL, kek, kek_len, k->der, k->der_len, der, der_len);
-
- memset(kek, 0, sizeof(kek));
- }
+/*
+ * Initialize keystore.
+ */
- done:
- hal_ks_unlock();
- return err;
-}
+static const hal_ks_driver_t hal_ks_volatile_driver[1] = {{
+ .read = block_read,
+ .write = block_write,
+ .deprecate = block_deprecate,
+ .zero = block_zero,
+ .erase = block_erase,
+ .erase_maybe = block_erase, /* sic */
+ .set_owner = block_set_owner,
+ .test_owner = block_test_owner
+}};
-static hal_error_t ks_delete(hal_ks_t *ks,
- hal_pkey_slot_t *slot)
+ hal_error_t hal_ks_volatile_init(const int alloc)
{
- if (ks == NULL || slot == NULL)
- return HAL_ERROR_BAD_ARGUMENTS;
-
- ks_t *ksv = ks_to_ksv(ks);
hal_error_t err = HAL_OK;
- unsigned b;
hal_ks_lock();
- if (ksv->db == NULL) {
- err = HAL_ERROR_KEYSTORE_ACCESS;
- goto done;
- }
-
- if ((err = hal_ks_index_find(&ksv->db->ksi, &slot->name, &b, &slot->hint)) != HAL_OK)
- goto done;
- if (!key_visible_to_session(ksv, slot->client_handle, slot->session_handle, &ksv->db->keys[b])) {
- err = HAL_ERROR_KEY_NOT_FOUND;
+ if (alloc && (err = hal_ks_alloc_common(&db.ks, STATIC_KS_VOLATILE_SLOTS, KS_VOLATILE_CACHE_SIZE)) != HAL_OK)
goto done;
- }
- if ((err = hal_ks_index_delete(&ksv->db->ksi, &slot->name, &b, &slot->hint)) != HAL_OK)
+ if ((err = hal_ks_init_common(&db.ks, hal_ks_volatile_driver)) != HAL_OK)
goto done;
- memset(&ksv->db->keys[b], 0, sizeof(ksv->db->keys[b]));
-
- done:
- hal_ks_unlock();
- return err;
-}
-
-static hal_error_t ks_match(hal_ks_t *ks,
- hal_client_handle_t client,
- hal_session_handle_t session,
- const hal_key_type_t type,
- const hal_curve_name_t curve,
- const hal_key_flags_t mask,
- const hal_key_flags_t flags,
- const hal_pkey_attribute_t *attributes,
- const unsigned attributes_len,
- hal_uuid_t *result,
- unsigned *result_len,
- const unsigned result_max,
- const hal_uuid_t * const previous_uuid)
-{
- if (ks == NULL || (attributes == NULL && attributes_len > 0) ||
- result == NULL || result_len == NULL || previous_uuid == NULL)
- return HAL_ERROR_BAD_ARGUMENTS;
-
- ks_t *ksv = ks_to_ksv(ks);
-
- if (ksv->db == NULL)
- return HAL_ERROR_KEYSTORE_ACCESS;
-
- hal_error_t err = HAL_OK;
- int i = -1;
-
- hal_ks_lock();
-
- *result_len = 0;
-
- err = hal_ks_index_find(&ksv->db->ksi, previous_uuid, NULL, &i);
-
- if (err == HAL_ERROR_KEY_NOT_FOUND)
- i--;
- else if (err != HAL_OK)
+ if (alloc && (db.keys = hal_allocate_static_memory(sizeof(*db.keys) * db.ks.size)) == NULL) {
+ err = HAL_ERROR_ALLOCATION_FAILURE;
goto done;
-
- while (*result_len < result_max && ++i < ksv->db->ksi.used) {
-
- unsigned b = ksv->db->ksi.index[i];
-
- if (type != HAL_KEY_TYPE_NONE && type != ksv->db->keys[b].type)
- continue;
-
- if (curve != HAL_CURVE_NONE && curve != ksv->db->keys[b].curve)
- continue;
-
- if (((flags ^ ksv->db->keys[b].flags) & mask) != 0)
- continue;
-
- if (!key_visible_to_session(ksv, client, session, &ksv->db->keys[b]))
- continue;
-
- if (attributes_len > 0) {
- const ks_key_t * const k = &ksv->db->keys[b];
- int ok = 1;
-
- if (k->attributes_len == 0)
- continue;
-
- hal_pkey_attribute_t key_attrs[k->attributes_len];
-
- if ((err = hal_ks_attribute_scan(k->der + k->der_len, sizeof(k->der) - k->der_len,
- key_attrs, k->attributes_len, NULL)) != HAL_OK)
- goto done;
-
- for (const hal_pkey_attribute_t *required = attributes;
- ok && required < attributes + attributes_len; required++) {
-
- hal_pkey_attribute_t *present = key_attrs;
- while (ok && present->type != required->type)
- ok = ++present < key_attrs + k->attributes_len;
-
- if (ok)
- ok = (present->length == required->length &&
- !memcmp(present->value, required->value, present->length));
- }
-
- if (!ok)
- continue;
- }
-
- result[*result_len] = ksv->db->ksi.names[b];
- ++*result_len;
- }
-
- err = HAL_OK;
-
- done:
- hal_ks_unlock();
- return err;
-}
-
-static hal_error_t ks_set_attributes(hal_ks_t *ks,
- hal_pkey_slot_t *slot,
- const hal_pkey_attribute_t *attributes,
- const unsigned attributes_len)
-{
- if (ks == NULL || slot == NULL || attributes == NULL || attributes_len == 0)
- return HAL_ERROR_BAD_ARGUMENTS;
-
- ks_t *ksv = ks_to_ksv(ks);
- hal_error_t err = HAL_OK;
- unsigned b;
-
- hal_ks_lock();
-
- {
- if (ksv->db == NULL) {
- err = HAL_ERROR_KEYSTORE_ACCESS;
- goto done;
- }
-
- if ((err = hal_ks_index_find(&ksv->db->ksi, &slot->name, &b, &slot->hint)) != HAL_OK)
- goto done;
-
- ks_key_t * const k = &ksv->db->keys[b];
-
- if (!key_visible_to_session(ksv, slot->client_handle, slot->session_handle, k)) {
- err = HAL_ERROR_KEY_NOT_FOUND;
- goto done;
- }
-
- hal_pkey_attribute_t attrs[k->attributes_len + attributes_len];
- uint8_t *bytes = k->der + k->der_len;
- size_t bytes_len = sizeof(k->der) - k->der_len;
- size_t total_len;
-
- if ((err = hal_ks_attribute_scan(bytes, bytes_len, attrs, k->attributes_len, &total_len)) != HAL_OK)
- goto done;
-
- for (const hal_pkey_attribute_t *a = attributes; a < attributes + attributes_len; a++) {
- if (a->length == HAL_PKEY_ATTRIBUTE_NIL)
- err = hal_ks_attribute_delete(bytes, bytes_len, attrs, &k->attributes_len, &total_len,
- a->type);
- else
- err = hal_ks_attribute_insert(bytes, bytes_len, attrs, &k->attributes_len, &total_len,
- a->type, a->value, a->length);
- if (err != HAL_OK)
- goto done;
- }
-
- err = HAL_OK;
-
}
- done:
- hal_ks_unlock();
- return err;
-}
-
-static hal_error_t ks_get_attributes(hal_ks_t *ks,
- hal_pkey_slot_t *slot,
- hal_pkey_attribute_t *attributes,
- const unsigned attributes_len,
- uint8_t *attributes_buffer,
- const size_t attributes_buffer_len)
-{
- if (ks == NULL || slot == NULL || attributes == NULL || attributes_len == 0 ||
- attributes_buffer == NULL)
- return HAL_ERROR_BAD_ARGUMENTS;
-
- ks_t *ksv = ks_to_ksv(ks);
- hal_error_t err = HAL_OK;
- unsigned b;
-
- hal_ks_lock();
-
- {
- if (ksv->db == NULL) {
- err = HAL_ERROR_KEYSTORE_ACCESS;
- goto done;
- }
-
- if ((err = hal_ks_index_find(&ksv->db->ksi, &slot->name, &b, &slot->hint)) != HAL_OK)
- goto done;
-
- const ks_key_t * const k = &ksv->db->keys[b];
-
- if (!key_visible_to_session(ksv, slot->client_handle, slot->session_handle, k)) {
- err = HAL_ERROR_KEY_NOT_FOUND;
- goto done;
- }
-
- hal_pkey_attribute_t attrs[k->attributes_len > 0 ? k->attributes_len : 1];
-
- if ((err = hal_ks_attribute_scan(k->der + k->der_len, sizeof(k->der) - k->der_len,
- attrs, k->attributes_len, NULL)) != HAL_OK)
+ for (unsigned b = 0; b < db.ks.size; i++)
+ if ((err = block_erase(&db.ks, b)) != HAL_OK)
goto done;
- uint8_t *abuf = attributes_buffer;
-
- for (int i = 0; i < attributes_len; i++) {
- int j = 0;
- while (j < k->attributes_len && attrs[j].type != attributes[i].type)
- j++;
- const int found = j < k->attributes_len;
-
- if (attributes_buffer_len == 0) {
- attributes[i].value = NULL;
- attributes[i].length = found ? attrs[j].length : 0;
- continue;
- }
-
- if (!found) {
- err = HAL_ERROR_ATTRIBUTE_NOT_FOUND;
- goto done;
- }
-
- if (attrs[j].length > attributes_buffer + attributes_buffer_len - abuf) {
- err = HAL_ERROR_RESULT_TOO_LONG;
- goto done;
- }
-
- memcpy(abuf, attrs[j].value, attrs[j].length);
- attributes[i].value = abuf;
- attributes[i].length = attrs[j].length;
- abuf += attrs[j].length;
- }
-
- err = HAL_OK;
-
- }
+ err = HAL_OK;
done:
hal_ks_unlock();
return err;
}
-const hal_ks_driver_t hal_ks_volatile_driver[1] = {{
- .init = ks_volatile_init,
- .shutdown = ks_volatile_shutdown,
- .open = ks_volatile_open,
- .close = ks_volatile_close,
- .store = ks_store,
- .fetch = ks_fetch,
- .delete = ks_delete,
- .match = ks_match,
- .set_attributes = ks_set_attributes,
- .get_attributes = ks_get_attributes
-}};
-
-#endif /* STATIC_KS_VOLATILE_SLOTS > 0 */
-
/*
* Local variables:
* indent-tabs-mode: nil