pdch/tbf: Move gprs_rlcmac_rcv_data_block_acknowledged into the pdch

Move the method into the PDCH. Extract the finding of TLLI into a
new class called Decoding. Move the assemble and forward LLC frames
into the TBF as it is poking in the internals of the TBF.
diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp
index 324e2b9..f2887b2 100644
--- a/src/gprs_rlcmac_data.cpp
+++ b/src/gprs_rlcmac_data.cpp
@@ -24,6 +24,7 @@
 #include <bts.h>
 #include <encoding.h>
 #include <tbf.h>
+#include <rlc.h>
 
 static struct gprs_rlcmac_cs gprs_rlcmac_cs[] = {
 /*	frame length	data block	max payload */
@@ -37,9 +38,6 @@
 
 extern void *tall_pcu_ctx;
 
-/* After receiving these frames, we send ack/nack. */
-#define SEND_ACK_AFTER_FRAMES 20
-
 /* After sending these frames, we poll for ack/nack. */
 #define POLL_ACK_AFTER_FRAMES 20
 
@@ -47,39 +45,6 @@
 #define POLLING_ASSIGNMENT_DL 1
 #define POLLING_ASSIGNMENT_UL 1
 
-extern "C" {
-/* TS 04.60  10.2.2 */
-struct rlc_ul_header {
-	uint8_t	r:1,
-		 si:1,
-		 cv:4,
-		 pt:2;
-	uint8_t	ti:1,
-		 tfi:5,
-		 pi:1,
-		 spare:1;
-	uint8_t	e:1,
-		 bsn:7;
-} __attribute__ ((packed));
-
-struct rlc_dl_header {
-	uint8_t	usf:3,
-		 s_p:1,
-		 rrbp:2,
-		 pt:2;
-	uint8_t	fbi:1,
-		 tfi:5,
-		 pr:2;
-	uint8_t	e:1,
-		 bsn:7;
-} __attribute__ ((packed));
-
-struct rlc_li_field {
-	uint8_t	e:1,
-		 m:1,
-		 li:6;
-} __attribute__ ((packed));
-}
 
 static void gprs_rlcmac_downlink_assignment(
 	gprs_rlcmac_tbf *tbf, uint8_t poll,
@@ -469,212 +434,6 @@
  * UL data block flow
  */
 
-/* get TLLI from received UL data block */
-static int tlli_from_ul_data(uint8_t *data, uint8_t len, uint32_t *tlli)
-{
-	struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
-	struct rlc_li_field *li;
-	uint8_t e;
-	uint32_t _tlli;
-
-	if (!rh->ti)
-		return -EINVAL;
-	
-	data += 3;
-	len -= 3;
-	e = rh->e;
-	/* if E is not set (LI follows) */
-	while (!e) {
-		if (!len) {
-			LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
-				"but no more data\n");
-			return -EINVAL;
-		}
-		/* get new E */
-		li = (struct rlc_li_field *)data;
-		if (li->e == 0) /* if LI==0, E is interpreted as '1' */
-			e = 1;
-		else
-			e = li->e;
-		data++;
-		len--;
-	}
-	if (len < 4) {
-		LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TLLI out of frame "
-			"border\n");
-		return -EINVAL;
-	}
-	memcpy(&_tlli, data, 4);
-	*tlli = ntohl(_tlli);
-
-	return 0;
-}
-
-/* Store received block data in LLC message(s) and forward to SGSN if complete.
- */
-static int gprs_rlcmac_assemble_llc(struct gprs_rlcmac_tbf *tbf, uint8_t *data,
-	uint8_t len)
-{
-	struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
-	uint8_t e, m;
-	struct rlc_li_field *li;
-	uint8_t frame_offset[16], offset = 0, chunk;
-	int i, frames = 0;
-
-	LOGP(DRLCMACUL, LOGL_DEBUG, "- Assembling frames: (len=%d)\n", len);
-	
-	data += 3;
-	len -= 3;
-	e = rh->e; /* if extended */
-	m = 1; /* more frames, that means: the first frame */
-
-	/* Parse frame offsets from length indicator(s), if any. */
-	while (1) {
-		if (frames == (int)sizeof(frame_offset)) {
-			LOGP(DRLCMACUL, LOGL_ERROR, "Too many frames in "
-				"block\n");
-			return -EINVAL;
-		}
-		frame_offset[frames++] = offset;
-		LOGP(DRLCMACUL, LOGL_DEBUG, "-- Frame %d starts at offset "
-			"%d\n", frames, offset);
-		if (!len)
-			break;
-		/* M == 0 and E == 0 is not allowed in this version. */
-		if (!m && !e) {
-			LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TBF=%d "
-				"ignored, because M='0' and E='0'.\n",
-				tbf->tfi);
-			return 0;
-		}
-		/* no more frames in this segment */
-		if (e) {
-			break;
-		}
-		/* There is a new frame and an LI that delimits it. */
-		if (m) {
-			li = (struct rlc_li_field *)data;
-			LOGP(DRLCMACUL, LOGL_DEBUG, "-- Delimiter len=%d\n",
-				li->li);
-			/* Special case: LI == 0
-			 * If the last segment would fit precisely into the
-			 * rest of the RLC MAC block, there would be no way
-			 * to delimit that this segment ends and is not
-			 * continued in the next block.
-			 * The special LI (0) is used to force the segment to
-			 * extend into the next block, so it is delimited there.
-			 * This LI must be skipped. Also it is the last LI.
-			 */
-			if (li->li == 0) {
-				data++;
-				len--;
-				m = 1; /* M is ignored, we know there is more */
-				break; /* handle E as '1', so we break! */
-			}
-			e = li->e;
-			m = li->m;
-			offset += li->li;
-			data++;
-			len--;
-			continue;
-		}
-	}
-	if (!m) {
-		LOGP(DRLCMACUL, LOGL_DEBUG, "- Last frame carries spare "
-			"data\n");
-	}
-
-	LOGP(DRLCMACUL, LOGL_DEBUG, "- Data length after length fields: %d\n",
-		len);
-	/* TLLI */
-	if (rh->ti) {
-		if (len < 4) {
-			LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TLLI out of "
-				"frame border\n");
-			return -EINVAL;
-		}
-		data += 4;
-		len -= 4;
-		LOGP(DRLCMACUL, LOGL_DEBUG, "- Length after skipping TLLI: "
-			"%d\n", len);
-	}
-
-	/* PFI */
-	if (rh->pi) {
-		LOGP(DRLCMACUL, LOGL_ERROR, "ERROR: PFI not supported, "
-			"please disable in SYSTEM INFORMATION\n");
-		if (len < 1) {
-			LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA PFI out of "
-				"frame border\n");
-			return -EINVAL;
-		}
-		data++;
-		len--;
-		LOGP(DRLCMACUL, LOGL_DEBUG, "- Length after skipping PFI: "
-			"%d\n", len);
-	}
-
-	/* Now we have:
-	 * - a list of frames offsets: frame_offset[]
-	 * - number of frames: i
-	 * - m == 0: Last frame carries spare data (end of TBF).
-	 */
-
-	/* Check if last offset would exceed frame. */
-	if (offset > len) {
-		LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TBF=%d ignored, "
-			"because LI delimits data that exceeds block size.\n",
-			tbf->tfi);
-		return -EINVAL;
-	}
-
-	/* create LLC frames */
-	for (i = 0; i < frames; i++) {
-		/* last frame ? */
-		if (i == frames - 1) {
-			/* no more data in last frame */
-			if (!m)
-				break;
-			/* data until end of frame */
-			chunk = len - frame_offset[i];
-		} else {
-			/* data until next frame */
-			chunk = frame_offset[i + 1] - frame_offset[i];
-		}
-		LOGP(DRLCMACUL, LOGL_DEBUG, "-- Appending chunk (len=%d) to "
-			"frame at %d.\n", chunk, tbf->llc_index);
-		if (tbf->llc_index + chunk > LLC_MAX_LEN) {
-			LOGP(DRLCMACUL, LOGL_NOTICE, "LLC frame exceeds "
-				"maximum size.\n");
-			chunk = LLC_MAX_LEN - tbf->llc_index;
-		}
-		memcpy(tbf->llc_frame + tbf->llc_index, data + frame_offset[i],
-			chunk);
-		tbf->llc_index += chunk;
-		/* not last frame. */
-		if (i != frames - 1) {
-			/* send frame to SGSN */
-			LOGP(DRLCMACUL, LOGL_INFO, "Complete UL frame for "
-				"TBF=%d: len=%d\n", tbf->tfi, tbf->llc_index);
-			gprs_rlcmac_tx_ul_ud(tbf);
-			tbf->llc_index = 0; /* reset frame space */
-		/* also check if CV==0, because the frame may fill up the
-		 * block precisely, then it is also complete. normally the
-		 * frame would be extended into the next block with a 0-length
-		 * delimiter added to this block. */
-		} else if (rh->cv == 0) {
-			/* send frame to SGSN */
-			LOGP(DRLCMACUL, LOGL_INFO, "Complete UL frame for "
-				"TBF=%d that fits precisely in last block: "
-				"len=%d\n", tbf->tfi, tbf->llc_index);
-			gprs_rlcmac_tx_ul_ud(tbf);
-			tbf->llc_index = 0; /* reset frame space */
-		}
-	}
-
-	return 0;
-}
-
 struct msgb *gprs_rlcmac_send_uplink_ack(
 	struct gprs_rlcmac_tbf *tbf,
 	uint32_t fn)
