|
@@ -155,6 +155,251 @@ static const struct key_val event_info[] = {
|
|
{ 0, },
|
|
{ 0, },
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static const struct key_val nai_vals[] = {
|
|
|
|
+ { 0x00, "spare" },
|
|
|
|
+ { 0x01, "subscriber number (national use)" },
|
|
|
|
+ { 0x02, "unknown (national use)" },
|
|
|
|
+ { 0x03, "national (significant) number" },
|
|
|
|
+ { 0x04, "international number" },
|
|
|
|
+ { 0x05, "network-specific number (national use)" },
|
|
|
|
+ { 0x06, "network routing number in national (significant) number format (national use)" },
|
|
|
|
+ { 0x07, "network routing number in network-specific number format (national use)" },
|
|
|
|
+ { 0x08, "network routing number concatenated with Called Directory Number (national use)" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct key_val inn_vals[] = {
|
|
|
|
+ { 0x00, "routing to internal network number allowed" },
|
|
|
|
+ { 0x01, "routing to internal network number not allowed" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct key_val ni_vals[] = {
|
|
|
|
+ { 0x00, "complete" },
|
|
|
|
+ { 0x01, "incomplete" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct key_val npi_vals[] = {
|
|
|
|
+ { 0x00, "spare" },
|
|
|
|
+ { 0x01, "ISDN (Telephony) numbering plan (ITU-T Recommendation E.164)" },
|
|
|
|
+ { 0x02, "spare" },
|
|
|
|
+ { 0x03, "Data numbering plan (ITU-T Recommendation X.121) (national use)" },
|
|
|
|
+ { 0x04, "Telex numbering plan (ITU-T Recommendation F.69) (national use)" },
|
|
|
|
+ { 0x05, "reserved for national use" },
|
|
|
|
+ { 0x06, "reserved for national use" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct key_val restrict_vals[] = {
|
|
|
|
+ { 0x00, "presentation allowed" },
|
|
|
|
+ { 0x01, "presentation restricted" },
|
|
|
|
+ { 0x02, "address not available (Note 1) (national use)" },
|
|
|
|
+ { 0x03, "reserved for restriction by the network" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct key_val screened_vals[] = {
|
|
|
|
+ { 0x00, "reserved (Note 2)" },
|
|
|
|
+ { 0x01, "user provided, verified and passed" },
|
|
|
|
+ { 0x02, "reserved (Note 2)" },
|
|
|
|
+ { 0x03, "network provided" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct key_val calling_cat_vals[] = {
|
|
|
|
+ { 0x00, "calling party's category unknown at this time (national use)" },
|
|
|
|
+ { 0x01, "operator, language French" },
|
|
|
|
+ { 0x02, "operator, language English" },
|
|
|
|
+ { 0x03, "operator, language German" },
|
|
|
|
+ { 0x04, "operator, language Russian" },
|
|
|
|
+ { 0x05, "operator, language Spanish" },
|
|
|
|
+ { 0x09, "reserved (see ITU-T Recommendation Q.104) (Note) (national use)" },
|
|
|
|
+ { 0x0A, "ordinary calling subscriber" },
|
|
|
|
+ { 0x0B, "calling subscriber with priority" },
|
|
|
|
+ { 0x0C, "data call (voice band data)" },
|
|
|
|
+ { 0x0D, "test call" },
|
|
|
|
+ { 0x0E, "spare" },
|
|
|
|
+ { 0x0F, "payphone" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct key_val nci_sat_vals[] = {
|
|
|
|
+ { 0x00, "no satellite circuit in the connection" },
|
|
|
|
+ { 0x01, "one satellite circuit in the connection" },
|
|
|
|
+ { 0x02, "two satellite circuits in the connection" },
|
|
|
|
+ { 0x03, "spare" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct key_val nci_con_vals[] = {
|
|
|
|
+ { 0x00, "continuity check not required" },
|
|
|
|
+ { 0x01, "continuity check required on this circuit" },
|
|
|
|
+ { 0x02, "continuity check performed on a previous circuit" },
|
|
|
|
+ { 0x03, "spare" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct key_val nci_echo_vals[] = {
|
|
|
|
+ { 0x00, "outgoing echo control device not included" },
|
|
|
|
+ { 0x01, "outgoing echo control device included" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/* Forward call indicators National/international call indicator */
|
|
|
|
+static const struct key_val fwc_nic_vals[] = {
|
|
|
|
+ { 0x00, "call to be treated as a national call" },
|
|
|
|
+ { 0x01, "call to be treated as an international call" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/* End-to-end method indicator */
|
|
|
|
+static const struct key_val fwc_etem_vals[] = {
|
|
|
|
+ { 0x00, "no end-to-end method available (only link-by-link method available)" },
|
|
|
|
+ { 0x01, "pass-along method available (national use)" },
|
|
|
|
+ { 0x02, "SCCP method available" },
|
|
|
|
+ { 0x03, "pass-along and SCCP methods available (national use)" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/* Interworking indicator */
|
|
|
|
+static const struct key_val fwc_iw_vals[] = {
|
|
|
|
+ { 0x00, "no interworking encountered (No. 7 signalling all the way)" },
|
|
|
|
+ { 0x01, "interworking encountered" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/* End-to-end information indicator */
|
|
|
|
+static const struct key_val fwc_etei_vals[] = {
|
|
|
|
+ { 0x00, "no end-to-end information available" },
|
|
|
|
+ { 0x01, "end-to-end information available" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/* ISDN user part indicator */
|
|
|
|
+static const struct key_val fwc_isup_vals[] = {
|
|
|
|
+ { 0x00, "ISDN user part not used all the way" },
|
|
|
|
+ { 0x01, "ISDN user part used all the way" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/* ISDN user part preference indicator */
|
|
|
|
+static const struct key_val fwc_isup_pref_vals[] = {
|
|
|
|
+ { 0x00, "ISDN user part preferred all the way" },
|
|
|
|
+ { 0x01, "ISDN user part not required all the way" },
|
|
|
|
+ { 0x02, "ISDN user part required all the way" },
|
|
|
|
+ { 0x03, "spare" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/* ISDN access indicator */
|
|
|
|
+static const struct key_val fwc_ia_vals[] = {
|
|
|
|
+ { 0x00, "originating access non-ISDN" },
|
|
|
|
+ { 0x01, "originating access ISD" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/* SCCP method indicator */
|
|
|
|
+static const struct key_val fwc_sccpm_vals[] = {
|
|
|
|
+ { 0x00, "no indication" },
|
|
|
|
+ { 0x01, "connectionless method available (national use)" },
|
|
|
|
+ { 0x02, "connection oriented method available" },
|
|
|
|
+ { 0x03, "connectionless and connection oriented methods available (national use)" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/* Transmission medium */
|
|
|
|
+static const struct key_val trans_medium_vals[] = {
|
|
|
|
+ { 0x00, "speech" },
|
|
|
|
+ { 0x01, "spare" },
|
|
|
|
+ { 0x02, "64 kbit/s unrestricted" },
|
|
|
|
+ { 0x03, "3.1 kHz audio" },
|
|
|
|
+ { 0x04, "reserved for alternate speech (service 2)/64 kbit/s unrestricted (service 1)" },
|
|
|
|
+ { 0x05, "reserved for alternate 64 kbit/s unrestricted (service 1)/speech (service 2)" },
|
|
|
|
+ { 0x06, "64 kbit/s preferred" },
|
|
|
|
+ { 0x07, "2 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x08, "384 kbit/s unrestricted" },
|
|
|
|
+ { 0x09, "1536 kbit/s unrestricted" },
|
|
|
|
+ { 0x0A, "1920 kbit/s unrestricted" },
|
|
|
|
+ { 0x10, "3 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x11, "4 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x12, "5 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x13, "spare" },
|
|
|
|
+ { 0x14, "7 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x15, "8 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x16, "9 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x17, "10 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x18, "11 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x19, "12 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x1A, "13 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x1B, "14 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x1C, "15 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x1D, "16 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x1E, "17 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x1F, "18 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x20, "19 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x21, "20 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x22, "21 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x23, "22 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x24, "23 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x25, "spare" },
|
|
|
|
+ { 0x26, "25 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x27, "26 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x28, "27 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x29, "28 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0x2A, "29 × 64 kbit/s unrestricted" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/* Q931 bearer capabilities */
|
|
|
|
+static const struct key_val q931_cstd_vals[] = {
|
|
|
|
+ { 0x00, "ITU-T standardized coding as described below" },
|
|
|
|
+ { 0x01, "ISO/IEC Standard" },
|
|
|
|
+ { 0x02, "National standard" },
|
|
|
|
+ { 0x03, "Standard defined for the network (either public or private) present on the network side of the interface" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct key_val q931_trs_cap_vals[] = {
|
|
|
|
+ { 0x00, "Speech" },
|
|
|
|
+ { 0x08, "Unrestricted digital information" },
|
|
|
|
+ { 0x09, "Restricted digital information" },
|
|
|
|
+ { 0x10, "3.1 kHz audio" },
|
|
|
|
+ { 0x11, "Unrestricted digital information with tones/announcements (Note 2)" },
|
|
|
|
+ { 0x18, "Video" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct key_val q931_trs_mde_vals[] = {
|
|
|
|
+ { 0x00, "Circuit mode" },
|
|
|
|
+ { 0x01, "Packet mode" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct key_val q931_trs_rte_vals[] = {
|
|
|
|
+ { 0x00, "packet-mode calls" },
|
|
|
|
+ { 0x10, "64 kbit/s" },
|
|
|
|
+ { 0x11, "2 × 64 kbit/s" },
|
|
|
|
+ { 0x13, "384 kbit/s" },
|
|
|
|
+ { 0x15, "1536 kbit/s" },
|
|
|
|
+ { 0x17, "1920 kbit/s" },
|
|
|
|
+ { 0x18, "Multirate (64 kbit/s base rate)" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct key_val q931_usr_info_vals[] = {
|
|
|
|
+ { 0x00, "ITU-T standardized rate adaption V.110, I.460 and X.30. This implies the presence of octet 5a and optionally octets 5b, 5c and 5d as defined below" },
|
|
|
|
+ { 0x02, "G.711 u-law" },
|
|
|
|
+ { 0x03, "G.711 a-law" },
|
|
|
|
+ { 0x04, "G.721 ADPCM" },
|
|
|
|
+ { 0x05, "H.221 and H.242" },
|
|
|
|
+ { 0x06, "H.223 and H.245" },
|
|
|
|
+ { 0x07, "Non-ITU-T standardized rate adaption" },
|
|
|
|
+ { 0x08, "V.120" },
|
|
|
|
+ { 0x09, "X.31" },
|
|
|
|
+ { 0, },
|
|
|
|
+};
|
|
|
|
+
|
|
static const char *lookup(const struct key_val *table, const uint8_t val, const char *deflt)
|
|
static const char *lookup(const struct key_val *table, const uint8_t val, const char *deflt)
|
|
{
|
|
{
|
|
while (1) {
|
|
while (1) {
|
|
@@ -190,7 +435,7 @@ static inline void decode_bcd(char *dest, const uint8_t *data, size_t len, int o
|
|
*dest = '\0';
|
|
*dest = '\0';
|
|
}
|
|
}
|
|
|
|
|
|
-static void append_e164(srjson_doc_t *doc, const char *name, const uint8_t *data, uint8_t len)
|
|
|
|
|
|
+static void append_e164(srjson_doc_t *doc, const char *name, const uint8_t *data, uint8_t len, const uint8_t type)
|
|
{
|
|
{
|
|
char num[17] = { 0, };
|
|
char num[17] = { 0, };
|
|
srjson_t *obj;
|
|
srjson_t *obj;
|
|
@@ -215,8 +460,30 @@ static void append_e164(srjson_doc_t *doc, const char *name, const uint8_t *data
|
|
}
|
|
}
|
|
|
|
|
|
odd = !!(data[0] & 0x80);
|
|
odd = !!(data[0] & 0x80);
|
|
|
|
+
|
|
|
|
+ if (type == ISUPCalledPartyNumber) {
|
|
|
|
+ uint8_t inn = data[1] >> 7;
|
|
|
|
+ srjson_AddNumberToObject(doc, obj, "inn", inn);
|
|
|
|
+ srjson_AddStringToObject(doc, obj, "inn_name", lookup(inn_vals, inn, "Unknown"));
|
|
|
|
+ } else {
|
|
|
|
+ uint8_t ni = data[1] >> 7;
|
|
|
|
+ uint8_t ap = (data[1] & 0x0C) >> 2;
|
|
|
|
+ uint8_t si = (data[1] & 0x03);
|
|
|
|
+
|
|
|
|
+ srjson_AddNumberToObject(doc, obj, "ni", ni);
|
|
|
|
+ srjson_AddStringToObject(doc, obj, "ni_name", lookup(ni_vals, ni, "Unknown"));
|
|
|
|
+
|
|
|
|
+ srjson_AddNumberToObject(doc, obj, "restrict", ap);
|
|
|
|
+ srjson_AddStringToObject(doc, obj, "restrict_name", lookup(restrict_vals, ap, "Unknown"));
|
|
|
|
+
|
|
|
|
+ srjson_AddNumberToObject(doc, obj, "screened", si);
|
|
|
|
+ srjson_AddStringToObject(doc, obj, "screened_name", lookup(screened_vals, si, "Unknown"));
|
|
|
|
+ }
|
|
|
|
+
|
|
srjson_AddNumberToObject(doc, obj, "ton", data[0] & 0x7F);
|
|
srjson_AddNumberToObject(doc, obj, "ton", data[0] & 0x7F);
|
|
|
|
+ srjson_AddStringToObject(doc, obj, "ton_name", lookup(nai_vals, data[0] & 0x7F, "Unknown"));
|
|
srjson_AddNumberToObject(doc, obj, "npi", (data[1] >> 4) & 0x07);
|
|
srjson_AddNumberToObject(doc, obj, "npi", (data[1] >> 4) & 0x07);
|
|
|
|
+ srjson_AddStringToObject(doc, obj, "npi_name", lookup(npi_vals, (data[1] >> 4) & 0x07, "Unknown"));
|
|
|
|
|
|
decode_bcd(num, &data[2], len - 2, odd);
|
|
decode_bcd(num, &data[2], len - 2, odd);
|
|
srjson_AddStringToObject(doc, obj, "num", num);
|
|
srjson_AddStringToObject(doc, obj, "num", num);
|
|
@@ -302,14 +569,232 @@ static void append_event_information(srjson_doc_t *doc, const char *name, const
|
|
srjson_AddItemToObject(doc, doc->root, name, obj);
|
|
srjson_AddItemToObject(doc, doc->root, name, obj);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void append_hop_counter(srjson_doc_t *doc, const char *name, const uint8_t *data, uint8_t len)
|
|
|
|
+{
|
|
|
|
+ uint8_t hop;
|
|
|
|
+
|
|
|
|
+ if (len < 1) {
|
|
|
|
+ LM_ERR("Not enough data for hop counter\n");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ memcpy(&hop, data, 1);
|
|
|
|
+ srjson_AddNumberToObject(doc, doc->root, name, hop);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void append_calling_party_category(srjson_doc_t *doc, const uint8_t *data, uint8_t len)
|
|
|
|
+{
|
|
|
|
+ srjson_t *obj;
|
|
|
|
+ uint8_t cat;
|
|
|
|
+
|
|
|
|
+ if (len < 1) {
|
|
|
|
+ LM_ERR("Not enough data for transport medium requirement\n");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ obj = srjson_CreateObject(doc);
|
|
|
|
+ if (!obj) {
|
|
|
|
+ LM_ERR("Can not allocate json object for transport medium requirement\n");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ memcpy(&cat, data, 1);
|
|
|
|
+ srjson_AddNumberToObject(doc, obj, "num", cat);
|
|
|
|
+ srjson_AddStringToObject(doc, obj, "name", lookup(calling_cat_vals, cat, "Unknown"));
|
|
|
|
+
|
|
|
|
+ srjson_AddItemToObject(doc, doc->root, "calling_party", obj);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void append_nci(srjson_doc_t *doc, const char *name, const uint8_t *data, uint8_t len)
|
|
|
|
+{
|
|
|
|
+ uint8_t sat, con, ech;
|
|
|
|
+ srjson_t *obj;
|
|
|
|
+
|
|
|
|
+ if (len != 1) {
|
|
|
|
+ LM_ERR("Unpexected size(%u) for nature of connection indicators\n", len);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ obj = srjson_CreateObject(doc);
|
|
|
|
+ if (!obj) {
|
|
|
|
+ LM_ERR("Can not allocate json object for %s\n", name);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ sat = data[0] & 0x03;
|
|
|
|
+ con = (data[0] & 0x0C) >> 2;
|
|
|
|
+ ech = (data[0] & 0x10) >> 4;
|
|
|
|
+
|
|
|
|
+ srjson_AddNumberToObject(doc, obj, "satellite", sat);
|
|
|
|
+ srjson_AddStringToObject(doc, obj, "satellite_name", lookup(nci_sat_vals, sat, "Unknown"));
|
|
|
|
+ srjson_AddNumberToObject(doc, obj, "continuity_check", con);
|
|
|
|
+ srjson_AddStringToObject(doc, obj, "continuity_check_name", lookup(nci_con_vals, sat, "Unknown"));
|
|
|
|
+ srjson_AddNumberToObject(doc, obj, "echo_device", ech);
|
|
|
|
+ srjson_AddStringToObject(doc, obj, "echo_device_name", lookup(nci_echo_vals, ech, "Unknown"));
|
|
|
|
+
|
|
|
|
+ srjson_AddItemToObject(doc, doc->root, name, obj);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void append_forward_call(srjson_doc_t *doc, const char *name, const uint8_t *data, uint8_t len)
|
|
|
|
+{
|
|
|
|
+ uint16_t val;
|
|
|
|
+ srjson_t *obj;
|
|
|
|
+ size_t i;
|
|
|
|
+ uint8_t off = 0;
|
|
|
|
+
|
|
|
|
+ static const struct bit_masks {
|
|
|
|
+ uint8_t num_bits;
|
|
|
|
+ const struct key_val *vals;
|
|
|
|
+ const char *name;
|
|
|
|
+ const char *bit_names;
|
|
|
|
+ } bits[] = {
|
|
|
|
+ { 1, fwc_nic_vals, "national_international_call", "A" },
|
|
|
|
+ { 2, fwc_etem_vals, "end_to_end_method", "CB" },
|
|
|
|
+ { 1, fwc_iw_vals, "interworking", "D" },
|
|
|
|
+ { 1, fwc_etei_vals, "end_to_end_information", "E" },
|
|
|
|
+ { 1, fwc_isup_vals, "isup", "F" },
|
|
|
|
+ { 2, fwc_isup_pref_vals, "isup_preference", "HG" },
|
|
|
|
+ { 1, fwc_ia_vals, "isdn_access", "I" },
|
|
|
|
+ { 2, fwc_sccpm_vals, "sccp_method", "KJ" },
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ if (len != 2) {
|
|
|
|
+ LM_ERR("Unpexected size(%u) for forward call indicators\n", len);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ obj = srjson_CreateObject(doc);
|
|
|
|
+ if (!obj) {
|
|
|
|
+ LM_ERR("Can not allocate json object for %s\n", name);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ memcpy(&val, data, sizeof(val));
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < (sizeof(bits)/sizeof(bits[0])); ++i) {
|
|
|
|
+ char buf[128];
|
|
|
|
+ const struct bit_masks *mask_info = &bits[i];
|
|
|
|
+ uint8_t mask = 0, tmp;
|
|
|
|
+ int b;
|
|
|
|
+
|
|
|
|
+ /* build a mask */
|
|
|
|
+ for (b = 0; b < mask_info->num_bits; ++b)
|
|
|
|
+ mask = (mask << 1) | 0x01;
|
|
|
|
+
|
|
|
|
+ snprintf(buf, sizeof(buf), "%s_name", mask_info->name);
|
|
|
|
+
|
|
|
|
+ tmp = (val >> off) & mask;
|
|
|
|
+ srjson_AddNumberToObject(doc, obj, mask_info->name, tmp);
|
|
|
|
+ srjson_AddStringToObject(doc, obj, buf, lookup(mask_info->vals, tmp, mask_info->bit_names));
|
|
|
|
+ off += mask_info->num_bits;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ srjson_AddItemToObject(doc, doc->root, name, obj);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void append_transmission_medium(srjson_doc_t *doc, const uint8_t *data, const uint8_t len)
|
|
|
|
+{
|
|
|
|
+ srjson_t *obj;
|
|
|
|
+
|
|
|
|
+ if (len != 1) {
|
|
|
|
+ LM_ERR("Unpexected size(%u)\n", len);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ obj = srjson_CreateObject(doc);
|
|
|
|
+ if (!obj) {
|
|
|
|
+ LM_ERR("Can not allocate json object\n");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ srjson_AddNumberToObject(doc, obj, "num", data[0]);
|
|
|
|
+ srjson_AddStringToObject(doc, obj, "name", lookup(trans_medium_vals, data[0], "Unknown"));
|
|
|
|
+
|
|
|
|
+ srjson_AddItemToObject(doc, doc->root, "transmission_medium", obj);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Decode the Q.931 bearer capabilities now. At least three octets
|
|
|
|
+ * but for some channels it will be four. Also only ITU caps will
|
|
|
|
+ * be parsed.
|
|
|
|
+ */
|
|
|
|
+static void append_user_information(srjson_doc_t *doc, const uint8_t *data, const uint8_t len)
|
|
|
|
+{
|
|
|
|
+ srjson_t *obj;
|
|
|
|
+ uint8_t coding_standard, transfer_capability;
|
|
|
|
+ uint8_t transfer_mode, transfer_rate;
|
|
|
|
+ uint8_t layer1_ident, layer1_protocol;
|
|
|
|
+ uint8_t octet5;
|
|
|
|
+ int rate_multiplier = -1;
|
|
|
|
+
|
|
|
|
+ if (len < 3) {
|
|
|
|
+ LM_ERR("Insufficient size(%u)\n", len);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ coding_standard = (data[0] & 0x60) >> 5;
|
|
|
|
+ transfer_capability = data[0] & 0x1F;
|
|
|
|
+ transfer_mode = (data[1] & 0x60) >> 5;
|
|
|
|
+ transfer_rate = data[1] & 0x1F;
|
|
|
|
+
|
|
|
|
+ if (transfer_rate == 0x18) {
|
|
|
|
+ if (len < 4) {
|
|
|
|
+ LM_ERR("Insufficient size(%u) for multirate\n", len);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ rate_multiplier = data[2] & 0x7F;
|
|
|
|
+ octet5 = data[3];
|
|
|
|
+ } else
|
|
|
|
+ octet5 = data[2];
|
|
|
|
+
|
|
|
|
+ layer1_ident = (octet5 & 0x60) >> 5;
|
|
|
|
+ layer1_protocol = octet5 & 0x1F;
|
|
|
|
+
|
|
|
|
+ obj = srjson_CreateObject(doc);
|
|
|
|
+ if (!obj) {
|
|
|
|
+ LM_ERR("Can not allocate json object\n");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* numbers first and maybe names if it is ITU */
|
|
|
|
+ srjson_AddStringToObject(doc, obj, "coding_standard_name", lookup(q931_cstd_vals, coding_standard, "Unknown"));
|
|
|
|
+ srjson_AddNumberToObject(doc, obj, "coding_standard", coding_standard);
|
|
|
|
+ srjson_AddNumberToObject(doc, obj, "transfer_capability", transfer_capability);
|
|
|
|
+
|
|
|
|
+ srjson_AddNumberToObject(doc, obj, "transfer_mode", transfer_mode);
|
|
|
|
+ srjson_AddNumberToObject(doc, obj, "transfer_rate", transfer_rate);
|
|
|
|
+ if (rate_multiplier >= 0)
|
|
|
|
+ srjson_AddNumberToObject(doc, obj, "rate_multiplier", rate_multiplier);
|
|
|
|
+ srjson_AddNumberToObject(doc, obj, "layer1_ident", layer1_ident);
|
|
|
|
+ srjson_AddNumberToObject(doc, obj, "layer1_protocol", layer1_protocol);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /* ITU-T coding values */
|
|
|
|
+ if (coding_standard == 0x00) {
|
|
|
|
+ srjson_AddStringToObject(doc, obj, "transfer_capability_name",
|
|
|
|
+ lookup(q931_trs_cap_vals, transfer_capability, "Unknown"));
|
|
|
|
+ srjson_AddStringToObject(doc, obj, "transfer_mode_name",
|
|
|
|
+ lookup(q931_trs_mde_vals, transfer_mode, "Unknown"));
|
|
|
|
+ srjson_AddStringToObject(doc, obj, "transfer_rate_name",
|
|
|
|
+ lookup(q931_trs_rte_vals, transfer_rate, "Unknown"));
|
|
|
|
+ srjson_AddStringToObject(doc, obj, "layer1_protocol_name",
|
|
|
|
+ lookup(q931_usr_info_vals, layer1_protocol, "Unknown"));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ srjson_AddItemToObject(doc, doc->root, "user_information", obj);
|
|
|
|
+}
|
|
|
|
+
|
|
static void isup_visitor(uint8_t type, const uint8_t *data, uint8_t len, struct isup_state *ptrs)
|
|
static void isup_visitor(uint8_t type, const uint8_t *data, uint8_t len, struct isup_state *ptrs)
|
|
{
|
|
{
|
|
switch (type) {
|
|
switch (type) {
|
|
case ISUPCalledPartyNumber:
|
|
case ISUPCalledPartyNumber:
|
|
- append_e164(ptrs->json, "called_number", data, len);
|
|
|
|
|
|
+ append_e164(ptrs->json, "called_number", data, len, ISUPCalledPartyNumber);
|
|
break;
|
|
break;
|
|
case ISUPCallingPartyNumber:
|
|
case ISUPCallingPartyNumber:
|
|
- append_e164(ptrs->json, "calling_number", data, len);
|
|
|
|
|
|
+ append_e164(ptrs->json, "calling_number", data, len, ISUPCallingPartyNumber);
|
|
|
|
+ break;
|
|
|
|
+ case ISUPCallingPartysCategory:
|
|
|
|
+ append_calling_party_category(ptrs->json, data, len);
|
|
break;
|
|
break;
|
|
case ISUPCauseIndicators:
|
|
case ISUPCauseIndicators:
|
|
append_cause(ptrs->json, "cause", data, len);
|
|
append_cause(ptrs->json, "cause", data, len);
|
|
@@ -317,6 +802,21 @@ static void isup_visitor(uint8_t type, const uint8_t *data, uint8_t len, struct
|
|
case ISUPEventInformation:
|
|
case ISUPEventInformation:
|
|
append_event_information(ptrs->json, "event", data, len);
|
|
append_event_information(ptrs->json, "event", data, len);
|
|
break;
|
|
break;
|
|
|
|
+ case ISUPHopCounter:
|
|
|
|
+ append_hop_counter(ptrs->json, "hop_counter", data, len);
|
|
|
|
+ break;
|
|
|
|
+ case ISUPNatureOfConnectionIndicators:
|
|
|
|
+ append_nci(ptrs->json, "nature_of_connnection", data, len);
|
|
|
|
+ break;
|
|
|
|
+ case ISUPForwardCallIndicators:
|
|
|
|
+ append_forward_call(ptrs->json, "forward_call", data, len);
|
|
|
|
+ break;
|
|
|
|
+ case ISUPTransmissionMediumRequirement:
|
|
|
|
+ append_transmission_medium(ptrs->json, data, len);
|
|
|
|
+ break;
|
|
|
|
+ case ISUPUserServiceInformation:
|
|
|
|
+ append_user_information(ptrs->json, data, len);
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|