<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>