ASCI: Add IE transcoding according to 3GPP TS 48.008

Change-Id: Ic1fc714bb04228a7f32e9925811e21c8efc610bd
diff --git a/include/osmocom/gsm/gsm0808_utils.h b/include/osmocom/gsm/gsm0808_utils.h
index 85244a5..dbe2abf 100644
--- a/include/osmocom/gsm/gsm0808_utils.h
+++ b/include/osmocom/gsm/gsm0808_utils.h
@@ -31,6 +31,8 @@
 #include <osmocom/gsm/gsm23003.h>
 #include <osmocom/gsm/gsm_utils.h>
 #include <osmocom/gsm/tlv.h>
+#include <osmocom/gsm/gsm48.h>
+#include <osmocom/core/endian.h>
 
  /*! (225-1)/2 is the maximum number of elements in a cell identifier list. */
 #define GSM0808_CELL_ID_LIST2_MAXLEN		127
@@ -62,6 +64,164 @@
 	unsigned int id_list_len;
 };
 
+/*! Packed representation of a Priority IE (GGPP TS 48.008 3.2.2.18) */
+struct gsm0808_priority {
+#if OSMO_IS_LITTLE_ENDIAN
+	uint8_t pvi:1,			/* Preemption Vulnerability indicator */
+		qa:1,			/* Queuing allowed indicator */
+		priority_level:4,	/* Priority level: 1 == hightest, 14 == lowest */
+		pci:1,			/* Preemption Capability indicator */
+		spare:1;
+#elif OSMO_IS_BIG_ENDIAN
+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
+	uint8_t spare:1, pci:1, priority_level:4, qa:1, pvi:1;
+#endif
+} __attribute__ ((packed));
+
+/*! Packed representation of a VGCS Feature Flags IE (3GPP TS 48.008 3.2.2.88) */
+struct gsm0808_vgcs_feature_flags {
+#if OSMO_IS_LITTLE_ENDIAN
+	uint8_t tp_ind:1,		/* Talker priority supported */
+		as_ind_circuit:1,	/* A-interface circuit sharing supported */
+		as_ind_link:1,		/* A-interface link sharing supported */
+		bss_res:1,		/* BSS supports re-establishment */
+		tcp:1,			/* Talker channel parameter supported */
+		spare:3;
+#elif OSMO_IS_BIG_ENDIAN
+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
+	uint8_t spare:3, tcp:1, bss_res:1, as_ind_link:1, as_ind_circuit:1, tp_ind:1;
+#endif
+} __attribute__ ((packed));
+
+/* TS 48.008 3.2.2.52 */
+enum gsm0808_assignment_requirement {
+	GSM0808_ASRQ_DELAY_ALLOWED		= 0x00,
+	GSM0808_ASRQ_IMMEDIATE			= 0x01,
+	GSM0808_ASRQ_IMMEDIATE_ON_DEMAND	= 0x02,
+};
+
+/* TS 48.008 Table 10.5.8 */
+enum gsm0808_service_flag {
+	GSM0808_SF_VBS				= 0,
+	GSM0808_SF_VGCS				= 1,
+};
+
+enum gsm0808_call_priority {
+	GSM0808_CALL_PRIORITY_NONE		= 0x00,
+	GSM0808_CALL_PRIORITY_LEVEL_4		= 0x01,
+	GSM0808_CALL_PRIORITY_LEVEL_3		= 0x02,
+	GSM0808_CALL_PRIORITY_LEVEL_2		= 0x03,
+	GSM0808_CALL_PRIORITY_LEVEL_1		= 0x04,
+	GSM0808_CALL_PRIORITY_LEVEL_0		= 0x05,
+	GSM0808_CALL_PRIORITY_LEVEL_B		= 0x06,
+	GSM0808_CALL_PRIORITY_LEVEL_A		= 0x07,
+};
+
+/*! Packed representation of a Group Call Reference IE (3GPP TS 48.008 3.2.2.55) */
+struct gsm0808_group_callref {
+#if OSMO_IS_LITTLE_ENDIAN
+	uint8_t call_ref_hi[3];
+	uint8_t call_priority:3,
+		af:1,			/* Acknowledgement flag */
+		sf:1,			/* Service flag */
+		call_ref_lo:3;
+	uint8_t spare:4,
+		ciphering_info:4;
+#elif OSMO_IS_BIG_ENDIAN
+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
+	uint8_t call_ref_hi[3];
+	uint8_t call_ref_lo:3, sf:1, af:1, call_priority:3;
+	uint8_t ciphering_info:4, spare:4;
+#endif
+} __attribute__ ((packed));
+
+/* TS 48.008 3.2.2.26 */
+enum gsm0808_downlink_dtx_flag {
+	GSM0808_DTX_FLAG_ALLOW			= 0,
+	GSM0808_DTX_FLAG_FORBID			= 1,
+};
+
+/*! Parsed representation of a Cell Identifier List Segment IE (3GPP TS 48.008 3.2.2.27a) */
+struct gsm0808_cell_id_list_segment {
+	uint8_t seq_last;
+	uint8_t seq_number;
+	struct gsm0808_cell_id_list2 cil;
+};
+
+/*! Parsed representation of a Circuit Pool List IE (3GPP TS 48.008 3.2.2.26) */
+#define CIRCUIT_POOL_LIST_MAXLEN 252
+struct gsm0808_circuit_pool_list {
+	uint8_t pool[CIRCUIT_POOL_LIST_MAXLEN];
+	unsigned int list_len;
+};
+
+/* 3GPP TS 48.008 Table  3.2.2.90.1 Talker Priority */
+enum gsm0808_talker_priority {
+	GSM0808_TALKER_PRIORITY_NORMAL		= 0x00,
+	GSM0808_TALKER_PRIORITY_PRIVILEGED	= 0x01,
+	GSM0808_TALKER_PRIORITY_EMERGENCY	= 0x02,
+};
+
+/*! Parsed representation of a Layer 3 Information IE (3GPP TS 48.008 3.2.2.24) */
+#define LAYER_3_INFORMATION_MAXLEN 252
+struct gsm0808_layer_3_information {
+	uint8_t l3[LAYER_3_INFORMATION_MAXLEN];
+	unsigned int l3_len;
+};
+
+/*! Parsed representation of a Talker Identity IE (3GPP TS 48.008 3.2.2.91) */
+#define TALKER_IDENTITY_MAXLEN 17
+struct gsm0808_talker_identity {
+	uint8_t talker_id[TALKER_IDENTITY_MAXLEN];
+	unsigned int id_bits;
+};
+
+/* 3GPP TS 48.008 3.2.2.94 VGCS/VBS Cell Status */
+enum gsm0808_vgcs_vbs_cell_status {
+	GSM0808_CSTAT_ESTABLISHED		= 0x00,
+	GSM0808_CSTAT_NOT_ESTABLISHED1		= 0x01,
+	GSM0808_CSTAT_RELEASED_NO_USER		= 0x02,
+	GSM0808_CSTAT_NOT_ESTABLISHED2		= 0x03,
+};
+
+/*! Parsed representation of a SMS to VGCS IE (3GPP TS 48.008 3.2.2.92) */
+#define SMS_TO_VGCS_MAXLEN 252
+struct gsm0808_sms_to_vgcs {
+	uint8_t sms[SMS_TO_VGCS_MAXLEN];
+	unsigned int sms_len;
+};
+
+/*! Parsed representation of a Application Data IE (3GPP TS 48.008 3.2.2.98) */
+#define APP_DATA_MAXLEN 9
+struct gsm0808_application_data {
+	uint8_t data[APP_DATA_MAXLEN];
+	unsigned int data_len;
+};
+
+/*! Packed representation of a Data Identity IE (GGPP TS 48.008 3.2.2.99) */
+enum gsm0808_application_idndicator {
+	GSM0808_AI_APP_DATA			= 0x00,
+	GSM0808_AI_CONFIRM_APP_DATA		= 0x01,
+};
+
+#define GSM0808_DP_MASK_TALKERS_LISTENERS	0x04
+#define GSM0808_DP_MASK_DISPATCHERS		0x02
+#define GSM0808_DP_MASK_NETWORK_APP		0x01
+
+struct gsm0808_data_identity {
+#if OSMO_IS_LITTLE_ENDIAN
+	uint8_t ai:1,	/* Application Indicator */
+		di:4,	/* Data identifier */
+		dp:3;	/* Distribution parameter (bit mask) */
+#elif OSMO_IS_BIG_ENDIAN
+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
+	uint8_t dp:3, di:4, ai:1;
+#endif
+} __attribute__ ((packed));
+
+/*! Parsed representation of a MSISDN IE (3GPP TS 48.008 3.2.2.101) */
+#define MSISDN_MAXLEN 20
+
 /*! LCLS-related parameters from 3GPP TS 48.008 */
 struct osmo_lcls {
 	enum gsm0808_lcls_config config;   /**< §3.2.2.116 Configuration */
@@ -303,4 +463,23 @@
 char *gsm0808_channel_type_name_buf(char *buf, size_t buf_len, const struct gsm0808_channel_type *ct);
 char *gsm0808_channel_type_name_c(const void *ctx, const struct gsm0808_channel_type *ct);
 
+uint8_t gsm0808_enc_group_callref(struct msgb *msg, const struct gsm0808_group_callref *gc);
+int gsm0808_dec_group_callref(struct gsm0808_group_callref *gc, const uint8_t *elem, uint8_t len);
+uint8_t gsm0808_enc_priority(struct msgb *msg, const struct gsm0808_priority *pri);
+int gsm0808_dec_priority(struct gsm0808_priority *pri, const uint8_t *elem, uint8_t len);
+uint8_t gsm0808_enc_vgcs_feature_flags(struct msgb *msg, const struct gsm0808_vgcs_feature_flags *ff);
+int gsm0808_dec_vgcs_feature_flags(struct gsm0808_vgcs_feature_flags *ff, const uint8_t *elem, uint8_t len);
+uint8_t gsm0808_enc_talker_identity(struct msgb *msg, const struct gsm0808_talker_identity *ti);
+int gsm0808_dec_talker_identity(struct gsm0808_talker_identity *ti, const uint8_t *elem, uint8_t len);
+uint8_t gsm0808_enc_data_identity(struct msgb *msg, const struct gsm0808_data_identity *ai);
+int gsm0808_dec_data_identity(struct gsm0808_data_identity *ai, const uint8_t *elem, uint8_t len);
+uint8_t gsm0808_enc_msisdn(struct msgb *msg, const char *msisdn);
+int gsm0808_dec_msisdn(char *msisdn, const char *elem, uint8_t len);
+uint8_t gsm0808_enc_assign_req(struct msgb *msg, const enum gsm0808_assignment_requirement ar);
+int gsm0808_dec_assign_req(enum gsm0808_assignment_requirement *ar, const uint8_t *elem, uint8_t len);
+uint8_t gsm0808_enc_cell_id_list_segment(struct msgb *msg, uint8_t ie_type,
+					 const struct gsm0808_cell_id_list_segment *ci);
+int gsm0808_dec_cell_id_list_segment(struct gsm0808_cell_id_list_segment *ci, const uint8_t *elem, uint8_t len);
+int gsm0808_dec_call_id(uint32_t *ci, const uint8_t *elem, uint8_t len);
+
 /*! @} */