<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/21610">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  laforge: Looks good to me, approved
  pespin: Looks good to me, but someone else must approve
  Jenkins Builder: Verified

Objections:
  daniel: I would prefer this is not merged as is

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">bssgp2: Encoding + Decoding functions for BVC and MS flow control<br><br>Change-Id: I9c89bb1c03550930c07aad7ff8f67129ee7a6320<br>Related: OS#4891<br>---<br>M include/osmocom/gprs/gprs_bssgp2.h<br>M include/osmocom/gprs/protocol/gsm_08_18.h<br>M src/gb/gprs_bssgp2.c<br>M src/gb/libosmogb.map<br>4 files changed, 259 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/gprs/gprs_bssgp2.h b/include/osmocom/gprs/gprs_bssgp2.h</span><br><span>index 0ab3619..bf814cb 100644</span><br><span>--- a/include/osmocom/gprs/gprs_bssgp2.h</span><br><span>+++ b/include/osmocom/gprs/gprs_bssgp2.h</span><br><span>@@ -4,10 +4,41 @@</span><br><span> #include <osmocom/gprs/protocol/gsm_08_18.h></span><br><span> #include <osmocom/gprs/gprs_ns2.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct bssgp2_flow_ctrl;</span><br><span> struct gprs_ns2_inst;</span><br><span> struct gprs_ra_id;</span><br><span> struct msgb;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct bssgp2_flow_ctrl {</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t tag;</span><br><span style="color: hsl(120, 100%, 40%);">+  /* maximum bucket size (Bmax) in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+     uint64_t bucket_size_max;</span><br><span style="color: hsl(120, 100%, 40%);">+     /*! bucket leak rate in _bytes_ per second */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint64_t bucket_leak_rate;</span><br><span style="color: hsl(120, 100%, 40%);">+    /* percentage how full the given bucket is */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t bucket_full_ratio;</span><br><span style="color: hsl(120, 100%, 40%);">+    bool bucket_full_ratio_present;</span><br><span style="color: hsl(120, 100%, 40%);">+       union {</span><br><span style="color: hsl(120, 100%, 40%);">+               /*! FC-BVC specifi members */</span><br><span style="color: hsl(120, 100%, 40%);">+         struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /*! default maximum bucket size per MS in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+                    uint64_t bmax_default_ms;</span><br><span style="color: hsl(120, 100%, 40%);">+                     /*! default bucket leak rate (R) for MS flow control bucket */</span><br><span style="color: hsl(120, 100%, 40%);">+                        uint64_t r_default_ms;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                      /*! average milliseconds of queueing delay for a BVC */</span><br><span style="color: hsl(120, 100%, 40%);">+                       uint32_t measurement;</span><br><span style="color: hsl(120, 100%, 40%);">+                 bool measurement_present;</span><br><span style="color: hsl(120, 100%, 40%);">+             } bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+                /*! FC-MS specifi members */</span><br><span style="color: hsl(120, 100%, 40%);">+          struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /*! TLLI of the MS */</span><br><span style="color: hsl(120, 100%, 40%);">+                 uint32_t tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+                } ms;</span><br><span style="color: hsl(120, 100%, 40%);">+ } u;</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%);">+</span><br><span> int bssgp2_nsi_tx_ptp(struct gprs_ns2_inst *nsi, uint16_t nsei, uint16_t bvci,</span><br><span>                     struct msgb *msg, uint32_t lsp);</span><br><span> </span><br><span>@@ -29,3 +60,11 @@</span><br><span>                                    const uint8_t *feat_bm, const uint8_t *ext_feat_bm);</span><br><span> </span><br><span> struct msgb *bssgp2_enc_status(uint8_t cause, const uint16_t *bvci, const struct msgb *orig_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%);">+int bssgp2_dec_fc_bvc(struct bssgp2_flow_ctrl *fc, const struct tlv_parsed *tp);</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_fc_bvc(const struct bssgp2_flow_ctrl *fc, enum bssgp_fc_granularity *gran);</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_fc_bvc_ack(uint8_t tag);</span><br><span style="color: hsl(120, 100%, 40%);">+int bssgp2_dec_fc_ms(struct bssgp2_flow_ctrl *fc, struct tlv_parsed *tp);</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_fc_ms(const struct bssgp2_flow_ctrl *fc, enum bssgp_fc_granularity *gran);</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_fc_ms_ack(uint32_t tlli, uint8_t tag);</span><br><span>diff --git a/include/osmocom/gprs/protocol/gsm_08_18.h b/include/osmocom/gprs/protocol/gsm_08_18.h</span><br><span>index 0ce28f5..466b0c5 100644</span><br><span>--- a/include/osmocom/gprs/protocol/gsm_08_18.h</span><br><span>+++ b/include/osmocom/gprs/protocol/gsm_08_18.h</span><br><span>@@ -341,3 +341,11 @@</span><br><span> #define      BSSGP_XFEAT_DCN         0x20    /* Dedicated CN */</span><br><span> #define   BSSGP_XFEAT_eDRX        0x40    /* eDRX */</span><br><span> #define   BSSGP_XFEAT_MSAD        0x80    /* MS-assisted Dedicated CN selection */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Flow Control Granularity (Section 11.3.102) */</span><br><span style="color: hsl(120, 100%, 40%);">+enum bssgp_fc_granularity {</span><br><span style="color: hsl(120, 100%, 40%);">+    BSSGP_FC_GRAN_100       = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+  BSSGP_FC_GRAN_1000      = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+  BSSGP_FC_GRAN_10000     = 2,</span><br><span style="color: hsl(120, 100%, 40%);">+  BSSGP_FC_GRAN_100000    = 3,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span>diff --git a/src/gb/gprs_bssgp2.c b/src/gb/gprs_bssgp2.c</span><br><span>index e741fb4..a54a8d9 100644</span><br><span>--- a/src/gb/gprs_bssgp2.c</span><br><span>+++ b/src/gb/gprs_bssgp2.c</span><br><span>@@ -238,3 +238,209 @@</span><br><span> </span><br><span>    return msg;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const unsigned int bssgp_fc_gran_tbl[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ [BSSGP_FC_GRAN_100]     = 100,</span><br><span style="color: hsl(120, 100%, 40%);">+        [BSSGP_FC_GRAN_1000]    = 1000,</span><br><span style="color: hsl(120, 100%, 40%);">+       [BSSGP_FC_GRAN_10000]   = 10000,</span><br><span style="color: hsl(120, 100%, 40%);">+      [BSSGP_FC_GRAN_100000]  = 100000,</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%);">+/*! Decode a FLOW-CONTROL-BVC PDU as per TS 48.018 Section 10.4.4.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] fc caller-allocated memory for parsed output</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] tp pre-parsed TLVs; caller must ensure mandatory IE presence/length</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 bssgp2_dec_fc_bvc(struct bssgp2_flow_ctrl *fc, 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 granularity = 100;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* optional "Flow Control Granularity IE" (11.3.102); applies to</span><br><span style="color: hsl(120, 100%, 40%);">+     * bucket_size_max, bucket_leak_rate and PFC FC params IE */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (TLVP_PRESENT(tp, BSSGP_IE_FLOW_CTRL_GRANULARITY)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               uint8_t gran = *TLVP_VAL(tp, BSSGP_IE_FLOW_CTRL_GRANULARITY);</span><br><span style="color: hsl(120, 100%, 40%);">+         granularity = bssgp_fc_gran_tbl[gran & 3];</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%);">+   /* mandatory IEs */</span><br><span style="color: hsl(120, 100%, 40%);">+   fc->tag = *TLVP_VAL(tp, BSSGP_IE_TAG);</span><br><span style="color: hsl(120, 100%, 40%);">+     fc->bucket_size_max = granularity * tlvp_val16be(tp, BSSGP_IE_BVC_BUCKET_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+    fc->bucket_leak_rate = (granularity * tlvp_val16be(tp, BSSGP_IE_BUCKET_LEAK_RATE)) / 8;</span><br><span style="color: hsl(120, 100%, 40%);">+    fc->u.bvc.bmax_default_ms = granularity * tlvp_val16be(tp, BSSGP_IE_BMAX_DEFAULT_MS);</span><br><span style="color: hsl(120, 100%, 40%);">+      fc->u.bvc.r_default_ms = (granularity * tlvp_val16be(tp, BSSGP_IE_R_DEFAULT_MS)) / 8;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* optional / conditional */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (TLVP_PRESENT(tp, BSSGP_IE_BUCKET_FULL_RATIO)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           fc->bucket_full_ratio_present = true;</span><br><span style="color: hsl(120, 100%, 40%);">+              fc->bucket_full_ratio = *TLVP_VAL(tp, BSSGP_IE_BUCKET_FULL_RATIO);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              fc->bucket_full_ratio_present = false;</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%);">+   if (TLVP_PRESENT(tp, BSSGP_IE_BVC_MEASUREMENT)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             uint16_t val = tlvp_val16be(tp, BSSGP_IE_BVC_MEASUREMENT);</span><br><span style="color: hsl(120, 100%, 40%);">+            fc->u.bvc.measurement_present = true;</span><br><span style="color: hsl(120, 100%, 40%);">+              /* convert from centi-seconds to milli-seconds */</span><br><span style="color: hsl(120, 100%, 40%);">+             if (val == 0xffff)</span><br><span style="color: hsl(120, 100%, 40%);">+                    fc->u.bvc.measurement = 0xffffffff;</span><br><span style="color: hsl(120, 100%, 40%);">+                else</span><br><span style="color: hsl(120, 100%, 40%);">+                  fc->u.bvc.measurement = val * 10;</span><br><span style="color: hsl(120, 100%, 40%);">+  } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              fc->u.bvc.measurement_present = false;</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%);">+   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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Encode a FLOW-CONTROL-BVC PDU as per TS 48.018 Section 10.4.4.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] fc structure describing to-be-encoded FC parameters</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] gran if non-NULL: Encode using specified unit granularity</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns encoded PDU or NULL in case of error */</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_fc_bvc(const struct bssgp2_flow_ctrl *fc, enum bssgp_fc_granularity *gran)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct msgb *msg = bssgp_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bssgp_normal_hdr *bgph;</span><br><span style="color: hsl(120, 100%, 40%);">+        unsigned int granularity = 100;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (gran)</span><br><span style="color: hsl(120, 100%, 40%);">+             granularity = bssgp_fc_gran_tbl[*gran & 3];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));</span><br><span style="color: hsl(120, 100%, 40%);">+      bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &fc->tag);</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_tvlv_put_16be(msg, BSSGP_IE_BVC_BUCKET_SIZE, fc->bucket_size_max / granularity);</span><br><span style="color: hsl(120, 100%, 40%);">+      msgb_tvlv_put_16be(msg, BSSGP_IE_BUCKET_LEAK_RATE, fc->bucket_leak_rate * 8 / granularity);</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_tvlv_put_16be(msg, BSSGP_IE_BMAX_DEFAULT_MS, fc->u.bvc.bmax_default_ms / granularity);</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_tvlv_put_16be(msg, BSSGP_IE_R_DEFAULT_MS, fc->u.bvc.r_default_ms * 8 / granularity);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (fc->bucket_full_ratio_present)</span><br><span style="color: hsl(120, 100%, 40%);">+         msgb_tvlv_put(msg, BSSGP_IE_BUCKET_FULL_RATIO, 1, &fc->bucket_full_ratio);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (fc->u.bvc.measurement_present) {</span><br><span style="color: hsl(120, 100%, 40%);">+               uint16_t val;</span><br><span style="color: hsl(120, 100%, 40%);">+         /* convert from ms to cs */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (fc->u.bvc.measurement == 0xffffffff)</span><br><span style="color: hsl(120, 100%, 40%);">+                   val = 0xffff;</span><br><span style="color: hsl(120, 100%, 40%);">+         else</span><br><span style="color: hsl(120, 100%, 40%);">+                  val = fc->u.bvc.measurement / 10;</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_tvlv_put_16be(msg, BSSGP_IE_BVC_MEASUREMENT, val);</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%);">+   if (gran) {</span><br><span style="color: hsl(120, 100%, 40%);">+           uint8_t val = *gran & 3;</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_tvlv_put(msg, BSSGP_IE_FLOW_CTRL_GRANULARITY, 1, &val);</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%);">+   return 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 FLOW-CONTROL-BVC-ACK PDU as per TS 48.018 Section 10.4.4.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] tag the tag IE value to encode</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns encoded PDU or NULL in case of error */</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_fc_bvc_ack(uint8_t tag)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct msgb *msg = bssgp_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bssgp_normal_hdr *bgph;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));</span><br><span style="color: hsl(120, 100%, 40%);">+      bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC_ACK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &tag);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return 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%);">+/*! Decode a FLOW-CONTROL-MS PDU as per TS 48.018 Section 10.4.6.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] fc caller-allocated memory for parsed output</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] tp pre-parsed TLVs; caller must ensure mandatory IE presence/length</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 bssgp2_dec_fc_ms(struct bssgp2_flow_ctrl *fc, struct tlv_parsed *tp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int granularity = 100;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* optional "Flow Control Granularity IE" (11.3.102); applies to</span><br><span style="color: hsl(120, 100%, 40%);">+     * bucket_size_max, bucket_leak_rate and PFC FC params IE */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (TLVP_PRESENT(tp, BSSGP_IE_FLOW_CTRL_GRANULARITY)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               uint8_t gran = *TLVP_VAL(tp, BSSGP_IE_FLOW_CTRL_GRANULARITY);</span><br><span style="color: hsl(120, 100%, 40%);">+         granularity = bssgp_fc_gran_tbl[gran & 3];</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%);">+   /* mandatory IEs */</span><br><span style="color: hsl(120, 100%, 40%);">+   fc->u.ms.tlli = tlvp_val32be(tp, BSSGP_IE_TLLI);</span><br><span style="color: hsl(120, 100%, 40%);">+   fc->tag = *TLVP_VAL(tp, BSSGP_IE_TAG);</span><br><span style="color: hsl(120, 100%, 40%);">+     fc->bucket_size_max = granularity * tlvp_val16be(tp, BSSGP_IE_MS_BUCKET_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+     fc->bucket_leak_rate = (granularity * tlvp_val16be(tp, BSSGP_IE_BUCKET_LEAK_RATE)) / 8;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* optional / conditional */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (TLVP_PRESENT(tp, BSSGP_IE_BUCKET_FULL_RATIO)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           fc->bucket_full_ratio_present = true;</span><br><span style="color: hsl(120, 100%, 40%);">+              fc->bucket_full_ratio = *TLVP_VAL(tp, BSSGP_IE_BUCKET_FULL_RATIO);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              fc->bucket_full_ratio_present = false;</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%);">+   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 FLOW-CONTROL-MS PDU as per TS 48.018 Section 10.4.6.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] fc structure describing to-be-encoded FC parameters</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] gran if non-NULL: Encode using specified unit granularity</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns encoded PDU or NULL in case of error */</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_fc_ms(const struct bssgp2_flow_ctrl *fc, enum bssgp_fc_granularity *gran)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct msgb *msg = bssgp_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bssgp_normal_hdr *bgph;</span><br><span style="color: hsl(120, 100%, 40%);">+        unsigned int granularity = 100;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (gran)</span><br><span style="color: hsl(120, 100%, 40%);">+             granularity = bssgp_fc_gran_tbl[*gran & 3];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));</span><br><span style="color: hsl(120, 100%, 40%);">+      bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_MS;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_tvlv_put_32be(msg, BSSGP_IE_TLLI, fc->u.ms.tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &fc->tag);</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_tvlv_put_16be(msg, BSSGP_IE_MS_BUCKET_SIZE, fc->bucket_size_max / granularity);</span><br><span style="color: hsl(120, 100%, 40%);">+       msgb_tvlv_put_16be(msg, BSSGP_IE_BUCKET_LEAK_RATE, fc->bucket_leak_rate * 8 / granularity);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (fc->bucket_full_ratio_present)</span><br><span style="color: hsl(120, 100%, 40%);">+         msgb_tvlv_put(msg, BSSGP_IE_BUCKET_FULL_RATIO, 1, &fc->bucket_full_ratio);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (gran) {</span><br><span style="color: hsl(120, 100%, 40%);">+           uint8_t val = *gran & 3;</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_tvlv_put(msg, BSSGP_IE_FLOW_CTRL_GRANULARITY, 1, &val);</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%);">+   return 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 FLOW-CONTROL-BVC-ACK PDU as per TS 48.018 Section 10.4.7.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] tlli the TLLI IE value to encode</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] tag the tag IE value to encode</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns encoded PDU or NULL in case of error */</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_fc_ms_ack(uint32_t tlli, uint8_t tag)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct msgb *msg = bssgp_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bssgp_normal_hdr *bgph;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));</span><br><span style="color: hsl(120, 100%, 40%);">+      bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC_ACK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_tvlv_put_32be(msg, BSSGP_IE_TLLI, tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &tag);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return msg;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/gb/libosmogb.map b/src/gb/libosmogb.map</span><br><span>index e605d27..f8ad901 100644</span><br><span>--- a/src/gb/libosmogb.map</span><br><span>+++ b/src/gb/libosmogb.map</span><br><span>@@ -47,12 +47,18 @@</span><br><span> </span><br><span> bssgp2_nsi_tx_ptp;</span><br><span> bssgp2_nsi_tx_sig;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp2_dec_fc_bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp2_dec_fc_ms;</span><br><span> bssgp2_enc_bvc_block;</span><br><span> bssgp2_enc_bvc_block_ack;</span><br><span> bssgp2_enc_bvc_unblock;</span><br><span> bssgp2_enc_bvc_unblock_ack;</span><br><span> bssgp2_enc_bvc_reset;</span><br><span> bssgp2_enc_bvc_reset_ack;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp2_enc_fc_bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp2_enc_fc_bvc_ack;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp2_enc_fc_ms;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp2_enc_fc_ms_ack;</span><br><span> bssgp2_enc_status;</span><br><span> </span><br><span> bssgp_bvc_fsm_alloc_sig_bss;</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/21610">change 21610</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/libosmocore/+/21610"/><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-Change-Id: I9c89bb1c03550930c07aad7ff8f67129ee7a6320 </div>
<div style="display:none"> Gerrit-Change-Number: 21610 </div>
<div style="display:none"> Gerrit-PatchSet: 3 </div>
<div style="display:none"> Gerrit-Owner: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: daniel <dwillmann@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: lynxis lazus <lynxis@fe80.eu> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>