diff --git a/lib/ngtcp2_acktr.c b/lib/ngtcp2_acktr.c
index 568f86750bec2b9991a4e398c0ae636c6ec1c789..e4c658a2c228d95e47c3dc14733108e41e3430b6 100644
--- a/lib/ngtcp2_acktr.c
+++ b/lib/ngtcp2_acktr.c
@@ -36,8 +36,6 @@ int ngtcp2_acktr_entry_new(ngtcp2_acktr_entry **ent, uint64_t pkt_num,
     return NGTCP2_ERR_NOMEM;
   }
 
-  (*ent)->next = NULL;
-  (*ent)->pprev = NULL;
   (*ent)->pkt_num = pkt_num;
   (*ent)->tstamp = tstamp;
 
@@ -48,6 +46,8 @@ void ngtcp2_acktr_entry_del(ngtcp2_acktr_entry *ent, ngtcp2_mem *mem) {
   ngtcp2_mem_free(mem, ent);
 }
 
+static int greater(int64_t lhs, int64_t rhs) { return lhs > rhs; }
+
 int ngtcp2_acktr_init(ngtcp2_acktr *acktr, int delayed_ack, ngtcp2_log *log,
                       ngtcp2_mem *mem) {
   int rv;
@@ -58,11 +58,14 @@ int ngtcp2_acktr_init(ngtcp2_acktr *acktr, int delayed_ack, ngtcp2_log *log,
     return rv;
   }
 
-  acktr->ent = NULL;
-  acktr->tail = NULL;
+  rv = ngtcp2_ksl_init(&acktr->ent, greater, -1, mem);
+  if (rv != 0) {
+    ngtcp2_ringbuf_free(&acktr->acks);
+    return rv;
+  }
+
   acktr->log = log;
   acktr->mem = mem;
-  acktr->nack = 0;
   acktr->flags =
       delayed_ack ? NGTCP2_ACKTR_FLAG_DELAYED_ACK : NGTCP2_ACKTR_FLAG_NONE;
   acktr->first_unacked_ts = UINT64_MAX;
@@ -71,51 +74,44 @@ int ngtcp2_acktr_init(ngtcp2_acktr *acktr, int delayed_ack, ngtcp2_log *log,
 }
 
 void ngtcp2_acktr_free(ngtcp2_acktr *acktr) {
-  ngtcp2_acktr_entry *ent, *next;
   ngtcp2_acktr_ack_entry *ack_ent;
   size_t i;
+  ngtcp2_ksl_it it;
 
   if (acktr == NULL) {
     return;
   }
 
+  for (it = ngtcp2_ksl_begin(&acktr->ent); !ngtcp2_ksl_it_end(&it);
+       ngtcp2_ksl_it_next(&it)) {
+    ngtcp2_acktr_entry_del(ngtcp2_ksl_it_get(&it), acktr->mem);
+  }
+  ngtcp2_ksl_free(&acktr->ent);
+
   for (i = 0; i < acktr->acks.len; ++i) {
     ack_ent = ngtcp2_ringbuf_get(&acktr->acks, i);
     ngtcp2_mem_free(acktr->mem, ack_ent->ack);
   }
   ngtcp2_ringbuf_free(&acktr->acks);
-
-  for (ent = acktr->ent; ent;) {
-    next = ent->next;
-    ngtcp2_acktr_entry_del(ent, acktr->mem);
-    ent = next;
-  }
 }
 
 int ngtcp2_acktr_add(ngtcp2_acktr *acktr, ngtcp2_acktr_entry *ent,
                      int active_ack, ngtcp2_tstamp ts) {
-  ngtcp2_acktr_entry **pent;
-  ngtcp2_acktr_entry *tail;
+  ngtcp2_ksl_it it;
+  ngtcp2_acktr_entry *delent;
+  int rv;
 
-  for (pent = &acktr->ent; *pent; pent = &(*pent)->next) {
-    if ((*pent)->pkt_num > ent->pkt_num) {
-      continue;
-    }
+  it = ngtcp2_ksl_lower_bound(&acktr->ent, (int64_t)ent->pkt_num);
+  if (!ngtcp2_ksl_it_end(&it) &&
+      ngtcp2_ksl_it_key(&it) == (int64_t)ent->pkt_num) {
     /* TODO What to do if we receive duplicated packet number? */
-    if ((*pent)->pkt_num == ent->pkt_num) {
-      return NGTCP2_ERR_INVALID_ARGUMENT;
-    }
-    break;
+    return NGTCP2_ERR_INVALID_ARGUMENT;
   }
 
-  ent->next = *pent;
-  ent->pprev = pent;
-  if (ent->next) {
-    ent->next->pprev = &ent->next;
-  } else {
-    acktr->tail = ent;
+  rv = ngtcp2_ksl_insert(&acktr->ent, NULL, (int64_t)ent->pkt_num, ent);
+  if (rv != 0) {
+    return rv;
   }
-  *pent = ent;
 
   if (active_ack) {
     acktr->flags |= NGTCP2_ACKTR_FLAG_ACTIVE_ACK;
@@ -124,57 +120,38 @@ int ngtcp2_acktr_add(ngtcp2_acktr *acktr, ngtcp2_acktr_entry *ent,
     }
   }
 
-  if (++acktr->nack > NGTCP2_ACKTR_MAX_ENT) {
-    assert(acktr->tail);
-
-    tail = acktr->tail;
-    *tail->pprev = NULL;
-
-    acktr->tail = ngtcp2_struct_of(tail->pprev, ngtcp2_acktr_entry, next);
-
-    ngtcp2_acktr_entry_del(tail, acktr->mem);
-    --acktr->nack;
+  if (ngtcp2_ksl_len(&acktr->ent) > NGTCP2_ACKTR_MAX_ENT) {
+    it = ngtcp2_ksl_end(&acktr->ent);
+    ngtcp2_ksl_it_prev(&it);
+    delent = ngtcp2_ksl_it_get(&it);
+    ngtcp2_ksl_remove(&acktr->ent, NULL, (int64_t)delent->pkt_num);
+    ngtcp2_acktr_entry_del(delent, acktr->mem);
   }
 
   return 0;
 }
 
-void ngtcp2_acktr_forget(ngtcp2_acktr *acktr, ngtcp2_acktr_entry *ent) {
-  ngtcp2_acktr_entry *next;
+int ngtcp2_acktr_forget(ngtcp2_acktr *acktr, ngtcp2_acktr_entry *ent) {
+  ngtcp2_ksl_it it;
+  int rv;
 
-  if (ent->pprev != &acktr->ent) {
-    *ent->pprev = NULL;
-    acktr->tail = ngtcp2_struct_of(ent->pprev, ngtcp2_acktr_entry, next);
-  } else {
-    acktr->ent = acktr->tail = NULL;
-  }
+  it = ngtcp2_ksl_lower_bound(&acktr->ent, (int64_t)ent->pkt_num);
+  assert(ngtcp2_ksl_it_key(&it) == (int64_t)ent->pkt_num);
 
-  for (; ent;) {
-    next = ent->next;
+  for (; !ngtcp2_ksl_it_end(&it);) {
+    ent = ngtcp2_ksl_it_get(&it);
+    rv = ngtcp2_ksl_remove(&acktr->ent, &it, (int64_t)ent->pkt_num);
+    if (rv != 0) {
+      return rv;
+    }
     ngtcp2_acktr_entry_del(ent, acktr->mem);
-    ent = next;
-    --acktr->nack;
   }
-}
 
-ngtcp2_acktr_entry **ngtcp2_acktr_get(ngtcp2_acktr *acktr) {
-  return &acktr->ent;
+  return 0;
 }
 
-void ngtcp2_acktr_pop(ngtcp2_acktr *acktr) {
-  ngtcp2_acktr_entry *ent = acktr->ent;
-
-  assert(acktr->ent);
-
-  --acktr->nack;
-  acktr->ent = acktr->ent->next;
-  if (acktr->ent) {
-    acktr->ent->pprev = &acktr->ent;
-  } else {
-    acktr->tail = NULL;
-  }
-
-  ngtcp2_acktr_entry_del(ent, acktr->mem);
+ngtcp2_ksl_it ngtcp2_acktr_get(ngtcp2_acktr *acktr) {
+  return ngtcp2_ksl_begin(&acktr->ent);
 }
 
 ngtcp2_acktr_ack_entry *ngtcp2_acktr_add_ack(ngtcp2_acktr *acktr,
@@ -197,78 +174,91 @@ ngtcp2_acktr_ack_entry *ngtcp2_acktr_add_ack(ngtcp2_acktr *acktr,
   return ent;
 }
 
-static void acktr_remove(ngtcp2_acktr *acktr, ngtcp2_acktr_entry **pent) {
-  ngtcp2_acktr_entry *ent;
+/*
+ * acktr_remove removes |ent| from |acktr|.  The iterator which points
+ * to the entry next to |ent| is assigned to |it|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGTCP2_ERR_NOMEM
+ *     Out of memory.
+ */
+static int acktr_remove(ngtcp2_acktr *acktr, ngtcp2_ksl_it *it,
+                        ngtcp2_acktr_entry *ent) {
+  int rv;
 
-  ent = *pent;
-  *pent = (*pent)->next;
-  if (*pent) {
-    (*pent)->pprev = pent;
-  } else {
-    acktr->tail = ngtcp2_struct_of(pent, ngtcp2_acktr_entry, next);
+  rv = ngtcp2_ksl_remove(&acktr->ent, it, (int64_t)ent->pkt_num);
+  if (rv != 0) {
+    return rv;
   }
 
   ngtcp2_acktr_entry_del(ent, acktr->mem);
 
-  --acktr->nack;
+  return 0;
 }
 
-static void acktr_on_ack(ngtcp2_acktr *acktr, ngtcp2_ringbuf *rb,
-                         size_t ack_ent_offset) {
-  ngtcp2_acktr_ack_entry *ent;
+static int acktr_on_ack(ngtcp2_acktr *acktr, ngtcp2_ringbuf *rb,
+                        size_t ack_ent_offset) {
+  ngtcp2_acktr_ack_entry *ack_ent;
+  ngtcp2_acktr_entry *ent;
   ngtcp2_ack *fr;
-  ngtcp2_acktr_entry **pent;
   uint64_t largest_ack, min_ack;
   size_t i;
+  ngtcp2_ksl_it it;
+  int rv;
 
-  ent = ngtcp2_ringbuf_get(rb, ack_ent_offset);
-  fr = ent->ack;
+  ack_ent = ngtcp2_ringbuf_get(rb, ack_ent_offset);
+  fr = ack_ent->ack;
   largest_ack = fr->largest_ack;
+  min_ack = largest_ack - fr->first_ack_blklen;
 
   /* Assume that ngtcp2_pkt_validate_ack(fr) returns 0 */
-  for (pent = &acktr->ent; *pent; pent = &(*pent)->next) {
-    if (largest_ack >= (*pent)->pkt_num) {
-      break;
-    }
-  }
-  if (*pent == NULL) {
+  it = ngtcp2_ksl_lower_bound(&acktr->ent, (int64_t)largest_ack);
+  if (ngtcp2_ksl_it_end(&it)) {
     goto fin;
   }
 
-  min_ack = largest_ack - fr->first_ack_blklen;
-
-  for (; *pent;) {
-    if (min_ack <= (*pent)->pkt_num && (*pent)->pkt_num <= largest_ack) {
-      acktr_remove(acktr, pent);
-      continue;
+  for (; !ngtcp2_ksl_it_end(&it);) {
+    ent = ngtcp2_ksl_it_get(&it);
+    if (ent->pkt_num < min_ack) {
+      break;
+    }
+    rv = acktr_remove(acktr, &it, ent);
+    if (rv != 0) {
+      return rv;
     }
-    break;
   }
 
-  for (i = 0; i < fr->num_blks && *pent;) {
+  for (i = 0; i < fr->num_blks && !ngtcp2_ksl_it_end(&it); ++i) {
     largest_ack = min_ack - fr->blks[i].gap - 2;
     min_ack = largest_ack - fr->blks[i].blklen;
 
-    for (; *pent;) {
-      if ((*pent)->pkt_num > largest_ack) {
-        pent = &(*pent)->next;
-        continue;
-      }
-      if ((*pent)->pkt_num < min_ack) {
+    it = ngtcp2_ksl_lower_bound(&acktr->ent, (int64_t)largest_ack);
+    if (ngtcp2_ksl_it_end(&it)) {
+      break;
+    }
+
+    for (; !ngtcp2_ksl_it_end(&it);) {
+      ent = ngtcp2_ksl_it_get(&it);
+      if (ent->pkt_num < min_ack) {
         break;
       }
-      acktr_remove(acktr, pent);
+      rv = acktr_remove(acktr, &it, ent);
+      if (rv != 0) {
+        return rv;
+      }
     }
-
-    ++i;
   }
 
 fin:
   for (i = ack_ent_offset; i < rb->len; ++i) {
-    ent = ngtcp2_ringbuf_get(rb, i);
-    ngtcp2_mem_free(acktr->mem, ent->ack);
+    ack_ent = ngtcp2_ringbuf_get(rb, i);
+    ngtcp2_mem_free(acktr->mem, ack_ent->ack);
   }
   ngtcp2_ringbuf_resize(rb, ack_ent_offset);
+
+  return 0;
 }
 
 int ngtcp2_acktr_recv_ack(ngtcp2_acktr *acktr, const ngtcp2_ack *fr,
@@ -278,6 +268,7 @@ int ngtcp2_acktr_recv_ack(ngtcp2_acktr *acktr, const ngtcp2_ack *fr,
   size_t i, j;
   ngtcp2_ringbuf *rb = &acktr->acks;
   size_t nacks = ngtcp2_ringbuf_len(rb);
+  int rv;
 
   /* Assume that ngtcp2_pkt_validate_ack(fr) returns 0 */
   for (j = 0; j < nacks; ++j) {
@@ -294,7 +285,10 @@ int ngtcp2_acktr_recv_ack(ngtcp2_acktr *acktr, const ngtcp2_ack *fr,
 
   for (;;) {
     if (min_ack <= ent->pkt_num && ent->pkt_num <= largest_ack) {
-      acktr_on_ack(acktr, rb, j);
+      rv = acktr_on_ack(acktr, rb, j);
+      if (rv != 0) {
+        return rv;
+      }
       if (conn && largest_ack == ent->pkt_num && ent->ack_only) {
         ngtcp2_conn_update_rtt(conn, ts - ent->ts, fr->ack_delay_unscaled,
                                ent->ack_only);
@@ -304,7 +298,7 @@ int ngtcp2_acktr_recv_ack(ngtcp2_acktr *acktr, const ngtcp2_ack *fr,
     break;
   }
 
-  for (i = 0; i < fr->num_blks && j < nacks;) {
+  for (i = 0; i < fr->num_blks && j < nacks; ++i) {
     largest_ack = min_ack - fr->blks[i].gap - 2;
     min_ack = largest_ack - fr->blks[i].blklen;
 
@@ -320,11 +314,8 @@ int ngtcp2_acktr_recv_ack(ngtcp2_acktr *acktr, const ngtcp2_ack *fr,
       if (ent->pkt_num < min_ack) {
         break;
       }
-      acktr_on_ack(acktr, rb, j);
-      return 0;
+      return acktr_on_ack(acktr, rb, j);
     }
-
-    ++i;
   }
 
   return 0;
diff --git a/lib/ngtcp2_acktr.h b/lib/ngtcp2_acktr.h
index 1394a97edd0f9b643cd80093abe8acc6110f162e..b2d41abd5d625db9f21f886b2e505a63ab44a607 100644
--- a/lib/ngtcp2_acktr.h
+++ b/lib/ngtcp2_acktr.h
@@ -33,6 +33,7 @@
 
 #include "ngtcp2_mem.h"
 #include "ngtcp2_ringbuf.h"
+#include "ngtcp2_ksl.h"
 
 /* NGTCP2_ACKTR_MAX_ENT is the maximum number of ngtcp2_acktr_entry
    which ngtcp2_acktr stores. */
@@ -54,7 +55,6 @@ typedef struct ngtcp2_log ngtcp2_log;
  * ngtcp2_acktr_entry is a single packet which needs to be acked.
  */
 struct ngtcp2_acktr_entry {
-  ngtcp2_acktr_entry **pprev, *next;
   uint64_t pkt_num;
   ngtcp2_tstamp tstamp;
 };
@@ -105,12 +105,11 @@ typedef enum {
  */
 typedef struct {
   ngtcp2_ringbuf acks;
-  /* ent points to the head of list which is ordered by the decreasing
-     order of packet number. */
-  ngtcp2_acktr_entry *ent, *tail;
+  /* ent includes ngtcp2_acktr_entry sorted by decreasing order of
+     packet number. */
+  ngtcp2_ksl ent;
   ngtcp2_log *log;
   ngtcp2_mem *mem;
-  size_t nack;
   /* flags is bitwise OR of zero, or more of ngtcp2_ack_flag. */
   uint16_t flags;
   /* first_unacked_ts is timestamp when ngtcp2_acktr_entry is added
@@ -151,24 +150,24 @@ int ngtcp2_acktr_add(ngtcp2_acktr *acktr, ngtcp2_acktr_entry *ent,
                      int active_ack, ngtcp2_tstamp ts);
 
 /*
- * ngtcp2_acktr_forget removes all entries from |ent| to the end of
- * the list.  This function assumes that |ent| is linked directly, or
- * indirectly from acktr->ent.
+ * ngtcp2_acktr_forget removes all entries which have the packet
+ * number that is equal to or less than ent->pkt_num.  This function
+ * assumes that |acktr| includes |ent|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGTCP2_ERR_NOMEM
+ *     Out of memory.
  */
-void ngtcp2_acktr_forget(ngtcp2_acktr *acktr, ngtcp2_acktr_entry *ent);
+int ngtcp2_acktr_forget(ngtcp2_acktr *acktr, ngtcp2_acktr_entry *ent);
 
 /*
  * ngtcp2_acktr_get returns the pointer to pointer to the entry which
  * has the largest packet number to be acked.  If there is no entry,
- * this function returns a pointer which includes NULL on dereference.
- */
-ngtcp2_acktr_entry **ngtcp2_acktr_get(ngtcp2_acktr *acktr);
-
-/*
- * ngtcp2_acktr_removes and frees the head of entries, which has the
- * largest packet number.
+ * returned value satisfies ngtcp2_ksl_it_end(&it) != 0.
  */
-void ngtcp2_acktr_pop(ngtcp2_acktr *acktr);
+ngtcp2_ksl_it ngtcp2_acktr_get(ngtcp2_acktr *acktr);
 
 /*
  * ngtcp2_acktr_add_ack adds the outgoing ACK frame |fr| to |acktr|.
diff --git a/lib/ngtcp2_conn.c b/lib/ngtcp2_conn.c
index 773467eb64709294e873362aeab9c139ca78df07..1a08b6f5bcd0c6b66251724a0ec1fa60e6e0d145 100644
--- a/lib/ngtcp2_conn.c
+++ b/lib/ngtcp2_conn.c
@@ -487,7 +487,8 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr,
   ngtcp2_ack_blk *blk;
   int initial = 1;
   uint64_t gap;
-  ngtcp2_acktr_entry **prpkt;
+  ngtcp2_ksl_it it;
+  ngtcp2_acktr_entry *rpkt;
   ngtcp2_frame *fr;
   ngtcp2_ack *ack;
   /* TODO Measure an actual size of ACK bloks to find the best default
@@ -503,8 +504,8 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr,
     return 0;
   }
 
-  prpkt = ngtcp2_acktr_get(acktr);
-  if (*prpkt == NULL) {
+  it = ngtcp2_acktr_get(acktr);
+  if (ngtcp2_ksl_it_end(&it)) {
     ngtcp2_acktr_commit_ack(acktr);
     return 0;
   }
@@ -517,19 +518,21 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr,
 
   ack = &fr->ack;
 
-  first_pkt_num = last_pkt_num = (*prpkt)->pkt_num;
+  rpkt = ngtcp2_ksl_it_get(&it);
+  first_pkt_num = last_pkt_num = rpkt->pkt_num;
 
   ack->type = NGTCP2_FRAME_ACK;
   ack->largest_ack = first_pkt_num;
-  ack->ack_delay_unscaled = ts - (*prpkt)->tstamp;
+  ack->ack_delay_unscaled = ts - rpkt->tstamp;
   ack->ack_delay = (ack->ack_delay_unscaled / 1000) >> ack_delay_exponent;
   ack->num_blks = 0;
 
-  prpkt = &(*prpkt)->next;
+  ngtcp2_ksl_it_next(&it);
 
-  for (; *prpkt; prpkt = &(*prpkt)->next) {
-    if ((*prpkt)->pkt_num + 1 == last_pkt_num) {
-      last_pkt_num = (*prpkt)->pkt_num;
+  for (; !ngtcp2_ksl_it_end(&it); ngtcp2_ksl_it_next(&it)) {
+    rpkt = ngtcp2_ksl_it_get(&it);
+    if (rpkt->pkt_num + 1 == last_pkt_num) {
+      last_pkt_num = rpkt->pkt_num;
       continue;
     }
 
@@ -549,10 +552,10 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr,
       blk->blklen = first_pkt_num - last_pkt_num;
     }
 
-    gap = last_pkt_num - (*prpkt)->pkt_num - 2;
-    first_pkt_num = last_pkt_num = (*prpkt)->pkt_num;
+    gap = last_pkt_num - rpkt->pkt_num - 2;
+    first_pkt_num = last_pkt_num = rpkt->pkt_num;
 
-    if (ack->num_blks == NGTCP2_MAX_ACK_BLKS) {
+    if (ack->num_blks == NGTCP2_MAX_ACK_BLKS - 1) {
       break;
     }
   }
@@ -572,10 +575,13 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr,
     blk->blklen = first_pkt_num - last_pkt_num;
   }
 
-  /* TODO Just remove entries which cannot be fit into a single ACK
-     frame for now. */
-  if (*prpkt) {
-    ngtcp2_acktr_forget(acktr, *prpkt);
+  /* TODO Just remove entries which cannot fit into a single ACK frame
+     for now. */
+  if (!ngtcp2_ksl_it_end(&it)) {
+    rv = ngtcp2_acktr_forget(acktr, ngtcp2_ksl_it_get(&it));
+    if (rv != 0) {
+      return rv;
+    }
   }
 
   *pfr = fr;
@@ -1583,10 +1589,12 @@ static ssize_t conn_write_server_handshake(ngtcp2_conn *conn, uint8_t *dest,
   ngtcp2_crypto_data *cdata;
   ssize_t nwrite;
   ssize_t res = 0;
+  ngtcp2_ksl_it it;
 
   for (;;) {
     if (ngtcp2_ringbuf_len(rb) == 0) {
-      if (conn->early_ckm && *ngtcp2_acktr_get(&conn->pktns.acktr)) {
+      it = ngtcp2_acktr_get(&conn->pktns.acktr);
+      if (conn->early_ckm && !ngtcp2_ksl_it_end(&it)) {
         assert(conn->pktns.tx_ckm);
 
         nwrite = conn_write_protected_ack_pkt(conn, dest, destlen, ts);
diff --git a/tests/ngtcp2_acktr_test.c b/tests/ngtcp2_acktr_test.c
index c1be61c6ff159ff335466aece8aa5e5d7c1a097d..c42d43fd339fb97f34764bee12372858072a6372 100644
--- a/tests/ngtcp2_acktr_test.c
+++ b/tests/ngtcp2_acktr_test.c
@@ -33,7 +33,8 @@ void test_ngtcp2_acktr_add(void) {
   ngtcp2_acktr acktr;
   ngtcp2_acktr_entry *ents[7];
   uint64_t max_pkt_num[] = {1, 5, 7, 7, 7, 7, 7};
-  ngtcp2_acktr_entry **pent;
+  ngtcp2_acktr_entry *ent;
+  ngtcp2_ksl_it it;
   size_t i;
   int rv;
   ngtcp2_mem *mem = ngtcp2_mem_default();
@@ -55,20 +56,26 @@ void test_ngtcp2_acktr_add(void) {
 
     CU_ASSERT(0 == rv);
 
-    pent = ngtcp2_acktr_get(&acktr);
+    it = ngtcp2_acktr_get(&acktr);
+    ent = ngtcp2_ksl_it_get(&it);
 
-    CU_ASSERT(max_pkt_num[i] == (*pent)->pkt_num);
+    CU_ASSERT(max_pkt_num[i] == ent->pkt_num);
   }
 
   for (i = 0; i < arraylen(ents); ++i) {
-    ngtcp2_acktr_pop(&acktr);
+    it = ngtcp2_acktr_get(&acktr);
+    ent = ngtcp2_ksl_it_get(&it);
+    ngtcp2_ksl_remove(&acktr.ent, NULL, (int64_t)ent->pkt_num);
+    ngtcp2_acktr_entry_del(ent, mem);
 
-    pent = ngtcp2_acktr_get(&acktr);
+    it = ngtcp2_acktr_get(&acktr);
 
     if (i != arraylen(ents) - 1) {
-      CU_ASSERT(arraylen(ents) - i - 1 == (*pent)->pkt_num);
+      ent = ngtcp2_ksl_it_get(&it);
+
+      CU_ASSERT(arraylen(ents) - i - 1 == ent->pkt_num);
     } else {
-      CU_ASSERT(NULL == *pent);
+      CU_ASSERT(ngtcp2_ksl_it_end(&it));
     }
   }
 
@@ -93,9 +100,10 @@ void test_ngtcp2_acktr_eviction(void) {
   ngtcp2_acktr acktr;
   ngtcp2_mem *mem = ngtcp2_mem_default();
   size_t i;
-  ngtcp2_acktr_entry *ent, *next;
+  ngtcp2_acktr_entry *ent;
   const size_t extra = 17;
   ngtcp2_log log;
+  ngtcp2_ksl_it it;
 
   ngtcp2_log_init(&log, NULL, NULL, 0, NULL);
   ngtcp2_acktr_init(&acktr, 0 /* delayed_ack */, &log, mem);
@@ -105,19 +113,13 @@ void test_ngtcp2_acktr_eviction(void) {
     ngtcp2_acktr_add(&acktr, ent, 1, 999 + i);
   }
 
-  CU_ASSERT(NGTCP2_ACKTR_MAX_ENT == acktr.nack);
-  CU_ASSERT(NULL != acktr.ent);
+  CU_ASSERT(NGTCP2_ACKTR_MAX_ENT == ngtcp2_ksl_len(&acktr.ent));
 
-  for (ent = acktr.ent; ent; ent = ent->next) {
-    CU_ASSERT(ent == *ent->pprev);
-  }
-
-  for (i = 0, ent = acktr.ent; ent; ++i) {
-    next = ent->next;
+  for (i = 0, it = ngtcp2_acktr_get(&acktr); !ngtcp2_ksl_it_end(&it);
+       ++i, ngtcp2_ksl_it_next(&it)) {
+    ent = ngtcp2_ksl_it_get(&it);
 
     CU_ASSERT(NGTCP2_ACKTR_MAX_ENT + extra - i - 1 == ent->pkt_num);
-
-    ent = next;
   }
 
   ngtcp2_acktr_free(&acktr);
@@ -130,19 +132,13 @@ void test_ngtcp2_acktr_eviction(void) {
     ngtcp2_acktr_add(&acktr, ent, 1, 999 + i);
   }
 
-  CU_ASSERT(NGTCP2_ACKTR_MAX_ENT == acktr.nack);
-  CU_ASSERT(NULL != acktr.ent);
+  CU_ASSERT(NGTCP2_ACKTR_MAX_ENT == ngtcp2_ksl_len(&acktr.ent));
 
-  for (ent = acktr.ent; ent; ent = ent->next) {
-    CU_ASSERT(ent == *ent->pprev);
-  }
-
-  for (i = 0, ent = acktr.ent; ent; ++i) {
-    next = ent->next;
+  for (i = 0, it = ngtcp2_acktr_get(&acktr); !ngtcp2_ksl_it_end(&it);
+       ++i, ngtcp2_ksl_it_next(&it)) {
+    ent = ngtcp2_ksl_it_get(&it);
 
     CU_ASSERT(NGTCP2_ACKTR_MAX_ENT + extra - i - 1 == ent->pkt_num);
-
-    ent = next;
   }
 
   ngtcp2_acktr_free(&acktr);
@@ -154,6 +150,7 @@ void test_ngtcp2_acktr_forget(void) {
   size_t i;
   ngtcp2_acktr_entry *ent;
   ngtcp2_log log;
+  ngtcp2_ksl_it it;
 
   ngtcp2_log_init(&log, NULL, NULL, 0, NULL);
   ngtcp2_acktr_init(&acktr, 0 /* delayed_ack */, &log, mem);
@@ -163,19 +160,38 @@ void test_ngtcp2_acktr_forget(void) {
     ngtcp2_acktr_add(&acktr, ent, 1, 999 + i);
   }
 
-  CU_ASSERT(7 == acktr.nack);
+  CU_ASSERT(7 == ngtcp2_ksl_len(&acktr.ent));
+
+  it = ngtcp2_acktr_get(&acktr);
+  ngtcp2_ksl_it_next(&it);
+  ngtcp2_ksl_it_next(&it);
+  ngtcp2_ksl_it_next(&it);
+  ent = ngtcp2_ksl_it_get(&it);
+  ngtcp2_acktr_forget(&acktr, ent);
+
+  CU_ASSERT(3 == ngtcp2_ksl_len(&acktr.ent));
+
+  it = ngtcp2_acktr_get(&acktr);
+  ent = ngtcp2_ksl_it_get(&it);
 
-  ngtcp2_acktr_forget(&acktr, acktr.ent->next->next->next);
+  CU_ASSERT(6 == ent->pkt_num);
 
-  CU_ASSERT(3 == acktr.nack);
-  CU_ASSERT(NULL == acktr.ent->next->next->next);
-  CU_ASSERT(acktr.ent->next->next == acktr.tail);
+  ngtcp2_ksl_it_next(&it);
+  ent = ngtcp2_ksl_it_get(&it);
 
-  ngtcp2_acktr_forget(&acktr, acktr.ent);
+  CU_ASSERT(5 == ent->pkt_num);
 
-  CU_ASSERT(0 == acktr.nack);
-  CU_ASSERT(NULL == acktr.ent);
-  CU_ASSERT(NULL == acktr.tail);
+  ngtcp2_ksl_it_next(&it);
+  ent = ngtcp2_ksl_it_get(&it);
+
+  CU_ASSERT(4 == ent->pkt_num);
+
+  it = ngtcp2_acktr_get(&acktr);
+  ent = ngtcp2_ksl_it_get(&it);
+
+  ngtcp2_acktr_forget(&acktr, ent);
+
+  CU_ASSERT(0 == ngtcp2_ksl_len(&acktr.ent));
 
   ngtcp2_acktr_free(&acktr);
 }
@@ -192,6 +208,7 @@ void test_ngtcp2_acktr_recv_ack(void) {
   uint64_t pkt_num;
   ngtcp2_ack_blk *blks;
   ngtcp2_log log;
+  ngtcp2_ksl_it it;
 
   ngtcp2_log_init(&log, NULL, NULL, 0, NULL);
   ngtcp2_acktr_init(&acktr, 0 /* delayed_ack */, &log, mem);
@@ -228,20 +245,32 @@ void test_ngtcp2_acktr_recv_ack(void) {
   ngtcp2_acktr_recv_ack(&acktr, &ackfr, NULL, 1000000009);
 
   CU_ASSERT(0 == ngtcp2_ringbuf_len(&acktr.acks));
-  CU_ASSERT(5 == acktr.nack);
+  CU_ASSERT(5 == ngtcp2_ksl_len(&acktr.ent));
 
-  ent = acktr.ent;
+  it = ngtcp2_acktr_get(&acktr);
+  ent = ngtcp2_ksl_it_get(&it);
 
   CU_ASSERT(4497 == ent->pkt_num);
-  ent = ent->next;
+
+  ngtcp2_ksl_it_next(&it);
+  ent = ngtcp2_ksl_it_get(&it);
+
   CU_ASSERT(4496 == ent->pkt_num);
-  ent = ent->next;
+
+  ngtcp2_ksl_it_next(&it);
+  ent = ngtcp2_ksl_it_get(&it);
+
   CU_ASSERT(4494 == ent->pkt_num);
-  ent = ent->next;
+
+  ngtcp2_ksl_it_next(&it);
+  ent = ngtcp2_ksl_it_get(&it);
+
   CU_ASSERT(4490 == ent->pkt_num);
-  ent = ent->next;
+
+  ngtcp2_ksl_it_next(&it);
+  ent = ngtcp2_ksl_it_get(&it);
+
   CU_ASSERT(4483 == ent->pkt_num);
-  CU_ASSERT(ent == acktr.tail);
 
   ngtcp2_acktr_free(&acktr);
 }
diff --git a/tests/ngtcp2_conn_test.c b/tests/ngtcp2_conn_test.c
index 74fc7803334c30bf533a2317d39b34f1a3983d51..2843b600da0d22bc077de297d54414ab66a243c5 100644
--- a/tests/ngtcp2_conn_test.c
+++ b/tests/ngtcp2_conn_test.c
@@ -1801,7 +1801,7 @@ void test_ngtcp2_conn_recv_delayed_handshake_pkt(void) {
   rv = ngtcp2_conn_recv(conn, buf, pktlen, 1);
 
   CU_ASSERT(0 == rv);
-  CU_ASSERT(1 == conn->hs_pktns.acktr.nack);
+  CU_ASSERT(1 == ngtcp2_ksl_len(&conn->hs_pktns.acktr.ent));
   CU_ASSERT(conn->hs_pktns.acktr.flags & NGTCP2_ACKTR_FLAG_ACTIVE_ACK);
 
   ngtcp2_conn_del(conn);
@@ -1845,7 +1845,7 @@ void test_ngtcp2_conn_recv_delayed_handshake_pkt(void) {
   rv = ngtcp2_conn_recv(conn, buf, pktlen, 1);
 
   CU_ASSERT(0 == rv);
-  CU_ASSERT(1 == conn->hs_pktns.acktr.nack);
+  CU_ASSERT(1 == ngtcp2_ksl_len(&conn->hs_pktns.acktr.ent));
   CU_ASSERT(!conn->hs_pktns.acktr.flags);
 
   ngtcp2_conn_del(conn);
@@ -2875,6 +2875,7 @@ void test_ngtcp2_conn_recv_compound_pkt(void) {
   ngtcp2_tstamp t = 0;
   ngtcp2_acktr_entry *ackent;
   int rv;
+  ngtcp2_ksl_it it;
 
   /* 2 QUIC long packets in one UDP packet */
   setup_handshake_server(&conn);
@@ -2897,11 +2898,13 @@ void test_ngtcp2_conn_recv_compound_pkt(void) {
 
   CU_ASSERT(spktlen > 0);
 
-  ackent = conn->in_pktns.acktr.ent;
+  it = ngtcp2_acktr_get(&conn->in_pktns.acktr);
+  ackent = ngtcp2_ksl_it_get(&it);
 
   CU_ASSERT(ackent->pkt_num == pkt_num);
 
-  ackent = ackent->next;
+  ngtcp2_ksl_it_next(&it);
+  ackent = ngtcp2_ksl_it_get(&it);
 
   CU_ASSERT(ackent->pkt_num == pkt_num - 1);
 
@@ -2931,11 +2934,13 @@ void test_ngtcp2_conn_recv_compound_pkt(void) {
 
   CU_ASSERT(0 == rv);
 
-  ackent = conn->pktns.acktr.ent;
+  it = ngtcp2_acktr_get(&conn->pktns.acktr);
+  ackent = ngtcp2_ksl_it_get(&it);
 
   CU_ASSERT(ackent->pkt_num == pkt_num);
 
-  ackent = conn->hs_pktns.acktr.ent;
+  it = ngtcp2_acktr_get(&conn->hs_pktns.acktr);
+  ackent = ngtcp2_ksl_it_get(&it);
 
   CU_ASSERT(ackent->pkt_num == pkt_num - 1);
 
@@ -2973,7 +2978,7 @@ void test_ngtcp2_conn_pkt_payloadlen(void) {
   spktlen = ngtcp2_conn_handshake(conn, buf, sizeof(buf), buf, pktlen, ++t);
 
   CU_ASSERT(spktlen == 0);
-  CU_ASSERT(NULL == conn->in_pktns.acktr.ent);
+  CU_ASSERT(0 == ngtcp2_ksl_len(&conn->in_pktns.acktr.ent));
 
   ngtcp2_conn_del(conn);
 }