diff --git a/debian/libwsutil0.symbols b/debian/libwsutil0.symbols index f154f40512..0bf78dd611 100644 --- a/debian/libwsutil0.symbols +++ b/debian/libwsutil0.symbols @@ -123,6 +123,9 @@ libwsutil.so.0 libwsutil0 #MINVER# json_dumper_value_string@Base 2.9.0 json_dumper_value_va_list@Base 2.9.1 json_dumper_write_base64@Base 2.9.1 + json_get_array@Base 3.5.0 + json_get_array_index@Base 3.5.0 + json_get_array_len@Base 3.5.0 json_get_double@Base 3.1.0 json_get_object@Base 3.1.0 json_get_string@Base 3.1.0 diff --git a/epan/dissectors/asn1/ngap/packet-ngap-template.c b/epan/dissectors/asn1/ngap/packet-ngap-template.c index 3ae36d772e..ad6af626ad 100644 --- a/epan/dissectors/asn1/ngap/packet-ngap-template.c +++ b/epan/dissectors/asn1/ngap/packet-ngap-template.c @@ -589,15 +589,42 @@ dissect_ngap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_ return dissect_NGAP_PDU_PDU(tvb, pinfo, ngap_tree, NULL); } +static gboolean +find_n2_info_content(char *json_data, jsmntok_t *token, const char *n2_info_content, + const char *content_id, dissector_handle_t *subdissector) +{ + jsmntok_t *n2_info_content_token, *ngap_data_token; + char *str; + gdouble ngap_msg_type; + + n2_info_content_token = json_get_object(json_data, token, n2_info_content); + if (!n2_info_content_token) + return FALSE; + ngap_data_token = json_get_object(json_data, n2_info_content_token, "ngapData"); + if (!ngap_data_token) + return FALSE; + str = json_get_string(json_data, ngap_data_token, "contentId"); + if (!str || strcmp(str, content_id)) + return FALSE; + str = json_get_string(json_data, n2_info_content_token, "ngapIeType"); + if (str) + *subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str); + else if (json_get_double(json_data, n2_info_content_token, "ngapMessageType", &ngap_msg_type)) + *subdissector = ngap_handle; + else + *subdissector = NULL; + return TRUE; +} + /* 3GPP TS 29.502 chapter 6.1.6.4.3 and 29.518 chapter 6.1.6.4.3 */ static int dissect_ngap_media_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) { int ret; char *json_data; - const char *n2_info_class, *str, *content_id_str; - jsmntok_t *tokens, *cur_tok, *n2_info_content_tok; - dissector_handle_t subdissector; + const char *n2_info_class; + jsmntok_t *tokens, *cur_tok; + dissector_handle_t subdissector = NULL; tvbuff_t* json_tvb = (tvbuff_t*)p_get_proto_data(pinfo->pool, pinfo, proto_json, 0); http_message_info_t *message_info = (http_message_info_t *)data; @@ -618,81 +645,85 @@ dissect_ngap_media_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi } if (cur_tok) { n2_info_class = json_get_string(json_data, cur_tok, "n2InformationClass"); - if (!n2_info_class) - return 0; - if (!strcmp(n2_info_class, "SM")) { - cur_tok = json_get_object(json_data, cur_tok, "smInfo"); - if (!cur_tok) - return 0; - n2_info_content_tok = json_get_object(json_data, cur_tok, "n2InfoContent"); - if (!n2_info_content_tok) - return 0; - str = json_get_string(json_data, n2_info_content_tok, "ngapIeType"); - if (!str) - return 0; - subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str); - } else if (!strcmp(n2_info_class, "RAN")) { - cur_tok = json_get_object(json_data, cur_tok, "ranInfo"); - if (!cur_tok) - return 0; - n2_info_content_tok = json_get_object(json_data, cur_tok, "n2InfoContent"); - if (!n2_info_content_tok) - return 0; - str = json_get_string(json_data, n2_info_content_tok, "ngapIeType"); - if (!str) - return 0; - subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str); - } else if (!strcmp(n2_info_class, "NRPPa")) { - cur_tok = json_get_object(json_data, cur_tok, "nrppaInfo"); - if (!cur_tok) - return 0; - n2_info_content_tok = json_get_object(json_data, cur_tok, "nrppaPdu"); - if (!n2_info_content_tok) - return 0; - str = json_get_string(json_data, n2_info_content_tok, "ngapIeType"); - if (!str) - return 0; - subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str); - } else if (!strcmp(n2_info_class, "PWS") || - !strcmp(n2_info_class, "PWS-BCAL") || - !strcmp(n2_info_class, "PWS-RF")) { - cur_tok = json_get_object(json_data, cur_tok, "pwsInfo"); - if (!cur_tok) - return 0; - n2_info_content_tok = json_get_object(json_data, cur_tok, "pwsContainer"); - if (!n2_info_content_tok) - return 0; - subdissector = ngap_handle; - } else { - return 0; - } - cur_tok = json_get_object(json_data, n2_info_content_tok, "ngapData"); - if (!cur_tok) - return 0; - content_id_str = json_get_string(json_data, cur_tok, "contentId"); - } else { - cur_tok = json_get_object(json_data, tokens, "n2SmInfo"); - if (cur_tok) { - content_id_str = json_get_string(json_data, cur_tok, "contentId"); - str = json_get_string(json_data, tokens, "n2SmInfoType"); - if (!str) - return 0; - subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str); - } else { - return 0; + if (n2_info_class) { + if (!strcmp(n2_info_class, "SM")) { + cur_tok = json_get_object(json_data, cur_tok, "smInfo"); + if (cur_tok && find_n2_info_content(json_data, cur_tok, "n2InfoContent", + message_info->content_id, &subdissector)) + goto found; + } + if (!strcmp(n2_info_class, "RAN")) { + cur_tok = json_get_object(json_data, cur_tok, "ranInfo"); + if (cur_tok && find_n2_info_content(json_data, cur_tok, "n2InfoContent", + message_info->content_id, &subdissector)) + goto found; + } + if (!strcmp(n2_info_class, "NRPPa")) { + cur_tok = json_get_object(json_data, cur_tok, "nrppaInfo"); + if (cur_tok && find_n2_info_content(json_data, cur_tok, "nrppaPdu", + message_info->content_id, &subdissector)) + goto found; + } + if (!strcmp(n2_info_class, "PWS") || + !strcmp(n2_info_class, "PWS-BCAL") || + !strcmp(n2_info_class, "PWS-RF")) { + cur_tok = json_get_object(json_data, cur_tok, "pwsInfo"); + if (cur_tok && find_n2_info_content(json_data, cur_tok, "pwsContainer", + message_info->content_id, &subdissector)) + goto found; + } } } + cur_tok = json_get_object(json_data, tokens, "n2SmInfo"); + if (cur_tok) { + const char *content_id_str = json_get_string(json_data, cur_tok, "contentId"); + if (content_id_str && !strcmp(content_id_str, message_info->content_id)) { + const char *str = json_get_string(json_data, tokens, "n2SmInfoType"); + if (str) + subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str); + else + subdissector = NULL; + goto found; + } + } + cur_tok = json_get_array(json_data, tokens, "pduSessionList"); + if (cur_tok) { + int i, count; + count = json_get_array_len(cur_tok); + for (i = 0; i < count; i++) { + jsmntok_t *array_tok = json_get_array_index(cur_tok, i); + if (find_n2_info_content(json_data, array_tok, "n2InfoContent", + message_info->content_id, &subdissector)) + goto found; + } + } + if (find_n2_info_content(json_data, tokens, "sourceToTargetData", + message_info->content_id, &subdissector)) + goto found; + if (find_n2_info_content(json_data, tokens, "targetToSourceData", + message_info->content_id, &subdissector)) + goto found; + if (find_n2_info_content(json_data, tokens, "targetToSourceFailureData", + message_info->content_id, &subdissector)) + goto found; + if (find_n2_info_content(json_data, tokens, "ueRadioCapability", + message_info->content_id, &subdissector)) + goto found; +found: if (subdissector) { proto_item *ngap_item; proto_tree *ngap_tree; + gboolean save_writable; - if (!content_id_str || strcmp(content_id_str, message_info->content_id)) - return 0; col_append_sep_str(pinfo->cinfo, COL_PROTOCOL, "/", "NGAP"); - ngap_item = proto_tree_add_item(tree, proto_ngap, tvb, 0, -1, ENC_NA); - ngap_tree = proto_item_add_subtree(ngap_item, ett_ngap); - gboolean save_writable = col_get_writable(pinfo->cinfo, COL_PROTOCOL); + if (subdissector != ngap_handle) { + ngap_item = proto_tree_add_item(tree, proto_ngap, tvb, 0, -1, ENC_NA); + ngap_tree = proto_item_add_subtree(ngap_item, ett_ngap); + } else { + ngap_tree = tree; + } + save_writable = col_get_writable(pinfo->cinfo, COL_PROTOCOL); col_set_writable(pinfo->cinfo, COL_PROTOCOL, FALSE); call_dissector_with_data(subdissector, tvb, pinfo, ngap_tree, NULL); col_set_writable(pinfo->cinfo, COL_PROTOCOL, save_writable); diff --git a/epan/dissectors/packet-ngap.c b/epan/dissectors/packet-ngap.c index 79e2521089..22c09b06f3 100644 --- a/epan/dissectors/packet-ngap.c +++ b/epan/dissectors/packet-ngap.c @@ -21605,15 +21605,42 @@ dissect_ngap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_ return dissect_NGAP_PDU_PDU(tvb, pinfo, ngap_tree, NULL); } +static gboolean +find_n2_info_content(char *json_data, jsmntok_t *token, const char *n2_info_content, + const char *content_id, dissector_handle_t *subdissector) +{ + jsmntok_t *n2_info_content_token, *ngap_data_token; + char *str; + gdouble ngap_msg_type; + + n2_info_content_token = json_get_object(json_data, token, n2_info_content); + if (!n2_info_content_token) + return FALSE; + ngap_data_token = json_get_object(json_data, n2_info_content_token, "ngapData"); + if (!ngap_data_token) + return FALSE; + str = json_get_string(json_data, ngap_data_token, "contentId"); + if (!str || strcmp(str, content_id)) + return FALSE; + str = json_get_string(json_data, n2_info_content_token, "ngapIeType"); + if (str) + *subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str); + else if (json_get_double(json_data, n2_info_content_token, "ngapMessageType", &ngap_msg_type)) + *subdissector = ngap_handle; + else + *subdissector = NULL; + return TRUE; +} + /* 3GPP TS 29.502 chapter 6.1.6.4.3 and 29.518 chapter 6.1.6.4.3 */ static int dissect_ngap_media_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) { int ret; char *json_data; - const char *n2_info_class, *str, *content_id_str; - jsmntok_t *tokens, *cur_tok, *n2_info_content_tok; - dissector_handle_t subdissector; + const char *n2_info_class; + jsmntok_t *tokens, *cur_tok; + dissector_handle_t subdissector = NULL; tvbuff_t* json_tvb = (tvbuff_t*)p_get_proto_data(pinfo->pool, pinfo, proto_json, 0); http_message_info_t *message_info = (http_message_info_t *)data; @@ -21634,81 +21661,85 @@ dissect_ngap_media_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi } if (cur_tok) { n2_info_class = json_get_string(json_data, cur_tok, "n2InformationClass"); - if (!n2_info_class) - return 0; - if (!strcmp(n2_info_class, "SM")) { - cur_tok = json_get_object(json_data, cur_tok, "smInfo"); - if (!cur_tok) - return 0; - n2_info_content_tok = json_get_object(json_data, cur_tok, "n2InfoContent"); - if (!n2_info_content_tok) - return 0; - str = json_get_string(json_data, n2_info_content_tok, "ngapIeType"); - if (!str) - return 0; - subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str); - } else if (!strcmp(n2_info_class, "RAN")) { - cur_tok = json_get_object(json_data, cur_tok, "ranInfo"); - if (!cur_tok) - return 0; - n2_info_content_tok = json_get_object(json_data, cur_tok, "n2InfoContent"); - if (!n2_info_content_tok) - return 0; - str = json_get_string(json_data, n2_info_content_tok, "ngapIeType"); - if (!str) - return 0; - subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str); - } else if (!strcmp(n2_info_class, "NRPPa")) { - cur_tok = json_get_object(json_data, cur_tok, "nrppaInfo"); - if (!cur_tok) - return 0; - n2_info_content_tok = json_get_object(json_data, cur_tok, "nrppaPdu"); - if (!n2_info_content_tok) - return 0; - str = json_get_string(json_data, n2_info_content_tok, "ngapIeType"); - if (!str) - return 0; - subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str); - } else if (!strcmp(n2_info_class, "PWS") || - !strcmp(n2_info_class, "PWS-BCAL") || - !strcmp(n2_info_class, "PWS-RF")) { - cur_tok = json_get_object(json_data, cur_tok, "pwsInfo"); - if (!cur_tok) - return 0; - n2_info_content_tok = json_get_object(json_data, cur_tok, "pwsContainer"); - if (!n2_info_content_tok) - return 0; - subdissector = ngap_handle; - } else { - return 0; - } - cur_tok = json_get_object(json_data, n2_info_content_tok, "ngapData"); - if (!cur_tok) - return 0; - content_id_str = json_get_string(json_data, cur_tok, "contentId"); - } else { - cur_tok = json_get_object(json_data, tokens, "n2SmInfo"); - if (cur_tok) { - content_id_str = json_get_string(json_data, cur_tok, "contentId"); - str = json_get_string(json_data, tokens, "n2SmInfoType"); - if (!str) - return 0; - subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str); - } else { - return 0; + if (n2_info_class) { + if (!strcmp(n2_info_class, "SM")) { + cur_tok = json_get_object(json_data, cur_tok, "smInfo"); + if (cur_tok && find_n2_info_content(json_data, cur_tok, "n2InfoContent", + message_info->content_id, &subdissector)) + goto found; + } + if (!strcmp(n2_info_class, "RAN")) { + cur_tok = json_get_object(json_data, cur_tok, "ranInfo"); + if (cur_tok && find_n2_info_content(json_data, cur_tok, "n2InfoContent", + message_info->content_id, &subdissector)) + goto found; + } + if (!strcmp(n2_info_class, "NRPPa")) { + cur_tok = json_get_object(json_data, cur_tok, "nrppaInfo"); + if (cur_tok && find_n2_info_content(json_data, cur_tok, "nrppaPdu", + message_info->content_id, &subdissector)) + goto found; + } + if (!strcmp(n2_info_class, "PWS") || + !strcmp(n2_info_class, "PWS-BCAL") || + !strcmp(n2_info_class, "PWS-RF")) { + cur_tok = json_get_object(json_data, cur_tok, "pwsInfo"); + if (cur_tok && find_n2_info_content(json_data, cur_tok, "pwsContainer", + message_info->content_id, &subdissector)) + goto found; + } } } + cur_tok = json_get_object(json_data, tokens, "n2SmInfo"); + if (cur_tok) { + const char *content_id_str = json_get_string(json_data, cur_tok, "contentId"); + if (content_id_str && !strcmp(content_id_str, message_info->content_id)) { + const char *str = json_get_string(json_data, tokens, "n2SmInfoType"); + if (str) + subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str); + else + subdissector = NULL; + goto found; + } + } + cur_tok = json_get_array(json_data, tokens, "pduSessionList"); + if (cur_tok) { + int i, count; + count = json_get_array_len(cur_tok); + for (i = 0; i < count; i++) { + jsmntok_t *array_tok = json_get_array_index(cur_tok, i); + if (find_n2_info_content(json_data, array_tok, "n2InfoContent", + message_info->content_id, &subdissector)) + goto found; + } + } + if (find_n2_info_content(json_data, tokens, "sourceToTargetData", + message_info->content_id, &subdissector)) + goto found; + if (find_n2_info_content(json_data, tokens, "targetToSourceData", + message_info->content_id, &subdissector)) + goto found; + if (find_n2_info_content(json_data, tokens, "targetToSourceFailureData", + message_info->content_id, &subdissector)) + goto found; + if (find_n2_info_content(json_data, tokens, "ueRadioCapability", + message_info->content_id, &subdissector)) + goto found; +found: if (subdissector) { proto_item *ngap_item; proto_tree *ngap_tree; + gboolean save_writable; - if (!content_id_str || strcmp(content_id_str, message_info->content_id)) - return 0; col_append_sep_str(pinfo->cinfo, COL_PROTOCOL, "/", "NGAP"); - ngap_item = proto_tree_add_item(tree, proto_ngap, tvb, 0, -1, ENC_NA); - ngap_tree = proto_item_add_subtree(ngap_item, ett_ngap); - gboolean save_writable = col_get_writable(pinfo->cinfo, COL_PROTOCOL); + if (subdissector != ngap_handle) { + ngap_item = proto_tree_add_item(tree, proto_ngap, tvb, 0, -1, ENC_NA); + ngap_tree = proto_item_add_subtree(ngap_item, ett_ngap); + } else { + ngap_tree = tree; + } + save_writable = col_get_writable(pinfo->cinfo, COL_PROTOCOL); col_set_writable(pinfo->cinfo, COL_PROTOCOL, FALSE); call_dissector_with_data(subdissector, tvb, pinfo, ngap_tree, NULL); col_set_writable(pinfo->cinfo, COL_PROTOCOL, save_writable); @@ -22151,7 +22182,7 @@ proto_reg_handoff_ngap(void) /*--- End of included file: packet-ngap-dis-tab.c ---*/ -#line 724 "./asn1/ngap/packet-ngap-template.c" +#line 755 "./asn1/ngap/packet-ngap-template.c" dissector_add_string("media_type", "application/vnd.3gpp.ngap", ngap_media_type_handle); } else { @@ -26820,7 +26851,7 @@ void proto_register_ngap(void) { "UnsuccessfulOutcome_value", HFILL }}, /*--- End of included file: packet-ngap-hfarr.c ---*/ -#line 992 "./asn1/ngap/packet-ngap-template.c" +#line 1023 "./asn1/ngap/packet-ngap-template.c" }; /* List of subtrees */ @@ -27475,7 +27506,7 @@ void proto_register_ngap(void) { &ett_ngap_UnsuccessfulOutcome, /*--- End of included file: packet-ngap-ettarr.c ---*/ -#line 1039 "./asn1/ngap/packet-ngap-template.c" +#line 1070 "./asn1/ngap/packet-ngap-template.c" }; static ei_register_info ei[] = { diff --git a/wsutil/wsjson.c b/wsutil/wsjson.c index 474c9246b6..c6a9afcfba 100644 --- a/wsutil/wsjson.c +++ b/wsutil/wsjson.c @@ -99,7 +99,7 @@ jsmntok_t *json_get_next_object(jsmntok_t *cur) return next; } -jsmntok_t *json_get_object(const char *buf, jsmntok_t *parent, const gchar* name) +jsmntok_t *json_get_object(const char *buf, jsmntok_t *parent, const char *name) { int i; jsmntok_t *cur = parent+1; @@ -116,7 +116,44 @@ jsmntok_t *json_get_object(const char *buf, jsmntok_t *parent, const gchar* name return NULL; } -char *json_get_string(char *buf, jsmntok_t *parent, const gchar* name) +jsmntok_t *json_get_array(const char *buf, jsmntok_t *parent, const char *name) +{ + int i; + jsmntok_t *cur = parent+1; + + for (i = 0; i < parent->size; i++) { + if (cur->type == JSMN_STRING && + !strncmp(&buf[cur->start], name, cur->end - cur->start) + && strlen(name) == (size_t)(cur->end - cur->start) && + cur->size == 1 && (cur+1)->type == JSMN_ARRAY) { + return cur+1; + } + cur = json_get_next_object(cur); + } + return NULL; +} + +int json_get_array_len(jsmntok_t *array) +{ + if (array->type != JSMN_ARRAY) + return -1; + return array->size; +} + +jsmntok_t *json_get_array_index(jsmntok_t *array, int idx) +{ + int i; + jsmntok_t *cur = array+1; + + + if (array->type != JSMN_ARRAY || idx < 0 || idx >= array->size) + return NULL; + for (i = 0; i < idx; i++) + cur = json_get_next_object(cur); + return cur; +} + +char *json_get_string(char *buf, jsmntok_t *parent, const char *name) { int i; jsmntok_t *cur = parent+1; @@ -136,7 +173,7 @@ char *json_get_string(char *buf, jsmntok_t *parent, const gchar* name) return NULL; } -gboolean json_get_double(char *buf, jsmntok_t *parent, const gchar* name, gdouble *val) +gboolean json_get_double(char *buf, jsmntok_t *parent, const char *name, gdouble *val) { int i; jsmntok_t *cur = parent+1; diff --git a/wsutil/wsjson.h b/wsutil/wsjson.h index 165de1e743..1e0028c57b 100644 --- a/wsutil/wsjson.h +++ b/wsutil/wsjson.h @@ -33,20 +33,38 @@ WS_DLL_PUBLIC int json_parse(const char *buf, jsmntok_t *tokens, unsigned int ma * Get the pointer to an object belonging to parent object and named as the name variable. * Returns NULL if not found. */ -WS_DLL_PUBLIC jsmntok_t *json_get_object(const char *buf, jsmntok_t *parent, const gchar* name); +WS_DLL_PUBLIC jsmntok_t *json_get_object(const char *buf, jsmntok_t *parent, const char *name); + +/** + * Get the pointer to an array belonging to parent object and named as the name variable. + * Returns NULL if not found. + */ +WS_DLL_PUBLIC jsmntok_t *json_get_array(const char *buf, jsmntok_t *parent, const char *name); + +/** + * Get the number of elements of an array. + * Returns -1 if the JSON objecct is not an array. + */ +WS_DLL_PUBLIC int json_get_array_len(jsmntok_t *array); + +/** + * Get the pointer to idx element of an array. + * Returns NULL if not found. + */ +WS_DLL_PUBLIC jsmntok_t *json_get_array_index(jsmntok_t *parent, int idx); /** * Get the unescaped value of a string object belonging to parent object and named as the name variable. * Returns NULL if not found. Caution: it modifies input buffer. */ -WS_DLL_PUBLIC char *json_get_string(char *buf, jsmntok_t *parent, const gchar* name); +WS_DLL_PUBLIC char *json_get_string(char *buf, jsmntok_t *parent, const char *name); /** * Get the value of a number object belonging to parent object and named as the name variable. * Returns FALSE if not found. Caution: it modifies input buffer. * Scientific notation not supported yet. */ -WS_DLL_PUBLIC gboolean json_get_double(char *buf, jsmntok_t *parent, const gchar* name, gdouble *val); +WS_DLL_PUBLIC gboolean json_get_double(char *buf, jsmntok_t *parent, const char *name, gdouble *val); /** * Decode the contents of a JSON string value by overwriting the input data.