summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmocom/gsm/tlv.h2
-rw-r--r--src/gsm/libosmogsm.map2
-rw-r--r--src/gsm/tlv_parser.c60
3 files changed, 64 insertions, 0 deletions
diff --git a/include/osmocom/gsm/tlv.h b/include/osmocom/gsm/tlv.h
index cf09969d..701fe688 100644
--- a/include/osmocom/gsm/tlv.h
+++ b/include/osmocom/gsm/tlv.h
@@ -436,6 +436,8 @@ static inline uint32_t tlvp_val32_unal(const struct tlv_parsed *tp, int pos)
return res;
}
+struct tlv_parsed *osmo_tlvp_copy(const struct tlv_parsed *tp_orig, void *ctx);
+int osmo_tlvp_merge(struct tlv_parsed *dst, const struct tlv_parsed *src);
int osmo_shift_v_fixed(uint8_t **data, size_t *data_len,
size_t len, uint8_t **value);
int osmo_match_shift_tv_fixed(uint8_t **data, size_t *data_len,
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index 199d05af..b84f859f 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -324,6 +324,8 @@ tlv_parse_one;
tvlv_att_def;
vtvlv_gan_att_def;
+osmo_tlvp_copy;
+osmo_tlvp_merge;
osmo_shift_v_fixed;
osmo_match_shift_tv_fixed;
osmo_shift_tlv;
diff --git a/src/gsm/tlv_parser.c b/src/gsm/tlv_parser.c
index e84edd97..4cc43f67 100644
--- a/src/gsm/tlv_parser.c
+++ b/src/gsm/tlv_parser.c
@@ -19,6 +19,7 @@
#include <stdio.h>
#include <stdint.h>
+#include <errno.h>
#include <osmocom/core/utils.h>
#include <osmocom/gsm/tlv.h>
@@ -43,6 +44,65 @@ int tlv_dump(struct tlv_parsed *dec)
return 0;
}
+/*! \brief Copy \ref tlv_parsed using given talloc context
+ * \param[in] tp_orig Parsed TLV structure
+ * \param[in] ctx Talloc context for allocations
+ * \returns NULL on errors, \ref tlv_parsed pointer otherwise
+ */
+struct tlv_parsed *osmo_tlvp_copy(const struct tlv_parsed *tp_orig, void *ctx)
+{
+ struct tlv_parsed *tp_out;
+ size_t i, len;
+
+ tp_out = talloc_zero(ctx, struct tlv_parsed);
+ if (!tp_out)
+ return NULL;
+
+ /* if the original is NULL, return empty tlvp */
+ if (!tp_orig)
+ return tp_out;
+
+ for (i = 0; i < ARRAY_SIZE(tp_orig->lv); i++) {
+ len = tp_orig->lv[i].len;
+ tp_out->lv[i].len = len;
+ if (len && tp_out->lv[i].val) {
+ tp_out->lv[i].val = talloc_zero_size(tp_out, len);
+ if (!tp_out->lv[i].val) {
+ talloc_free(tp_out);
+ return NULL;
+ }
+ memcpy((uint8_t *)tp_out->lv[i].val, tp_orig->lv[i].val,
+ len);
+ }
+ }
+
+ return tp_out;
+}
+
+/*! \brief Merge all \ref tlv_parsed attributes of 'src' into 'dst'
+ * \param[in] dst Parsed TLV structure to merge into
+ * \param[in] src Parsed TLV structure to merge from
+ * \returns 0 on success, negative on error
+ */
+int osmo_tlvp_merge(struct tlv_parsed *dst, const struct tlv_parsed *src)
+{
+ size_t i, len;
+ for (i = 0; i < ARRAY_SIZE(dst->lv); i++) {
+ len = src->lv[i].len;
+ if (len == 0 || src->lv[i].val == NULL)
+ continue;
+ if (dst->lv[i].val) {
+ talloc_free((uint8_t *) dst->lv[i].val);
+ dst->lv[i].len = 0;
+ }
+ dst->lv[i].val = talloc_zero_size(dst, len);
+ if (!dst->lv[i].val)
+ return -ENOMEM;
+ memcpy((uint8_t *) dst->lv[i].val, src->lv[i].val, len);
+ }
+ return 0;
+}
+
/*! \brief Parse a single TLV encoded IE
* \param[out] o_tag the tag of the IE that was found
* \param[out] o_len length of the IE that was found