tbf: Use LListHead instead of llist_pods

LListHead does basically the same like llist_pods, but more C++ish
and with type safety.

This commit turns the former list field of gprs_rlcmac_tbf into a
private field, provides accessors, moves the related code from
pcu_vty.c to pcu_vty_functions.cpp, and removes the llist_pods
type and related code.

Sponsored-by: On-Waves ehf
diff --git a/src/bts.cpp b/src/bts.cpp
index 1eea082..52811c2 100644
--- a/src/bts.cpp
+++ b/src/bts.cpp
@@ -127,8 +127,6 @@
 	, m_ms_store(this)
 {
 	memset(&m_bts, 0, sizeof(m_bts));
-	INIT_LLIST_HEAD(&m_bts.ul_tbfs);
-	INIT_LLIST_HEAD(&m_bts.dl_tbfs);
 	m_bts.bts = this;
 
 	/* initialize back pointers */
@@ -214,14 +212,14 @@
 {
 	uint8_t l, trx, ts, any_tbf = 0;
 	struct gprs_rlcmac_tbf *tbf;
-	struct llist_pods *lpods;
+	LListHead<gprs_rlcmac_tbf> *pos;
 	struct gprs_rlcmac_paging *pag;
 	uint8_t slot_mask[8];
 	int8_t first_ts; /* must be signed */
 
-	llist_head *tbfs_lists[] = {
-		&m_bts.ul_tbfs,
-		&m_bts.dl_tbfs,
+	LListHead<gprs_rlcmac_tbf> *tbfs_lists[] = {
+		&m_ul_tbfs,
+		&m_dl_tbfs,
 		NULL
 	};
 
@@ -235,7 +233,8 @@
 	 * Don't mark, if TBF uses a different slot that is already marked. */
 	memset(slot_mask, 0, sizeof(slot_mask));
 	for (l = 0; tbfs_lists[l]; l++) {
-		llist_pods_for_each_entry(tbf, tbfs_lists[l], list, lpods) {
+		llist_for_each(pos, tbfs_lists[l]) {
+			tbf = pos->entry();
 			first_ts = -1;
 			for (ts = 0; ts < 8; ts++) {
 				if (tbf->pdch[ts]) {
@@ -296,11 +295,12 @@
 gprs_rlcmac_dl_tbf *BTS::dl_tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts)
 {
 	struct gprs_rlcmac_dl_tbf *tbf;
-	struct llist_pods *lpods;
+	LListHead<gprs_rlcmac_tbf> *pos;
 
 	/* only one TBF can poll on specific TS/FN, because scheduler can only
 	 * schedule one downlink control block (with polling) at a FN per TS */
-	llist_pods_for_each_entry(tbf, &m_bts.dl_tbfs, list, lpods) {
+	llist_for_each(pos, &m_dl_tbfs) {
+		tbf = as_dl_tbf(pos->entry());
 		if (tbf->state_is_not(GPRS_RLCMAC_RELEASING)
 		 && tbf->poll_state == GPRS_RLCMAC_POLL_SCHED
 		 && tbf->poll_fn == fn && tbf->trx->trx_no == trx
@@ -313,11 +313,12 @@
 gprs_rlcmac_ul_tbf *BTS::ul_tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts)
 {
 	struct gprs_rlcmac_ul_tbf *tbf;
-	struct llist_pods *lpods;
+	LListHead<gprs_rlcmac_tbf> *pos;
 
 	/* only one TBF can poll on specific TS/FN, because scheduler can only
 	 * schedule one downlink control block (with polling) at a FN per TS */
-	llist_pods_for_each_entry(tbf, &m_bts.ul_tbfs, list, lpods) {
+	llist_for_each(pos, &m_ul_tbfs) {
+		tbf = as_ul_tbf(pos->entry());
 		if (tbf->state_is_not(GPRS_RLCMAC_RELEASING)
 		 && tbf->poll_state == GPRS_RLCMAC_POLL_SCHED
 		 && tbf->poll_fn == fn && tbf->trx->trx_no == trx
@@ -1241,13 +1242,15 @@
 	return rc;
 }
 
-gprs_rlcmac_tbf *gprs_rlcmac_pdch::tbf_from_list_by_tfi(struct llist_head *tbf_list, uint8_t tfi,
+gprs_rlcmac_tbf *gprs_rlcmac_pdch::tbf_from_list_by_tfi(
+		LListHead<gprs_rlcmac_tbf> *tbf_list, uint8_t tfi,
 		enum gprs_rlcmac_tbf_direction dir)
 {
 	gprs_rlcmac_tbf *tbf;
-	struct llist_pods *lpods;
+	LListHead<gprs_rlcmac_tbf> *pos;
 
-	llist_pods_for_each_entry(tbf, tbf_list, list, lpods) {
+	llist_for_each(pos, tbf_list) {
+		tbf = pos->entry();
 		if (tbf->tfi() != tfi)
 			continue;
 		if (!tbf->pdch[ts_no])
diff --git a/src/bts.h b/src/bts.h
index 45432ea..704a5be 100644
--- a/src/bts.h
+++ b/src/bts.h
@@ -109,7 +109,8 @@
 	void rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *, uint32_t fn);
 	void rcv_resource_request(Packet_Resource_Request_t *t, uint32_t fn);
 	void rcv_measurement_report(Packet_Measurement_Report_t *t, uint32_t fn);
-	gprs_rlcmac_tbf *tbf_from_list_by_tfi(struct llist_head *tbf_list, uint8_t tfi,
+	gprs_rlcmac_tbf *tbf_from_list_by_tfi(
+		LListHead<gprs_rlcmac_tbf> *tbf_list, uint8_t tfi,
 		enum gprs_rlcmac_tbf_direction dir);
 	gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi,
 		enum gprs_rlcmac_tbf_direction dir);
@@ -185,12 +186,6 @@
 	struct {int16_t low; int16_t high;} cs_lqual_ranges[4];
 	uint16_t cs_downgrade_threshold; /* downgrade if less packets left (DL) */
 
-	/* TBF handling, make private or move into TBFController */
-	/* list of uplink TBFs */
-	struct llist_head ul_tbfs;
-	/* list of downlink TBFs */
-	struct llist_head dl_tbfs;
-
 	/* State for dynamic algorithm selection */
 	int multislot_disabled;
 
@@ -319,6 +314,8 @@
 	struct rate_ctr_group *rate_counters() const;
 	struct osmo_stat_item_group *stat_items() const;
 
+	LListHead<gprs_rlcmac_tbf>& ul_tbfs();
+	LListHead<gprs_rlcmac_tbf>& dl_tbfs();
 private:
 	int m_cur_fn;
 	int m_cur_blk_fn;
@@ -330,6 +327,11 @@
 
 	GprsMsStorage m_ms_store;
 
+	/* list of uplink TBFs */
+	LListHead<gprs_rlcmac_tbf> m_ul_tbfs;
+	/* list of downlink TBFs */
+	LListHead<gprs_rlcmac_tbf> m_dl_tbfs;
+
 private:
 	/* disable copying to avoid slicing */
 	BTS(const BTS&);
@@ -361,6 +363,16 @@
 	return ms_store().get_ms(0, 0, imsi);
 }
 
+inline LListHead<gprs_rlcmac_tbf>& BTS::ul_tbfs()
+{
+	return m_ul_tbfs;
+}
+
+inline LListHead<gprs_rlcmac_tbf>& BTS::dl_tbfs()
+{
+	return m_dl_tbfs;
+}
+
 inline BTS *gprs_rlcmac_pdch::bts() const
 {
 	return trx->bts;
diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp
index 8bf2573..4939efd 100644
--- a/src/gprs_rlcmac_sched.cpp
+++ b/src/gprs_rlcmac_sched.cpp
@@ -25,7 +25,7 @@
 
 #include "pcu_utils.h"
 
-static uint32_t sched_poll(struct gprs_rlcmac_bts *bts,
+static uint32_t sched_poll(BTS *bts,
 		    uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr,
 		    struct gprs_rlcmac_tbf **poll_tbf,
 		    struct gprs_rlcmac_tbf **ul_ass_tbf,
@@ -34,7 +34,7 @@
 {
 	struct gprs_rlcmac_ul_tbf *ul_tbf;
 	struct gprs_rlcmac_dl_tbf *dl_tbf;
-	struct llist_pods *lpods;
+	LListHead<gprs_rlcmac_tbf> *pos;
 	uint32_t poll_fn;
 
 	/* check special TBF for events */
@@ -42,7 +42,9 @@
 	if ((block_nr % 3) == 2)
 		poll_fn ++;
 	poll_fn = poll_fn % 2715648;
-	llist_pods_for_each_entry(ul_tbf, &bts->ul_tbfs, list, lpods) {
+	llist_for_each(pos, &bts->ul_tbfs()) {
+		ul_tbf = as_ul_tbf(pos->entry());
+		OSMO_ASSERT(ul_tbf);
 		/* this trx, this ts */
 		if (ul_tbf->trx->trx_no != trx || ul_tbf->control_ts != ts)
 			continue;
@@ -58,7 +60,9 @@
 			*ul_ass_tbf = ul_tbf;
 #warning "Is this supposed to be fair? The last TBF for each wins? Maybe use llist_add_tail and skip once we have all states?"
 	}
-	llist_pods_for_each_entry(dl_tbf, &bts->dl_tbfs, list, lpods) {
+	llist_for_each(pos, &bts->dl_tbfs()) {
+		dl_tbf = as_dl_tbf(pos->entry());
+		OSMO_ASSERT(dl_tbf);
 		/* this trx, this ts */
 		if (dl_tbf->trx->trx_no != trx || dl_tbf->control_ts != ts)
 			continue;
@@ -292,7 +296,7 @@
 	/* store last frame number of RTS */
 	pdch->last_rts_fn = fn;
 
-	poll_fn = sched_poll(bts, trx, ts, fn, block_nr, &poll_tbf, &ul_ass_tbf,
+	poll_fn = sched_poll(bts->bts, trx, ts, fn, block_nr, &poll_tbf, &ul_ass_tbf,
 		&dl_ass_tbf, &ul_ack_tbf);
 	/* check uplink resource for polling */
 	if (poll_tbf)
diff --git a/src/pcu_vty.c b/src/pcu_vty.c
index aa29b4c..ce9db29 100644
--- a/src/pcu_vty.c
+++ b/src/pcu_vty.c
@@ -775,19 +775,7 @@
       SHOW_STR "information about TBFs\n" "All TBFs\n")
 {
 	struct gprs_rlcmac_bts *bts = bts_main_data();
-	struct llist_head *tbf;
-
-	vty_out(vty, "UL TBFs%s", VTY_NEWLINE);
-	llist_for_each(tbf, &bts->ul_tbfs) {
-		tbf_print_vty_info(vty, tbf);
-	}
-
-	vty_out(vty, "%sDL TBFs%s", VTY_NEWLINE, VTY_NEWLINE);
-	llist_for_each(tbf, &bts->dl_tbfs) {
-		tbf_print_vty_info(vty, tbf);
-	}
-
-	return CMD_SUCCESS;
+	return pcu_vty_show_tbf_all(vty, bts);
 }
 
 DEFUN(show_ms_all,
diff --git a/src/pcu_vty_functions.cpp b/src/pcu_vty_functions.cpp
index 74780c2..7082d99 100644
--- a/src/pcu_vty_functions.cpp
+++ b/src/pcu_vty_functions.cpp
@@ -39,9 +39,8 @@
 	return CMD_SUCCESS;
 }
 
-void tbf_print_vty_info(struct vty *vty, struct llist_head *ltbf)
+static void tbf_print_vty_info(struct vty *vty, gprs_rlcmac_tbf *tbf)
 {
-	gprs_rlcmac_tbf *tbf = llist_pods_entry(ltbf, gprs_rlcmac_tbf);
 	vty_out(vty, "TBF: TFI=%d TLLI=0x%08x (%s) DIR=%s IMSI=%s%s", tbf->tfi(),
 			tbf->tlli(), tbf->is_tlli_valid() ? "valid" : "invalid",
 			tbf->direction == GPRS_RLCMAC_UL_TBF ? "UL" : "DL",
@@ -60,6 +59,22 @@
 		VTY_NEWLINE, VTY_NEWLINE);
 }
 
+int pcu_vty_show_tbf_all(struct vty *vty, struct gprs_rlcmac_bts *bts_data)
+{
+	BTS *bts = bts_data->bts;
+	LListHead<gprs_rlcmac_tbf> *ms_iter;
+
+	vty_out(vty, "UL TBFs%s", VTY_NEWLINE);
+	llist_for_each(ms_iter, &bts->ul_tbfs())
+		tbf_print_vty_info(vty, ms_iter->entry());
+
+	vty_out(vty, "%sDL TBFs%s", VTY_NEWLINE, VTY_NEWLINE);
+	llist_for_each(ms_iter, &bts->dl_tbfs())
+		tbf_print_vty_info(vty, ms_iter->entry());
+
+	return CMD_SUCCESS;
+}
+
 int pcu_vty_show_ms_all(struct vty *vty, struct gprs_rlcmac_bts *bts_data)
 {
 	BTS *bts = bts_data->bts;
diff --git a/src/pcu_vty_functions.h b/src/pcu_vty_functions.h
index 170ad2e..35acf64 100644
--- a/src/pcu_vty_functions.h
+++ b/src/pcu_vty_functions.h
@@ -28,14 +28,13 @@
 struct gprs_rlcmac_bts;
 
 int pcu_vty_config_write_pcu_ext(struct vty *vty);
+int pcu_vty_show_tbf_all(struct vty *vty, struct gprs_rlcmac_bts *bts_data);
 int pcu_vty_show_ms_all(struct vty *vty, struct gprs_rlcmac_bts *bts_data);
 int pcu_vty_show_ms_by_tlli(struct vty *vty, struct gprs_rlcmac_bts *bts_data,
 	uint32_t tlli);
 int pcu_vty_show_ms_by_imsi(struct vty *vty, struct gprs_rlcmac_bts *bts_data,
 	const char *imsi);
 
-void tbf_print_vty_info(struct vty *vty, struct llist_head *tbf);
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/poll_controller.cpp b/src/poll_controller.cpp
index 8108f74..54e3bc7 100644
--- a/src/poll_controller.cpp
+++ b/src/poll_controller.cpp
@@ -30,14 +30,14 @@
 
 void PollController::expireTimedout(int frame_number, unsigned max_delay)
 {
-	struct gprs_rlcmac_bts *bts = m_bts.bts_data();
 	struct gprs_rlcmac_dl_tbf *dl_tbf;
 	struct gprs_rlcmac_ul_tbf *ul_tbf;
 	struct gprs_rlcmac_sba *sba, *sba2;
-	struct llist_pods *lpods;
+	LListHead<gprs_rlcmac_tbf> *pos;
 	uint32_t elapsed;
 
-	llist_pods_for_each_entry(ul_tbf, &bts->ul_tbfs, list, lpods) {
+	llist_for_each(pos, &m_bts.ul_tbfs()) {
+		ul_tbf = as_ul_tbf(pos->entry());
 		if (ul_tbf->poll_state == GPRS_RLCMAC_POLL_SCHED) {
 			elapsed = (frame_number + 2715648 - ul_tbf->poll_fn)
 								% 2715648;
@@ -45,7 +45,8 @@
 				ul_tbf->poll_timeout();
 		}
 	}
-	llist_pods_for_each_entry(dl_tbf, &bts->dl_tbfs, list, lpods) {
+	llist_for_each(pos, &m_bts.dl_tbfs()) {
+		dl_tbf = as_dl_tbf(pos->entry());
 		if (dl_tbf->poll_state == GPRS_RLCMAC_POLL_SCHED) {
 			elapsed = (frame_number + 2715648 - dl_tbf->poll_fn)
 								% 2715648;
diff --git a/src/rlc.h b/src/rlc.h
index c7bb98d..46d821d 100644
--- a/src/rlc.h
+++ b/src/rlc.h
@@ -136,11 +136,7 @@
 
 
 /**
- * TODO: The UL/DL code could/should share a baseclass but
- * we are using llist_for_each_entry for the TBF which
- * requires everything which creates a requirement for a POD
- * type and in < C++11 something that is using even if the
- * most simple form of inheritance is not a POD anymore.
+ * TODO: The UL/DL code could/should share a base class.
  */
 struct gprs_rlc_dl_window {
 	void reset();
diff --git a/src/tbf.cpp b/src/tbf.cpp
index b3d0c0d..185f0bd 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -74,12 +74,12 @@
 	m_ms(NULL),
 	m_ta(0),
 	m_ms_class(0),
+	m_list(this),
 	m_ms_list(this),
 	m_egprs_enabled(false)
 {
 	/* The classes of these members do not have proper constructors yet.
 	 * Just set them to 0 like talloc_zero did */
-	memset(&list, 0, sizeof(list));
 	memset(&pdch, 0, sizeof(pdch));
 	memset(&timer, 0, sizeof(timer));
 	memset(&m_rlc, 0, sizeof(m_rlc));
@@ -88,9 +88,6 @@
 	m_llc.init();
 
 	m_name_buf[0] = '\0';
-
-	/* Back pointer for PODS llist compatibility */
-	list.back = this;
 }
 
 gprs_rlcmac_bts *gprs_rlcmac_tbf::bts_data() const
@@ -336,7 +333,7 @@
 	tbf->stop_timer();
 	#warning "TODO: Could/Should generate  bssgp_tx_llc_discarded"
 	tbf_unlink_pdch(tbf);
-	llist_del(&tbf->list.list);
+	llist_del(&tbf->list());
 
 	if (tbf->direction == GPRS_RLCMAC_UL_TBF)
 		tbf->bts->tbf_ul_freed();
@@ -633,7 +630,7 @@
 		return NULL;
 	}
 
-	llist_add(&tbf->list.list, &bts->ul_tbfs);
+	llist_add(&tbf->list(), &bts->bts->ul_tbfs());
 	tbf->bts->tbf_ul_created();
 
 	return tbf;
@@ -694,7 +691,7 @@
 		return NULL;
 	}
 
-	llist_add(&tbf->list.list, &bts->dl_tbfs);
+	llist_add(&tbf->list(), &bts->bts->dl_tbfs());
 	tbf->bts->tbf_dl_created();
 
 	tbf->m_last_dl_poll_fn = -1;
@@ -1093,11 +1090,11 @@
 
 void gprs_rlcmac_tbf::rotate_in_list()
 {
-	llist_del(&list.list);
+	llist_del(&list());
 	if (direction == GPRS_RLCMAC_UL_TBF)
-		llist_add(&list.list, &bts->bts_data()->ul_tbfs);
+		llist_add(&list(), &bts->ul_tbfs());
 	else
-		llist_add(&list.list, &bts->bts_data()->dl_tbfs);
+		llist_add(&list(), &bts->dl_tbfs());
 }
 
 uint8_t gprs_rlcmac_tbf::tsc() const
diff --git a/src/tbf.h b/src/tbf.h
index de7063d..8ba6575 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -88,28 +88,6 @@
 #define GPRS_RLCMAC_FLAG_TO_DL_ASS	7
 #define GPRS_RLCMAC_FLAG_TO_MASK	0xf0 /* timeout bits */
 
-struct llist_pods {
-	struct llist_head list;
-	void *back;
-};
-
-#define llist_pods_entry(ptr, type) \
-	((type *)(container_of(ptr, struct llist_pods, list)->back))
-
-/**
- * llist_pods_for_each_entry - like llist_for_each_entry, but uses
- * struct llist_pods ->back to access the entry.
- * This is necessary for non-PODS classes because container_of is
- * not guaranteed to work anymore. */
-#define llist_pods_for_each_entry(pos, head, member, lpods)			\
-	for (lpods = llist_entry((head)->next, typeof(struct llist_pods), list), \
-		     pos = ((typeof(pos))lpods->back),	\
-		     prefetch(pos->member.list.next);				\
-	     &lpods->list != (head);					\
-	     lpods = llist_entry(lpods->list.next, typeof(struct llist_pods), list), \
-		     pos = ((typeof(pos))lpods->back),\
-		     prefetch(pos->member.list.next))
-
 struct gprs_rlcmac_tbf {
 	gprs_rlcmac_tbf(BTS *bts_, gprs_rlcmac_tbf_direction dir);
 
@@ -175,7 +153,9 @@
 	LListHead<gprs_rlcmac_tbf>& ms_list() {return this->m_ms_list;}
 	const LListHead<gprs_rlcmac_tbf>& ms_list() const {return this->m_ms_list;}
 
-	struct llist_pods list;
+	LListHead<gprs_rlcmac_tbf>& list();
+	const LListHead<gprs_rlcmac_tbf>& list() const;
+
 	uint32_t state_flags;
 	enum gprs_rlcmac_tbf_direction direction;
 	struct gprs_rlcmac_trx *trx;
@@ -251,6 +231,7 @@
 	uint8_t m_ms_class;
 
 private:
+	LListHead<gprs_rlcmac_tbf> m_list;
 	LListHead<gprs_rlcmac_tbf> m_ms_list;
 	bool m_egprs_enabled;
 
@@ -302,6 +283,16 @@
 	state = new_state;
 }
 
+inline LListHead<gprs_rlcmac_tbf>& gprs_rlcmac_tbf::list()
+{
+	return this->m_list;
+}
+
+inline const LListHead<gprs_rlcmac_tbf>& gprs_rlcmac_tbf::list() const
+{
+	return this->m_list;
+}
+
 inline GprsMs *gprs_rlcmac_tbf::ms() const
 {
 	return m_ms;
diff --git a/tests/alloc/AllocTest.cpp b/tests/alloc/AllocTest.cpp
index d338b78..c3efd4d 100644
--- a/tests/alloc/AllocTest.cpp
+++ b/tests/alloc/AllocTest.cpp
@@ -52,23 +52,23 @@
 static void check_tfi_usage(BTS *the_bts)
 {
 	int pdch_no;
-	struct gprs_rlcmac_bts *bts = the_bts->bts_data();
 
 	struct gprs_rlcmac_tbf *tfi_usage[8][8][2][32] = {{{{NULL}}}};
-	struct llist_head *tbf_lists[2] = {
-		&bts->ul_tbfs,
-		&bts->dl_tbfs
+	LListHead<gprs_rlcmac_tbf> *tbf_lists[2] = {
+		&the_bts->ul_tbfs(),
+		&the_bts->dl_tbfs()
 	};
 
+	LListHead<gprs_rlcmac_tbf> *pos;
 	gprs_rlcmac_tbf *tbf;
-	struct llist_pods *lpods;
 	unsigned list_idx;
 	struct gprs_rlcmac_tbf **tbf_var;
 
 	for (list_idx = 0; list_idx < ARRAY_SIZE(tbf_lists); list_idx += 1)
 	{
 
-		llist_pods_for_each_entry(tbf, tbf_lists[list_idx], list, lpods) {
+		llist_for_each(pos, tbf_lists[list_idx]) {
+			tbf = pos->entry();
 			for (pdch_no = 0; pdch_no < 8; pdch_no += 1) {
 				struct gprs_rlcmac_pdch *pdch = tbf->pdch[pdch_no];
 				if (pdch == NULL)