<p>Harald Welte has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/12900">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">TLV: Add one-shot TLV encoder<br><br>So far, the TLV code contained two types of functions<br>* tlp_parse() to parse all TLVs according to definition into tlvp_parsed<br>* various helper functions to encode individual TLVs during message<br>  generation<br><br>This patch implements the inverse of tlv_parse(): tlv_encode(), which<br>takes a full 'struct tlv_pared' and encodes all IEs found in it.  The<br>order of IEs is in numerically ascending order of the tag.<br><br>As many protocols have different IE/TLV ordering requirements, let's add<br>a tlv_encode_ordered() function where the caller can specify the TLV<br>ordering during the one-shot encode.<br><br>Change-Id: I761a30bf20355a9f80a4a8e0c60b0b0f78515efe<br>---<br>M include/osmocom/gsm/tlv.h<br>M src/gsm/libosmogsm.map<br>M src/gsm/tlv_parser.c<br>3 files changed, 96 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/00/12900/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/gsm/tlv.h b/include/osmocom/gsm/tlv.h</span><br><span>index d0c9552..bb0e8fc 100644</span><br><span>--- a/include/osmocom/gsm/tlv.h</span><br><span>+++ b/include/osmocom/gsm/tlv.h</span><br><span>@@ -457,6 +457,12 @@</span><br><span> /* take a master (src) tlv def and fill up all empty slots in 'dst' */</span><br><span> void tlv_def_patch(struct tlv_definition *dst, const struct tlv_definition *src);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int tlv_encode_one(struct msgb *msg, enum tlv_type type, uint8_t tag,</span><br><span style="color: hsl(120, 100%, 40%);">+               unsigned int len, const uint8_t *val);</span><br><span style="color: hsl(120, 100%, 40%);">+int tlv_encode(struct msgb *msg, const struct tlv_definition *def, const struct tlv_parsed *tp);</span><br><span style="color: hsl(120, 100%, 40%);">+int tlv_encode_ordered(struct msgb *msg, const struct tlv_definition *def, const struct tlv_parsed *tp,</span><br><span style="color: hsl(120, 100%, 40%);">+                  const uint8_t *tag_order, unsigned int tag_order_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #define TLVP_PRESENT(x, y)  ((x)->lv[y].val)</span><br><span> #define TLVP_LEN(x, y)           (x)->lv[y].len</span><br><span> #define TLVP_VAL(x, y)             (x)->lv[y].val</span><br><span>diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map</span><br><span>index ae7c0a1..c123dfc 100644</span><br><span>--- a/src/gsm/libosmogsm.map</span><br><span>+++ b/src/gsm/libosmogsm.map</span><br><span>@@ -493,6 +493,9 @@</span><br><span> tlv_parse;</span><br><span> tlv_parse2;</span><br><span> tlv_parse_one;</span><br><span style="color: hsl(120, 100%, 40%);">+tlv_encode;</span><br><span style="color: hsl(120, 100%, 40%);">+tlv_encode_ordered;</span><br><span style="color: hsl(120, 100%, 40%);">+tlv_encode_one;</span><br><span> tvlv_att_def;</span><br><span> vtvlv_gan_att_def;</span><br><span> </span><br><span>diff --git a/src/gsm/tlv_parser.c b/src/gsm/tlv_parser.c</span><br><span>index 6e089f7..b227c84 100644</span><br><span>--- a/src/gsm/tlv_parser.c</span><br><span>+++ b/src/gsm/tlv_parser.c</span><br><span>@@ -120,6 +120,93 @@</span><br><span>        return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Encode a single TLV into given message buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[inout] msg Caller-allocated message buffer with sufficient tailroom</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] type TLV type/format to use during encode</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] tag Tag of TLV to be encoded</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \parma[in] len Length of TLV to be encoded</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] val Value part of TLV to be encoded</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success; negative in case of error */</span><br><span style="color: hsl(120, 100%, 40%);">+int tlv_encode_one(struct msgb *msg, enum tlv_type type, uint8_t tag,</span><br><span style="color: hsl(120, 100%, 40%);">+               unsigned int len, const uint8_t *val)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (type) {</span><br><span style="color: hsl(120, 100%, 40%);">+       case TLV_TYPE_NONE:</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case TLV_TYPE_FIXED:</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_tv_fixed_put(msg, tag, len, val);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case TLV_TYPE_T:</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_v_put(msg, tag);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case TLV_TYPE_TV:</span><br><span style="color: hsl(120, 100%, 40%);">+             msgb_tv_put(msg, tag, val[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case TLV_TYPE_TLV:</span><br><span style="color: hsl(120, 100%, 40%);">+            msgb_tlv_put(msg, tag, len, val);</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case TLV_TYPE_TL16V:</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_tl16v_put(msg, tag, len, val);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case TLV_TYPE_TvLV:</span><br><span style="color: hsl(120, 100%, 40%);">+           msgb_tvlv_put(msg, tag, len, val);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case TLV_TYPE_SINGLE_TV:</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_v_put(msg, (tag << 4) | (val[0] & 0xf));</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case TLV_TYPE_vTvLV_GAN:</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_vtvlv_gan_put(msg, tag, len, val);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</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%);">+/*! Encode a set of decoded TLVs according to a given definition into a message buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[inout] msg Caller-allocated message buffer with sufficient tailroom</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] def structure defining the valid TLV tags / configurations</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] tp decoded values to be encoded</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns number of bytes consumed in msg; negative in case of error */</span><br><span style="color: hsl(120, 100%, 40%);">+int tlv_encode(struct msgb *msg, const struct tlv_definition *def, const struct tlv_parsed *tp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     unsigned int tailroom_before = msgb_tailroom(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     for (i = 0; i < ARRAY_SIZE(tp->lv); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = tlv_encode_one(msg, def->def[i].type, i, TLVP_LEN(tp, i), TLVP_VAL(tp, i));</span><br><span style="color: hsl(120, 100%, 40%);">+           if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     return tailroom_before - msgb_tailroom(msg);</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%);">+/*! Encode a set of decoded TLVs according to a given definition and IE order into a message buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[inout] msg Caller-allocated message buffer with sufficient tailroom</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] def structure defining the valid TLV tags / configurations</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] tp decoded values to be encoded</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] tag_order array of tags determining the IE encoding order</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] tag_order_len length of tag_order</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns number of bytes consumed in msg; negative in case of error */</span><br><span style="color: hsl(120, 100%, 40%);">+int tlv_encode_ordered(struct msgb *msg, const struct tlv_definition *def, const struct tlv_parsed *tp,</span><br><span style="color: hsl(120, 100%, 40%);">+                    const uint8_t *tag_order, unsigned int tag_order_len)</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%);">+    unsigned int tailroom_before = msgb_tailroom(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     for (i = 0; i < tag_order_len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              uint8_t tag = tag_order[i];</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = tlv_encode_one(msg, def->def[tag].type, tag, TLVP_LEN(tp, i), TLVP_VAL(tp, i));</span><br><span style="color: hsl(120, 100%, 40%);">+               if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     return tailroom_before - msgb_tailroom(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Parse a single TLV encoded IE</span><br><span>  *  \param[out] o_tag the tag of the IE that was found</span><br><span>  *  \param[out] o_len length of the IE that was found</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/12900">change 12900</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/12900"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: libosmocore </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I761a30bf20355a9f80a4a8e0c60b0b0f78515efe </div>
<div style="display:none"> Gerrit-Change-Number: 12900 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Harald Welte <laforge@gnumonks.org> </div>