<p>pespin has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-pcu/+/21387">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Dl TBF: Get rid of LLC UI dummy blocks following other data<br><br>According to:<br>* 3GPP TS 44.060 version 16.0.0 "9.3.1a Delayed release of downlink Temporary Block Flow"<br>* 3GPP TS 44.064 version 16.0.0 "6.4.2.2 Unconfirmed Information (UI) Dummy command"<br><br>LLC UI Dummy frames are to be used when there no more data to send, only<br>in order to delay the release of a TBF. Hence, while not incorrect per<br>se, makes no sense to send those LLC UI Dummy frames inserted into<br>rlcmac blocks which already contain other LLC frames, since the MS in<br>that case is already being kept active.<br>It only makes sense to send those LLC UI Dummy frames when we have<br>nothing else to send, that is, alone inside a RLCMAC block without other<br>LLC frames.<br><br>Related: OS#4849<br>Change-Id: Ifae1a7b2b3dfad8df19585063088ba0df2749c8f<br>---<br>M src/encoding.cpp<br>M src/encoding.h<br>M src/tbf_dl.cpp<br>3 files changed, 80 insertions(+), 60 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/87/21387/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/encoding.cpp b/src/encoding.cpp</span><br><span>index 23e1460..847e0a1 100644</span><br><span>--- a/src/encoding.cpp</span><br><span>+++ b/src/encoding.cpp</span><br><span>@@ -1397,9 +1397,10 @@</span><br><span> "larger than space (%d) left in block: copy "</span><br><span> "only remaining space, and we are done\n",</span><br><span> chunk, space);</span><br><span style="color: hsl(0, 100%, 40%);">- /* block is filled, so there is no extension */</span><br><span style="color: hsl(0, 100%, 40%);">- if (e_pointer)</span><br><span style="color: hsl(0, 100%, 40%);">- *e_pointer |= 0x01;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (e_pointer) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* LLC frame not finished, so there is no extension octet */</span><br><span style="color: hsl(120, 100%, 40%);">+ *e_pointer |= 0x02; /* set previous M bit = 1 */</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> /* fill only space */</span><br><span> llc->consume(data, space);</span><br><span> if (count_payload)</span><br><span>@@ -1438,6 +1439,10 @@</span><br><span> if (delimiter != data)</span><br><span> memmove(delimiter + 1, delimiter,</span><br><span> data - delimiter);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (e_pointer) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *e_pointer &= 0xfe; /* set previous E bit = 0 */</span><br><span style="color: hsl(120, 100%, 40%);">+ *e_pointer |= 0x02; /* set previous M bit = 1 */</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> data++;</span><br><span> (*offset)++;</span><br><span> space--;</span><br><span>@@ -1465,12 +1470,16 @@</span><br><span> /* make space for delimiter */</span><br><span> if (delimiter != data)</span><br><span> memmove(delimiter + 1, delimiter, data - delimiter);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (e_pointer) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *e_pointer &= 0xfe; /* set previous E bit = 0 */</span><br><span style="color: hsl(120, 100%, 40%);">+ *e_pointer |= 0x02; /* set previous M bit = 1 */</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> data++;</span><br><span> (*offset)++;</span><br><span> space--;</span><br><span> /* add LI to delimit frame */</span><br><span> li = (struct rlc_li_field *)delimiter;</span><br><span style="color: hsl(0, 100%, 40%);">- li->e = 0; /* Extension bit, maybe set later */</span><br><span style="color: hsl(120, 100%, 40%);">+ li->e = 1; /* not more extension, maybe set later */</span><br><span> li->m = 0; /* will be set later, if there is more LLC data */</span><br><span> li->li = chunk; /* length of chunk */</span><br><span> rdbi->e = 0; /* 0: extensions present */</span><br><span>@@ -1483,22 +1492,19 @@</span><br><span> space -= chunk;</span><br><span> (*offset) += chunk;</span><br><span> /* if we have more data and we have space left */</span><br><span style="color: hsl(0, 100%, 40%);">- if (space > 0 && !is_final) {</span><br><span style="color: hsl(0, 100%, 40%);">- li->m = 1; /* we indicate more frames to follow */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (space > 0 && !is_final)</span><br><span> return Encoding::AR_COMPLETED_SPACE_LEFT;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* if we don't have more LLC frames */</span><br><span> if (is_final) {</span><br><span> LOGP(DRLCMACDL, LOGL_DEBUG, "-- Final block, so we "</span><br><span> "done.\n");</span><br><span style="color: hsl(0, 100%, 40%);">- li->e = 1; /* we cannot extend */</span><br><span> rdbi->cv = 0;</span><br><span> return Encoding::AR_COMPLETED_BLOCK_FILLED;</span><br><span> }</span><br><span> /* we have no space left */</span><br><span> LOGP(DRLCMACDL, LOGL_DEBUG, "-- No space left, so we are "</span><br><span> "done.\n");</span><br><span style="color: hsl(0, 100%, 40%);">- li->e = 1; /* we cannot extend */</span><br><span> return Encoding::AR_COMPLETED_BLOCK_FILLED;</span><br><span> }</span><br><span> </span><br><span>@@ -1594,7 +1600,7 @@</span><br><span> space -= 1;</span><br><span> /* add LI to delimit frame */</span><br><span> li = (struct rlc_li_field_egprs *)delimiter;</span><br><span style="color: hsl(0, 100%, 40%);">- li->e = 1; /* Extension bit, maybe set later */</span><br><span style="color: hsl(120, 100%, 40%);">+ li->e = 1; /* not more extension, maybe set later */</span><br><span> li->li = chunk; /* length of chunk */</span><br><span> /* tell previous extension header about the new one */</span><br><span> if (prev_li)</span><br><span>@@ -1611,56 +1617,21 @@</span><br><span> space -= chunk;</span><br><span> (*offset) += chunk;</span><br><span> /* if we have more data and we have space left */</span><br><span style="color: hsl(0, 100%, 40%);">- if (space > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (!is_final)</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!is_final) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (space > 0) {</span><br><span> return Encoding::AR_COMPLETED_SPACE_LEFT;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* we have no space left */</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DRLCMACDL, LOGL_DEBUG, "-- No space left, so we are "</span><br><span style="color: hsl(120, 100%, 40%);">+ "done.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return Encoding::AR_COMPLETED_BLOCK_FILLED;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span> /* we don't have more LLC frames */</span><br><span style="color: hsl(0, 100%, 40%);">- /* We will have to add another chunk with filling octets */</span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DRLCMACDL, LOGL_DEBUG,</span><br><span style="color: hsl(0, 100%, 40%);">- "-- There is remaining space (%d): add filling byte chunk\n",</span><br><span style="color: hsl(0, 100%, 40%);">- space);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (delimiter != data)</span><br><span style="color: hsl(0, 100%, 40%);">- memmove(delimiter + 1, delimiter, data - delimiter);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- data += 1;</span><br><span style="color: hsl(0, 100%, 40%);">- (*offset) += 1;</span><br><span style="color: hsl(0, 100%, 40%);">- space -= 1;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* set filling bytes extension */</span><br><span style="color: hsl(0, 100%, 40%);">- li = (struct rlc_li_field_egprs *)delimiter;</span><br><span style="color: hsl(0, 100%, 40%);">- li->e = 1;</span><br><span style="color: hsl(0, 100%, 40%);">- li->li = 127;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* tell previous extension header about the new one */</span><br><span style="color: hsl(0, 100%, 40%);">- if (prev_li)</span><br><span style="color: hsl(0, 100%, 40%);">- prev_li->e = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- delimiter++;</span><br><span style="color: hsl(0, 100%, 40%);">- (*num_chunks)++;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- rdbi->cv = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DRLCMACDL, LOGL_DEBUG, "-- Final block, so we "</span><br><span style="color: hsl(0, 100%, 40%);">- "are done.\n");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- *offset = rdbi->data_len;</span><br><span style="color: hsl(0, 100%, 40%);">- return Encoding::AR_COMPLETED_BLOCK_FILLED;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (is_final) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* we don't have more LLC frames */</span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DRLCMACDL, LOGL_DEBUG, "-- Final block, so we "</span><br><span style="color: hsl(0, 100%, 40%);">- "are done.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DRLCMACDL, LOGL_DEBUG, "-- Final block, so we are done.\n");</span><br><span> rdbi->cv = 0;</span><br><span> return Encoding::AR_COMPLETED_BLOCK_FILLED;</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* we have no space left */</span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DRLCMACDL, LOGL_DEBUG, "-- No space left, so we are "</span><br><span style="color: hsl(0, 100%, 40%);">- "done.\n");</span><br><span style="color: hsl(0, 100%, 40%);">- return Encoding::AR_COMPLETED_BLOCK_FILLED;</span><br><span> }</span><br><span> </span><br><span> /*!</span><br><span>@@ -1697,6 +1668,36 @@</span><br><span> return AR_NEED_MORE_BLOCKS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+void Encoding::rlc_data_to_dl_append_egprs_li_padding(</span><br><span style="color: hsl(120, 100%, 40%);">+ int offset, int num_chunks, uint8_t *data_block)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct rlc_li_field_egprs *li;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct rlc_li_field_egprs *prev_li;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *delimiter, *data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DRLCMACDL, LOGL_DEBUG, "Adding LI=127 to signal padding\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ data = data_block + offset;</span><br><span style="color: hsl(120, 100%, 40%);">+ delimiter = data_block + num_chunks;</span><br><span style="color: hsl(120, 100%, 40%);">+ prev_li = (struct rlc_li_field_egprs *)</span><br><span style="color: hsl(120, 100%, 40%);">+ (num_chunks ? delimiter - 1 : NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* we don't have more LLC frames */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We will have to add another chunk with filling octets */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (delimiter != data)</span><br><span style="color: hsl(120, 100%, 40%);">+ memmove(delimiter + 1, delimiter, data - delimiter);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* set filling bytes extension */</span><br><span style="color: hsl(120, 100%, 40%);">+ li = (struct rlc_li_field_egprs *)delimiter;</span><br><span style="color: hsl(120, 100%, 40%);">+ li->e = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ li->li = 127;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* tell previous extension header about the new one */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (prev_li)</span><br><span style="color: hsl(120, 100%, 40%);">+ prev_li->e = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*</span><br><span> * Refer 44.060 version 7.27.0 Release 7</span><br><span> * section 7.1.3.2.1 On receipt of a PACKET RESOURCE REQUEST message</span><br><span>diff --git a/src/encoding.h b/src/encoding.h</span><br><span>index 5f8496e..6ac004d 100644</span><br><span>--- a/src/encoding.h</span><br><span>+++ b/src/encoding.h</span><br><span>@@ -104,4 +104,6 @@</span><br><span> struct gprs_rlc_data_block_info *rdbi, enum CodingScheme cs,</span><br><span> gprs_llc *llc, int *offset, int *num_chunks,</span><br><span> uint8_t *data, bool is_final, int *count_payload);</span><br><span style="color: hsl(120, 100%, 40%);">+ static void rlc_data_to_dl_append_egprs_li_padding(</span><br><span style="color: hsl(120, 100%, 40%);">+ int offset, int num_chunks, uint8_t *data_block);</span><br><span> };</span><br><span>diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp</span><br><span>index 4b184b8..d932a83 100644</span><br><span>--- a/src/tbf_dl.cpp</span><br><span>+++ b/src/tbf_dl.cpp</span><br><span>@@ -680,9 +680,30 @@</span><br><span> int payload_written = 0;</span><br><span> </span><br><span> if (m_llc.frame_length() == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* nothing to sent - delay the release of the TBF */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* It is not clear, when the next real data will</span><br><span style="color: hsl(120, 100%, 40%);">+ * arrive, so request a DL ack/nack now */</span><br><span style="color: hsl(120, 100%, 40%);">+ request_dl_ack();</span><br><span> </span><br><span> int space = block_data_len - write_offset;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (num_chunks != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Nothing to send, and we already put some data in</span><br><span style="color: hsl(120, 100%, 40%);">+ * rlcmac data block, we are done */</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPTBFDL(this, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+ "LLC queue completely drained and there's "</span><br><span style="color: hsl(120, 100%, 40%);">+ "still %d free bytes in rlcmac data block\n", space);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (mcs_is_edge(cs)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* in EGPRS there's no M bit, so we need</span><br><span style="color: hsl(120, 100%, 40%);">+ * to flag padding with LI=127 */</span><br><span style="color: hsl(120, 100%, 40%);">+ Encoding::rlc_data_to_dl_append_egprs_li_padding(write_offset, num_chunks, data);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Nothing to send from upper layers (LLC), but still</span><br><span style="color: hsl(120, 100%, 40%);">+ * requested to send something to MS to delay the</span><br><span style="color: hsl(120, 100%, 40%);">+ * release of the TBF. See 3GPP TS 44.060 9.3.1a</span><br><span style="color: hsl(120, 100%, 40%);">+ * "Delayed release of downlink Temporary Block Flow" */</span><br><span> /* A header will need to by added, so we just need</span><br><span> * space-1 octets */</span><br><span> m_llc.put_dummy_frame(space - 1);</span><br><span>@@ -691,10 +712,6 @@</span><br><span> if (m_last_dl_drained_fn < 0)</span><br><span> m_last_dl_drained_fn = fn;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* It is not clear, when the next real data will</span><br><span style="color: hsl(0, 100%, 40%);">- * arrive, so request a DL ack/nack now */</span><br><span style="color: hsl(0, 100%, 40%);">- request_dl_ack();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> LOGPTBFDL(this, LOGL_DEBUG,</span><br><span> "Empty chunk, added LLC dummy command of size %d, drained_since=%d\n",</span><br><span> m_llc.frame_length(), frames_since_last_drain(fn));</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-pcu/+/21387">change 21387</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-pcu/+/21387"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: osmo-pcu </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ifae1a7b2b3dfad8df19585063088ba0df2749c8f </div>
<div style="display:none"> Gerrit-Change-Number: 21387 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>