@@ -731,228 +490,6 @@
 	return msg;
 }
 
-/* receive UL data block
- *
- * The blocks are defragmented and forwarded as LLC frames, if complete.
- */
-int gprs_rlcmac_rcv_data_block_acknowledged(struct gprs_rlcmac_bts *bts,
-	uint8_t trx, uint8_t ts,
-	uint8_t *data, uint8_t len, int8_t rssi)
-{
-	struct gprs_rlcmac_tbf *tbf;
-	struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
-	uint16_t mod_sns, mod_sns_half, offset_v_q, offset_v_r, index;
-	int rc;
-
-	switch (len) {
-		case 54:
-			/* omitting spare bits */
-			len = 53;
-			break;
-		case 40:
-			/* omitting spare bits */
-			len = 39;
-			break;
-		case 34:
-			/* omitting spare bits */
-			len = 33;
-			break;
-		case 23:
-			break;
-	default:
-		LOGP(DRLCMACUL, LOGL_ERROR, "Dropping data block with invalid"
-			"length: %d)\n", len);
-		return -EINVAL;
-	}
-
-	/* find TBF inst from given TFI */
-	tbf = tbf_by_tfi(bts, rh->tfi, trx, GPRS_RLCMAC_UL_TBF);
-	if (!tbf) {
-		LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA unknown TBF=%d\n",
-			rh->tfi);
-		return 0;
-	}
-	tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_UL_DATA);
-
-	LOGP(DRLCMACUL, LOGL_DEBUG, "UL DATA TBF=%d received (V(Q)=%d .. "
-		"V(R)=%d)\n", rh->tfi, tbf->dir.ul.v_q, tbf->dir.ul.v_r);
-
-	/* process RSSI */
-	gprs_rlcmac_rssi(tbf, rssi);
-
-	/* get TLLI */
-	if (!tbf->tlli_valid) {
-		struct gprs_rlcmac_tbf *dl_tbf, *ul_tbf;
-
-		/* no TLLI yet */
-		if (!rh->ti) {
-			LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TBF=%d without "
-				"TLLI, but no TLLI received yet\n", rh->tfi);
-			return 0;
-		}
-		rc = tlli_from_ul_data(data, len, &tbf->tlli);
-		if (rc) {
-			LOGP(DRLCMACUL, LOGL_NOTICE, "Failed to decode TLLI "
-				"of UL DATA TBF=%d.\n", rh->tfi);
-			return 0;
-		}
-		LOGP(DRLCMACUL, LOGL_INFO, "Decoded premier TLLI=0x%08x of "
-			"UL DATA TBF=%d.\n", tbf->tlli, rh->tfi);
-		if ((dl_tbf = bts->bts->tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_DL_TBF))) {
-			LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
-				"TLLI=0x%08x while DL TBF=%d still exists. "
-				"Killing pending DL TBF\n", tbf->tlli,
-				dl_tbf->tfi);
-			tbf_free(dl_tbf);
-		}
-		/* tbf_by_tlli will not find your TLLI, because it is not
-		 * yet marked valid */
-		if ((ul_tbf = bts->bts->tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_UL_TBF))) {
-			LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
-				"TLLI=0x%08x while UL TBF=%d still exists. "
-				"Killing pending UL TBF\n", tbf->tlli,
-				ul_tbf->tfi);
-			tbf_free(ul_tbf);
-		}
-		/* mark TLLI valid now */
-		tbf->tlli_valid = 1;
-		/* store current timing advance */
-		bts->bts->timing_advance()->remember(tbf->tlli, tbf->ta);
-	/* already have TLLI, but we stille get another one */
-	} else if (rh->ti) {
-		uint32_t tlli;
-		rc = tlli_from_ul_data(data, len, &tlli);
-		if (rc) {
-			LOGP(DRLCMACUL, LOGL_NOTICE, "Failed to decode TLLI "
-				"of UL DATA TBF=%d.\n", rh->tfi);
-			return 0;
-		}
-		if (tlli != tbf->tlli) {
-			LOGP(DRLCMACUL, LOGL_NOTICE, "TLLI mismatch on UL "
-				"DATA TBF=%d. (Ignoring due to contention "
-				"resolution)\n", rh->tfi);
-			return 0;
-		}
-	}
-
-	mod_sns = tbf->sns - 1;
-	mod_sns_half = (tbf->sns >> 1) - 1;
-
-	/* restart T3169 */
-	tbf_timer_start(tbf, 3169, bts->t3169, 0);
-
-	/* Increment RX-counter */
-	tbf->dir.ul.rx_counter++;
-
-	/* current block relative to lowest unreceived block */
-	offset_v_q = (rh->bsn - tbf->dir.ul.v_q) & mod_sns;
-	/* If out of window (may happen if blocks below V(Q) are received
-	 * again. */
-	if (offset_v_q >= tbf->ws) {
-		LOGP(DRLCMACUL, LOGL_DEBUG, "- BSN %d out of window "
-			"%d..%d (it's normal)\n", rh->bsn, tbf->dir.ul.v_q,
-			(tbf->dir.ul.v_q + tbf->ws - 1) & mod_sns);
-		return 0;
-	}
-	/* Write block to buffer and set receive state array. */
-	index = rh->bsn & mod_sns_half; /* memory index of block */
-	memcpy(tbf->rlc_block[index], data, len); /* Copy block. */
-	tbf->rlc_block_len[index] = len;
-	tbf->dir.ul.v_n[index] = 'R'; /* Mark received block. */
-	LOGP(DRLCMACUL, LOGL_DEBUG, "- BSN %d storing in window (%d..%d)\n",
-		rh->bsn, tbf->dir.ul.v_q,
-		(tbf->dir.ul.v_q + tbf->ws - 1) & mod_sns);
-	/* Raise V(R) to highest received sequence number not received. */
-	offset_v_r = (rh->bsn + 1 - tbf->dir.ul.v_r) & mod_sns;
-	if (offset_v_r < (tbf->sns >> 1)) { /* Positive offset, so raise. */
-		while (offset_v_r--) {
-			if (offset_v_r) /* all except the received block */
-				tbf->dir.ul.v_n[tbf->dir.ul.v_r & mod_sns_half]
-					= 'N'; /* Mark block as not received */
-			tbf->dir.ul.v_r = (tbf->dir.ul.v_r + 1) & mod_sns;
-				/* Inc V(R). */
-		}
-		LOGP(DRLCMACUL, LOGL_DEBUG, "- Raising V(R) to %d\n",
-			tbf->dir.ul.v_r);
-	}
-
-	/* Raise V(Q) if possible, and retrieve LLC frames from blocks.
-	 * This is looped until there is a gap (non received block) or
-	 * the window is empty.*/
-	while (tbf->dir.ul.v_q != tbf->dir.ul.v_r && tbf->dir.ul.v_n[
-			(index = tbf->dir.ul.v_q & mod_sns_half)] == 'R') {
-		LOGP(DRLCMACUL, LOGL_DEBUG, "- Taking block %d out, raising "
-			"V(Q) to %d\n", tbf->dir.ul.v_q,
-			(tbf->dir.ul.v_q + 1) & mod_sns);
-		/* get LLC data from block */
-		gprs_rlcmac_assemble_llc(tbf, tbf->rlc_block[index],
-			tbf->rlc_block_len[index]);
-		/* raise V(Q), because block already received */
-		tbf->dir.ul.v_q = (tbf->dir.ul.v_q + 1) & mod_sns;
-	}
-
-	/* Check CV of last frame in buffer */
-	if (tbf->state_is(GPRS_RLCMAC_FLOW) /* still in flow state */
-	 && tbf->dir.ul.v_q == tbf->dir.ul.v_r) { /* if complete */
-		struct rlc_ul_header *last_rh = (struct rlc_ul_header *)
-			tbf->rlc_block[(tbf->dir.ul.v_r - 1) & mod_sns_half];
-		LOGP(DRLCMACUL, LOGL_DEBUG, "- No gaps in received block, "
-			"last block: BSN=%d CV=%d\n", last_rh->bsn,
-			last_rh->cv);
-		if (last_rh->cv == 0) {
-			LOGP(DRLCMACUL, LOGL_DEBUG, "- Finished with UL "
-				"TBF\n");
-			tbf_new_state(tbf, GPRS_RLCMAC_FINISHED);
-			/* Reset N3103 counter. */
-			tbf->dir.ul.n3103 = 0;
-		}
-	}
-
-	/* If TLLI is included or if we received half of the window, we send
-	 * an ack/nack */
-	if (rh->si || rh->ti || tbf->state_is(GPRS_RLCMAC_FINISHED)
-	 || (tbf->dir.ul.rx_counter % SEND_ACK_AFTER_FRAMES) == 0) {
-		if (rh->si) {
-			LOGP(DRLCMACUL, LOGL_NOTICE, "- Scheduling Ack/Nack, "
-				"because MS is stalled.\n");
-		}
-		if (rh->ti) {
-			LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, "
-				"because TLLI is included.\n");
-		}
-		if (tbf->state_is(GPRS_RLCMAC_FINISHED)) {
-			LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, "
-				"because last block has CV==0.\n");
-		}
-		if ((tbf->dir.ul.rx_counter % SEND_ACK_AFTER_FRAMES) == 0) {
-			LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, "
-				"because %d frames received.\n",
-				SEND_ACK_AFTER_FRAMES);
-		}
-		if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_NONE) {
-#ifdef DEBUG_DIAGRAM
-			if (rh->si)
-				debug_diagram(bts->bts, tbf->diag, "sched UL-ACK stall");
-			if (rh->ti)
-				debug_diagram(bts->bts, tbf->diag, "sched UL-ACK TLLI");
-			if (tbf->state_is(GPRS_RLCMAC_FINISHED))
-				debug_diagram(bts->bts, tbf->diag, "sched UL-ACK CV==0");
-			if ((tbf->dir.ul.rx_counter % SEND_ACK_AFTER_FRAMES) == 0)
-				debug_diagram(bts->bts, tbf->diag, "sched UL-ACK n=%d",
-					tbf->dir.ul.rx_counter);
-#endif
-			/* trigger sending at next RTS */
-			tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_SEND_ACK;
-		} else {
-			/* already triggered */
-			LOGP(DRLCMACUL, LOGL_DEBUG, "-  Sending Ack/Nack is "
-				"already triggered, don't schedule!\n");
-		}
-	}
-
-	return 0;
-}
-
 struct msgb *gprs_rlcmac_send_packet_uplink_assignment(
 	struct gprs_rlcmac_tbf *tbf, uint32_t fn)
 {