summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-sip.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/packet-sip.c')
-rw-r--r--epan/dissectors/packet-sip.c7933
1 files changed, 7933 insertions, 0 deletions
diff --git a/epan/dissectors/packet-sip.c b/epan/dissectors/packet-sip.c
new file mode 100644
index 00000000..36c81ae8
--- /dev/null
+++ b/epan/dissectors/packet-sip.c
@@ -0,0 +1,7933 @@
+/* packet-sip.c
+ * Routines for the Session Initiation Protocol (SIP) dissection.
+ * RFCs 3261-3264
+ *
+ * TODO:
+ * hf_ display filters for headers of SIP extension RFCs (ongoing)
+ *
+ * Copyright 2000, Heikki Vatiainen <hessu@cs.tut.fi>
+ * Copyright 2001, Jean-Francois Mule <jfm@cablelabs.com>
+ * Copyright 2004, Anders Broman <anders.broman@ericsson.com>
+ * Copyright 2011, Anders Broman <anders.broman@ericsson.com>, Johan Wahl <johan.wahl@ericsson.com>
+ * Copyright 2018, Anders Broman <anders.broman@ericsson.com>
+ * Copyright 2020, Atul Sharma <asharm37@ncsu.edu>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+
+#include "config.h"
+
+#include <epan/packet.h>
+
+#include <epan/exported_pdu.h>
+#include <epan/expert.h>
+#include <epan/prefs.h>
+#include <epan/req_resp_hdrs.h>
+#include <epan/stat_tap_ui.h>
+#include <epan/proto_data.h>
+#include <epan/uat.h>
+#include <epan/follow.h>
+#include <epan/addr_resolv.h>
+#include <epan/epan_dissect.h>
+#include <epan/iana_charsets.h>
+
+#include <wsutil/str_util.h>
+#include <wsutil/wsgcrypt.h>
+
+#include "packet-tls.h"
+
+#include "packet-isup.h"
+#include "packet-e164.h"
+#include "packet-e212.h"
+#include "packet-sip.h"
+
+#include "packet-media-type.h"
+#include "packet-acdr.h"
+
+#include "packet-sdp.h" /* SDP needs a transport layer to determine request/response */
+
+/* un-comment the following as well as this line in conversation.c, to enable debug printing */
+/* #define DEBUG_CONVERSATION */
+#include "conversation_debug.h"
+
+#define TLS_PORT_SIP 5061
+#define DEFAULT_SIP_PORT_RANGE "5060"
+
+void proto_register_sip(void);
+
+static gint sip_tap = -1;
+static gint sip_follow_tap = -1;
+static gint exported_pdu_tap = -1;
+static dissector_handle_t sip_handle;
+static dissector_handle_t sip_tcp_handle;
+static dissector_handle_t sigcomp_handle;
+static dissector_handle_t sip_diag_handle;
+static dissector_handle_t sip_uri_userinfo_handle;
+static dissector_handle_t sip_via_branch_handle;
+static dissector_handle_t sip_via_be_route_handle;
+/* Dissector to dissect the text part of an reason code */
+static dissector_handle_t sip_reason_code_handle;
+
+/* Initialize the protocol and registered fields */
+static gint proto_sip = -1;
+static gint proto_raw_sip = -1;
+static gint hf_sip_raw_line = -1;
+static gint hf_sip_msg_hdr = -1;
+static gint hf_sip_Method = -1;
+static gint hf_Request_Line = -1;
+static gint hf_sip_ruri_display = -1;
+static gint hf_sip_ruri = -1;
+static gint hf_sip_ruri_user = -1;
+static gint hf_sip_ruri_host = -1;
+static gint hf_sip_ruri_port = -1;
+static gint hf_sip_ruri_param = -1;
+static gint hf_sip_Status_Code = -1;
+static gint hf_sip_Status_Line = -1;
+static gint hf_sip_display = -1;
+static gint hf_sip_to_display = -1;
+static gint hf_sip_to_addr = -1;
+static gint hf_sip_to_user = -1;
+static gint hf_sip_to_host = -1;
+static gint hf_sip_to_port = -1;
+static gint hf_sip_to_param = -1;
+static gint hf_sip_to_tag = -1;
+static gint hf_sip_from_display = -1;
+static gint hf_sip_from_addr = -1;
+static gint hf_sip_from_user = -1;
+static gint hf_sip_from_host = -1;
+static gint hf_sip_from_port = -1;
+static gint hf_sip_from_param = -1;
+static gint hf_sip_from_tag = -1;
+static gint hf_sip_tag = -1;
+static gint hf_sip_pai_display = -1;
+static gint hf_sip_pai_addr = -1;
+static gint hf_sip_pai_user = -1;
+static gint hf_sip_pai_host = -1;
+static gint hf_sip_pai_port = -1;
+static gint hf_sip_pai_param = -1;
+static gint hf_sip_pmiss_display = -1;
+static gint hf_sip_pmiss_addr = -1;
+static gint hf_sip_pmiss_user = -1;
+static gint hf_sip_pmiss_host = -1;
+static gint hf_sip_pmiss_port = -1;
+static gint hf_sip_pmiss_param = -1;
+static gint hf_sip_ppi_display = -1;
+static gint hf_sip_ppi_addr = -1;
+static gint hf_sip_ppi_user = -1;
+static gint hf_sip_ppi_host = -1;
+static gint hf_sip_ppi_port = -1;
+static gint hf_sip_ppi_param = -1;
+static gint hf_sip_tc_display = -1;
+static gint hf_sip_tc_addr = -1;
+static gint hf_sip_tc_user = -1;
+static gint hf_sip_tc_host = -1;
+static gint hf_sip_tc_port = -1;
+static gint hf_sip_tc_param = -1;
+static gint hf_sip_tc_turi = -1;
+static gint hf_sip_contact_param = -1;
+static gint hf_sip_resend = -1;
+static gint hf_sip_original_frame = -1;
+static gint hf_sip_matching_request_frame = -1;
+static gint hf_sip_response_time = -1;
+static gint hf_sip_release_time = -1;
+static gint hf_sip_curi_display = -1;
+static gint hf_sip_curi = -1;
+static gint hf_sip_curi_user = -1;
+static gint hf_sip_curi_host = -1;
+static gint hf_sip_curi_port = -1;
+static gint hf_sip_curi_param = -1;
+static gint hf_sip_route_display = -1;
+static gint hf_sip_route = -1;
+static gint hf_sip_route_user = -1;
+static gint hf_sip_route_host = -1;
+static gint hf_sip_route_port = -1;
+static gint hf_sip_route_param = -1;
+static gint hf_sip_record_route_display = -1;
+static gint hf_sip_record_route = -1;
+static gint hf_sip_record_route_user = -1;
+static gint hf_sip_record_route_host = -1;
+static gint hf_sip_record_route_port = -1;
+static gint hf_sip_record_route_param = -1;
+static gint hf_sip_service_route_display = -1;
+static gint hf_sip_service_route = -1;
+static gint hf_sip_service_route_user = -1;
+static gint hf_sip_service_route_host = -1;
+static gint hf_sip_service_route_port = -1;
+static gint hf_sip_service_route_param = -1;
+static gint hf_sip_path_display = -1;
+static gint hf_sip_path = -1;
+static gint hf_sip_path_user = -1;
+static gint hf_sip_path_host = -1;
+static gint hf_sip_path_port = -1;
+static gint hf_sip_path_param = -1;
+
+static gint hf_sip_auth = -1;
+static gint hf_sip_auth_scheme = -1;
+static gint hf_sip_auth_digest_response = -1;
+static gint hf_sip_auth_nc = -1;
+static gint hf_sip_auth_username = -1;
+static gint hf_sip_auth_realm = -1;
+static gint hf_sip_auth_nonce = -1;
+static gint hf_sip_auth_algorithm = -1;
+static gint hf_sip_auth_opaque = -1;
+static gint hf_sip_auth_qop = -1;
+static gint hf_sip_auth_cnonce = -1;
+static gint hf_sip_auth_uri = -1;
+static gint hf_sip_auth_domain = -1;
+static gint hf_sip_auth_stale = -1;
+static gint hf_sip_auth_auts = -1;
+static gint hf_sip_auth_rspauth = -1;
+static gint hf_sip_auth_nextnonce = -1;
+static gint hf_sip_auth_ik = -1;
+static gint hf_sip_auth_ck = -1;
+
+static gint hf_sip_cseq_seq_no = -1;
+static gint hf_sip_cseq_method = -1;
+
+static gint hf_sip_via_transport = -1;
+static gint hf_sip_via_sent_by_address = -1;
+static gint hf_sip_via_sent_by_port = -1;
+static gint hf_sip_via_branch = -1;
+static gint hf_sip_via_maddr = -1;
+static gint hf_sip_via_rport = -1;
+static gint hf_sip_via_received = -1;
+static gint hf_sip_via_ttl = -1;
+static gint hf_sip_via_comp = -1;
+static gint hf_sip_via_sigcomp_id = -1;
+static gint hf_sip_via_oc = -1;
+static gint hf_sip_via_oc_val = -1;
+static gint hf_sip_via_oc_algo = -1;
+static gint hf_sip_via_oc_validity = -1;
+static gint hf_sip_via_oc_seq = -1;
+static gint hf_sip_oc_seq_timestamp = -1;
+static gint hf_sip_via_be_route = -1;
+
+static gint hf_sip_rack_rseq_no = -1;
+static gint hf_sip_rack_cseq_no = -1;
+static gint hf_sip_rack_cseq_method = -1;
+
+static gint hf_sip_reason_protocols = -1;
+static gint hf_sip_reason_cause_q850 = -1;
+static gint hf_sip_reason_cause_sip = -1;
+static gint hf_sip_reason_cause_other = -1;
+static gint hf_sip_reason_text = -1;
+
+static gint hf_sip_msg_body = -1;
+static gint hf_sip_sec_mechanism = -1;
+static gint hf_sip_sec_mechanism_alg = -1;
+static gint hf_sip_sec_mechanism_ealg = -1;
+static gint hf_sip_sec_mechanism_prot = -1;
+static gint hf_sip_sec_mechanism_spi_c = -1;
+static gint hf_sip_sec_mechanism_spi_s = -1;
+static gint hf_sip_sec_mechanism_port1 = -1;
+static gint hf_sip_sec_mechanism_port_c = -1;
+static gint hf_sip_sec_mechanism_port2 = -1;
+static gint hf_sip_sec_mechanism_port_s = -1;
+static gint hf_sip_session_id_sess_id = -1;
+static gint hf_sip_session_id_param = -1;
+static gint hf_sip_session_id_local_uuid = -1;
+static gint hf_sip_session_id_remote_uuid = -1;
+static gint hf_sip_session_id_logme = -1;
+static gint hf_sip_continuation = -1;
+static gint hf_sip_feature_cap = -1;
+
+static gint hf_sip_p_acc_net_i_acc_type = -1;
+static gint hf_sip_p_acc_net_i_ucid_3gpp = -1;
+
+static gint hf_sip_service_priority = -1;
+static gint hf_sip_icid_value = -1;
+static gint hf_sip_icid_gen_addr = -1;
+static gint hf_sip_call_id_gen = -1;
+
+/* Initialize the subtree pointers */
+static gint ett_sip = -1;
+static gint ett_sip_reqresp = -1;
+static gint ett_sip_hdr = -1;
+static gint ett_sip_ext_hdr = -1;
+static gint ett_raw_text = -1;
+static gint ett_sip_element = -1;
+static gint ett_sip_hist = -1;
+static gint ett_sip_uri = -1;
+static gint ett_sip_contact_item = -1;
+static gint ett_sip_message_body = -1;
+static gint ett_sip_cseq = -1;
+static gint ett_sip_via = -1;
+static gint ett_sip_reason = -1;
+static gint ett_sip_security_client = -1;
+static gint ett_sip_security_server = -1;
+static gint ett_sip_security_verify = -1;
+static gint ett_sip_rack = -1;
+static gint ett_sip_route = -1;
+static gint ett_sip_record_route = -1;
+static gint ett_sip_service_route = -1;
+static gint ett_sip_path = -1;
+static gint ett_sip_ruri = -1;
+static gint ett_sip_to_uri = -1;
+static gint ett_sip_curi = -1;
+static gint ett_sip_from_uri = -1;
+static gint ett_sip_pai_uri = -1;
+static gint ett_sip_pmiss_uri = -1;
+static gint ett_sip_ppi_uri = -1;
+static gint ett_sip_tc_uri = -1;
+static gint ett_sip_session_id = -1;
+static gint ett_sip_p_access_net_info = -1;
+static gint ett_sip_p_charging_vector = -1;
+static gint ett_sip_feature_caps = -1;
+static gint ett_sip_via_be_route = -1;
+
+static expert_field ei_sip_unrecognized_header = EI_INIT;
+static expert_field ei_sip_header_no_colon = EI_INIT;
+static expert_field ei_sip_header_not_terminated = EI_INIT;
+#if 0
+static expert_field ei_sip_odd_register_response = EI_INIT;
+#endif
+static expert_field ei_sip_call_id_invalid = EI_INIT;
+static expert_field ei_sip_sipsec_malformed = EI_INIT;
+static expert_field ei_sip_via_sent_by_port = EI_INIT;
+static expert_field ei_sip_content_length_invalid = EI_INIT;
+static expert_field ei_sip_retry_after_invalid = EI_INIT;
+static expert_field ei_sip_Status_Code_invalid = EI_INIT;
+static expert_field ei_sip_authorization_invalid = EI_INIT;
+static expert_field ei_sip_session_id_sess_id = EI_INIT;
+
+/* patterns used for tvb_ws_mempbrk_pattern_guint8 */
+static ws_mempbrk_pattern pbrk_comma_semi;
+static ws_mempbrk_pattern pbrk_whitespace;
+static ws_mempbrk_pattern pbrk_param_end;
+static ws_mempbrk_pattern pbrk_param_end_colon_brackets;
+static ws_mempbrk_pattern pbrk_header_end_dquote;
+static ws_mempbrk_pattern pbrk_tab_sp_fslash;
+static ws_mempbrk_pattern pbrk_addr_end;
+static ws_mempbrk_pattern pbrk_via_param_end;
+
+
+/* PUBLISH method added as per https://tools.ietf.org/html/draft-ietf-sip-publish-01 */
+static const char *sip_methods[] = {
+#define SIP_METHOD_INVALID 0
+ "<Invalid method>", /* Pad so that the real methods start at index 1 */
+#define SIP_METHOD_ACK 1
+ "ACK",
+#define SIP_METHOD_BYE 2
+ "BYE",
+#define SIP_METHOD_CANCEL 3
+ "CANCEL",
+#define SIP_METHOD_DO 4
+ "DO",
+#define SIP_METHOD_INFO 5
+ "INFO",
+#define SIP_METHOD_INVITE 6
+ "INVITE",
+#define SIP_METHOD_MESSAGE 7
+ "MESSAGE",
+#define SIP_METHOD_NOTIFY 8
+ "NOTIFY",
+#define SIP_METHOD_OPTIONS 9
+ "OPTIONS",
+#define SIP_METHOD_PRACK 10
+ "PRACK",
+#define SIP_METHOD_QAUTH 11
+ "QAUTH",
+#define SIP_METHOD_REFER 12
+ "REFER",
+#define SIP_METHOD_REGISTER 13
+ "REGISTER",
+#define SIP_METHOD_SPRACK 14
+ "SPRACK",
+#define SIP_METHOD_SUBSCRIBE 15
+ "SUBSCRIBE",
+#define SIP_METHOD_UPDATE 16
+ "UPDATE",
+#define SIP_METHOD_PUBLISH 17
+ "PUBLISH"
+};
+
+/* from RFC 3261
+ * Updated with info from https://www.iana.org/assignments/sip-parameters
+ * (last updated 2009-11-11)
+ * Updated with: https://tools.ietf.org/html/draft-ietf-sip-resource-priority-05
+ */
+typedef struct {
+ const char *name;
+ const char *compact_name;
+} sip_header_t;
+static const sip_header_t sip_headers[] = {
+ { "Unknown-header", NULL }, /* 0 Pad so that the real headers start at index 1 */
+ { "Accept", NULL }, /* */
+#define POS_ACCEPT 1
+ { "Accept-Contact", "a" }, /* RFC3841 */
+#define POS_ACCEPT_CONTACT 2
+ { "Accept-Encoding", NULL }, /* */
+#define POS_ACCEPT_ENCODING 3
+ { "Accept-Language", NULL }, /* */
+#define POS_ACCEPT_LANGUAGE 4
+ { "Accept-Resource-Priority", NULL }, /* RFC4412 */
+#define POS_ACCEPT_RESOURCE_PRIORITY 5
+ { "Additional-Identity", NULL }, /* 3GPP TS 24.229 v16.7.0 */
+#define POS_ADDITIONAL_IDENTITY 6
+ { "Alert-Info", NULL },
+#define POS_ALERT_INFO 7
+ { "Allow", NULL },
+#define POS_ALLOW 8
+ { "Allow-Events", "u" }, /* RFC3265 */
+#define POS_ALLOW_EVENTS 9
+ { "Answer-Mode", NULL }, /* RFC5373 */
+#define POS_ANSWER_MODE 10
+ { "Attestation-Info", NULL }, /* [3GPP TS 24.229 v15.11.0] */
+#define POS_ATTESTATION_INFO 11
+ { "Authentication-Info", NULL },
+#define POS_AUTHENTICATION_INFO 12
+ { "Authorization", NULL }, /* */
+#define POS_AUTHORIZATION 13
+ { "Call-ID", "i" },
+#define POS_CALL_ID 14
+ { "Call-Info", NULL },
+#define POS_CALL_INFO 15
+ { "Cellular-Network-Info", NULL }, /* [3GPP TS 24.229 v13.9.0] */
+#define POS_CELLULAR_NETWORK_INFO 16
+ { "Contact", "m" },
+#define POS_CONTACT 17
+ { "Content-Disposition", NULL },
+#define POS_CONTENT_DISPOSITION 18
+ { "Content-Encoding", "e" }, /* */
+#define POS_CONTENT_ENCODING 19
+ { "Content-Language", NULL },
+#define POS_CONTENT_LANGUAGE 20
+ { "Content-Length", "l" },
+#define POS_CONTENT_LENGTH 21
+ { "Content-Type", "c" },
+#define POS_CONTENT_TYPE 22
+ { "CSeq", NULL },
+#define POS_CSEQ 23
+ { "Date", NULL }, /* */
+#define POS_DATE 24
+/* Encryption (Deprecated) [RFC3261] */
+ { "Error-Info", NULL }, /* */
+#define POS_ERROR_INFO 25
+ { "Event", "o" }, /* */
+#define POS_EVENT 26
+ { "Expires", NULL }, /* */
+#define POS_EXPIRES 27
+ { "Feature-Caps", NULL }, /* RFC6809 */
+#define POS_FEATURE_CAPS 28
+ { "Flow-Timer", NULL }, /* RFC5626 */
+#define POS_FLOW_TIMER 29
+ { "From", "f" }, /* */
+#define POS_FROM 30
+
+ { "Geolocation", NULL }, /* */
+#define POS_GEOLOCATION 31
+ { "Geolocation-Error", NULL }, /* */
+#define POS_GEOLOCATION_ERROR 32
+ { "Geolocation-Routing", NULL }, /* */
+#define POS_GEOLOCATION_ROUTING 33
+
+/* Hide RFC3261 (deprecated)*/
+ { "History-Info", NULL }, /* RFC4244 */
+#define POS_HISTORY_INFO 34
+ { "Identity", "y" }, /* RFC4474 */
+#define POS_IDENTITY 35
+ { "Identity-Info", "n" }, /* RFC4474 */
+#define POS_IDENTITY_INFO 36
+ { "Info-Package", NULL }, /* RFC-ietf-sipcore-info-events-10.txt */
+#define POS_INFO_PKG 37
+ { "In-Reply-To", NULL }, /* RFC3261 */
+#define POS_IN_REPLY_TO 38
+ { "Join", NULL }, /* RFC3911 */
+#define POS_JOIN 39
+ { "Max-Breadth", NULL }, /* RFC5393*/
+#define POS_MAX_BREADTH 40
+ { "Max-Forwards", NULL }, /* */
+#define POS_MAX_FORWARDS 41
+ { "MIME-Version", NULL }, /* */
+#define POS_MIME_VERSION 42
+ { "Min-Expires", NULL }, /* */
+#define POS_MIN_EXPIRES 43
+ { "Min-SE", NULL }, /* RFC4028 */
+#define POS_MIN_SE 44
+ { "Organization", NULL }, /* RFC3261 */
+#define POS_ORGANIZATION 45
+ { "Origination-Id", NULL }, /* [3GPP TS 24.229 v15.11.0] */
+#define POS_ORIGINATION_ID 46
+ { "P-Access-Network-Info", NULL }, /* RFC3455 */
+#define POS_P_ACCESS_NETWORK_INFO 47
+ { "P-Answer-State", NULL }, /* RFC4964 */
+#define POS_P_ANSWER_STATE 48
+ { "P-Asserted-Identity", NULL }, /* RFC3325 */
+#define POS_P_ASSERTED_IDENTITY 49
+ { "P-Asserted-Service", NULL }, /* RFC6050 */
+#define POS_P_ASSERTED_SERV 50
+ { "P-Associated-URI", NULL }, /* RFC3455 */
+#define POS_P_ASSOCIATED_URI 51
+ { "P-Called-Party-ID", NULL }, /* RFC3455 */
+#define POS_P_CALLED_PARTY_ID 52
+ { "P-Charge-Info", NULL }, /* RFC8496 */
+#define POS_P_CHARGE_INFO 53
+ { "P-Charging-Function-Addresses", NULL }, /* RFC3455 */
+#define POS_P_CHARGING_FUNC_ADDRESSES 54
+ { "P-Charging-Vector", NULL }, /* RFC3455 */
+#define POS_P_CHARGING_VECTOR 55
+ { "P-DCS-Trace-Party-ID", NULL }, /* RFC5503 */
+#define POS_P_DCS_TRACE_PARTY_ID 56
+ { "P-DCS-OSPS", NULL }, /* RFC5503 */
+#define POS_P_DCS_OSPS 57
+ { "P-DCS-Billing-Info", NULL }, /* RFC5503 */
+#define POS_P_DCS_BILLING_INFO 58
+ { "P-DCS-LAES", NULL }, /* RFC5503 */
+#define POS_P_DCS_LAES 59
+ { "P-DCS-Redirect", NULL }, /* RFC5503 */
+#define POS_P_DCS_REDIRECT 60
+ { "P-Early-Media", NULL }, /* RFC5009 */
+#define POS_P_EARLY_MEDIA 61
+ { "P-Media-Authorization", NULL }, /* RFC3313 */
+#define POS_P_MEDIA_AUTHORIZATION 62
+ { "P-Preferred-Identity", NULL }, /* RFC3325 */
+#define POS_P_PREFERRED_IDENTITY 63
+ { "P-Preferred-Service", NULL }, /* RFC6050 */
+#define POS_P_PREFERRED_SERV 64
+ { "P-Profile-Key", NULL }, /* RFC5002 */
+#define POS_P_PROFILE_KEY 65
+ { "P-Refused-URI-List", NULL }, /* RFC5318 */
+#define POS_P_REFUSED_URI_LST 66
+ { "P-Served-User", NULL }, /* RFC5502 */
+#define POS_P_SERVED_USER 67
+ { "P-User-Database", NULL }, /* RFC4457 */
+#define POS_P_USER_DATABASE 68
+ { "P-Visited-Network-ID", NULL }, /* RFC3455 */
+#define POS_P_VISITED_NETWORK_ID 69
+ { "Path", NULL }, /* RFC3327 */
+#define POS_PATH 70
+ { "Permission-Missing", NULL }, /* RFC5360 */
+#define POS_PERMISSION_MISSING 71
+ { "Policy-Contact", NULL }, /* RFC3261 */
+#define POS_POLICY_CONTACT 72
+ { "Policy-ID", NULL }, /* RFC3261 */
+#define POS_POLICY_ID 73
+ { "Priority", NULL }, /* RFC3261 */
+#define POS_PRIORITY 74
+ { "Priority-Share", NULL }, /* [3GPP TS 24.229 v13.16.0] */
+#define POS_PRIORITY_SHARE 75
+ { "Priv-Answer-Mode", NULL }, /* RFC5373 */
+#define POS_PRIV_ANSWER_MODE 76
+ { "Privacy", NULL }, /* RFC3323 */
+#define POS_PRIVACY 77
+ { "Proxy-Authenticate", NULL }, /* */
+#define POS_PROXY_AUTHENTICATE 78
+ { "Proxy-Authorization", NULL }, /* */
+#define POS_PROXY_AUTHORIZATION 79
+ { "Proxy-Require", NULL }, /* */
+#define POS_PROXY_REQUIRE 80
+ { "RAck", NULL }, /* RFC3262 */
+#define POS_RACK 81
+ { "Reason", NULL }, /* RFC3326 */
+#define POS_REASON 82
+ { "Reason-Phrase", NULL }, /* RFC3326 */
+#define POS_REASON_PHRASE 83
+ { "Record-Route", NULL }, /* */
+#define POS_RECORD_ROUTE 84
+ { "Recv-Info", NULL }, /* RFC6086 */
+#define POS_RECV_INFO 85
+ { "Refer-Sub", NULL }, /* RFC4488 */
+#define POS_REFER_SUB 86
+ { "Refer-To", "r" }, /* RFC3515 */
+#define POS_REFER_TO 87
+ { "Referred-By", "b" }, /* RFC3892 */
+#define POS_REFERRED_BY 88
+ { "Reject-Contact", "j" }, /* RFC3841 */
+#define POS_REJECT_CONTACT 89
+ { "Relayed-Charge", NULL }, /* [3GPP TS 24.229 v12.14.0] */
+#define POS_RELAYED_CHARGE 90
+ { "Replaces", NULL }, /* RFC3891 */
+#define POS_REPLACES 91
+ { "Reply-To", NULL }, /* RFC3261 */
+#define POS_REPLY_TO 92
+ { "Request-Disposition", "d" }, /* RFC3841 */
+#define POS_REQUEST_DISPOSITION 93
+ { "Require", NULL }, /* RFC3261 */
+#define POS_REQUIRE 94
+ { "Resource-Priority", NULL }, /* RFC4412 */
+#define POS_RESOURCE_PRIORITY 95
+ { "Resource-Share", NULL }, /* [3GPP TS 24.229 v13.7.0] */
+#define POS_RESOURCE_SHARE 96
+ /*{ "Response-Key (Deprecated) [RFC3261]*/
+ { "Response-Source", NULL }, /* [3GPP TS 24.229 v15.11.0] */
+#define POS_RESPONSE_SOURCE 97
+ { "Restoration-Info", NULL }, /* [3GPP TS 24.229 v12.14.0] */
+#define POS_RESTORATION_INFO 98
+ { "Retry-After", NULL }, /* RFC3261 */
+#define POS_RETRY_AFTER 99
+ { "Route", NULL }, /* RFC3261 */
+#define POS_ROUTE 100
+ { "RSeq", NULL }, /* RFC3262 */
+#define POS_RSEQ 101
+ { "Security-Client", NULL }, /* RFC3329 */
+#define POS_SECURITY_CLIENT 102
+ { "Security-Server", NULL }, /* RFC3329 */
+#define POS_SECURITY_SERVER 103
+ { "Security-Verify", NULL }, /* RFC3329 */
+#define POS_SECURITY_VERIFY 104
+ { "Server", NULL }, /* RFC3261 */
+#define POS_SERVER 105
+ { "Service-Interact-Info", NULL }, /* [3GPP TS 24.229 v13.18.0] */
+#define POS_SERVICE_INTERACT_INFO 106
+ { "Service-Route", NULL }, /* RFC3608 */
+#define POS_SERVICE_ROUTE 107
+ { "Session-Expires", "x" }, /* RFC4028 */
+#define POS_SESSION_EXPIRES 108
+ { "Session-ID", NULL }, /* RFC7329 */
+#define POS_SESSION_ID 109
+ { "SIP-ETag", NULL }, /* RFC3903 */
+#define POS_SIP_ETAG 110
+ { "SIP-If-Match", NULL }, /* RFC3903 */
+#define POS_SIP_IF_MATCH 111
+ { "Subject", "s" }, /* RFC3261 */
+#define POS_SUBJECT 112
+ { "Subscription-State", NULL }, /* RFC3265 */
+#define POS_SUBSCRIPTION_STATE 113
+ { "Supported", "k" }, /* RFC3261 */
+#define POS_SUPPORTED 114
+ { "Suppress-If-Match", NULL }, /* RFC5839 */
+#define POS_SUPPRESS_IF_MATCH 115
+ { "Target-Dialog", NULL }, /* RFC4538 */
+#define POS_TARGET_DIALOG 116
+ { "Timestamp", NULL }, /* RFC3261 */
+#define POS_TIMESTAMP 117
+ { "To", "t" }, /* RFC3261 */
+#define POS_TO 118
+ { "Trigger-Consent", NULL }, /* RFC5360 */
+#define POS_TRIGGER_CONSENT 119
+ { "Unsupported", NULL }, /* RFC3261 */
+#define POS_UNSUPPORTED 120
+ { "User-Agent", NULL }, /* RFC3261 */
+#define POS_USER_AGENT 121
+ { "Via", "v" }, /* RFC3261 */
+#define POS_VIA 122
+ { "Warning", NULL }, /* RFC3261 */
+#define POS_WARNING 123
+ { "WWW-Authenticate", NULL }, /* RFC3261 */
+#define POS_WWW_AUTHENTICATE 124
+ { "Diversion", NULL }, /* RFC5806 */
+#define POS_DIVERSION 125
+ { "User-to-User", NULL }, /* RFC7433 */
+#define POS_USER_TO_USER 126
+};
+
+
+
+
+static gint hf_header_array[] = {
+ -1, /* 0"Unknown-header" - Pad so that the real headers start at index 1 */
+ -1, /* 1"Accept" */
+ -1, /* 2"Accept-Contact" RFC3841 */
+ -1, /* 3"Accept-Encoding" */
+ -1, /* 4"Accept-Language" */
+ -1, /* 5"Accept-Resource-Priority" RFC4412 */
+ -1, /* 6"Additional-Identity [3GPP TS 24.229 v16.7.0] */
+ -1, /* 7"Alert-Info", */
+ -1, /* 8"Allow", */
+ -1, /* 9"Allow-Events", RFC3265 */
+ -1, /* 10"Answer-Mode" RFC5373 */
+ -1, /* 11"Attestation-Info [3GPP TS 24.229 v15.11.0] */
+ -1, /* 12"Authentication-Info" */
+ -1, /* 13"Authorization", */
+ -1, /* 14"Call-ID", */
+ -1, /* 15"Call-Info" */
+ -1, /* 16"Cellular-Network-Info [3GPP TS 24.229 v13.9.0] */
+ -1, /* 17"Contact", */
+ -1, /* 18"Content-Disposition", */
+ -1, /* 19"Content-Encoding", */
+ -1, /* 20"Content-Language", */
+ -1, /* 21"Content-Length", */
+ -1, /* 22"Content-Type", */
+ -1, /* 23"CSeq", */
+ -1, /* 24"Date", */
+ -1, /* 25"Error-Info", */
+ -1, /* 26"Event", */
+ -1, /* 27"Expires", */
+ -1, /* 28"Feature-Caps", */
+ -1, /* 29"Flow-Timer", RFC5626 */
+ -1, /* 30"From", */
+ -1, /* 31"Geolocation", */
+ -1, /* 32"Geolocation-Error", */
+ -1, /* 33"Geolocation-Routing", */
+ -1, /* 34"History-Info", RFC4244 */
+ -1, /* 35"Identity", */
+ -1, /* 36"Identity-Info", RFC4474 */
+ -1, /* 37"Info-Package", RFC-ietf-sipcore-info-events-10.txt */
+ -1, /* 38"In-Reply-To", RFC3261 */
+ -1, /* 39"Join", RFC3911 */
+ -1, /* 40"Max-Breadth" RFC5393 */
+ -1, /* 41"Max-Forwards", */
+ -1, /* 42"MIME-Version", */
+ -1, /* 43"Min-Expires", */
+ -1, /* 44"Min-SE", RFC4028 */
+ -1, /* 45"Organization", */
+ -1, /* 46"Origination-Id [3GPP TS 24.229 v15.11.0] */
+ -1, /* 47"P-Access-Network-Info", RFC3455 */
+ -1, /* 48"P-Answer-State", RFC4964 */
+ -1, /* 49"P-Asserted-Identity", RFC3325 */
+ -1, /* 50"P-Asserted-Service", RFC-drage-sipping-service-identification-05.txt */
+ -1, /* 51"P-Associated-URI", RFC3455 */
+ -1, /* 52"P-Charge-Info", RFC8496 */
+ -1, /* 53"P-Called-Party-ID", RFC3455 */
+ -1, /* 54"P-Charging-Function-Addresses", RFC3455 */
+ -1, /* 55"P-Charging-Vector", RFC3455 */
+ -1, /* 56"P-DCS-Trace-Party-ID", RFC3603 */
+ -1, /* 57"P-DCS-OSPS", RFC3603 */
+ -1, /* 58"P-DCS-Billing-Info", RFC3603 */
+ -1, /* 59"P-DCS-LAES", RFC3603 */
+ -1, /* 60"P-DCS-Redirect", RFC3603 */
+ -1, /* 61"P-Early-Media", */
+ -1, /* 62"P-Media-Authorization", RFC3313 */
+ -1, /* 63"P-Preferred-Identity", RFC3325 */
+ -1, /* 64"P-Preferred-Service", RFC-drage-sipping-service-identification-05.txt */
+ -1, /* 65"P-Profile-Key", */
+ -1, /* 66"P-Refused-URI-List", RFC5318 */
+ -1, /* 67"P-Served-User", RFC5502 */
+ -1, /* 68"P-User-Database RFC4457 */
+ -1, /* 69"P-Visited-Network-ID", RFC3455 */
+ -1, /* 70"Path", RFC3327 */
+ -1, /* 71"Permission-Missing" RFC5360 */
+ -1, /* 72"Policy-Contact" RFC5360 */
+ -1, /* 73"Policy-ID" RFC5360 */
+ -1, /* 74"Priority" */
+ -1, /* 75"Priority-Share [3GPP TS 24.229 v13.16.0] */
+ -1, /* 76"Priv-Answer-mode" RFC5373 */
+ -1, /* 77"Privacy", RFC3323 */
+ -1, /* 78"Proxy-Authenticate", */
+ -1, /* 79"Proxy-Authorization", */
+ -1, /* 80"Proxy-Require", */
+ -1, /* 81"RAck", RFC3262 */
+ -1, /* 82"Reason", RFC3326 */
+ -1, /* 83"Reason-Phrase", RFC3326 */
+ -1, /* 84"Record-Route", */
+ -1, /* 85"Recv-Info", RFC6086 */
+ -1, /* 86"Refer-Sub",", RFC4488 */
+ -1, /* 87"Refer-To", RFC3515 */
+ -1, /* 88"Referred-By", */
+ -1, /* 89"Reject-Contact", RFC3841 */
+ -1, /* 90"Relayed-Charge [3GPP TS 24.229 v12.14.0] */
+ -1, /* 91"Replaces", RFC3891 */
+ -1, /* 92"Reply-To", RFC3261 */
+ -1, /* 93"Request-Disposition", RFC3841 */
+ -1, /* 94"Require", RFC3261 */
+ -1, /* 95"Resource-Priority", RFC4412 */
+ -1, /* 96"Resource-Share [3GPP TS 24.229 v13.7.0] */
+ -1, /* 97"Response-Source [3GPP TS 24.229 v15.11.0] */
+ -1, /* 98"Restoration-Info [3GPP TS 24.229 v12.14.0] */
+ -1, /* 99"Retry-After", RFC3261 */
+ -1, /* 100"Route", RFC3261 */
+ -1, /* 101"RSeq", RFC3262 */
+ -1, /* 102"Security-Client", RFC3329 */
+ -1, /* 103"Security-Server", RFC3329 */
+ -1, /* 104"Security-Verify", RFC3329 */
+ -1, /* 105"Server", RFC3261 */
+ -1, /* 106"Service-Interact-Info [3GPP TS 24.229 v13.18.0] */
+ -1, /* 107"Service-Route", RFC3608 */
+ -1, /* 108"Session-Expires", RFC4028 */
+ -1, /* 109"Session-ID", RFC7329 */
+ -1, /* 110"SIP-ETag", RFC3903 */
+ -1, /* 111"SIP-If-Match", RFC3903 */
+ -1, /* 112"Subject", RFC3261 */
+ -1, /* 113"Subscription-State", RFC3265 */
+ -1, /* 114"Supported", RFC3261 */
+ -1, /* 115"Suppress-If-Match", RFC4538 */
+ -1, /* 116"Target-Dialog", RFC4538 */
+ -1, /* 117"Timestamp", RFC3261 */
+ -1, /* 118"To", RFC3261 */
+ -1, /* 119"Trigger-Consent" RFC5380 */
+ -1, /* 120"Unsupported", RFC3261 */
+ -1, /* 121"User-Agent", RFC3261 */
+ -1, /* 122"Via", RFC3261 */
+ -1, /* 123"Warning", RFC3261 */
+ -1, /* 124"WWW-Authenticate", RFC3261 */
+ -1, /* 125"Diversion", RFC5806 */
+ -1, /* 126"User-to-User", draft-johnston-sipping-cc-uui-09 */
+};
+
+/* Track associations between parameter name and hf item */
+typedef struct {
+ const char *param_name;
+ const gint *hf_item;
+} header_parameter_t;
+
+static header_parameter_t auth_parameters_hf_array[] =
+{
+ {"response", &hf_sip_auth_digest_response},
+ {"nc", &hf_sip_auth_nc},
+ {"username", &hf_sip_auth_username},
+ {"realm", &hf_sip_auth_realm},
+ {"nonce", &hf_sip_auth_nonce},
+ {"algorithm", &hf_sip_auth_algorithm},
+ {"opaque", &hf_sip_auth_opaque},
+ {"qop", &hf_sip_auth_qop},
+ {"cnonce", &hf_sip_auth_cnonce},
+ {"uri", &hf_sip_auth_uri},
+ {"domain", &hf_sip_auth_domain},
+ {"stale", &hf_sip_auth_stale},
+ {"auts", &hf_sip_auth_auts},
+ {"rspauth", &hf_sip_auth_rspauth},
+ {"nextnonce", &hf_sip_auth_nextnonce},
+ {"ik", &hf_sip_auth_ik},
+ {"ck", &hf_sip_auth_ck}
+};
+
+static header_parameter_t via_parameters_hf_array[] =
+{
+ {"branch", &hf_sip_via_branch},
+ {"maddr", &hf_sip_via_maddr},
+ {"rport", &hf_sip_via_rport},
+ {"received", &hf_sip_via_received},
+ {"ttl", &hf_sip_via_ttl},
+ {"comp", &hf_sip_via_comp},
+ {"sigcomp-id", &hf_sip_via_sigcomp_id},
+ {"oc", &hf_sip_via_oc},
+ {"oc-validity", &hf_sip_via_oc_validity },
+ {"oc-seq", &hf_sip_via_oc_seq},
+ {"oc-algo", &hf_sip_via_oc_algo},
+ {"be-route", &hf_sip_via_be_route}
+};
+
+typedef enum {
+ MECH_PARA_STRING = 0,
+ MECH_PARA_UINT = 1,
+} mech_parameter_type_t;
+
+/* Track associations between parameter name and hf item for security mechanism*/
+typedef struct {
+ const char *param_name;
+ const gint para_type;
+ const gint *hf_item;
+} mech_parameter_t;
+
+static mech_parameter_t sec_mechanism_parameters_hf_array[] =
+{
+ {"alg", MECH_PARA_STRING, &hf_sip_sec_mechanism_alg},
+ {"ealg", MECH_PARA_STRING, &hf_sip_sec_mechanism_ealg},
+ {"prot", MECH_PARA_STRING, &hf_sip_sec_mechanism_prot},
+ {"spi-c", MECH_PARA_UINT, &hf_sip_sec_mechanism_spi_c},
+ {"spi-s", MECH_PARA_UINT, &hf_sip_sec_mechanism_spi_s},
+ {"port1", MECH_PARA_UINT, &hf_sip_sec_mechanism_port1},
+ {"port-c", MECH_PARA_UINT, &hf_sip_sec_mechanism_port_c},
+ {"port2", MECH_PARA_UINT, &hf_sip_sec_mechanism_port2},
+ {"port-s", MECH_PARA_UINT, &hf_sip_sec_mechanism_port_s},
+ {NULL, 0, 0}
+};
+
+typedef struct {
+ gint *hf_sip_display;
+ gint *hf_sip_addr;
+ gint *hf_sip_user;
+ gint *hf_sip_host;
+ gint *hf_sip_port;
+ gint *hf_sip_param;
+ gint *ett_uri;
+} hf_sip_uri_t;
+
+static hf_sip_uri_t sip_pai_uri = {
+ &hf_sip_pai_display,
+ &hf_sip_pai_addr,
+ &hf_sip_pai_user,
+ &hf_sip_pai_host,
+ &hf_sip_pai_port,
+ &hf_sip_pai_param,
+ &ett_sip_pai_uri
+};
+
+static hf_sip_uri_t sip_ppi_uri = {
+ &hf_sip_ppi_display,
+ &hf_sip_ppi_addr,
+ &hf_sip_ppi_user,
+ &hf_sip_ppi_host,
+ &hf_sip_ppi_port,
+ &hf_sip_ppi_param,
+ &ett_sip_ppi_uri
+};
+
+static hf_sip_uri_t sip_pmiss_uri = {
+ &hf_sip_pmiss_display,
+ &hf_sip_pmiss_addr,
+ &hf_sip_pmiss_user,
+ &hf_sip_pmiss_host,
+ &hf_sip_pmiss_port,
+ &hf_sip_pmiss_param,
+ &ett_sip_pmiss_uri
+};
+
+static hf_sip_uri_t sip_tc_uri = {
+ &hf_sip_tc_display,
+ &hf_sip_tc_addr,
+ &hf_sip_tc_user,
+ &hf_sip_tc_host,
+ &hf_sip_tc_port,
+ &hf_sip_tc_param,
+ &ett_sip_tc_uri
+};
+
+static hf_sip_uri_t sip_to_uri = {
+ &hf_sip_to_display,
+ &hf_sip_to_addr,
+ &hf_sip_to_user,
+ &hf_sip_to_host,
+ &hf_sip_to_port,
+ &hf_sip_to_param,
+ &ett_sip_to_uri
+};
+
+static hf_sip_uri_t sip_from_uri = {
+ &hf_sip_from_display,
+ &hf_sip_from_addr,
+ &hf_sip_from_user,
+ &hf_sip_from_host,
+ &hf_sip_from_port,
+ &hf_sip_from_param,
+ &ett_sip_from_uri
+};
+
+static hf_sip_uri_t sip_req_uri = {
+ &hf_sip_ruri_display,
+ &hf_sip_ruri,
+ &hf_sip_ruri_user,
+ &hf_sip_ruri_host,
+ &hf_sip_ruri_port,
+ &hf_sip_ruri_param,
+ &ett_sip_ruri
+};
+
+static hf_sip_uri_t sip_contact_uri = {
+ &hf_sip_curi_display,
+ &hf_sip_curi,
+ &hf_sip_curi_user,
+ &hf_sip_curi_host,
+ &hf_sip_curi_port,
+ &hf_sip_curi_param,
+ &ett_sip_curi
+};
+
+static hf_sip_uri_t sip_route_uri = {
+ &hf_sip_route_display,
+ &hf_sip_route,
+ &hf_sip_route_user,
+ &hf_sip_route_host,
+ &hf_sip_route_port,
+ &hf_sip_route_param,
+ &ett_sip_route
+};
+
+static hf_sip_uri_t sip_record_route_uri = {
+ &hf_sip_record_route_display,
+ &hf_sip_record_route,
+ &hf_sip_record_route_user,
+ &hf_sip_record_route_host,
+ &hf_sip_record_route_port,
+ &hf_sip_record_route_param,
+ &ett_sip_record_route
+};
+
+static hf_sip_uri_t sip_service_route_uri = {
+ &hf_sip_service_route_display,
+ &hf_sip_service_route,
+ &hf_sip_service_route_user,
+ &hf_sip_service_route_host,
+ &hf_sip_service_route_port,
+ &hf_sip_service_route_param,
+ &ett_sip_service_route
+};
+
+static hf_sip_uri_t sip_path_uri = {
+ &hf_sip_path_display,
+ &hf_sip_path,
+ &hf_sip_path_user,
+ &hf_sip_path_host,
+ &hf_sip_path_port,
+ &hf_sip_path_param,
+ &ett_sip_path
+};
+
+/*
+ * Type of line. It's either a SIP Request-Line, a SIP Status-Line, or
+ * another type of line.
+ */
+typedef enum {
+ REQUEST_LINE,
+ STATUS_LINE,
+ OTHER_LINE
+} line_type_t;
+
+/* Preferences */
+static guint sip_tls_port = TLS_PORT_SIP;
+
+/* global_sip_raw_text determines whether we are going to display */
+/* the raw text of the SIP message, much like the MEGACO dissector does. */
+static gboolean global_sip_raw_text = FALSE;
+/* global_sip_raw_text_without_crlf determines whether we are going to display */
+/* the raw text of the SIP message with or without the '\r\n'. */
+static gboolean global_sip_raw_text_without_crlf = FALSE;
+/* global_sip_raw_text_body_default_encoding determines what charset we are going to display the body */
+static gint global_sip_raw_text_body_default_encoding = IANA_CS_UTF_8;
+/* strict_sip_version determines whether the SIP dissector enforces
+ * the SIP version to be "SIP/2.0". */
+static gboolean strict_sip_version = TRUE;
+
+/*
+ * desegmentation of SIP headers
+ * (when we are over TCP or another protocol providing the desegmentation API)
+ */
+static gboolean sip_desegment_headers = TRUE;
+
+/*
+ * desegmentation of SIP bodies
+ * (when we are over TCP or another protocol providing the desegmentation API)
+ */
+static gboolean sip_desegment_body = TRUE;
+
+/*
+ * same source port for retransmissions
+ */
+static gboolean sip_retrans_the_same_sport = TRUE;
+
+/* whether we hold off tracking RTP conversations until an SDP answer is received */
+static gboolean sip_delay_sdp_changes = FALSE;
+
+/* Hide the generated Call IDs or not */
+static gboolean sip_hide_generatd_call_ids = FALSE;
+
+/* Extension header subdissectors */
+static dissector_table_t ext_hdr_subdissector_table;
+
+/* Custom SIP headers */
+typedef struct _header_field_t {
+ gchar* header_name;
+ gchar* header_desc;
+} header_field_t;
+
+static header_field_t* sip_custom_header_fields;
+static guint sip_custom_num_header_fields;
+static GHashTable *sip_custom_header_fields_hash;
+static hf_register_info *dynamic_hf;
+static guint dynamic_hf_size;
+
+static bool
+header_fields_update_cb(void *r, char **err)
+{
+ header_field_t *rec = (header_field_t *)r;
+ char c;
+
+ if (rec->header_name == NULL) {
+ *err = g_strdup("Header name can't be empty");
+ return FALSE;
+ }
+
+ g_strstrip(rec->header_name);
+ if (rec->header_name[0] == 0) {
+ *err = g_strdup("Header name can't be empty");
+ return FALSE;
+ }
+
+ /* Check for invalid characters (to avoid asserting out when
+ * registering the field).
+ */
+ c = proto_check_field_name(rec->header_name);
+ if (c) {
+ *err = ws_strdup_printf("Header name can't contain '%c'", c);
+ return FALSE;
+ }
+
+ *err = NULL;
+ return TRUE;
+}
+
+static void *
+header_fields_copy_cb(void* n, const void* o, size_t siz _U_)
+{
+ header_field_t* new_rec = (header_field_t*)n;
+ const header_field_t* old_rec = (const header_field_t*)o;
+
+ new_rec->header_name = g_strdup(old_rec->header_name);
+ new_rec->header_desc = g_strdup(old_rec->header_desc);
+
+ return new_rec;
+}
+
+static void
+header_fields_free_cb(void*r)
+{
+ header_field_t* rec = (header_field_t*)r;
+
+ g_free(rec->header_name);
+ g_free(rec->header_desc);
+}
+
+static void
+deregister_header_fields(void)
+{
+ if (dynamic_hf) {
+ /* Deregister all fields */
+ for (guint i = 0; i < dynamic_hf_size; i++) {
+ proto_deregister_field(proto_sip, *(dynamic_hf[i].p_id));
+ g_free(dynamic_hf[i].p_id);
+ }
+
+ proto_add_deregistered_data(dynamic_hf);
+ dynamic_hf = NULL;
+ dynamic_hf_size = 0;
+ }
+
+ if (sip_custom_header_fields_hash) {
+ g_hash_table_destroy(sip_custom_header_fields_hash);
+ sip_custom_header_fields_hash = NULL;
+ }
+}
+
+static void
+header_fields_post_update_cb(void)
+{
+ gint* hf_id;
+ gchar* header_name;
+ gchar* header_name_key;
+
+ deregister_header_fields();
+
+ if (sip_custom_num_header_fields) {
+ sip_custom_header_fields_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+ dynamic_hf = g_new0(hf_register_info, sip_custom_num_header_fields);
+ dynamic_hf_size = sip_custom_num_header_fields;
+
+ for (guint i = 0; i < dynamic_hf_size; i++) {
+ hf_id = g_new(gint, 1);
+ *hf_id = -1;
+ header_name = g_strdup(sip_custom_header_fields[i].header_name);
+ header_name_key = g_ascii_strdown(header_name, -1);
+
+ dynamic_hf[i].p_id = hf_id;
+ dynamic_hf[i].hfinfo.name = header_name;
+ dynamic_hf[i].hfinfo.abbrev = ws_strdup_printf("sip.%s", header_name);
+ dynamic_hf[i].hfinfo.type = FT_STRING;
+ dynamic_hf[i].hfinfo.display = BASE_NONE;
+ dynamic_hf[i].hfinfo.strings = NULL;
+ dynamic_hf[i].hfinfo.bitmask = 0;
+ dynamic_hf[i].hfinfo.blurb = g_strdup(sip_custom_header_fields[i].header_desc);
+ HFILL_INIT(dynamic_hf[i]);
+
+ g_hash_table_insert(sip_custom_header_fields_hash, header_name_key, hf_id);
+ }
+
+ proto_register_field_array(proto_sip, dynamic_hf, dynamic_hf_size);
+ }
+}
+
+static void
+header_fields_reset_cb(void)
+{
+ deregister_header_fields();
+}
+
+UAT_CSTRING_CB_DEF(sip_custom_header_fields, header_name, header_field_t)
+UAT_CSTRING_CB_DEF(sip_custom_header_fields, header_desc, header_field_t)
+
+/* SIP authorization parameters */
+static gboolean global_sip_validate_authorization = FALSE;
+
+typedef struct _authorization_user_t {
+ gchar* username;
+ gchar* realm;
+ gchar* password;
+} authorization_user_t;
+
+static authorization_user_t* sip_authorization_users = NULL;
+static guint sip_authorization_num_users = 0;
+
+static bool
+authorization_users_update_cb(void *r, char **err)
+{
+ authorization_user_t *rec = (authorization_user_t *)r;
+ char c;
+
+ if (rec->username == NULL) {
+ *err = g_strdup("Username can't be empty");
+ return FALSE;
+ }
+
+ g_strstrip(rec->username);
+ if (rec->username[0] == 0) {
+ *err = g_strdup("Username can't be empty");
+ return FALSE;
+ }
+
+ /* Check for invalid characters (to avoid asserting out when
+ * registering the field).
+ */
+ c = proto_check_field_name(rec->username);
+ if (c) {
+ *err = ws_strdup_printf("Username can't contain '%c'", c);
+ return FALSE;
+ }
+
+ *err = NULL;
+ return TRUE;
+}
+
+static void *
+authorization_users_copy_cb(void* n, const void* o, size_t siz _U_)
+{
+ authorization_user_t* new_rec = (authorization_user_t*)n;
+ const authorization_user_t* old_rec = (const authorization_user_t*)o;
+
+ new_rec->username = g_strdup(old_rec->username);
+ new_rec->realm = g_strdup(old_rec->realm);
+ new_rec->password = g_strdup(old_rec->password);
+
+ return new_rec;
+}
+
+static void
+authorization_users_free_cb(void*r)
+{
+ authorization_user_t* rec = (authorization_user_t*)r;
+
+ g_free(rec->username);
+ g_free(rec->realm);
+ g_free(rec->password);
+}
+
+UAT_CSTRING_CB_DEF(sip_authorization_users, username, authorization_user_t)
+UAT_CSTRING_CB_DEF(sip_authorization_users, realm, authorization_user_t)
+UAT_CSTRING_CB_DEF(sip_authorization_users, password, authorization_user_t)
+
+/* Forward declaration we need below */
+void proto_reg_handoff_sip(void);
+static gboolean dissect_sip_common(tvbuff_t *tvb, int offset, int remaining_length, packet_info *pinfo,
+ proto_tree *tree, gboolean is_heur, gboolean use_reassembly);
+static line_type_t sip_parse_line(tvbuff_t *tvb, int offset, gint linelen,
+ guint *token_1_len);
+static gboolean sip_is_known_request(tvbuff_t *tvb, int meth_offset,
+ guint meth_len, guint *meth_idx);
+static gint sip_is_known_sip_header(gchar *header_name, guint header_len);
+static void dfilter_sip_request_line(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, gint offset,
+ guint meth_len, gint linelen);
+static void dfilter_sip_status_line(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, gint line_end, gint offset);
+static void tvb_raw_text_add(tvbuff_t *tvb, int offset, int length, int body_offset, packet_info* pinfo, proto_tree *tree);
+static guint sip_is_packet_resend(packet_info *pinfo,
+ const char *cseq_method,
+ gchar* call_id,
+ guchar cseq_number_set, guint32 cseq_number,
+ line_type_t line_type);
+
+static guint sip_find_request(packet_info *pinfo,
+ const char *cseq_method,
+ gchar* call_id,
+ guchar cseq_number_set, guint32 cseq_number,
+ guint32 *response_time);
+
+static guint sip_find_invite(packet_info *pinfo,
+ const char *cseq_method,
+ gchar* call_id,
+ guchar cseq_number_set, guint32 cseq_number,
+ guint32 *response_time);
+
+typedef struct
+{
+ gchar * username;
+ gchar * realm;
+ gchar * uri;
+ gchar * nonce;
+ gchar * cnonce;
+ gchar * nonce_count;
+ gchar * response;
+ gchar * qop;
+ gchar * algorithm;
+ gchar * method;
+} sip_authorization_t;
+
+static authorization_user_t * sip_get_authorization(sip_authorization_t *authorization_info);
+static gboolean sip_validate_authorization(sip_authorization_t *authorization_info, gchar *password);
+
+static authorization_user_t * sip_get_authorization(sip_authorization_t *authorization_info)
+{
+ guint i;
+ for (i = 0; i < sip_authorization_num_users; i++) {
+ if ((!strcmp(sip_authorization_users[i].username, authorization_info->username)) &&
+ (!strcmp(sip_authorization_users[i].realm, authorization_info->realm))) {
+ return &sip_authorization_users[i];
+ }
+ }
+ return NULL;
+}
+
+/* SIP content type and internet media type used by other dissectors
+ * are the same. List of media types from IANA at:
+ * http://www.iana.org/assignments/media-types/index.html */
+static dissector_table_t media_type_dissector_table;
+
+static heur_dissector_list_t heur_subdissector_list;
+
+#define SIP2_HDR "SIP/2.0"
+#define SIP2_HDR_LEN 7
+
+/* Store the info needed by the SIP tap for one packet */
+static sip_info_value_t *stat_info;
+
+/* The buffer size for the cseq_method name */
+#define MAX_CSEQ_METHOD_SIZE 16
+
+/****************************************************************************
+ * Conversation-type definitions
+ *
+ * For each call, keep track of the current cseq number and state of
+ * transaction, in order to be able to detect retransmissions.
+ *
+ * Don't use the conversation mechanism, but instead:
+ * - store with each dissected packet original frame (if any)
+ * - maintain a global hash table of
+ * (call_id, source_addr, dest_addr) -> (cseq, transaction_state, frame)
+ *
+ * N.B. This is broken for a couple of reasons:
+ * - it won't cope properly with overlapping transactions within the
+ * same dialog
+ * - request response mapping won't work where the response uses a different
+ * address pair from the request
+ *
+ * TODO: proper transaction matching uses RFC fields (use Max-forwards or
+ * maybe Via count as extra key to limit view to one hop)
+ ****************************************************************************/
+
+static GHashTable *sip_hash = NULL; /* Hash table */
+static GHashTable *sip_headers_hash = NULL; /* Hash table */
+
+/* Types for hash table keys and values */
+#define MAX_CALL_ID_SIZE 128
+#define MAGIC_SOURCE_PORT 0
+
+/* Conversation-type key */
+typedef struct
+{
+ char call_id[MAX_CALL_ID_SIZE];
+ address source_address;
+ guint32 source_port;
+ address dest_address;
+ guint32 dest_port;
+} sip_hash_key;
+
+
+typedef enum
+{
+ nothing_seen,
+ request_seen,
+ provisional_response_seen,
+ final_response_seen
+} transaction_state_t;
+
+/* Current conversation-type value */
+typedef struct
+{
+ guint32 cseq;
+ transaction_state_t transaction_state;
+ const char *method;
+ nstime_t request_time;
+ guint32 response_code;
+ gint frame_number;
+} sip_hash_value;
+
+/* Result to be stored in per-packet info */
+typedef struct
+{
+ gint original_frame_num;
+ gint response_request_frame_num;
+ gint response_time;
+} sip_frame_result_value;
+
+
+/************************/
+/* Hash table functions */
+
+/* Equal keys */
+static gint sip_equal(gconstpointer v, gconstpointer v2)
+{
+ const sip_hash_key* val1 = (const sip_hash_key*)v;
+ const sip_hash_key* val2 = (const sip_hash_key*)v2;
+
+ /* Call id must match */
+ if (strcmp(val1->call_id, val2->call_id) != 0)
+ {
+ return 0;
+ }
+
+ /* Addresses must match */
+ return (addresses_equal(&(val1->source_address), &(val2->source_address))) &&
+ (val1->source_port == val2->source_port) &&
+ (addresses_equal(&(val1->dest_address), &(val2->dest_address))) &&
+ (val1->dest_port == val2->dest_port);
+}
+
+
+/* Initializes the hash table each time a new
+ * file is loaded or re-loaded in wireshark */
+static void
+sip_init_protocol(void)
+{
+ guint i;
+ gchar *value_copy;
+ sip_hash = g_hash_table_new(g_str_hash , sip_equal);
+
+ /* Hash table for quick lookup of SIP headers names to hf entry (POS_x) */
+ sip_headers_hash = g_hash_table_new(g_str_hash , g_str_equal);
+ for (i = 1; i < array_length(sip_headers); i++){
+ value_copy = wmem_strdup(wmem_file_scope(), sip_headers[i].name);
+ ascii_strdown_inplace(value_copy);
+ g_hash_table_insert(sip_headers_hash, (gpointer)value_copy, GINT_TO_POINTER(i));
+ }
+}
+
+static void
+sip_cleanup_protocol(void)
+{
+ g_hash_table_destroy(sip_hash);
+ g_hash_table_destroy(sip_headers_hash);
+}
+
+/* Call the export PDU tap with relevant data */
+static void
+export_sip_pdu(packet_info *pinfo, tvbuff_t *tvb)
+{
+ exp_pdu_data_t *exp_pdu_data = export_pdu_create_common_tags(pinfo, "sip", EXP_PDU_TAG_DISSECTOR_NAME);
+
+ exp_pdu_data->tvb_captured_length = tvb_captured_length(tvb);
+ exp_pdu_data->tvb_reported_length = tvb_reported_length(tvb);
+ exp_pdu_data->pdu_tvb = tvb;
+
+ tap_queue_packet(exported_pdu_tap, pinfo, exp_pdu_data);
+
+}
+
+typedef enum
+{
+ SIP_URI_TYPE_ABSOLUTE_URI,
+ SIP_URI_TYPE_SIP,
+ SIP_URI_TYPE_TEL
+
+} sip_uri_type_enum_t;
+
+/* Structure to collect info about a sip uri */
+typedef struct _uri_offset_info
+{
+ sip_uri_type_enum_t uri_type;
+ gint display_name_start;
+ gint display_name_end;
+ gint uri_start;
+ gint uri_end;
+ gint uri_parameters_start;
+ gint uri_parameters_end;
+ gint name_addr_start;
+ gint name_addr_end;
+ gint uri_user_start;
+ gint uri_user_end;
+ gint uri_host_start;
+ gint uri_host_end;
+ gint uri_host_port_start;
+ gint uri_host_port_end;
+} uri_offset_info;
+
+static void
+sip_uri_offset_init(uri_offset_info *uri_offsets){
+
+ /* Initialize the uri_offsets */
+ uri_offsets->uri_type = SIP_URI_TYPE_ABSOLUTE_URI;
+ uri_offsets->display_name_start = -1;
+ uri_offsets->display_name_end = -1;
+ uri_offsets->uri_start = -1;
+ uri_offsets->uri_end = -1;
+ uri_offsets->uri_parameters_start = -1;
+ uri_offsets->uri_parameters_end = -1;
+ uri_offsets->name_addr_start = -1;
+ uri_offsets->name_addr_end = -1;
+ uri_offsets->uri_user_start = -1;
+ uri_offsets->uri_user_end = -1;
+ uri_offsets->uri_host_start = -1;
+ uri_offsets->uri_host_end = -1;
+ uri_offsets->uri_host_port_start = -1;
+ uri_offsets->uri_host_port_end = -1;
+
+}
+/* Code to parse a sip uri.
+ * Returns Offset end off parsing or -1 for unsuccessful parsing
+ * - sip_uri_offset_init() must have been called first.
+ */
+static gint
+dissect_sip_uri(tvbuff_t *tvb, packet_info *pinfo _U_, gint start_offset,
+ gint line_end_offset, uri_offset_info *uri_offsets)
+{
+ guchar c = '\0';
+ gint current_offset;
+ gint queried_offset;
+ gint parameter_end_offset;
+ gboolean in_ipv6 = FALSE;
+
+ /* skip Spaces and Tabs */
+ current_offset = tvb_skip_wsp(tvb, start_offset, line_end_offset - start_offset);
+
+ if(current_offset >= line_end_offset) {
+ /* Nothing to parse */
+ return -1;
+ }
+ /* Set uri start offset in case this was called directly */
+ uri_offsets->uri_start = current_offset;
+
+ /* Check if it's really a sip uri ( it might be a tel uri, parse that?) */
+ if (tvb_strneql(tvb, current_offset, "sip", 3) != 0){
+ if (uri_offsets->uri_end != -1) {
+ /* We know where the URI ends, set the offsets*/
+ return uri_offsets->name_addr_end;
+ }
+ return -1;
+ }
+
+ uri_offsets->uri_type = SIP_URI_TYPE_SIP;
+
+ if(uri_offsets->uri_end == -1)
+ {
+ /* name-addr form was NOT used e.g no closing ">" */
+ /* look for the first ',' or ';' which will mark the end of this URI
+ * In this case a semicolon indicates a header field parameter, and not an uri parameter.
+ */
+ int end_offset;
+
+ end_offset = tvb_ws_mempbrk_pattern_guint8(tvb, current_offset, line_end_offset - current_offset, &pbrk_comma_semi, NULL);
+
+ if (end_offset != -1)
+ {
+ uri_offsets->uri_end = end_offset - 1;
+ }
+ else
+ {
+ /* We don't have a semicolon or a comma.
+ * In that case, we assume that the end of the URI is at the line end
+ */
+ uri_offsets->uri_end = line_end_offset - 3; /* remove '\r\n' */
+ }
+ uri_offsets->name_addr_end = uri_offsets->uri_end;
+ }
+
+ /* Look for URI address parts (user, host, host-port) */
+
+ /* Look for '@' within URI */
+ queried_offset = tvb_find_guint8(tvb, uri_offsets->uri_start, uri_offsets->uri_end - uri_offsets->uri_start, '@');
+ if(queried_offset == -1)
+ {
+ /* no '@' = no user part */
+ uri_offsets->uri_host_start = tvb_find_guint8(tvb, uri_offsets->uri_start, uri_offsets->uri_end - uri_offsets->uri_start, ':')+1;
+ }
+ else
+ {
+ /* with '@' = with user part */
+ uri_offsets->uri_user_start = tvb_find_guint8(tvb, uri_offsets->uri_start, uri_offsets->uri_end - uri_offsets->uri_start, ':')+1;
+ uri_offsets->uri_user_end = tvb_find_guint8(tvb, uri_offsets->uri_user_start, uri_offsets->uri_end - uri_offsets->uri_start, '@')-1;
+ uri_offsets->uri_host_start = uri_offsets->uri_user_end + 2;
+ }
+
+ /* find URI-Host end*/
+ parameter_end_offset = uri_offsets->uri_host_start;
+
+ in_ipv6 = (tvb_get_guint8(tvb, parameter_end_offset) == '[');
+ while (parameter_end_offset < line_end_offset)
+ {
+ parameter_end_offset++;
+ parameter_end_offset = tvb_ws_mempbrk_pattern_guint8(tvb, parameter_end_offset, line_end_offset - parameter_end_offset, &pbrk_param_end_colon_brackets, &c);
+ if (parameter_end_offset == -1)
+ {
+ parameter_end_offset = line_end_offset;
+ break;
+ }
+
+ /* after adding character to this switch() , update also pbrk_param_end_colon_brackets */
+ switch (c) {
+ case '>':
+ case ',':
+ goto uri_host_end_found;
+ case ';':
+ uri_offsets->uri_parameters_start = parameter_end_offset + 1;
+ goto uri_host_end_found;
+ case '?':
+ case ' ':
+ case '\r':
+ goto uri_host_end_found;
+ case ':':
+ if (!in_ipv6)
+ goto uri_host_end_found;
+ break;
+ case '[':
+ in_ipv6 = TRUE;
+ break;
+ case ']':
+ in_ipv6 = FALSE;
+ break;
+ default :
+ DISSECTOR_ASSERT_NOT_REACHED();
+ break;
+ }
+ }
+
+uri_host_end_found:
+
+ uri_offsets->uri_host_end = parameter_end_offset - 1;
+
+ if (c == ':')
+ {
+ uri_offsets->uri_host_port_start = parameter_end_offset + 1;
+ parameter_end_offset = uri_offsets->uri_host_port_start;
+ while (parameter_end_offset < line_end_offset)
+ {
+ parameter_end_offset++;
+ parameter_end_offset = tvb_ws_mempbrk_pattern_guint8(tvb, parameter_end_offset, line_end_offset - parameter_end_offset, &pbrk_param_end, &c);
+ if (parameter_end_offset == -1)
+ {
+ parameter_end_offset = line_end_offset;
+ break;
+ }
+
+ /* after adding character to this switch(), update also pbrk_param_end */
+ switch (c) {
+ case '>':
+ case ',':
+ goto uri_host_port_end_found;
+ case ';':
+ uri_offsets->uri_parameters_start = parameter_end_offset + 1;
+ goto uri_host_port_end_found;
+ case '?':
+ case ' ':
+ case '\r':
+ goto uri_host_port_end_found;
+ default :
+ DISSECTOR_ASSERT_NOT_REACHED();
+ break;
+ }
+ }
+
+ uri_host_port_end_found:
+
+ uri_offsets->uri_host_port_end = parameter_end_offset -1;
+ }
+
+ return uri_offsets->name_addr_end;
+}
+
+void
+dfilter_store_sip_from_addr(tvbuff_t *tvb,proto_tree *tree,guint parameter_offset, guint parameter_len)
+{
+ proto_item *pi;
+
+ pi = proto_tree_add_item(tree, hf_sip_from_addr, tvb, parameter_offset, parameter_len, ENC_UTF_8);
+ proto_item_set_generated(pi);
+}
+
+static proto_item *
+sip_proto_tree_add_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length, gint value_offset, gint value_len)
+{
+ const char *str;
+ unsigned long val;
+
+ /* don't fetch string when field is not referenced */
+ if (!proto_field_is_referenced(tree, hfindex))
+ return tree;
+
+ str = tvb_get_string_enc(wmem_packet_scope(), tvb, value_offset, value_len, ENC_UTF_8|ENC_NA);
+ val = strtoul(str, NULL, 10);
+
+ return proto_tree_add_uint(tree, hfindex, tvb, start, length, (guint32) val);
+}
+
+static proto_item *
+sip_proto_tree_add_string(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length, gint value_offset, gint value_len)
+{
+ const char *str;
+
+ /* don't fetch string when field is not referenced */
+ if (!proto_field_is_referenced(tree, hfindex))
+ return tree;
+
+ str = tvb_get_string_enc(wmem_packet_scope(), tvb, value_offset, value_len, ENC_UTF_8|ENC_NA);
+
+ return proto_tree_add_string(tree, hfindex, tvb, start, length, str);
+}
+
+static void
+sip_proto_set_format_text(const proto_tree *tree, proto_item *item, tvbuff_t *tvb, int offset, int length)
+{
+ if (tree != item && item && PTREE_DATA(item)->visible)
+ proto_item_set_text(item, "%s", tvb_format_text(wmem_packet_scope(), tvb, offset, length));
+}
+/*
+ * XXXX If/when more parameters are added consider doing something similar to what's done in
+ * packet-magaco.c for find_megaco_localParam_names() possibly adding the hf to the array and have a generic
+ * dissection function here.
+ */
+static void
+dissect_sip_generic_parameters(tvbuff_t *tvb, proto_tree* tree, packet_info *pinfo _U_, gint current_offset, gint line_end_offset)
+{
+ gint semi_colon_offset, par_name_end_offset, equals_offset, length;
+ /* Loop over the generic parameter(s)*/
+ while (current_offset < line_end_offset) {
+ gchar *param_name = NULL;
+
+ /* skip Spaces and Tabs */
+ current_offset = tvb_skip_wsp(tvb, current_offset, line_end_offset - current_offset);
+
+ semi_colon_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, ';');
+
+ if (semi_colon_offset == -1) {
+ semi_colon_offset = line_end_offset;
+ }
+
+ length = semi_colon_offset - current_offset;
+
+ /* Parse parameter and value */
+ equals_offset = tvb_find_guint8(tvb, current_offset + 1, length, '=');
+ if (equals_offset != -1) {
+ /* Has value part */
+ par_name_end_offset = equals_offset;
+ /* Extract the parameter name */
+ param_name = tvb_get_string_enc(wmem_packet_scope(), tvb, current_offset, par_name_end_offset - current_offset, ENC_UTF_8 | ENC_NA);
+ /* Access-Info fields */
+ if ((param_name != NULL) && (g_ascii_strcasecmp(param_name, "service-priority") == 0)) {
+ proto_tree_add_item(tree, hf_sip_service_priority, tvb,
+ equals_offset + 1, semi_colon_offset - equals_offset - 1, ENC_UTF_8 | ENC_NA);
+ }
+ else {
+ proto_tree_add_format_text(tree, tvb, current_offset, length);
+ }
+ }
+ else {
+ proto_tree_add_format_text(tree, tvb, current_offset, length);
+ }
+ current_offset = semi_colon_offset + 1;
+ }
+}
+
+
+/*
+ * History-Info = "History-Info" HCOLON
+ * hi-entry *(COMMA hi-entry)
+ *
+ * hi-entry = hi-targeted-to-uri *( SEMI hi-param )
+ * hi-targeted-to-uri= name-addr
+ *
+ *
+ * hi-param = hi-index / hi-extension
+ *
+ * hi-index = "index" EQUAL 1*DIGIT *(DOT 1*DIGIT)
+ *
+ * hi-extension = generic-param
+ */
+
+static gint
+dissect_sip_history_info(tvbuff_t *tvb, proto_tree* tree, packet_info *pinfo _U_, gint current_offset,
+ gint line_end_offset)
+{
+ int comma_offset;
+ gboolean first_time = TRUE;
+
+ /* split the line at the commas */
+ while (line_end_offset > current_offset){
+ comma_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, ',');
+ if(comma_offset == -1){
+ if(first_time == TRUE){
+ /* It was only on parameter no need to split it up */
+ return line_end_offset;
+ }
+ /* Last parameter */
+ comma_offset = line_end_offset;
+ }
+ first_time = FALSE;
+ proto_tree_add_format_text(tree, tvb, current_offset, comma_offset-current_offset);
+
+ current_offset = comma_offset+1;
+ }
+
+ return line_end_offset;
+
+}
+
+
+/*
+ * The syntax for the P-Charging-Function-Addresses header is described
+ * as follows:
+ *
+ * P-Charging-Addr = "P-Charging-Function-Addresses" HCOLON
+ * charge-addr-params
+ * *(SEMI charge-addr-params)
+ * charge-addr-params = ccf / ecf / generic-param
+ * ccf = "ccf" EQUAL gen-value
+ * ecf = "ecf" EQUAL gen-value
+ * generic-param = token [ EQUAL gen-value ]
+ * gen-value = token / host / quoted-string
+ *
+ */
+
+static gint
+dissect_sip_p_charging_func_addresses(tvbuff_t *tvb, proto_tree* tree, packet_info *pinfo _U_, gint current_offset,
+ gint line_end_offset)
+{
+ gint semi_offset, start_quote_offset, end_quote_offset;
+ gboolean first_time = TRUE;
+
+ while (line_end_offset > current_offset){
+ /* Do we have a quoted string ? */
+ start_quote_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, '"');
+ if(start_quote_offset>0){
+ /* Find end of quoted string */
+ end_quote_offset = tvb_find_guint8(tvb, start_quote_offset+1, line_end_offset - (start_quote_offset+1), '"');
+ /* Find parameter end */
+ if (end_quote_offset>0)
+ semi_offset = tvb_find_guint8(tvb, end_quote_offset+1, line_end_offset - (end_quote_offset+1), ';');
+ else {
+ /* XXX expert info about unterminated string */
+ semi_offset = tvb_find_guint8(tvb, start_quote_offset+1, line_end_offset - (start_quote_offset+1), ';');
+ }
+ }else{
+ /* Find parameter end */
+ semi_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, ';');
+ }
+ if(semi_offset == -1){
+ if(first_time == TRUE){
+ /* It was only one parameter no need to split it up */
+ return line_end_offset;
+ }
+ /* Last parameter */
+ semi_offset = line_end_offset;
+ }
+ first_time = FALSE;
+ proto_tree_add_format_text(tree, tvb, current_offset, semi_offset-current_offset);
+
+ current_offset = semi_offset+1;
+
+ }
+
+ return current_offset;
+}
+
+/*
+ * token = 1*(alphanum / "-" / "." / "!" / "%" / "*"
+ * / "_" / "+" / "`" / "'" / "~" )
+ * LWS = [*WSP CRLF] 1*WSP ; linear whitespace
+ * name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
+ * addr-spec = SIP-URI / SIPS-URI / absoluteURI
+ * display-name = *(token LWS)/ quoted-string
+ * absoluteURI = scheme ":" ( hier-part / opaque-part )
+ */
+
+static gint
+dissect_sip_name_addr_or_addr_spec(tvbuff_t *tvb, packet_info *pinfo _U_, gint start_offset,
+ gint line_end_offset, uri_offset_info *uri_offsets)
+{
+ gchar c;
+ gint i;
+ gint current_offset;
+ gint queried_offset;
+ gint colon_offset;
+ gboolean uri_without_angle_quotes = FALSE;
+
+ /* skip Spaces and Tabs */
+ current_offset = tvb_skip_wsp(tvb, start_offset, line_end_offset - start_offset);
+
+ if(current_offset >= line_end_offset) {
+ /* Nothing to parse */
+ return -1;
+ }
+
+ uri_offsets->name_addr_start = current_offset;
+
+ /* First look, if we have a display name */
+ c=tvb_get_guint8(tvb, current_offset);
+ switch(c)
+ {
+ case '"':
+ /* We have a display name, look for the next unescaped '"' */
+ uri_offsets->display_name_start = current_offset;
+ do
+ {
+ queried_offset = tvb_find_guint8(tvb, current_offset + 1, line_end_offset - (current_offset + 1), '"');
+ if(queried_offset == -1)
+ {
+ /* malformed URI */
+ return -1;
+ }
+ current_offset = queried_offset;
+
+ /* Is it escaped? */
+ /* count back slashes before '"' */
+ for(i=1;tvb_get_guint8(tvb, queried_offset - i) == '\\';i++);
+ i--;
+
+ if(i % 2 == 0)
+ {
+ /* not escaped */
+ break;
+ }
+ } while (current_offset < line_end_offset);
+ if(current_offset >= line_end_offset)
+ {
+ /* malformed URI */
+ return -1;
+ }
+
+ uri_offsets->display_name_end = current_offset;
+
+ /* find start of the URI */
+ queried_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, '<');
+ if(queried_offset == -1)
+ {
+ /* malformed Uri */
+ return -1;
+ }
+ current_offset = queried_offset + 1;
+ break;
+
+ case '<':
+ /* We don't have a display name */
+ current_offset++;
+ break;
+
+ default:
+ /* We have either an URI without angles or a display name with a limited character set */
+ /* Look for the right angle quote or colon */
+ queried_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, '<');
+ colon_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, ':');
+ if(queried_offset != -1 && colon_offset != -1)
+ {
+ if(queried_offset < colon_offset)
+ {
+ /* we have an URI with angle quotes */
+ uri_offsets->display_name_start = current_offset;
+ uri_offsets->display_name_end = queried_offset - 1;
+ current_offset = queried_offset + 1;
+ }
+ else
+ {
+ /* we have an URI without angle quotes */
+ uri_without_angle_quotes = TRUE;
+ }
+ }
+ else
+ {
+ if(queried_offset != -1)
+ {
+ /* we have an URI with angle quotes */
+ uri_offsets->display_name_start = current_offset;
+ uri_offsets->display_name_end = queried_offset - 1;
+ current_offset = queried_offset + 1;
+ break;
+ }
+ if(colon_offset != -1)
+ {
+ /* we have an URI without angle quotes */
+ uri_without_angle_quotes = TRUE;
+ break;
+ }
+ /* If this point is reached, we can't parse the URI */
+ return -1;
+ }
+ break;
+ }
+ /* Start of URI */
+ uri_offsets->uri_start = current_offset;
+ if(uri_without_angle_quotes==FALSE){
+ /* name-addr form was used */
+ /* look for closing angle quote */
+ queried_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, '>');
+ if(queried_offset == -1)
+ {
+ /* malformed Uri */
+ return -1;
+ }
+ uri_offsets->name_addr_end = queried_offset;
+ uri_offsets->uri_end = queried_offset - 1;
+ }
+ return dissect_sip_uri(tvb, pinfo, current_offset, line_end_offset, uri_offsets);
+}
+
+
+/*
+* Code to add dissected SIP URI Information to proto tree
+*/
+
+static proto_tree *
+display_sip_uri (tvbuff_t *tvb, proto_tree *sip_element_tree, packet_info *pinfo, uri_offset_info* uri_offsets, hf_sip_uri_t* uri)
+{
+ proto_item *ti;
+ proto_tree *uri_item_tree = NULL;
+ tvbuff_t *next_tvb;
+
+ if(uri_offsets->display_name_end != uri_offsets->display_name_start) {
+ proto_tree_add_item(sip_element_tree, *(uri->hf_sip_display), tvb, uri_offsets->display_name_start,
+ uri_offsets->display_name_end - uri_offsets->display_name_start + 1, ENC_UTF_8|ENC_NA);
+ ti = proto_tree_add_item(sip_element_tree, hf_sip_display, tvb, uri_offsets->display_name_start,
+ uri_offsets->display_name_end - uri_offsets->display_name_start + 1, ENC_UTF_8);
+ proto_item_set_hidden(ti);
+ }
+
+ ti = proto_tree_add_item(sip_element_tree, *(uri->hf_sip_addr),
+ tvb, uri_offsets->uri_start, uri_offsets->uri_end - uri_offsets->uri_start + 1, ENC_UTF_8|ENC_NA);
+ uri_item_tree = proto_item_add_subtree(ti, *(uri->ett_uri));
+
+ if (uri_offsets->uri_type != SIP_URI_TYPE_SIP) {
+ return ti;
+ }
+
+ if(uri_offsets->uri_user_end > uri_offsets->uri_user_start) {
+ proto_tree_add_item(uri_item_tree, *(uri->hf_sip_user), tvb, uri_offsets->uri_user_start,
+ uri_offsets->uri_user_end - uri_offsets->uri_user_start + 1, ENC_UTF_8|ENC_NA);
+ if (tvb_get_guint8(tvb, uri_offsets->uri_user_start) == '+') {
+ dissect_e164_msisdn(tvb, uri_item_tree, uri_offsets->uri_user_start + 1, uri_offsets->uri_user_end - uri_offsets->uri_user_start, E164_ENC_UTF8);
+ }
+
+ /* If we have a SIP diagnostics sub dissector call it */
+ if (sip_uri_userinfo_handle) {
+ next_tvb = tvb_new_subset_length(tvb, uri_offsets->uri_user_start,
+ uri_offsets->uri_user_end - uri_offsets->uri_user_start + 1);
+ call_dissector(sip_uri_userinfo_handle, next_tvb, pinfo, uri_item_tree);
+ }
+
+ }
+
+ proto_tree_add_item(uri_item_tree, *(uri->hf_sip_host), tvb, uri_offsets->uri_host_start,
+ uri_offsets->uri_host_end - uri_offsets->uri_host_start + 1, ENC_UTF_8|ENC_NA);
+
+ if(uri_offsets->uri_host_port_end > uri_offsets->uri_host_port_start) {
+ proto_tree_add_item(uri_item_tree, *(uri->hf_sip_port), tvb, uri_offsets->uri_host_port_start,
+ uri_offsets->uri_host_port_end - uri_offsets->uri_host_port_start + 1, ENC_UTF_8|ENC_NA);
+ }
+
+ if (uri_offsets->uri_parameters_start != -1) {
+ /* Move current offset to the start of the first param */
+ gint current_offset = uri_offsets->uri_parameters_start;
+ gint uri_params_start_offset = current_offset;
+ gint queried_offset;
+ gint uri_param_end_offset = -1;
+ gchar c;
+
+ /* Put the contact parameters in the tree */
+
+ while (current_offset < uri_offsets->name_addr_end) {
+ queried_offset = tvb_ws_mempbrk_pattern_guint8(tvb, current_offset, uri_offsets->name_addr_end - current_offset, &pbrk_comma_semi, &c);
+
+ if (queried_offset == -1) {
+ /* Reached line end */
+ /* Check if the line ends with a ">", if so decrement end offset. */
+ c = tvb_get_guint8(tvb, uri_offsets->name_addr_end);
+
+ if (c == '>') {
+ uri_param_end_offset = uri_offsets->name_addr_end - 1;
+ } else {
+ uri_param_end_offset = uri_offsets->name_addr_end;
+ }
+ current_offset = uri_offsets->name_addr_end;
+ } else if (c==',') {
+ uri_param_end_offset = queried_offset;
+ current_offset = queried_offset+1; /* must move forward */
+ } else if (c==';') {
+ /* More parameters */
+ uri_param_end_offset = queried_offset-1;
+ current_offset = tvb_skip_wsp(tvb, queried_offset+1, uri_offsets->name_addr_end - queried_offset + 1);
+ }
+
+ proto_tree_add_item(uri_item_tree, *(uri->hf_sip_param), tvb, uri_params_start_offset ,
+ uri_param_end_offset - uri_params_start_offset +1, ENC_UTF_8|ENC_NA);
+
+ /* In case there are more parameters, point to the start of it */
+ uri_params_start_offset = current_offset;
+ }
+ }
+
+ return uri_item_tree;
+}
+
+
+
+
+/* Code to parse a contact header item
+ * Returns Offset end off parsing or -1 for unsuccessful parsing
+ * * contact-param = (name-addr / addr-spec) *(SEMI contact-params)
+ */
+static gint
+dissect_sip_contact_item(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint start_offset, gint line_end_offset,
+ guchar* contacts_expires_0, guchar* contacts_expires_unknown)
+{
+ gchar c;
+ gint current_offset;
+ gint queried_offset;
+ gint contact_params_start_offset = -1;
+ /*gint contact_param_end_offset = -1;*/
+ uri_offset_info uri_offsets;
+ gboolean end_of_hdr = FALSE;
+ gboolean has_expires_param = FALSE;
+
+ /* skip Spaces and Tabs */
+ start_offset = tvb_skip_wsp(tvb, start_offset, line_end_offset - start_offset);
+
+ if(start_offset >= line_end_offset) {
+ /* Nothing to parse */
+ return -1;
+ }
+
+ /* Initialize the uri_offsets */
+ sip_uri_offset_init(&uri_offsets);
+ /* contact-param = (name-addr / addr-spec) *(SEMI contact-params) */
+ current_offset = dissect_sip_name_addr_or_addr_spec(tvb, pinfo, start_offset, line_end_offset, &uri_offsets);
+ if(current_offset == -1)
+ {
+ /* Parsing failed */
+ return -1;
+ }
+ display_sip_uri(tvb, tree, pinfo, &uri_offsets, &sip_contact_uri);
+
+ /* check if there's a comma before a ';', in which case we stop parsing this item at the comma */
+ queried_offset = tvb_find_guint8(tvb, uri_offsets.uri_end, line_end_offset - uri_offsets.uri_end, ',');
+
+ /* Check if we have contact parameters, the uri should be followed by a ';' */
+ contact_params_start_offset = tvb_find_guint8(tvb, uri_offsets.uri_end, line_end_offset - uri_offsets.uri_end, ';');
+
+ if (queried_offset != -1 && (queried_offset < contact_params_start_offset || contact_params_start_offset == -1)) {
+ /* no expires param */
+ (*contacts_expires_unknown)++;
+ return queried_offset;
+ }
+
+ /* check if contact-params is present */
+ if(contact_params_start_offset == -1) {
+ /* no expires param */
+ (*contacts_expires_unknown)++;
+ return line_end_offset;
+ }
+
+ /* Move current offset to the start of the first param */
+ contact_params_start_offset++;
+ current_offset = contact_params_start_offset;
+
+ /* Put the contact parameters in the tree */
+
+ queried_offset = current_offset;
+
+ while(current_offset< line_end_offset){
+ c = '\0';
+ queried_offset++;
+ queried_offset = (queried_offset < line_end_offset) ? tvb_ws_mempbrk_pattern_guint8(tvb, queried_offset, line_end_offset - queried_offset, &pbrk_header_end_dquote, &c) : -1;
+ if (queried_offset != -1)
+ {
+ switch (c) {
+ /* prevent tree from displaying the '\r\n' as part of the param */
+ case '\r':
+ case '\n':
+ end_of_hdr = TRUE;
+ /* fall through */
+ case ',':
+ case ';':
+ case '"':
+ break;
+ default :
+ DISSECTOR_ASSERT_NOT_REACHED();
+ break;
+ }
+ }
+
+ if (queried_offset == -1) {
+ /* Last parameter, line end */
+ current_offset = line_end_offset;
+ }else if(c=='"'){
+ /* Do we have a quoted string ? */
+ queried_offset = tvb_find_guint8(tvb, queried_offset+1, line_end_offset - queried_offset, '"');
+ if(queried_offset==-1){
+ /* We have an opening quote but no closing quote. */
+ current_offset = line_end_offset;
+ } else {
+ current_offset = tvb_ws_mempbrk_pattern_guint8(tvb, queried_offset+1, line_end_offset - queried_offset, &pbrk_comma_semi, &c);
+ if(current_offset==-1){
+ /* Last parameter, line end */
+ current_offset = line_end_offset;
+ }
+ }
+ }else{
+ current_offset = queried_offset;
+ }
+ proto_tree_add_item(tree, hf_sip_contact_param, tvb, contact_params_start_offset ,
+ current_offset - contact_params_start_offset, ENC_UTF_8);
+
+ /* need to check for an 'expires' parameter
+ * TODO: this should be done in a common way for all headers,
+ * but To/From/etc do their own right now so doing the same here
+ */
+ /* also, this is a bad way of checking param names, but it's what To/From
+ * etc, do. But legally "exPiRes = value" is also legit.
+ */
+ if (tvb_strncaseeql(tvb, contact_params_start_offset, "expires=", 8) == 0) {
+ gint32 expire;
+ /* if the expires param value is 0, then it's de-registering
+ * this assumes the message is a REGISTER request/response, but these
+ * contacts_expires_0/contacts_expires_unknown variables only get used then,
+ * so that's ok
+ */
+ if (!ws_strtoi32(tvb_get_string_enc(wmem_packet_scope(), tvb, contact_params_start_offset+8,
+ current_offset - (contact_params_start_offset+8), ENC_UTF_8|ENC_NA), NULL, &expire))
+ return contact_params_start_offset+8;
+ has_expires_param = TRUE;
+ if (expire == 0) {
+ (*contacts_expires_0)++;
+ /* RFC 3261 10.3 "Processing REGISTER requests":
+ * "The registrar returns a 200 (OK) response. The response
+ * MUST contain Contact header field values enumerating all
+ * current bindings."
+ * This implies it is invalid for the response to contain the
+ * deregistered, no longer current, Contacts with expires=0.
+ * However, this warning was removed due to 3GPP usage.
+ * Cf. 3GPP TS 24.229 "5.4.1.4 User-initiated deregistration":
+ * "send a 200 (OK) response to a REGISTER request that
+ * contains a list of Contact header fields enumerating all
+ * contacts and flows that are currently registered, and all
+ * contacts that have been deregistered."
+ * https://gitlab.com/wireshark/wireshark/-/issues/10364
+ */
+#if 0
+ if (stat_info && stat_info->response_code > 199 && stat_info->response_code < 300) {
+ proto_tree_add_expert_format(tree, pinfo, &ei_sip_odd_register_response,
+ tvb, contact_params_start_offset, current_offset - contact_params_start_offset,
+ "SIP REGISTER %d response contains Contact with expires=0",
+ stat_info->response_code);
+ }
+#endif
+ }
+ }
+
+ /* In case there are more parameters, point to the start of it */
+ contact_params_start_offset = current_offset+1;
+ queried_offset = contact_params_start_offset;
+ if (end_of_hdr) {
+ /* '\r' or '\n' found, stop parsing and also set current offset to end
+ * so the return value indicates we reached line end
+ */
+ current_offset = line_end_offset;
+ }
+ if (c == ',') {
+ /* comma separator found, stop parsing of current contact-param here */
+ break;
+ }
+ }
+
+ if (!has_expires_param) {
+ (*contacts_expires_unknown)++;
+ }
+
+ return current_offset;
+}
+
+/* Code to parse an authorization header item
+ * Returns offset at end of parsing, or -1 for unsuccessful parsing
+ */
+static gint
+dissect_sip_authorization_item(tvbuff_t *tvb, proto_tree *tree, gint start_offset, gint line_end_offset, sip_authorization_t *authorization_info)
+{
+ gint current_offset, par_name_end_offset, queried_offset, value_offset, value_search_offset;
+ gint equals_offset = 0;
+ gchar *name;
+ header_parameter_t *auth_parameter;
+ guint i = 0;
+
+ /* skip Spaces and Tabs */
+ start_offset = tvb_skip_wsp(tvb, start_offset, line_end_offset - start_offset);
+
+ if (start_offset >= line_end_offset)
+ {
+ /* Nothing to parse */
+ return -1;
+ }
+
+ current_offset = start_offset;
+ equals_offset = tvb_find_guint8(tvb, current_offset + 1, line_end_offset - (current_offset + 1), '=');
+ if(equals_offset == -1){
+ /* malformed parameter */
+ return -1;
+ }
+ par_name_end_offset = equals_offset - 1;
+ par_name_end_offset = tvb_skip_wsp_return(tvb,par_name_end_offset);
+
+ /* Extract the parameter name */
+ name = tvb_get_string_enc(wmem_packet_scope(), tvb, start_offset, par_name_end_offset-start_offset, ENC_UTF_8|ENC_NA);
+
+ value_offset = tvb_skip_wsp(tvb, equals_offset + 1, line_end_offset - (equals_offset + 1));
+ if (tvb_get_guint8(tvb, value_offset) == '\"') {
+ /* quoted value */
+ value_search_offset = value_offset;
+ do {
+ value_search_offset++;
+ queried_offset = tvb_find_guint8 (tvb, value_search_offset, line_end_offset - value_search_offset, '\"');
+ } while ((queried_offset != -1) && (tvb_get_guint8(tvb, queried_offset - 1) == '\\'));
+ if (queried_offset == -1) {
+ /* Closing quote not found, return line end */
+ current_offset = line_end_offset;
+ } else {
+ /* Include closing quotes */
+ current_offset = queried_offset + 1;
+ }
+ } else {
+ /* unquoted value */
+ queried_offset = tvb_find_guint8 (tvb, value_offset, line_end_offset - value_offset, ',');
+ if (queried_offset == -1) {
+ /* Last parameter, line end */
+ current_offset = line_end_offset;
+ } else {
+ current_offset = queried_offset;
+ }
+ }
+
+ /* Try to add parameter as a filterable item */
+ for (auth_parameter = &auth_parameters_hf_array[i];
+ i < array_length(auth_parameters_hf_array);
+ i++, auth_parameter++)
+ {
+ if (g_ascii_strcasecmp(name, auth_parameter->param_name) == 0)
+ {
+ proto_tree_add_item(tree, *(auth_parameter->hf_item), tvb,
+ value_offset, current_offset - value_offset,
+ ENC_UTF_8|ENC_NA);
+ if (global_sip_validate_authorization) {
+ gint real_value_offset = value_offset;
+ gint real_value_length = current_offset - value_offset;
+ if ((tvb_get_guint8(tvb, value_offset) == '\"') && (tvb_get_guint8(tvb, current_offset - 1) == '\"') && (real_value_length > 1)) {
+ real_value_offset++;
+ real_value_length -= 2;
+ }
+ if (g_ascii_strcasecmp(name, "response") == 0) {
+ authorization_info->response = tvb_get_string_enc(wmem_packet_scope(), tvb, real_value_offset, real_value_length, ENC_ASCII);
+ } else if (g_ascii_strcasecmp(name, "nc") == 0) {
+ authorization_info->nonce_count = tvb_get_string_enc(wmem_packet_scope(), tvb, real_value_offset, real_value_length, ENC_ASCII);
+ } else if (g_ascii_strcasecmp(name, "username") == 0) {
+ authorization_info->username = tvb_get_string_enc(wmem_packet_scope(), tvb, real_value_offset, real_value_length, ENC_ASCII);
+ } else if (g_ascii_strcasecmp(name, "realm") == 0) {
+ authorization_info->realm = tvb_get_string_enc(wmem_packet_scope(), tvb, real_value_offset, real_value_length, ENC_ASCII);
+ } else if (g_ascii_strcasecmp(name, "algorithm") == 0) {
+ authorization_info->algorithm = tvb_get_string_enc(wmem_packet_scope(), tvb, real_value_offset, real_value_length, ENC_ASCII);
+ } else if (g_ascii_strcasecmp(name, "nonce") == 0) {
+ authorization_info->nonce = tvb_get_string_enc(wmem_packet_scope(), tvb, real_value_offset, real_value_length, ENC_ASCII);
+ } else if (g_ascii_strcasecmp(name, "qop") == 0) {
+ authorization_info->qop = tvb_get_string_enc(wmem_packet_scope(), tvb, real_value_offset, real_value_length, ENC_ASCII);
+ } else if (g_ascii_strcasecmp(name, "cnonce") == 0) {
+ authorization_info->cnonce = tvb_get_string_enc(wmem_packet_scope(), tvb, real_value_offset, real_value_length, ENC_ASCII);
+ } else if (g_ascii_strcasecmp(name, "uri") == 0) {
+ authorization_info->uri = tvb_get_string_enc(wmem_packet_scope(), tvb, real_value_offset, real_value_length, ENC_ASCII);
+ }
+ }
+ break;
+ }
+ }
+
+ /* If not matched, just add as text... */
+ if (i == array_length(auth_parameters_hf_array))
+ {
+ proto_tree_add_format_text(tree, tvb, start_offset, current_offset-start_offset);
+ }
+
+ /* Find comma/end of line */
+ queried_offset = tvb_find_guint8 (tvb, current_offset, line_end_offset - current_offset, ',');
+ if (queried_offset == -1) {
+ current_offset = line_end_offset;
+ } else {
+ current_offset = queried_offset;
+ }
+ return current_offset;
+}
+
+/* Dissect the details of a Reason header
+ * Reason = "Reason" HCOLON reason-value *(COMMA reason-value)
+ * reason-value = protocol *(SEMI reason-params)
+ * protocol = "SIP" / "Q.850" / token
+ * reason-params = protocol-cause / reason-text / reason-extension
+ * protocol-cause = "cause" EQUAL cause
+ * cause = 1*DIGIT
+ * reason-text = "text" EQUAL quoted-string
+ * reason-extension = generic-param
+ */
+static void
+dissect_sip_reason_header(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, gint start_offset, gint line_end_offset){
+
+ gint current_offset, semi_colon_offset, length, end_quote_offset;
+ const guint8 *param_name = NULL;
+ guint cause_value;
+ sip_reason_code_info_t sip_reason_code_info;
+
+ /* skip Spaces and Tabs */
+ start_offset = tvb_skip_wsp(tvb, start_offset, line_end_offset - start_offset);
+
+ if (start_offset >= line_end_offset)
+ {
+ /* Nothing to parse */
+ return;
+ }
+
+ current_offset = start_offset;
+ semi_colon_offset = tvb_find_guint8(tvb, current_offset, line_end_offset-current_offset, ';');
+
+ if(semi_colon_offset == -1)
+ return;
+
+ length = semi_colon_offset - current_offset;
+ proto_tree_add_item_ret_string(tree, hf_sip_reason_protocols, tvb, start_offset, length, ENC_UTF_8|ENC_NA, wmem_packet_scope(), &param_name);
+ current_offset = tvb_find_guint8(tvb, semi_colon_offset, line_end_offset - semi_colon_offset, '=') + 1;
+ /* Do we have a text parameter too? */
+ semi_colon_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, ';');
+
+ if (semi_colon_offset == -1){
+ length = line_end_offset - current_offset;
+ } else {
+ /* Text parmeter exist, set length accordingly */
+ length = semi_colon_offset - current_offset;
+ }
+
+ /* Get cause value */
+ cause_value = (guint)strtoul(tvb_get_string_enc(wmem_packet_scope(), tvb, current_offset, length, ENC_UTF_8 | ENC_NA), NULL, 10);
+
+ if (g_ascii_strcasecmp(param_name, "Q.850") == 0){
+ proto_tree_add_uint(tree, hf_sip_reason_cause_q850, tvb, current_offset, length, cause_value);
+ sip_reason_code_info.protocol_type_num = SIP_PROTO_Q850;
+ }
+ else if (g_ascii_strcasecmp(param_name, "SIP") == 0) {
+ proto_tree_add_uint(tree, hf_sip_reason_cause_sip, tvb, current_offset, length, cause_value);
+ sip_reason_code_info.protocol_type_num = SIP_PROTO_SIP;
+ }
+ else {
+ proto_tree_add_uint(tree, hf_sip_reason_cause_other, tvb, current_offset, length, cause_value);
+ sip_reason_code_info.protocol_type_num = SIP_PROTO_OTHER;
+ }
+
+ if (semi_colon_offset == -1)
+ /* Nothing to parse */
+ return;
+
+ /* reason-text = "text" EQUAL quoted-string */
+ current_offset = tvb_find_guint8(tvb, semi_colon_offset, line_end_offset - semi_colon_offset, '"') + 1;
+ if (current_offset == -1)
+ /* Nothing to parse */
+ return;
+ end_quote_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, '"');
+ if (end_quote_offset == -1)
+ /* Nothing to parse */
+ return;
+ length = end_quote_offset - current_offset;
+ proto_tree_add_item(tree, hf_sip_reason_text, tvb, current_offset, length, ENC_UTF_8 | ENC_NA);
+
+ if (sip_reason_code_handle) {
+ tvbuff_t *next_tvb;
+
+ sip_reason_code_info.cause_value = cause_value;
+
+ next_tvb = tvb_new_subset_length(tvb, current_offset, length);
+ call_dissector_with_data(sip_reason_code_handle, next_tvb, pinfo, tree, &sip_reason_code_info);
+ }
+}
+
+/* Dissect the details of a security client header
+ * sec-mechanism = mechanism-name *(SEMI mech-parameters)
+ * mech-parameters = ( preference / digest-algorithm /
+ * digest-qop / digest-verify / extension )
+ * preference = "q" EQUAL qvalue
+ * qvalue = ( "0" [ "." 0*3DIGIT ] )
+ * / ( "1" [ "." 0*3("0") ] )
+ * digest-algorithm = "d-alg" EQUAL token
+ * digest-qop = "d-qop" EQUAL token
+ * digest-verify = "d-ver" EQUAL LDQUOT 32LHEX RDQUOT
+ * extension = generic-param
+ *
+ *
+ */
+static void
+dissect_sip_sec_mechanism(tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree, gint start_offset, gint line_end_offset){
+
+ gint current_offset, semi_colon_offset, length, par_name_end_offset, equals_offset;
+
+ /* skip Spaces and Tabs */
+ start_offset = tvb_skip_wsp(tvb, start_offset, line_end_offset - start_offset);
+
+ if (start_offset >= line_end_offset)
+ {
+ /* Nothing to parse */
+ return;
+ }
+
+ current_offset = start_offset;
+ semi_colon_offset = tvb_find_guint8(tvb, current_offset, line_end_offset-current_offset, ';');
+ if(semi_colon_offset == -1){
+ semi_colon_offset = line_end_offset;
+ }
+
+ length = semi_colon_offset-current_offset;
+ proto_tree_add_item(tree, hf_sip_sec_mechanism, tvb,
+ start_offset, length,
+ ENC_UTF_8);
+
+ current_offset = current_offset + length + 1;
+
+
+ while(current_offset < line_end_offset){
+ gchar *param_name = NULL, *value = NULL;
+ guint8 hf_index = 0;
+ /* skip Spaces and Tabs */
+ current_offset = tvb_skip_wsp(tvb, current_offset, line_end_offset - current_offset);
+
+ semi_colon_offset = tvb_find_guint8(tvb, current_offset, line_end_offset-current_offset, ';');
+
+ if(semi_colon_offset == -1){
+ semi_colon_offset = line_end_offset;
+ }
+
+ length = semi_colon_offset - current_offset;
+
+ /* Parse parameter and value */
+ equals_offset = tvb_find_guint8(tvb, current_offset + 1, length, '=');
+ if(equals_offset != -1){
+ /* Has value part */
+ par_name_end_offset = equals_offset;
+ /* Extract the parameter name */
+ param_name = tvb_get_string_enc(wmem_packet_scope(), tvb, current_offset, par_name_end_offset-current_offset, ENC_UTF_8|ENC_NA);
+ /* Extract the value */
+ value = tvb_get_string_enc(wmem_packet_scope(), tvb, equals_offset+1, semi_colon_offset-equals_offset+1, ENC_UTF_8|ENC_NA);
+ } else {
+ return;
+ }
+
+
+ while (sec_mechanism_parameters_hf_array[hf_index].param_name) {
+ /* Protection algorithm to be used */
+ if (g_ascii_strcasecmp(param_name, sec_mechanism_parameters_hf_array[hf_index].param_name) == 0) {
+ switch (sec_mechanism_parameters_hf_array[hf_index].para_type) {
+ case MECH_PARA_STRING:
+ proto_tree_add_item(tree, *sec_mechanism_parameters_hf_array[hf_index].hf_item, tvb,
+ equals_offset+1, semi_colon_offset-equals_offset-1,
+ ENC_UTF_8);
+ break;
+ case MECH_PARA_UINT:
+ if (!value) {
+ proto_tree_add_expert(tree, pinfo, &ei_sip_sipsec_malformed,
+ tvb, current_offset, -1);
+ } else {
+ guint32 semi_para;
+ semi_para = (guint32)strtoul(value, NULL, 10);
+ proto_tree_add_uint(tree, *sec_mechanism_parameters_hf_array[hf_index].hf_item, tvb,
+ equals_offset+1, semi_colon_offset-equals_offset-1, semi_para);
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ hf_index++;
+ }
+
+ if (!sec_mechanism_parameters_hf_array[hf_index].param_name) {
+ proto_tree_add_format_text(tree, tvb, current_offset, length);
+ }
+
+ current_offset = semi_colon_offset+1;
+ }
+
+}
+
+/* Dissect the details of a Route (and Record-Route) header */
+static void dissect_sip_route_header(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, hf_sip_uri_t *sip_route_uri_p, gint start_offset, gint line_end_offset)
+{
+ gint current_offset;
+ uri_offset_info uri_offsets;
+
+ current_offset = start_offset;
+
+ /* skip Spaces and Tabs */
+ current_offset = tvb_skip_wsp(tvb, current_offset, line_end_offset - current_offset);
+
+ if (current_offset >= line_end_offset) {
+ return;
+ }
+
+ while (current_offset < line_end_offset) {
+ current_offset = tvb_find_guint8(tvb, current_offset, (line_end_offset - 1) - current_offset, ',');
+
+ if (current_offset != -1) { /* found any ',' ? */
+ sip_uri_offset_init(&uri_offsets);
+ current_offset = dissect_sip_name_addr_or_addr_spec(tvb, pinfo, start_offset, current_offset, &uri_offsets);
+ if(current_offset == -1)
+ return;
+ display_sip_uri(tvb, tree, pinfo, &uri_offsets, sip_route_uri_p);
+
+ current_offset++;
+ start_offset = current_offset + 1;
+
+ } else {
+ /* current_offset = (line_end_offset - 1); */
+
+ sip_uri_offset_init(&uri_offsets);
+ current_offset = dissect_sip_name_addr_or_addr_spec(tvb, pinfo, start_offset, line_end_offset, &uri_offsets);
+ if(current_offset == -1)
+ return;
+ display_sip_uri(tvb, tree, pinfo, &uri_offsets, sip_route_uri_p);
+
+ return;
+ }
+
+ current_offset++;
+ }
+
+ return;
+}
+
+/* Dissect the details of a Via header
+ *
+ * Via = ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
+ * via-parm = sent-protocol LWS sent-by *( SEMI via-params )
+ * via-params = via-ttl / via-maddr
+ * / via-received / via-branch
+ * / via-extension
+ * via-ttl = "ttl" EQUAL ttl
+ * via-maddr = "maddr" EQUAL host
+ * via-received = "received" EQUAL (IPv4address / IPv6address)
+ * via-branch = "branch" EQUAL token
+ * via-extension = generic-param
+ * sent-protocol = protocol-name SLASH protocol-version
+ * SLASH transport
+ * protocol-name = "SIP" / token
+ * protocol-version = token
+ * transport = "UDP" / "TCP" / "TLS" / "SCTP"
+ * / other-transport
+ * sent-by = host [ COLON port ]
+ * ttl = 1*3DIGIT ; 0 to 255
+ *
+ */
+static void dissect_sip_via_header(tvbuff_t *tvb, proto_tree *tree, gint start_offset, gint line_end_offset, packet_info *pinfo)
+{
+ gint current_offset;
+ gint address_start_offset;
+ gint semicolon_offset;
+ gboolean colon_seen;
+ gboolean ipv6_reference;
+ gboolean ipv6_address;
+ guchar c;
+ gchar *param_name = NULL;
+
+ current_offset = start_offset;
+
+ while (1)
+ {
+ /* Reset flags and counters */
+ semicolon_offset = 0;
+ ipv6_reference = FALSE;
+ ipv6_address = FALSE;
+ colon_seen = FALSE;
+
+ /* skip Spaces and Tabs */
+ current_offset = tvb_skip_wsp(tvb, current_offset, line_end_offset - current_offset);
+
+ if (current_offset >= line_end_offset)
+ {
+ /* Nothing more to parse */
+ return;
+ }
+
+ /* Now look for the end of the SIP/2.0/transport parameter.
+ * There may be spaces between the slashes
+ * sent-protocol = protocol-name SLASH protocol-version
+ * SLASH transport
+ */
+
+ current_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, '/');
+ if (current_offset != -1)
+ {
+ current_offset++;
+ current_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, '/');
+ }
+
+ if (current_offset != -1)
+ {
+ current_offset++;
+ /* skip Spaces and Tabs */
+ current_offset = tvb_skip_wsp(tvb, current_offset, line_end_offset - current_offset);
+ } else
+ current_offset = line_end_offset;
+
+
+ /* We should now be at the start of the first transport name (or at the end of the line) */
+
+ /*
+ * transport = "UDP" / "TCP" / "TLS" / "SCTP"
+ * / other-transport
+ */
+ while (current_offset < line_end_offset)
+ {
+ int transport_start_offset = current_offset;
+
+ current_offset = tvb_ws_mempbrk_pattern_guint8(tvb, current_offset, line_end_offset - current_offset, &pbrk_tab_sp_fslash, &c);
+ if (current_offset != -1){
+ proto_tree_add_item(tree, hf_sip_via_transport, tvb, transport_start_offset,
+ current_offset - transport_start_offset, ENC_UTF_8);
+ /* Check if we have more transport parameters */
+ if(c=='/'){
+ current_offset++;
+ continue;
+ }
+ current_offset = tvb_skip_wsp(tvb, current_offset, line_end_offset - current_offset);
+ c = tvb_get_guint8(tvb, current_offset);
+ if(c=='/'){
+ current_offset++;
+ continue;
+ }
+ break;
+ }else{
+ current_offset = line_end_offset;
+ }
+
+ }
+
+ /* skip Spaces and Tabs */
+ current_offset = tvb_skip_wsp(tvb, current_offset, line_end_offset - current_offset);
+
+ /* Now read the address part */
+ address_start_offset = current_offset;
+ while (current_offset < line_end_offset)
+ {
+ current_offset = tvb_ws_mempbrk_pattern_guint8(tvb, current_offset, line_end_offset - current_offset, &pbrk_addr_end, &c);
+ if (current_offset == -1)
+ {
+ current_offset = line_end_offset;
+ break;
+ }
+
+ if (c == '[') {
+ ipv6_reference = TRUE;
+ ipv6_address = TRUE;
+ }
+ else if (c == ']')
+ {
+ ipv6_reference = FALSE;
+ }
+
+ if (colon_seen || (c == ' ') || (c == '\t') || ((c == ':') && (ipv6_reference == FALSE)) || (c == ';'))
+ {
+ break;
+ }
+
+ current_offset++;
+ }
+ /* Add address to tree */
+ if (ipv6_address == TRUE) {
+ proto_tree_add_item(tree, hf_sip_via_sent_by_address, tvb, address_start_offset + 1,
+ current_offset - address_start_offset - 2, ENC_UTF_8);
+ } else {
+ proto_tree_add_item(tree, hf_sip_via_sent_by_address, tvb, address_start_offset,
+ current_offset - address_start_offset, ENC_UTF_8);
+ }
+
+ /* Transport port number may follow ([space] : [space])*/
+ current_offset = tvb_skip_wsp(tvb, current_offset, line_end_offset - current_offset);
+ c = tvb_get_guint8(tvb, current_offset);
+
+ if (c == ':')
+ {
+ /* Port number will follow any space after : */
+ gint port_offset;
+ current_offset++;
+
+ /* Skip optional space after colon */
+ current_offset = tvb_skip_wsp(tvb, current_offset, line_end_offset - current_offset);
+
+ port_offset = current_offset;
+
+ /* Find digits of port number */
+ while (current_offset < line_end_offset)
+ {
+ c = tvb_get_guint8(tvb, current_offset);
+
+ if (!g_ascii_isdigit(c))
+ {
+ if (current_offset > port_offset)
+ {
+ /* Add address port number to tree */
+ guint16 port;
+ gboolean port_valid;
+ proto_item* pi;
+ port_valid = ws_strtou16(tvb_get_string_enc(wmem_packet_scope(), tvb, port_offset,
+ current_offset - port_offset, ENC_UTF_8|ENC_NA), NULL, &port);
+ pi = proto_tree_add_uint(tree, hf_sip_via_sent_by_port, tvb, port_offset,
+ current_offset - port_offset, port);
+ if (!port_valid)
+ expert_add_info(pinfo, pi, &ei_sip_via_sent_by_port);
+ }
+ else
+ {
+ /* Shouldn't see a colon without a port number given */
+ return;
+ }
+ break;
+ }
+
+ current_offset++;
+ }
+ }
+
+ /* skip Spaces and Tabs */
+ current_offset = tvb_skip_wsp(tvb, current_offset, line_end_offset - current_offset);
+
+
+ /* Dissect any parameters found */
+ while (current_offset < line_end_offset)
+ {
+ gboolean equals_found = FALSE;
+ gboolean found_end_of_parameters = FALSE;
+ gint parameter_name_end = 0;
+ header_parameter_t *via_parameter;
+ guint i = 0;
+
+ /* Look for the semicolon that signals the start of a parameter */
+ while (current_offset < line_end_offset)
+ {
+ c = tvb_get_guint8(tvb, current_offset);
+ if (c == ';')
+ {
+ semicolon_offset = current_offset;
+ current_offset++;
+ break;
+ }
+ else
+ if ((c != ' ') && (c != '\t'))
+ {
+ found_end_of_parameters = TRUE;
+ break;
+ }
+ current_offset++;
+ }
+
+ if (found_end_of_parameters)
+ {
+ break;
+ }
+
+ if (current_offset == line_end_offset)
+ {
+ return;
+ }
+
+ /* Look for end of parameter name */
+ while (current_offset < line_end_offset)
+ {
+ c = tvb_get_guint8(tvb, current_offset);
+ if (!g_ascii_isalpha(c) && (c != '-'))
+ {
+ break;
+ }
+ current_offset++;
+ }
+
+ /* Not all params have an = */
+ if (c == '=')
+ {
+ equals_found = TRUE;
+ }
+ parameter_name_end = current_offset;
+
+ /* Read until end of parameter value */
+ current_offset = tvb_ws_mempbrk_pattern_guint8(tvb, current_offset, line_end_offset - current_offset, &pbrk_via_param_end, NULL);
+ if (current_offset == -1)
+ current_offset = line_end_offset;
+
+ /* Note parameter name */
+ param_name = tvb_get_string_enc(wmem_packet_scope(), tvb, semicolon_offset+1,
+ parameter_name_end - semicolon_offset - 1, ENC_UTF_8|ENC_NA);
+
+ /* Try to add parameter as a filterable item */
+ for (via_parameter = &via_parameters_hf_array[i];
+ i < array_length(via_parameters_hf_array);
+ i++, via_parameter++)
+ {
+ if (g_ascii_strcasecmp(param_name, via_parameter->param_name) == 0)
+ {
+ if (equals_found)
+ {
+ proto_item* via_parameter_item;
+ via_parameter_item = proto_tree_add_item(tree, *(via_parameter->hf_item), tvb,
+ parameter_name_end + 1, current_offset - parameter_name_end - 1,
+ ENC_UTF_8 | ENC_NA);
+
+ if (sip_via_branch_handle && g_ascii_strcasecmp(param_name, "branch") == 0)
+ {
+ tvbuff_t *next_tvb;
+ next_tvb = tvb_new_subset_length(tvb, parameter_name_end + 1, current_offset - parameter_name_end - 1);
+
+ call_dissector(sip_via_branch_handle, next_tvb, pinfo, tree);
+ }
+ else if (g_ascii_strcasecmp(param_name, "oc") == 0) {
+ proto_item *ti;
+ char *value = tvb_get_string_enc(wmem_packet_scope(), tvb, parameter_name_end + 1,
+ current_offset - parameter_name_end - 1, ENC_UTF_8 | ENC_NA);
+ ti = proto_tree_add_uint(tree, hf_sip_via_oc_val, tvb,
+ parameter_name_end + 1, current_offset - parameter_name_end - 1,
+ (guint32)strtoul(value, NULL, 10));
+ proto_item_set_generated(ti);
+ }
+ else if (g_ascii_strcasecmp(param_name, "oc-seq") == 0) {
+ proto_item *ti;
+ nstime_t ts;
+ int dec_p_off = tvb_find_guint8(tvb, parameter_name_end + 1, - 1, '.');
+ char *value;
+
+ if(dec_p_off > 0){
+ value = tvb_get_string_enc(wmem_packet_scope(), tvb,
+ parameter_name_end + 1, dec_p_off - parameter_name_end, ENC_UTF_8 | ENC_NA);
+ ts.secs = (time_t)strtoul(value, NULL, 10);
+ value = tvb_get_string_enc(wmem_packet_scope(), tvb,
+ dec_p_off + 1, current_offset - parameter_name_end - 1, ENC_UTF_8 | ENC_NA);
+ ts.nsecs = (guint32)strtoul(value, NULL, 10) * 1000;
+ ti = proto_tree_add_time(tree, hf_sip_oc_seq_timestamp, tvb,
+ parameter_name_end + 1, current_offset - parameter_name_end - 1, &ts);
+ proto_item_set_generated(ti);
+ }
+ } else if (g_ascii_strcasecmp(param_name, "be-route") == 0) {
+ tvbuff_t* next_tvb;
+ next_tvb = tvb_new_subset_length(tvb, parameter_name_end + 1, current_offset - parameter_name_end - 1);
+ call_dissector(sip_via_be_route_handle, next_tvb, pinfo, proto_item_add_subtree(via_parameter_item, ett_sip_via_be_route));
+ }
+ }
+ else
+ {
+ proto_tree_add_item(tree, *(via_parameter->hf_item), tvb,
+ semicolon_offset+1, current_offset-semicolon_offset-1,
+ ENC_UTF_8|ENC_NA);
+ }
+ break;
+ }
+ }
+
+ /* If not matched, just add as text... */
+ if (i == array_length(via_parameters_hf_array))
+ {
+ proto_tree_add_format_text(tree, tvb, semicolon_offset+1, current_offset-semicolon_offset-1);
+ }
+
+ /* skip Spaces and Tabs */
+ current_offset = tvb_skip_wsp(tvb, current_offset, line_end_offset - current_offset);
+
+ /* There may be a comma, followed by more Via entries... */
+ if (current_offset < line_end_offset)
+ {
+ c = tvb_get_guint8(tvb, current_offset);
+ if (c == ',')
+ {
+ /* Skip it and get out of parameter loop */
+ current_offset++;
+ break;
+ }
+ }
+ }
+ }
+}
+
+/* Dissect the details of a Session-ID header
+ *
+ * Session-ID = "Session-ID" HCOLON sess-id
+ * *( SEMI generic-param )
+ * sess-id = 32(DIGIT / %x61-66) ; 32 chars of [0-9a-f]
+ */
+static void dissect_sip_session_id_header(tvbuff_t *tvb, proto_tree *tree, gint start_offset, gint line_end_offset, packet_info *pinfo)
+{
+ gint current_offset, semi_colon_offset, equals_offset, length, logme_end_offset;
+ GByteArray *bytes;
+ proto_item *pi;
+
+ current_offset = start_offset;
+ semi_colon_offset = tvb_find_guint8(tvb, current_offset, line_end_offset-current_offset, ';');
+ if(semi_colon_offset == -1){
+ semi_colon_offset = line_end_offset;
+ }
+
+ length = semi_colon_offset-current_offset;
+ bytes = g_byte_array_sized_new(16);
+ if (length != 0) {
+ pi = proto_tree_add_bytes_item(tree, hf_sip_session_id_sess_id, tvb,
+ start_offset, length, ENC_UTF_8|ENC_STR_HEX|ENC_SEP_NONE,
+ bytes, NULL, NULL);
+ } else {
+ pi = proto_tree_add_item(tree, hf_sip_session_id_sess_id, tvb,
+ start_offset, length, ENC_UTF_8 | ENC_STR_HEX | ENC_SEP_NONE);
+ expert_add_info(pinfo, pi, &ei_sip_session_id_sess_id);
+ }
+
+ current_offset = current_offset + length + 1;
+
+ /* skip Spaces and Tabs */
+ current_offset = tvb_skip_wsp(tvb, current_offset, line_end_offset - current_offset);
+
+ if (current_offset < line_end_offset) {
+ /* Parse parameter and value */
+ equals_offset = tvb_find_guint8(tvb, current_offset + 1, length, '=');
+ if (equals_offset != -1) {
+ /* Extract the parameter name */
+ GByteArray *uuid = g_byte_array_sized_new(16);
+ guint8 *param_name = tvb_get_string_enc(wmem_packet_scope(), tvb, current_offset,
+ tvb_skip_wsp_return(tvb, equals_offset - 1) - current_offset,
+ ENC_UTF_8|ENC_NA);
+
+ if ((bytes->len == 16) && (g_ascii_strcasecmp(param_name, "remote") == 0) &&
+ tvb_get_string_bytes(tvb, equals_offset + 1, line_end_offset - equals_offset - 1,
+ ENC_UTF_8|ENC_STR_HEX|ENC_SEP_NONE, uuid, NULL) &&
+ (uuid->len == 16)) {
+ /* Decode header as draft-ietf-insipid-session-id
+ *
+ * session-id = "Session-ID" HCOLON session-id-value
+ * session-id-value = local-uuid *(SEMI sess-id-param)
+ * local-uuid = sess-uuid / null
+ * remote-uuid = sess-uuid / null
+ * sess-uuid = 32(DIGIT / %x61-66) ;32 chars of [0-9a-f]
+ * sess-id-param = remote-param / generic-param
+ * remote-param = "remote" EQUAL remote-uuid
+ * null = 32("0")
+ */
+ e_guid_t guid;
+
+ proto_item_set_hidden(pi);
+ guid.data1 = (bytes->data[0] << 24) | (bytes->data[1] << 16) |
+ (bytes->data[2] << 8) | bytes->data[3];
+ guid.data2 = (bytes->data[4] << 8) | bytes->data[5];
+ guid.data3 = (bytes->data[6] << 8) | bytes->data[7];
+ memcpy(guid.data4, &bytes->data[8], 8);
+ proto_tree_add_guid(tree, hf_sip_session_id_local_uuid, tvb,
+ start_offset, semi_colon_offset - start_offset, &guid);
+ guid.data1 = (uuid->data[0] << 24) | (uuid->data[1] << 16) |
+ (uuid->data[2] << 8) | uuid->data[3];
+ guid.data2 = (uuid->data[4] << 8) | uuid->data[5];
+ guid.data3 = (uuid->data[6] << 8) | uuid->data[7];
+ memcpy(guid.data4, &uuid->data[8], 8);
+ proto_tree_add_guid(tree, hf_sip_session_id_remote_uuid, tvb,
+ equals_offset + 1, line_end_offset - equals_offset - 1, &guid);
+ /* Decode logme parameter as per https://tools.ietf.org/html/rfc8497
+ *
+ * sess-id-param =/ logme-param
+ * logme-param = "logme"
+ */
+ semi_colon_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, ';');
+ while(semi_colon_offset != -1){
+ current_offset = semi_colon_offset + 1;
+ if(current_offset != line_end_offset){
+ logme_end_offset = current_offset + 5;
+ current_offset = tvb_skip_wsp_return(tvb,semi_colon_offset);
+ /* Extract logme parameter name */
+ gchar *name = tvb_get_string_enc(wmem_packet_scope(), tvb, current_offset,logme_end_offset - current_offset, ENC_UTF_8|ENC_NA);
+ if(g_ascii_strcasecmp(name, "logme") == 0){
+ proto_tree_add_boolean(tree, hf_sip_session_id_logme, tvb, current_offset, logme_end_offset - current_offset, 1);
+ } else if(current_offset != line_end_offset){
+ proto_tree_add_item(tree, hf_sip_session_id_param, tvb, current_offset,line_end_offset - current_offset, ENC_UTF_8);
+ }
+ }
+ semi_colon_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, ';');
+ }
+ } else {
+ /* Display generic parameter */
+ proto_tree_add_item(tree, hf_sip_session_id_param, tvb, current_offset,
+ line_end_offset - current_offset, ENC_UTF_8);
+ }
+ g_byte_array_free(uuid, TRUE);
+ } else {
+ /* Display generic parameter */
+ proto_tree_add_item(tree, hf_sip_session_id_param, tvb, current_offset,
+ line_end_offset - current_offset, ENC_UTF_8);
+ }
+ }
+
+ g_byte_array_free(bytes, TRUE);
+}
+
+/* Dissect the headers for P-Access-Network-Info Headers
+ *
+ * Spec found in 3GPP 24.229 7.2A.4
+ * P-Access-Network-Info = "P-Access-Network-Info" HCOLON
+ * access-net-spec *(COMMA access-net-spec)
+ * access-net-spec = (access-type / access-class) *(SEMI access-info)
+ * access-type = "IEEE-802.11" / "IEEE-802.11a" / "IEEE-802.11b" / "IEEE-802.11g" / "IEEE-802.11n" / "3GPP-GERAN" /
+ * "3GPP-UTRAN-FDD" / "3GPP-UTRAN-TDD" / "3GPP-E-UTRAN-FDD" / "3GPP-E-UTRAN-TDD" / "ADSL" / "ADSL2" /
+ * "ADSL2+" / "RADSL" / "SDSL" / "HDSL" / "HDSL2" / "G.SHDSL" / "VDSL" / "IDSL" / "3GPP2-1X" /
+ * "3GPP2-1X-Femto" / "3GPP2-1X-HRPD" / "3GPP2-UMB" / "DOCSIS" / "IEEE-802.3" / "IEEE-802.3a" /
+ * "IEEE-802.3e" / "IEEE-802.3i" / "IEEE-802.3j" / "IEEE-802.3u" / "IEEE-802.3ab"/ "IEEE-802.3ae" /
+ * "IEEE-802.3ak" / "IEEE-802.3aq" / "IEEE-802.3an" / "IEEE-802.3y" / "IEEE-802.3z" / "GPON" /
+ "XGPON1" / "GSTN"/ token
+ * access-class = "3GPP-GERAN" / "3GPP-UTRAN" / "3GPP-E-UTRAN" / "3GPP-WLAN" / "3GPP-GAN" / "3GPP-HSPA" / token
+ * np = "network-provided"
+ * access-info = cgi-3gpp / utran-cell-id-3gpp / dsl-location / i-wlan-node-id / ci-3gpp2 / ci-3gpp2-femto /
+ eth-location / fiber-location / np / gstn-location / extension-access-info
+ * extension-access-info = gen-value
+ * cgi-3gpp = "cgi-3gpp" EQUAL (token / quoted-string)
+ * utran-cell-id-3gpp = "utran-cell-id-3gpp" EQUAL (token / quoted-string)
+ * i-wlan-node-id = "i-wlan-node-id" EQUAL (token / quoted-string)
+ * dsl-location = "dsl-location" EQUAL (token / quoted-string)
+ * eth-location = "eth-location" EQUAL (token / quoted-string)
+ * fiber-location = "fiber-location" EQUAL (token / quoted-string)
+ * ci-3gpp2 = "ci-3gpp2" EQUAL (token / quoted-string)
+ * ci-3gpp2-femto = "ci-3gpp2-femto" EQUAL (token / quoted-string)
+ * gstn-location = "gstn-location" EQUAL (token / quoted-string)
+ *
+ */
+void dissect_sip_p_access_network_info_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint start_offset, gint line_end_offset)
+{
+
+ gint current_offset, semi_colon_offset, length, par_name_end_offset, equals_offset;
+
+ /* skip Spaces and Tabs */
+ start_offset = tvb_skip_wsp(tvb, start_offset, line_end_offset - start_offset);
+
+ if (start_offset >= line_end_offset)
+ {
+ /* Nothing to parse */
+ return;
+ }
+
+ /* Get the Access Type / Access Class*/
+ current_offset = start_offset;
+ semi_colon_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, ';');
+
+ if (semi_colon_offset == -1)
+ return;
+
+ length = semi_colon_offset - current_offset;
+ proto_tree_add_item(tree, hf_sip_p_acc_net_i_acc_type, tvb, start_offset, length, ENC_UTF_8 | ENC_NA);
+
+ current_offset = current_offset + length + 1;
+
+
+ while (current_offset < line_end_offset){
+ gchar *param_name = NULL;
+
+ /* skip Spaces and Tabs */
+ current_offset = tvb_skip_wsp(tvb, current_offset, line_end_offset - current_offset);
+
+ semi_colon_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, ';');
+
+ if (semi_colon_offset == -1){
+ semi_colon_offset = line_end_offset;
+ }
+
+ length = semi_colon_offset - current_offset;
+
+ /* Parse parameter and value */
+ equals_offset = tvb_find_guint8(tvb, current_offset + 1, length, '=');
+ if (equals_offset != -1){
+ /* Has value part */
+ par_name_end_offset = equals_offset;
+ /* Extract the parameter name */
+ param_name = tvb_get_string_enc(wmem_packet_scope(), tvb, current_offset, par_name_end_offset - current_offset, ENC_UTF_8 | ENC_NA);
+ /* Access-Info fields */
+ if ((param_name != NULL)&&(g_ascii_strcasecmp(param_name, "utran-cell-id-3gpp") == 0)) {
+ proto_tree_add_item(tree, hf_sip_p_acc_net_i_ucid_3gpp, tvb,
+ equals_offset + 1, semi_colon_offset - equals_offset - 1, ENC_UTF_8 | ENC_NA);
+ dissect_e212_mcc_mnc_in_utf8_address(tvb, pinfo, tree, equals_offset + 1);
+ }
+ else {
+ proto_tree_add_format_text(tree, tvb, current_offset, length);
+ }
+ }
+ else {
+ proto_tree_add_format_text(tree, tvb, current_offset, length);
+ }
+
+ current_offset = semi_colon_offset + 1;
+ }
+}
+
+/*
+The syntax for the P-Charging-Vector header field is described as
+follows:
+
+ P-Charging-Vector = "P-Charging-Vector" HCOLON icid-value
+ *(SEMI charge-params)
+ charge-params = icid-gen-addr / orig-ioi / term-ioi /
+ transit-ioi / related-icid /
+ related-icid-gen-addr / generic-param
+ icid-value = "icid-value" EQUAL gen-value
+ icid-gen-addr = "icid-generated-at" EQUAL host
+ orig-ioi = "orig-ioi" EQUAL gen-value
+ term-ioi = "term-ioi" EQUAL gen-value
+ transit-ioi = "transit-ioi" EQUAL transit-ioi-list
+ transit-ioi-list = DQUOTE transit-ioi-param
+ *(COMMA transit-ioi-param) DQUOTE
+ transit-ioi-param = transit-ioi-indexed-value /
+ transit-ioi-void-value
+ transit-ioi-indexed-value = transit-ioi-name "."
+ transit-ioi-index
+ transit-ioi-name = ALPHA *(ALPHA / DIGIT)
+ transit-ioi-index = 1*DIGIT
+ transit-ioi-void-value = "void"
+ related-icid = "related-icid" EQUAL gen-value
+ related-icid-gen-addr = "related-icid-generated-at" EQUAL host
+*/
+static void
+dissect_sip_p_charging_vector_header(tvbuff_t *tvb, proto_tree *tree, gint start_offset, gint line_end_offset)
+{
+
+ gint current_offset, semi_colon_offset, length, equals_offset;
+
+ /* skip Spaces and Tabs */
+ start_offset = tvb_skip_wsp(tvb, start_offset, line_end_offset - start_offset);
+
+ if (start_offset >= line_end_offset)
+ {
+ /* Nothing to parse */
+ return;
+ }
+
+ /* icid-value = "icid-value" EQUAL gen-value */
+ current_offset = start_offset;
+ semi_colon_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, ';');
+
+ if (semi_colon_offset == -1) {
+ /* No parameters, is that allowed?*/
+ semi_colon_offset = line_end_offset;
+ }
+
+ length = semi_colon_offset - current_offset;
+
+ /* Parse parameter and value */
+ equals_offset = tvb_find_guint8(tvb, current_offset + 1, length, '=');
+ if (equals_offset == -1) {
+ /* Does not conform to ABNF */
+ return;
+ }
+
+ /* Get the icid-value */
+ proto_tree_add_item(tree, hf_sip_icid_value, tvb,
+ equals_offset + 1, semi_colon_offset - equals_offset - 1, ENC_UTF_8 | ENC_NA);
+
+ current_offset = semi_colon_offset + 1;
+
+ /* Add the rest of the parameters to the tree */
+ while (current_offset < line_end_offset) {
+ gchar *param_name = NULL;
+ gint par_name_end_offset;
+ /* skip Spaces and Tabs */
+ current_offset = tvb_skip_wsp(tvb, current_offset, line_end_offset - current_offset);
+
+ semi_colon_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, ';');
+
+ if (semi_colon_offset == -1) {
+ semi_colon_offset = line_end_offset;
+ }
+
+ length = semi_colon_offset - current_offset;
+
+ /* Parse parameter and value */
+ equals_offset = tvb_find_guint8(tvb, current_offset + 1, length, '=');
+ if (equals_offset != -1) {
+ /* Has value part */
+ par_name_end_offset = equals_offset;
+ /* Extract the parameter name */
+ param_name = tvb_get_string_enc(wmem_packet_scope(), tvb, current_offset, par_name_end_offset - current_offset, ENC_UTF_8 | ENC_NA);
+ /* charge-params */
+ if ((param_name != NULL) && (g_ascii_strcasecmp(param_name, "icid-gen-addr") == 0)) {
+ proto_tree_add_item(tree, hf_sip_icid_gen_addr, tvb,
+ equals_offset + 1, semi_colon_offset - equals_offset - 1, ENC_UTF_8 | ENC_NA);
+ }
+ else {
+ proto_tree_add_format_text(tree, tvb, current_offset, length);
+ }
+ }
+ else {
+ proto_tree_add_format_text(tree, tvb, current_offset, length);
+ }
+
+ current_offset = semi_colon_offset + 1;
+ }
+
+
+}
+
+/*
+https://tools.ietf.org/html/rfc6809
+The ABNF for the Feature-Caps header fields is:
+
+Feature-Caps = "Feature-Caps" HCOLON fc-value
+*(COMMA fc-value)
+fc-value = "*" *(SEMI feature-cap)
+
+The ABNF for the feature-capability indicator is:
+
+feature-cap = "+" fcap-name [EQUAL LDQUOT (fcap-value-list
+/ fcap-string-value ) RDQUOT]
+fcap-name = ftag-name
+fcap-value-list = tag-value-list
+fcap-string-value = string-value
+;; ftag-name, tag-value-list, string-value defined in RFC 3840
+
+NOTE: In comparison with media feature tags, the "+" sign in front of
+the feature-capability indicator name is mandatory.
+
+*/
+static void
+dissect_sip_p_feature_caps(tvbuff_t *tvb, proto_tree *tree, gint start_offset, gint line_end_offset)
+{
+ gint current_offset, next_offset, length;
+ guint16 semi_plus = 0x3b2b;
+
+ /* skip Spaces and Tabs */
+ next_offset = tvb_skip_wsp(tvb, start_offset, line_end_offset - start_offset);
+
+ if (next_offset >= line_end_offset) {
+ /* Nothing to parse */
+ return;
+ }
+
+ while (next_offset < line_end_offset) {
+ /* Find the end of feature cap or start of feature cap parameter, ";+" should indicate the start of a new feature-cap */
+ current_offset = next_offset;
+ next_offset = tvb_find_guint16(tvb, current_offset, line_end_offset - current_offset, semi_plus);
+ if (next_offset == -1) {
+ length = line_end_offset - current_offset;
+ next_offset = line_end_offset;
+ }
+ else {
+ length = next_offset - current_offset;
+ next_offset += 2;
+ }
+ proto_tree_add_item(tree, hf_sip_feature_cap, tvb, current_offset, length, ENC_UTF_8 | ENC_NA);
+ }
+}
+
+/* Code to actually dissect the packets */
+static int
+dissect_sip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+ guint8 octet;
+ int len;
+ int remaining_length;
+
+ octet = tvb_get_guint8(tvb,0);
+ if ((octet & 0xf8) == 0xf8){
+ call_dissector(sigcomp_handle, tvb, pinfo, tree);
+ return tvb_reported_length(tvb);
+ }
+
+ remaining_length = tvb_reported_length(tvb);
+ len = dissect_sip_common(tvb, 0, remaining_length, pinfo, tree, FALSE, FALSE);
+ if (len < 0)
+ return 0; /* not SIP */
+ else
+ return len;
+}
+
+static int
+dissect_sip_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+ guint8 octet;
+ int offset = 0, linelen;
+ int len;
+ int remaining_length;
+
+ octet = tvb_get_guint8(tvb,0);
+ if ((octet & 0xf8) == 0xf8){
+ call_dissector(sigcomp_handle, tvb, pinfo, tree);
+ return tvb_reported_length(tvb);
+ }
+
+ remaining_length = tvb_reported_length(tvb);
+ /* If we have exactly one non printable byte of payload, this is
+ * probably just a keep alive at the beginning of a capture. Better
+ * to treat it as such than to mark it and everything up to the next
+ * line end as Continuation Data.
+ */
+ if (remaining_length == 1 && !g_ascii_isprint(octet)) {
+ return 0;
+ }
+ /* Check if we have enough data or if we need another segment, as a safty measure set a length limit*/
+ if (remaining_length < 1500){
+ linelen = tvb_find_line_end(tvb, offset, remaining_length, NULL, TRUE);
+ if (linelen == -1){
+ pinfo->desegment_offset = offset;
+ pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
+ return -1;
+ }
+ }
+ len = dissect_sip_common(tvb, offset, remaining_length, pinfo, tree, TRUE, TRUE);
+ if (len <= 0)
+ return len;
+ offset += len;
+ remaining_length = remaining_length - len;
+
+ /*
+ * This is a bit of a cludge as the TCP dissector does not call the dissectors again if not all
+ * the data in the segment was dissected and we do not know if we need another segment or not.
+ * so DESEGMENT_ONE_MORE_SEGMENT can't be used in all cases.
+ *
+ */
+ while (remaining_length > 0) {
+ /* Check if we have enough data or if we need another segment, as a safty measure set a length limit*/
+ if (remaining_length < 1500){
+ linelen = tvb_find_line_end(tvb, offset, remaining_length, NULL, TRUE);
+ if (linelen == -1){
+ pinfo->desegment_offset = offset;
+ pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
+ return -1;
+ }
+ }
+ len = dissect_sip_common(tvb, offset, remaining_length, pinfo, tree, TRUE, TRUE);
+ if (len <= 0)
+ return len;
+ offset += len;
+ remaining_length = remaining_length - len;
+ }
+ return offset;
+}
+
+static gboolean
+dissect_sip_tcp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+ int offset = 0;
+ int len;
+ gboolean first = TRUE;
+ int remaining_length;
+
+ remaining_length = tvb_captured_length(tvb);
+ while (remaining_length > 0) {
+ len = dissect_sip_common(tvb, offset, remaining_length, pinfo, tree, !first, TRUE);
+ if (len == -2) {
+ if (first) {
+ /*
+ * If the first packet doesn't start with
+ * a valid SIP request or response, don't
+ * treat this as SIP.
+ */
+ return FALSE;
+ }
+ break;
+ }
+ if (len == -1)
+ break; /* need more data */
+ offset += len;
+ remaining_length = remaining_length - len;
+ first = FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+dissect_sip_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+ int remaining_length = tvb_captured_length(tvb);
+
+ return dissect_sip_common(tvb, 0, remaining_length, pinfo, tree, FALSE, FALSE) > 0;
+}
+
+static int
+dissect_sip_common(tvbuff_t *tvb, int offset, int remaining_length, packet_info *pinfo, proto_tree *tree,
+ gboolean dissect_other_as_continuation, gboolean use_reassembly)
+{
+ int orig_offset, body_offset;
+ gint next_offset, linelen;
+ int content_length, datalen, reported_datalen;
+ line_type_t line_type;
+ tvbuff_t *next_tvb;
+ gboolean is_known_request;
+ int found_match = 0;
+ const char *descr;
+ guint token_1_len = 0;
+ guint current_method_idx = SIP_METHOD_INVALID;
+ proto_item *ts, *ti_a = NULL, *th = NULL;
+ proto_tree *sip_tree, *reqresp_tree = NULL, *hdr_tree = NULL,
+ *message_body_tree = NULL, *cseq_tree = NULL,
+ *via_tree = NULL, *reason_tree = NULL, *rack_tree = NULL,
+ *route_tree = NULL, *security_client_tree = NULL, *session_id_tree = NULL,
+ *p_access_net_info_tree = NULL;
+ guchar contacts = 0, contact_is_star = 0, expires_is_0 = 0, contacts_expires_0 = 0, contacts_expires_unknown = 0;
+ guint32 cseq_number = 0;
+ guchar cseq_number_set = 0;
+ const char *cseq_method = "";
+ char *call_id = NULL;
+ gchar *media_type_str_lower_case = NULL;
+ media_content_info_t content_info = { MEDIA_CONTAINER_SIP_DATA, NULL, NULL, NULL };
+ char *content_encoding_parameter_str = NULL;
+ guint resend_for_packet = 0;
+ guint request_for_response = 0;
+ guint32 response_time = 0;
+ int strlen_to_copy;
+ heur_dtbl_entry_t *hdtbl_entry;
+
+ /*
+ * If this should be a request of response, do this quick check to see if
+ * it begins with a string...
+ * Otherwise, SIP heuristics are expensive...
+ *
+ */
+
+ if (!dissect_other_as_continuation &&
+ ((remaining_length < 1) || !g_ascii_isprint(tvb_get_guint8(tvb, offset))))
+ {
+ return -2;
+ }
+
+ /*
+ * Note that "tvb_find_line_end()" will return a value that
+ * is not longer than what's in the buffer, so the
+ * "tvb_get_ptr()" calls below won't throw exceptions.
+ *
+ * Note that "tvb_strneql()" doesn't throw exceptions, so
+ * "sip_parse_line()" won't throw an exception.
+ */
+ orig_offset = offset;
+ linelen = tvb_find_line_end(tvb, offset, remaining_length, &next_offset, FALSE);
+ if(linelen==0){
+ return -2;
+ }
+
+ if (tvb_strnlen(tvb, offset, linelen) > -1)
+ {
+ /*
+ * There's a NULL in the line,
+ * this may be SIP within another protocol.
+ * This heuristic still needs to improve.
+ */
+ return -2;
+ }
+ line_type = sip_parse_line(tvb, offset, linelen, &token_1_len);
+
+ if (line_type == OTHER_LINE) {
+ /*
+ * This is neither a SIP request nor response.
+ */
+ if (!dissect_other_as_continuation) {
+ /*
+ * We were asked to reject this.
+ */
+ return -2;
+ }
+
+ /*
+ * Just dissect it as a continuation.
+ */
+ } else if ((use_reassembly)&&( pinfo->ptype == PT_TCP)) {
+ /*
+ * Yes, it's a request or response.
+ * Do header desegmentation if we've been told to,
+ * and do body desegmentation if we've been told to and
+ * we find a Content-Length header.
+ *
+ * RFC 6594, Section 20.14. requires Content-Length for TCP.
+ */
+ if (!req_resp_hdrs_do_reassembly(tvb, offset, pinfo,
+ sip_desegment_headers, sip_desegment_body, FALSE, NULL,
+ NULL, NULL)) {
+ /*
+ * More data needed for desegmentation.
+ */
+ return -1;
+ }
+ }
+
+ /* Initialise stat info for passing to tap
+ * Note: this isn't _only_ for taps - internal code here uses it too
+ * also store stat info in proto_data for subdissectors
+ */
+ stat_info = wmem_new0(pinfo->pool, sip_info_value_t);
+ p_add_proto_data(pinfo->pool, pinfo, proto_sip, pinfo->curr_layer_num, stat_info);
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "SIP");
+
+ if (!pinfo->flags.in_error_pkt && have_tap_listener(exported_pdu_tap)) {
+ wmem_list_frame_t *cur;
+ guint proto_id;
+ const gchar *proto_name;
+ void *tmp;
+
+ /* For SIP messages with other sip messages embeded in the body, don't export those individually.
+ * E.g. if we are called from the mime_multipart dissector don't export the message.
+ */
+ cur = wmem_list_frame_prev(wmem_list_tail(pinfo->layers));
+ tmp = wmem_list_frame_data(cur);
+ proto_id = GPOINTER_TO_UINT(tmp);
+ proto_name = proto_get_protocol_filter_name(proto_id);
+ if (strcmp(proto_name, "mime_multipart") != 0) {
+ export_sip_pdu(pinfo, tvb);
+ }
+ }
+
+ DPRINT2(("------------------------------ dissect_sip_common ------------------------------"));
+
+ switch (line_type) {
+
+ case REQUEST_LINE:
+ is_known_request = sip_is_known_request(tvb, offset, token_1_len, &current_method_idx);
+ descr = is_known_request ? "Request" : "Unknown request";
+ col_add_lstr(pinfo->cinfo, COL_INFO,
+ descr, ": ",
+ tvb_format_text(pinfo->pool, tvb, offset, linelen - SIP2_HDR_LEN - 1),
+ COL_ADD_LSTR_TERMINATOR);
+ DPRINT(("got %s: %s", descr,
+ tvb_format_text(pinfo->pool, tvb, offset, linelen - SIP2_HDR_LEN - 1)));
+ break;
+
+ case STATUS_LINE:
+ descr = "Status";
+ col_add_lstr(pinfo->cinfo, COL_INFO,
+ "Status: ",
+ tvb_format_text(pinfo->pool, tvb, offset + SIP2_HDR_LEN + 1, linelen - SIP2_HDR_LEN - 1),
+ COL_ADD_LSTR_TERMINATOR);
+ stat_info->reason_phrase = tvb_get_string_enc(wmem_packet_scope(), tvb, offset + SIP2_HDR_LEN + 5,
+ linelen - (SIP2_HDR_LEN + 5),ENC_UTF_8|ENC_NA);
+ DPRINT(("got Response: %s",
+ tvb_format_text(pinfo->pool, tvb, offset + SIP2_HDR_LEN + 1, linelen - SIP2_HDR_LEN - 1)));
+ break;
+
+ case OTHER_LINE:
+ default: /* Squelch compiler complaints */
+ descr = "Continuation";
+ col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
+ DPRINT(("got continuation"));
+ break;
+ }
+
+ ts = proto_tree_add_item(tree, proto_sip, tvb, offset, -1, ENC_NA);
+ sip_tree = proto_item_add_subtree(ts, ett_sip);
+
+ switch (line_type) {
+
+ case REQUEST_LINE:
+ if (sip_tree) {
+ ti_a = proto_tree_add_item(sip_tree, hf_Request_Line, tvb,
+ offset, linelen, ENC_UTF_8);
+
+ reqresp_tree = proto_item_add_subtree(ti_a, ett_sip_reqresp);
+ }
+ dfilter_sip_request_line(tvb, reqresp_tree, pinfo, offset, token_1_len, linelen);
+ break;
+
+ case STATUS_LINE:
+ if (sip_tree) {
+ ti_a = proto_tree_add_item(sip_tree, hf_sip_Status_Line, tvb,
+ offset, linelen, ENC_UTF_8);
+ reqresp_tree = proto_item_add_subtree(ti_a, ett_sip_reqresp);
+ }
+ dfilter_sip_status_line(tvb, reqresp_tree, pinfo, linelen, offset);
+ break;
+
+ case OTHER_LINE:
+ if (sip_tree) {
+ reqresp_tree = proto_tree_add_subtree_format(sip_tree, tvb, offset, next_offset,
+ ett_sip_reqresp, NULL, "%s line: %s", descr,
+ tvb_format_text(pinfo->pool, tvb, offset, linelen));
+ /* XXX: Is adding to 'reqresp_tree as intended ? Changed from original 'sip_tree' */
+ proto_tree_add_item(reqresp_tree, hf_sip_continuation, tvb, offset, -1, ENC_NA);
+ }
+ return remaining_length;
+ }
+
+ remaining_length = remaining_length - (next_offset - offset);
+ offset = next_offset;
+
+ body_offset = offset;
+
+ /*
+ * Find the blank line separating the headers from the message body.
+ * Do this now so we can add the msg_hdr FT_STRING item with the correct
+ * length.
+ */
+ content_length = -1;
+ while (remaining_length > 0) {
+ gint line_end_offset;
+ guchar c;
+
+ linelen = tvb_find_line_end(tvb, body_offset, -1, &next_offset, FALSE);
+ if (linelen == 0) {
+ /*
+ * This is a blank line separating the
+ * message header from the message body.
+ */
+ body_offset = next_offset;
+ break;
+ }
+
+ line_end_offset = body_offset + linelen;
+ if(tvb_reported_length_remaining(tvb, next_offset) > 0){
+ while (tvb_offset_exists(tvb, next_offset) && ((c = tvb_get_guint8(tvb, next_offset)) == ' ' || c == '\t'))
+ {
+ /*
+ * This line end is not a header seperator.
+ * It just extends the header with another line.
+ * Look for next line end:
+ */
+ linelen += (next_offset - line_end_offset);
+ linelen += tvb_find_line_end(tvb, next_offset, -1, &next_offset, FALSE);
+ line_end_offset = body_offset + linelen;
+ }
+ }
+ remaining_length = remaining_length - (next_offset - body_offset);
+ body_offset = next_offset;
+ }/* End while */
+
+ remaining_length += (body_offset - offset);
+
+ th = proto_tree_add_item(sip_tree, hf_sip_msg_hdr, tvb, offset,
+ body_offset - offset, ENC_UTF_8);
+ proto_item_set_text(th, "Message Header");
+ hdr_tree = proto_item_add_subtree(th, ett_sip_hdr);
+
+ if (have_tap_listener(sip_follow_tap))
+ tap_queue_packet(sip_follow_tap, pinfo, tvb);
+
+ /*
+ * Process the headers - if we're not building a protocol tree,
+ * we just do this to find the blank line separating the
+ * headers from the message body.
+ */
+ content_length = -1;
+ while (remaining_length > 0) {
+ gint line_end_offset;
+ gint colon_offset;
+ gint semi_colon_offset;
+ gint parameter_offset;
+ gint parameter_end_offset;
+ gint parameter_len;
+ gint content_type_len, content_type_parameter_str_len;
+ gint header_len;
+ gchar *header_name;
+ dissector_handle_t ext_hdr_handle;
+ gint hf_index;
+ gint value_offset;
+ gint sub_value_offset;
+ gint comma_offset;
+ guchar c;
+ gint value_len;
+ gboolean is_no_header_termination = FALSE;
+ proto_tree *tc_uri_item_tree = NULL;
+ uri_offset_info uri_offsets;
+
+ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
+ if (linelen == 0) {
+ /*
+ * This is a blank line separating the
+ * message header from the message body.
+ */
+ offset = next_offset;
+ break;
+ }
+
+ line_end_offset = offset + linelen;
+ if(tvb_reported_length_remaining(tvb, next_offset) <= 0){
+ is_no_header_termination = TRUE;
+ }else{
+ while (tvb_offset_exists(tvb, next_offset) && ((c = tvb_get_guint8(tvb, next_offset)) == ' ' || c == '\t'))
+ {
+ /*
+ * This line end is not a header seperator.
+ * It just extends the header with another line.
+ * Look for next line end:
+ */
+ linelen += (next_offset - line_end_offset);
+ linelen += tvb_find_line_end(tvb, next_offset, -1, &next_offset, FALSE);
+ line_end_offset = offset + linelen;
+ }
+ }
+ colon_offset = tvb_find_guint8(tvb, offset, linelen, ':');
+ if (colon_offset == -1) {
+ /*
+ * Malformed header - no colon after the name.
+ */
+ expert_add_info(pinfo, th, &ei_sip_header_no_colon);
+ } else {
+ header_len = colon_offset - offset;
+ header_name = (gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, header_len, ENC_UTF_8|ENC_NA);
+ ascii_strdown_inplace(header_name);
+ hf_index = sip_is_known_sip_header(header_name, header_len);
+
+ /*
+ * Skip whitespace after the colon.
+ */
+ value_offset = tvb_skip_wsp(tvb, colon_offset + 1, line_end_offset - (colon_offset + 1));
+
+ value_len = (gint) (line_end_offset - value_offset);
+
+ if (hf_index == -1) {
+ gint *hf_ptr = NULL;
+ if (sip_custom_header_fields_hash) {
+ hf_ptr = (gint*)g_hash_table_lookup(sip_custom_header_fields_hash, header_name);
+ }
+ if (hf_ptr) {
+ sip_proto_tree_add_string(hdr_tree, *hf_ptr, tvb, offset,
+ next_offset - offset, value_offset, value_len);
+ } else {
+ proto_item *ti_c;
+ proto_tree *ti_tree = proto_tree_add_subtree(hdr_tree, tvb,
+ offset, next_offset - offset, ett_sip_ext_hdr, &ti_c,
+ tvb_format_text(pinfo->pool, tvb, offset, linelen));
+
+ ext_hdr_handle = dissector_get_string_handle(ext_hdr_subdissector_table, header_name);
+ if (ext_hdr_handle != NULL) {
+ tvbuff_t *next_tvb2;
+ next_tvb2 = tvb_new_subset_length(tvb, value_offset, value_len);
+ dissector_try_string(ext_hdr_subdissector_table, header_name, next_tvb2, pinfo, ti_tree, NULL);
+ } else {
+ expert_add_info_format(pinfo, ti_c, &ei_sip_unrecognized_header,
+ "Unrecognised SIP header (%s)",
+ header_name);
+ }
+ }
+ } else {
+ proto_item *sip_element_item;
+ proto_tree *sip_element_tree;
+
+ /*
+ * Add it to the protocol tree,
+ * but display the line as is.
+ */
+ switch ( hf_index ) {
+
+ case POS_TO :
+
+ /*if(hdr_tree)*/ {
+ proto_item *item;
+
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ sip_element_tree = proto_item_add_subtree( sip_element_item,
+ ett_sip_element);
+ /* To = ( "To" / "t" ) HCOLON ( name-addr
+ * / addr-spec ) *( SEMI to-param )
+ */
+ sip_uri_offset_init(&uri_offsets);
+ if((dissect_sip_name_addr_or_addr_spec(tvb, pinfo, value_offset, line_end_offset+2, &uri_offsets)) != -1){
+ display_sip_uri(tvb, sip_element_tree, pinfo, &uri_offsets, &sip_to_uri);
+ if((uri_offsets.name_addr_start != -1) && (uri_offsets.name_addr_end != -1)){
+ stat_info->tap_to_addr=tvb_get_string_enc(wmem_packet_scope(), tvb, uri_offsets.name_addr_start,
+ uri_offsets.name_addr_end - uri_offsets.name_addr_start + 1, ENC_UTF_8|ENC_NA);
+ }
+ offset = uri_offsets.name_addr_end +1;
+ }
+
+ /* Find parameter tag if present.
+ * TODO make this generic to find any interesting parameter
+ * use the same method as for SIP headers ?
+ */
+
+ parameter_offset = offset;
+ while (parameter_offset < line_end_offset
+ && (tvb_strneql(tvb, parameter_offset, "tag=", 4) != 0))
+ parameter_offset++;
+
+ if ( parameter_offset < line_end_offset ){ /* Tag found */
+ parameter_offset = parameter_offset + 4;
+ parameter_end_offset = tvb_find_guint8(tvb, parameter_offset,
+ (line_end_offset - parameter_offset), ';');
+ if ( parameter_end_offset == -1)
+ parameter_end_offset = line_end_offset;
+ parameter_len = parameter_end_offset - parameter_offset;
+ proto_tree_add_item(sip_element_tree, hf_sip_to_tag, tvb, parameter_offset,
+ parameter_len, ENC_UTF_8);
+ item = proto_tree_add_item(sip_element_tree, hf_sip_tag, tvb, parameter_offset,
+ parameter_len, ENC_UTF_8);
+ proto_item_set_hidden(item);
+
+ /* Tag indicates in-dialog messages, in case we have a INVITE, SUBSCRIBE or REFER, mark it */
+ switch (current_method_idx) {
+
+ case SIP_METHOD_INVITE:
+ case SIP_METHOD_SUBSCRIBE:
+ case SIP_METHOD_REFER:
+ col_append_str(pinfo->cinfo, COL_INFO, ", in-dialog");
+ break;
+ }
+ }
+ } /* if hdr_tree */
+ break;
+
+ case POS_FROM :
+ /*if(hdr_tree)*/ {
+ proto_item *item;
+
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ sip_element_tree = proto_item_add_subtree( sip_element_item, ett_sip_element);
+ /*
+ * From = ( "From" / "f" ) HCOLON from-spec
+ * from-spec = ( name-addr / addr-spec )
+ * *( SEMI from-param )
+ */
+
+ sip_uri_offset_init(&uri_offsets);
+ if((dissect_sip_name_addr_or_addr_spec(tvb, pinfo, value_offset, line_end_offset+2, &uri_offsets)) != -1){
+ display_sip_uri(tvb, sip_element_tree, pinfo, &uri_offsets, &sip_from_uri);
+ if((uri_offsets.name_addr_start != -1) && (uri_offsets.name_addr_end != -1)){
+ stat_info->tap_from_addr=tvb_get_string_enc(wmem_packet_scope(), tvb, uri_offsets.name_addr_start,
+ uri_offsets.name_addr_end - uri_offsets.name_addr_start + 1, ENC_UTF_8|ENC_NA);
+ }
+ offset = uri_offsets.name_addr_end +1;
+ }
+
+ /* Find parameter tag if present.
+ * TODO make this generic to find any interesting parameter
+ * use the same method as for SIP headers ?
+ */
+
+ parameter_offset = offset;
+ while (parameter_offset < line_end_offset
+ && (tvb_strneql(tvb, parameter_offset, "tag=", 4) != 0))
+ parameter_offset++;
+ if ( parameter_offset < line_end_offset ){ /* Tag found */
+ parameter_offset = parameter_offset + 4;
+ parameter_end_offset = tvb_find_guint8(tvb, parameter_offset,
+ (line_end_offset - parameter_offset), ';');
+ if ( parameter_end_offset == -1)
+ parameter_end_offset = line_end_offset;
+ parameter_len = parameter_end_offset - parameter_offset;
+ proto_tree_add_item(sip_element_tree, hf_sip_from_tag, tvb, parameter_offset,
+ parameter_len, ENC_UTF_8);
+ item = proto_tree_add_item(sip_element_tree, hf_sip_tag, tvb, parameter_offset,
+ parameter_len, ENC_UTF_8);
+ proto_item_set_hidden(item);
+ }
+ }/* hdr_tree */
+ break;
+
+ case POS_P_ASSERTED_IDENTITY :
+ if(hdr_tree)
+ {
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ sip_element_tree = proto_item_add_subtree( sip_element_item,
+ ett_sip_element);
+
+ /*
+ * PAssertedID = "P-Asserted-Identity" HCOLON PAssertedID-value
+ * *(COMMA PAssertedID-value)
+ * PAssertedID-value = name-addr / addr-spec
+ *
+ * Initialize the uri_offsets
+ */
+ sip_uri_offset_init(&uri_offsets);
+ if((dissect_sip_name_addr_or_addr_spec(tvb, pinfo, value_offset, line_end_offset+2, &uri_offsets)) != -1)
+ display_sip_uri(tvb, sip_element_tree, pinfo, &uri_offsets, &sip_pai_uri);
+ }
+ break;
+ case POS_P_ASSOCIATED_URI:
+ if (hdr_tree)
+ {
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+ /*
+ * P-Associated-URI = "P-Associated-URI" HCOLON
+ * [p-aso-uri-spec]
+ * *(COMMA p-aso-uri-spec)
+ * p-aso-uri-spec = name-addr *(SEMI ai-param)
+ * ai-param = generic-param
+ */
+ /* Skip to the end of the URI directly */
+ semi_colon_offset = tvb_find_guint8(tvb, value_offset, line_end_offset - value_offset, '>');
+ if (semi_colon_offset != -1) {
+ semi_colon_offset = tvb_find_guint8(tvb, semi_colon_offset, line_end_offset - semi_colon_offset, ';');
+ if (semi_colon_offset != -1) {
+ sip_element_tree = proto_item_add_subtree(sip_element_item,
+ ett_sip_element);
+ /* We have generic parameters */
+ dissect_sip_generic_parameters(tvb, sip_element_tree, pinfo, semi_colon_offset + 1, line_end_offset);
+ }
+ }
+
+ }
+ break;
+ case POS_HISTORY_INFO:
+ if(hdr_tree)
+ {
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ sip_element_tree = proto_item_add_subtree( sip_element_item,
+ ett_sip_hist);
+ dissect_sip_history_info(tvb, sip_element_tree, pinfo, value_offset, line_end_offset);
+ }
+ break;
+
+ case POS_P_CHARGING_FUNC_ADDRESSES:
+ if(hdr_tree)
+ {
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ sip_element_tree = proto_item_add_subtree( sip_element_item,
+ ett_sip_element);
+ dissect_sip_p_charging_func_addresses(tvb, sip_element_tree, pinfo, value_offset, line_end_offset);
+ }
+ break;
+
+ case POS_P_PREFERRED_IDENTITY :
+ if(hdr_tree)
+ {
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ sip_element_tree = proto_item_add_subtree( sip_element_item,
+ ett_sip_element);
+ /*
+ * PPreferredID = "P-Preferred-Identity" HCOLON PPreferredID-value
+ * *(COMMA PPreferredID-value)
+ * PPreferredID-value = name-addr / addr-spec
+ *
+ * Initialize the uri_offsets
+ */
+ sip_uri_offset_init(&uri_offsets);
+ if((dissect_sip_name_addr_or_addr_spec(tvb, pinfo, value_offset, line_end_offset+2, &uri_offsets)) != -1)
+ display_sip_uri(tvb, sip_element_tree, pinfo, &uri_offsets, &sip_ppi_uri);
+ }
+ break;
+
+ case POS_PERMISSION_MISSING :
+ if(hdr_tree)
+ {
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ sip_element_tree = proto_item_add_subtree( sip_element_item,
+ ett_sip_element);
+ /*
+ * Permission-Missing = "Permission-Missing" HCOLON per-miss-spec
+ * *( COMMA per-miss-spec )
+ * per-miss-spec = ( name-addr / addr-spec )
+ * *( SEMI generic-param )
+ * Initialize the uri_offsets
+ */
+ sip_uri_offset_init(&uri_offsets);
+ if((dissect_sip_name_addr_or_addr_spec(tvb, pinfo, value_offset, line_end_offset+2, &uri_offsets)) != -1)
+ display_sip_uri(tvb, sip_element_tree, pinfo, &uri_offsets, &sip_pmiss_uri);
+ }
+ break;
+
+
+ case POS_TRIGGER_CONSENT :
+ if(hdr_tree)
+ {
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ sip_element_tree = proto_item_add_subtree( sip_element_item,
+ ett_sip_element);
+ /*
+ * Trigger-Consent = "Trigger-Consent" HCOLON trigger-cons-spec
+ * *( COMMA trigger-cons-spec )
+ * trigger-cons-spec = ( SIP-URI / SIPS-URI )
+ * *( SEMI trigger-param )
+ * trigger-param = target-uri / generic-param
+ * target-uri = "target-uri" EQUAL
+ * LDQUOT *( qdtext / quoted-pair ) RDQUOT
+ * Initialize the uri_offsets
+ */
+ sip_uri_offset_init(&uri_offsets);
+ if((dissect_sip_uri(tvb, pinfo, value_offset, line_end_offset+2, &uri_offsets)) != -1) {
+
+ tc_uri_item_tree = display_sip_uri(tvb, sip_element_tree, pinfo, &uri_offsets, &sip_tc_uri);
+ if (line_end_offset > uri_offsets.uri_end) {
+ gint hparam_offset = uri_offsets.uri_end + 1;
+ /* Is there a header parameter */
+ if (tvb_find_guint8(tvb, hparam_offset, 1,';')) {
+ while ((hparam_offset != -1 && hparam_offset < line_end_offset) ) {
+ /* Is this a target-uri ? */
+ hparam_offset = hparam_offset + 1;
+ if (tvb_strncaseeql(tvb, hparam_offset, "target-uri=\"", 12) == 0) {
+ gint turi_start_offset = hparam_offset + 12;
+ gint turi_end_offset = tvb_find_guint8(tvb, turi_start_offset, -1,'\"');
+ if (turi_end_offset != -1)
+ proto_tree_add_item(tc_uri_item_tree, hf_sip_tc_turi, tvb, turi_start_offset,(turi_end_offset - turi_start_offset),ENC_UTF_8);
+ else
+ break; /* malformed */
+ }
+ hparam_offset = tvb_find_guint8(tvb, hparam_offset, -1,';');
+ }
+ }
+ }
+ }
+ }/* hdr_tree */
+ break;
+ case POS_RETRY_AFTER:
+ {
+ /* Store the retry number */
+ char *value = tvb_get_string_enc(wmem_packet_scope(), tvb, value_offset, value_len, ENC_UTF_8 | ENC_NA);
+ guint32 retry;
+ gboolean retry_valid = ws_strtou32(value, NULL, &retry);
+
+
+ sip_element_item = proto_tree_add_uint(hdr_tree, hf_header_array[hf_index],
+ tvb, offset, next_offset - offset,
+ retry);
+
+ if (!retry_valid) {
+ expert_add_info(pinfo, sip_element_item, &ei_sip_retry_after_invalid);
+ }
+ }
+ break;
+ case POS_CSEQ :
+ {
+ /* Store the sequence number */
+ char *value = tvb_get_string_enc(wmem_packet_scope(), tvb, value_offset, value_len, ENC_UTF_8|ENC_NA);
+
+ cseq_number = (guint32)strtoul(value, NULL, 10);
+ cseq_number_set = 1;
+ stat_info->tap_cseq_number=cseq_number;
+
+ /* Add CSeq tree */
+ if (hdr_tree) {
+ sip_element_item = proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ cseq_tree = proto_item_add_subtree(sip_element_item, ett_sip_cseq);
+ }
+
+ /* Walk past number and spaces characters to get to start
+ of method name */
+ for (sub_value_offset=0; sub_value_offset < value_len; sub_value_offset++)
+ {
+ if (!g_ascii_isdigit(value[sub_value_offset]))
+ {
+ proto_tree_add_uint(cseq_tree, hf_sip_cseq_seq_no,
+ tvb, value_offset, sub_value_offset,
+ cseq_number);
+ break;
+ }
+ }
+
+ for (; sub_value_offset < value_len; sub_value_offset++)
+ {
+ if (g_ascii_isalpha(value[sub_value_offset]))
+ {
+ /* Have reached start of method name */
+ break;
+ }
+ }
+
+ if (sub_value_offset == value_len)
+ {
+ /* Didn't find method name */
+ return offset - orig_offset;
+ }
+
+ /* Extract method name from value */
+ strlen_to_copy = (int)value_len-sub_value_offset;
+ if (strlen_to_copy > MAX_CSEQ_METHOD_SIZE) {
+ /* Note the error in the protocol tree */
+ proto_tree_add_string_format(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value+sub_value_offset, "%s String too big: %d bytes",
+ sip_headers[POS_CSEQ].name,
+ strlen_to_copy);
+ return offset - orig_offset;
+ }
+ else {
+ /* Add CSeq method to the tree */
+ proto_tree_add_item_ret_string(cseq_tree, hf_sip_cseq_method, tvb,
+ value_offset + sub_value_offset, strlen_to_copy, ENC_UTF_8,
+ pinfo->pool, (const guint8 **)&cseq_method);
+ }
+ }
+ break;
+
+ case POS_RACK :
+ {
+ char *value = tvb_get_string_enc(wmem_packet_scope(), tvb, value_offset, value_len, ENC_UTF_8|ENC_NA);
+ int cseq_no_offset;
+ /*int cseq_method_offset;*/
+
+ /* Add RAck tree */
+ if (hdr_tree) {
+ sip_element_item = proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ rack_tree = proto_item_add_subtree(sip_element_item, ett_sip_rack);
+ }
+
+ /* RSeq number */
+ for (sub_value_offset=0; sub_value_offset < value_len; sub_value_offset++)
+ {
+ if (!g_ascii_isdigit(value[sub_value_offset]))
+ {
+ proto_tree_add_uint(rack_tree, hf_sip_rack_rseq_no,
+ tvb, value_offset, sub_value_offset,
+ (guint32)strtoul(value, NULL, 10));
+ break;
+ }
+ }
+
+ /* Get to start of CSeq number */
+ for ( ; sub_value_offset < value_len; sub_value_offset++)
+ {
+ if (value[sub_value_offset] != ' ' &&
+ value[sub_value_offset] != '\t')
+ {
+ break;
+ }
+ }
+ cseq_no_offset = sub_value_offset;
+
+ /* CSeq number */
+ for ( ; sub_value_offset < value_len; sub_value_offset++)
+ {
+ if (!g_ascii_isdigit(value[sub_value_offset]))
+ {
+ proto_tree_add_uint(rack_tree, hf_sip_rack_cseq_no,
+ tvb, value_offset+cseq_no_offset,
+ sub_value_offset-cseq_no_offset,
+ (guint32)strtoul(value+cseq_no_offset, NULL, 10));
+ break;
+ }
+ }
+
+ /* Get to start of CSeq method name */
+ for ( ; sub_value_offset < value_len; sub_value_offset++)
+ {
+ if (g_ascii_isalpha(value[sub_value_offset]))
+ {
+ /* Have reached start of method name */
+ break;
+ }
+ }
+ /*cseq_method_offset = sub_value_offset;*/
+
+ if (sub_value_offset == linelen)
+ {
+ /* Didn't find method name */
+ return offset - orig_offset;
+ }
+
+ /* Add CSeq method to the tree */
+ if (cseq_tree)
+ {
+ proto_tree_add_item(rack_tree, hf_sip_rack_cseq_method, tvb,
+ value_offset + sub_value_offset,
+ (int)value_len-sub_value_offset, ENC_UTF_8);
+ }
+
+ break;
+ }
+
+ case POS_CALL_ID :
+ {
+ call_id = tvb_get_string_enc(pinfo->pool, tvb, value_offset, value_len, ENC_UTF_8|ENC_NA);
+ proto_item *gen_item;
+
+ /* Store the Call-id */
+ stat_info->tap_call_id = call_id;
+
+ /* Add 'Call-id' string item to tree */
+ sip_element_item = proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ call_id);
+ gen_item = proto_tree_add_string(hdr_tree,
+ hf_sip_call_id_gen, tvb,
+ offset, next_offset - offset,
+ call_id);
+ proto_item_set_generated(gen_item);
+ if (sip_hide_generatd_call_ids) {
+ proto_item_set_hidden(gen_item);
+ }
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+ }
+ break;
+
+ case POS_EXPIRES :
+ if (tvb_strneql(tvb, value_offset, "0", value_len) == 0)
+ {
+ expires_is_0 = 1;
+ }
+
+ /* Add 'Expires' string item to tree */
+ sip_proto_tree_add_uint(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ break;
+
+ /*
+ * Content-Type is the same as Internet
+ * media type used by other dissectors,
+ * appropriate dissector found by
+ * lookup in "media_type" dissector table.
+ */
+ case POS_CONTENT_TYPE :
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ content_type_len = value_len;
+ semi_colon_offset = tvb_find_guint8(tvb, value_offset, value_len, ';');
+ /* Content-Type = ( "Content-Type" / "c" ) HCOLON media-type
+ * media-type = m-type SLASH m-subtype *(SEMI m-parameter)
+ * SEMI = SWS ";" SWS ; semicolon
+ * LWS = [*WSP CRLF] 1*WSP ; linear whitespace
+ * SWS = [LWS] ; sep whitespace
+ */
+ if ( semi_colon_offset != -1) {
+ gint content_type_end;
+ /*
+ * Skip whitespace after the semicolon.
+ */
+ parameter_offset = tvb_skip_wsp(tvb, semi_colon_offset +1, value_offset + value_len - (semi_colon_offset +1));
+ content_type_end = tvb_skip_wsp_return(tvb, semi_colon_offset-1);
+ content_type_len = content_type_end - value_offset;
+ content_type_parameter_str_len = value_offset + value_len - parameter_offset;
+ content_info.media_str = tvb_get_string_enc(wmem_packet_scope(), tvb, parameter_offset,
+ content_type_parameter_str_len, ENC_UTF_8|ENC_NA);
+ }
+ media_type_str_lower_case = ascii_strdown_inplace(
+ (gchar *)tvb_get_string_enc(wmem_packet_scope(), tvb, value_offset, content_type_len, ENC_UTF_8|ENC_NA));
+
+ /* Debug code
+ proto_tree_add_debug_text(hdr_tree, tvb, value_offset,content_type_len,
+ "media_type_str(lower cased)=%s",media_type_str_lower_case);
+ */
+ break;
+
+ case POS_CONTENT_LENGTH :
+ {
+ char *value = tvb_get_string_enc(wmem_packet_scope(), tvb, value_offset, value_len, ENC_UTF_8|ENC_NA);
+ gboolean content_length_valid = ws_strtou32(value, NULL, &content_length);
+
+ sip_element_item = proto_tree_add_uint(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ content_length);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+ if (!content_length_valid)
+ expert_add_info(pinfo, sip_element_item, &ei_sip_content_length_invalid);
+
+ break;
+ }
+
+ case POS_MAX_BREADTH :
+ case POS_MAX_FORWARDS :
+ case POS_RSEQ :
+ sip_proto_tree_add_uint(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ break;
+
+ case POS_CONTACT :
+ /*
+ * Contact = ("Contact" / "m" ) HCOLON
+ * ( STAR / (contact-param *(COMMA contact-param)))
+ * contact-param = (name-addr / addr-spec) *(SEMI contact-params)
+ */
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ sip_element_tree = proto_item_add_subtree( sip_element_item,
+ ett_sip_element);
+
+ /* value_offset points to the first non SWS character after ':' */
+ c = tvb_get_guint8(tvb, value_offset);
+ if (c =='*'){
+ contact_is_star = 1;
+ break;
+ }
+
+ /*if(hdr_tree)*/ {
+ comma_offset = value_offset;
+ while((comma_offset = dissect_sip_contact_item(tvb, pinfo, sip_element_tree, comma_offset,
+ next_offset, &contacts_expires_0, &contacts_expires_unknown)) != -1)
+ {
+ contacts++;
+ if(comma_offset == next_offset)
+ {
+ /* Line End reached: Stop Parsing */
+ break;
+ }
+
+ if(tvb_get_guint8(tvb, comma_offset) != ',')
+ {
+ /* Undefined value reached: Stop Parsing */
+ break;
+ }
+ comma_offset++; /* skip comma */
+ }
+ }
+ break;
+
+ case POS_AUTHORIZATION:
+ /* Authorization = "Authorization" HCOLON credentials
+ * credentials = ("Digest" LWS digest-response)
+ * / other-response
+ * digest-response = dig-resp *(COMMA dig-resp)
+ * other-response = auth-scheme LWS auth-param
+ * *(COMMA auth-param)
+ */
+ case POS_WWW_AUTHENTICATE:
+ /* Proxy-Authenticate = "Proxy-Authenticate" HCOLON challenge
+ * challenge = ("Digest" LWS digest-cln *(COMMA digest-cln))
+ * / other-challenge
+ * other-challenge = auth-scheme LWS auth-param
+ * *(COMMA auth-param)
+ * auth-scheme = token
+ */
+ case POS_PROXY_AUTHENTICATE:
+ /* Proxy-Authenticate = "Proxy-Authenticate" HCOLON challenge
+ */
+ case POS_PROXY_AUTHORIZATION:
+ /* Proxy-Authorization = "Proxy-Authorization" HCOLON credentials
+ */
+ case POS_AUTHENTICATION_INFO:
+ /* Authentication-Info = "Authentication-Info" HCOLON ainfo
+ * *(COMMA ainfo)
+ * ainfo = nextnonce / message-qop
+ * / response-auth / cnonce
+ * / nonce-count
+ */
+ /* Add tree using whole text of line */
+ if (hdr_tree) {
+ proto_item *ti_c;
+ sip_authorization_t authorization_info = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ authorization_user_t * authorization_user = NULL;
+ /* Add whole line as header tree */
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ sip_element_tree = proto_item_add_subtree( sip_element_item,
+ ett_sip_element);
+
+ /* Set sip.auth as a hidden field/filter */
+ ti_c = proto_tree_add_item(hdr_tree, hf_sip_auth, tvb,
+ offset, next_offset-offset,
+ ENC_UTF_8);
+ proto_item_set_hidden(ti_c);
+
+ /* Check if we have any parameters */
+ if ((line_end_offset - value_offset) != 0) {
+ /* Authentication-Info does not begin with the scheme name */
+ if (hf_index != POS_AUTHENTICATION_INFO)
+ {
+ /* The first time comma_offset is "start of parameters" */
+ comma_offset = tvb_ws_mempbrk_pattern_guint8(tvb, value_offset, line_end_offset - value_offset, &pbrk_whitespace, NULL);
+ proto_tree_add_item(sip_element_tree, hf_sip_auth_scheme,
+ tvb, value_offset, comma_offset - value_offset,
+ ENC_UTF_8 | ENC_NA);
+ } else {
+ /* The first time comma_offset is "start of parameters" */
+ comma_offset = value_offset;
+ }
+
+ /* Parse each individual parameter in the line */
+ while ((comma_offset = dissect_sip_authorization_item(tvb, sip_element_tree, comma_offset, line_end_offset, &authorization_info)) != -1)
+ {
+ if (comma_offset == line_end_offset)
+ {
+ /* Line End reached: Stop Parsing */
+ break;
+ }
+
+ if (tvb_get_guint8(tvb, comma_offset) != ',')
+ {
+ /* Undefined value reached: Stop Parsing */
+ break;
+ }
+ comma_offset++; /* skip comma */
+ }
+ if ((authorization_info.response != NULL) && (global_sip_validate_authorization) &&
+ (authorization_info.username != NULL) && (authorization_info.realm != NULL)) { /* If there is a response, check for valid credentials */
+ authorization_user = sip_get_authorization(&authorization_info);
+ if (authorization_user) {
+ authorization_info.method = wmem_strdup(wmem_packet_scope(), stat_info->request_method);
+ if (!sip_validate_authorization(&authorization_info, authorization_user->password)) {
+ proto_tree_add_expert_format(tree, pinfo, &ei_sip_authorization_invalid, tvb, offset, line_end_offset - offset, "SIP digest does not match known password %s", authorization_user->password);
+ }
+ }
+ }
+ } /* Check if we have any parameters */
+ }/*hdr_tree*/
+ break;
+
+ case POS_ROUTE:
+ /* Add Route subtree */
+ if (hdr_tree) {
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ route_tree = proto_item_add_subtree(sip_element_item, ett_sip_route);
+ dissect_sip_route_header(tvb, route_tree, pinfo, &sip_route_uri, value_offset, line_end_offset);
+ }
+ break;
+ case POS_RECORD_ROUTE:
+ /* Add Record-Route subtree */
+ if (hdr_tree) {
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ route_tree = proto_item_add_subtree(sip_element_item, ett_sip_route);
+ dissect_sip_route_header(tvb, route_tree, pinfo, &sip_record_route_uri, value_offset, line_end_offset);
+ }
+ break;
+ case POS_SERVICE_ROUTE:
+ /* Add Service-Route subtree */
+ if (hdr_tree) {
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ route_tree = proto_item_add_subtree(sip_element_item, ett_sip_route);
+ dissect_sip_route_header(tvb, route_tree, pinfo, &sip_service_route_uri, value_offset, line_end_offset);
+ }
+ break;
+ case POS_PATH:
+ /* Add Path subtree */
+ if (hdr_tree) {
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ route_tree = proto_item_add_subtree(sip_element_item, ett_sip_route);
+ dissect_sip_route_header(tvb, route_tree, pinfo, &sip_path_uri, value_offset, line_end_offset);
+ }
+ break;
+ case POS_VIA:
+ /* Add Via subtree */
+ if (hdr_tree) {
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ via_tree = proto_item_add_subtree(sip_element_item, ett_sip_via);
+ dissect_sip_via_header(tvb, via_tree, value_offset, line_end_offset, pinfo);
+ }
+ break;
+ case POS_REASON:
+ if(hdr_tree) {
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ reason_tree = proto_item_add_subtree(sip_element_item, ett_sip_reason);
+ dissect_sip_reason_header(tvb, reason_tree, pinfo, value_offset, line_end_offset);
+ }
+ break;
+ case POS_CONTENT_ENCODING:
+ /* Content-Encoding = ( "Content-Encoding" / "e" ) HCOLON
+ * content-coding *(COMMA content-coding)
+ */
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ content_encoding_parameter_str = ascii_strdown_inplace(tvb_get_string_enc(wmem_packet_scope(), tvb, value_offset,
+ (line_end_offset-value_offset), ENC_UTF_8|ENC_NA));
+ break;
+ case POS_SECURITY_CLIENT:
+ /* security-client = "Security-Client" HCOLON
+ * sec-mechanism *(COMMA sec-mechanism)
+ */
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ comma_offset = tvb_find_guint8(tvb, value_offset, line_end_offset - value_offset, ',');
+ while(comma_offset<line_end_offset){
+ comma_offset = tvb_find_guint8(tvb, value_offset, line_end_offset - value_offset, ',');
+ if(comma_offset == -1){
+ comma_offset = line_end_offset;
+ }
+ security_client_tree = proto_item_add_subtree(sip_element_item, ett_sip_security_client);
+ dissect_sip_sec_mechanism(tvb, pinfo, security_client_tree, value_offset, comma_offset);
+ comma_offset = value_offset = comma_offset+1;
+ }
+
+ break;
+ case POS_SECURITY_SERVER:
+ /* security-server = "Security-Server" HCOLON
+ * sec-mechanism *(COMMA sec-mechanism)
+ */
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ comma_offset = tvb_find_guint8(tvb, value_offset, line_end_offset - value_offset, ',');
+ while(comma_offset<line_end_offset){
+ comma_offset = tvb_find_guint8(tvb, value_offset, line_end_offset - value_offset, ',');
+ if(comma_offset == -1){
+ comma_offset = line_end_offset;
+ }
+ security_client_tree = proto_item_add_subtree(sip_element_item, ett_sip_security_server);
+ dissect_sip_sec_mechanism(tvb, pinfo, security_client_tree, value_offset, comma_offset);
+ comma_offset = value_offset = comma_offset+1;
+ }
+
+ break;
+ case POS_SECURITY_VERIFY:
+ /* security-verify = "Security-Verify" HCOLON
+ * sec-mechanism *(COMMA sec-mechanism)
+ */
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+
+ comma_offset = tvb_find_guint8(tvb, value_offset, line_end_offset - value_offset, ',');
+ while(comma_offset<line_end_offset){
+ comma_offset = tvb_find_guint8(tvb, value_offset, line_end_offset - value_offset, ',');
+ if(comma_offset == -1){
+ comma_offset = line_end_offset;
+ }
+ security_client_tree = proto_item_add_subtree(sip_element_item, ett_sip_security_verify);
+ dissect_sip_sec_mechanism(tvb, pinfo, security_client_tree, value_offset, comma_offset);
+ comma_offset = value_offset = comma_offset+1;
+ }
+
+ break;
+ case POS_SESSION_ID:
+ if(hdr_tree) {
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+ session_id_tree = proto_item_add_subtree(sip_element_item, ett_sip_session_id);
+ dissect_sip_session_id_header(tvb, session_id_tree, value_offset, line_end_offset, pinfo);
+ }
+ break;
+ case POS_P_ACCESS_NETWORK_INFO:
+ /* Add P-Access-Network-Info subtree */
+ if (hdr_tree) {
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+ p_access_net_info_tree = proto_item_add_subtree(sip_element_item, ett_sip_p_access_net_info);
+ dissect_sip_p_access_network_info_header(tvb, pinfo, p_access_net_info_tree, value_offset, line_end_offset);
+ }
+ break;
+ case POS_P_CHARGING_VECTOR:
+ if (hdr_tree) {
+ proto_tree *p_charging_vector_tree;
+
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+ p_charging_vector_tree = proto_item_add_subtree(sip_element_item, ett_sip_p_charging_vector);
+ dissect_sip_p_charging_vector_header(tvb, p_charging_vector_tree, value_offset, line_end_offset);
+ }
+ break;
+ case POS_FEATURE_CAPS:
+ if (hdr_tree) {
+ proto_tree *feature_caps_tree;
+
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+ feature_caps_tree = proto_item_add_subtree(sip_element_item, ett_sip_feature_caps);
+ dissect_sip_p_feature_caps(tvb, feature_caps_tree, value_offset, line_end_offset);
+ }
+ break;
+ default :
+ /* Default case is to assume it's an FT_STRING field */
+ sip_element_item = sip_proto_tree_add_string(hdr_tree,
+ hf_header_array[hf_index], tvb,
+ offset, next_offset - offset,
+ value_offset, value_len);
+ sip_proto_set_format_text(hdr_tree, sip_element_item, tvb, offset, linelen);
+ break;
+ }/* end switch */
+ }/*if HF_index */
+ }/* if colon_offset */
+ if (is_no_header_termination == TRUE){
+ /* Header not terminated by empty line CRLF */
+ proto_tree_add_expert(hdr_tree, pinfo, &ei_sip_header_not_terminated,
+ tvb, line_end_offset, -1);
+ }
+ remaining_length = remaining_length - (next_offset - offset);
+ offset = next_offset;
+ }/* End while */
+
+ datalen = tvb_captured_length_remaining(tvb, offset);
+ reported_datalen = tvb_reported_length_remaining(tvb, offset);
+ if (content_length != -1) {
+ if (datalen > content_length)
+ datalen = content_length;
+ if (reported_datalen > content_length)
+ reported_datalen = content_length;
+ }
+
+ if (!call_id) {
+ call_id = wmem_strdup(pinfo->pool, "");
+ expert_add_info(pinfo, hdr_tree, &ei_sip_call_id_invalid);
+ /* XXX: The hash table lookups below (setup time, request/response,
+ * resend) are less reliable when the mandatory Call-Id header field
+ * is missing.
+ */
+ }
+
+ /* Add to info column interesting things learned from header fields. */
+
+ /* for either REGISTER requests or responses, any contacts without expires
+ * parameter use the Expires header's value
+ */
+ if (expires_is_0) {
+ /* this may add nothing, but that's ok */
+ contacts_expires_0 += contacts_expires_unknown;
+ }
+
+ /* Registration requests */
+ if (current_method_idx == SIP_METHOD_REGISTER)
+ {
+ /* TODO: what if there's a *-contact but also non-*-contacts?
+ * we should create expert info for that someday I guess
+ */
+ if (contact_is_star && expires_is_0)
+ {
+ col_append_str(pinfo->cinfo, COL_INFO, " (remove all bindings)");
+ }
+ else
+ if (contacts_expires_0 > 0)
+ {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (remove %d binding%s)",
+ contacts_expires_0, contacts_expires_0 == 1 ? "":"s");
+ if (contacts > contacts_expires_0) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (add %d binding%s)",
+ contacts - contacts_expires_0,
+ (contacts - contacts_expires_0 == 1) ? "":"s");
+ }
+ }
+ else
+ if (!contacts)
+ {
+ col_append_str(pinfo->cinfo, COL_INFO, " (fetch bindings)");
+ }
+ else
+ {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (%d binding%s)",
+ contacts, contacts == 1 ? "":"s");
+ }
+ }
+
+ /* Registration responses - this info only makes sense in 2xx responses */
+ if (line_type == STATUS_LINE && stat_info)
+ {
+ if (stat_info->response_code == 200)
+ {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", cseq_method);
+ }
+ if ((strcmp(cseq_method, "REGISTER") == 0) &&
+ stat_info->response_code > 199 && stat_info->response_code < 300)
+ {
+ if (contacts_expires_0 > 0) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (removed %d binding%s)",
+ contacts_expires_0, contacts_expires_0 == 1 ? "":"s");
+ if (contacts > contacts_expires_0) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (%d binding%s kept)",
+ contacts - contacts_expires_0,
+ (contacts - contacts_expires_0 == 1) ? "":"s");
+ }
+ } else {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (%d binding%s)",
+ contacts, contacts == 1 ? "":"s");
+ }
+ }
+ }
+
+ /* We've finished writing to the info col for this SIP message
+ * Set fence in case there is more than one (SIP)message in the frame
+ */
+ /* XXX: this produces ugly output, since usually there's only one SIP
+ * message in a frame yet this '|' gets added at the end. Need a better
+ * way to do this.
+ */
+ col_append_str(pinfo->cinfo, COL_INFO, " | ");
+ col_set_fence(pinfo->cinfo, COL_INFO);
+
+ /* Find the total setup time, Must be done before checking for resend
+ * As that will overwrite the "Request packet no".
+ */
+ if ((line_type == REQUEST_LINE)&&(strcmp(cseq_method, "ACK") == 0))
+ {
+ request_for_response = sip_find_invite(pinfo, cseq_method, call_id,
+ cseq_number_set, cseq_number,
+ &response_time);
+ stat_info->setup_time = response_time;
+ }
+
+ /* For responses, try to link back to request frame */
+ if (line_type == STATUS_LINE)
+ {
+ request_for_response = sip_find_request(pinfo, cseq_method, call_id,
+ cseq_number_set, cseq_number,
+ &response_time);
+ }
+
+ /* Check if this packet is a resend. */
+ resend_for_packet = sip_is_packet_resend(pinfo, cseq_method, call_id,
+ cseq_number_set, cseq_number,
+ line_type);
+ /* Mark whether this is a resend for the tap */
+ stat_info->resend = (resend_for_packet > 0);
+
+ /* Report this packet to the tap */
+ if (!pinfo->flags.in_error_pkt)
+ {
+ tap_queue_packet(sip_tap, pinfo, stat_info);
+ }
+
+ if (datalen > 0) {
+ /*
+ * There's a message body starting at "offset".
+ * Set the length of the header item.
+ */
+ sdp_setup_info_t setup_info;
+
+ setup_info.hf_id = hf_sip_call_id_gen;
+ setup_info.add_hidden = sip_hide_generatd_call_ids;
+ setup_info.hf_type = SDP_TRACE_ID_HF_TYPE_STR;
+ setup_info.trace_id.str = wmem_strdup(wmem_file_scope(), call_id);
+ content_info.data = &setup_info;
+
+ if(content_encoding_parameter_str != NULL &&
+ (!strncmp(content_encoding_parameter_str, "gzip", 4) ||
+ !strncmp(content_encoding_parameter_str,"deflate",7))){
+ /* The body is gzip:ed */
+ next_tvb = tvb_child_uncompress(tvb, tvb, offset, datalen);
+ if (next_tvb) {
+ add_new_data_source(pinfo, next_tvb, "gunzipped data");
+ if(sip_tree) {
+ ti_a = proto_tree_add_item(sip_tree, hf_sip_msg_body, next_tvb, 0, -1,
+ ENC_NA);
+ message_body_tree = proto_item_add_subtree(ti_a, ett_sip_message_body);
+ }
+ } else {
+ next_tvb = tvb_new_subset_length_caplen(tvb, offset, datalen, reported_datalen);
+ if(sip_tree) {
+ ti_a = proto_tree_add_item(sip_tree, hf_sip_msg_body, next_tvb, 0, -1,
+ ENC_NA);
+ message_body_tree = proto_item_add_subtree(ti_a, ett_sip_message_body);
+ }
+ }
+ }else{
+ next_tvb = tvb_new_subset_length_caplen(tvb, offset, datalen, reported_datalen);
+ if(sip_tree) {
+ ti_a = proto_tree_add_item(sip_tree, hf_sip_msg_body, next_tvb, 0, -1,
+ ENC_NA);
+ message_body_tree = proto_item_add_subtree(ti_a, ett_sip_message_body);
+ }
+ }
+
+ /* give the content type parameters to sub dissectors */
+ if ( media_type_str_lower_case != NULL ) {
+ /* SDP needs a transport layer to determine request/response */
+ if (!strcmp(media_type_str_lower_case, "application/sdp")) {
+ /* Resends don't count */
+ if (resend_for_packet == 0) {
+ if (line_type == REQUEST_LINE) {
+ DPRINT(("calling setup_sdp_transport() SDP_EXCHANGE_OFFER frame=%d",
+ pinfo->num));
+ DINDENT();
+ setup_sdp_transport(next_tvb, pinfo, SDP_EXCHANGE_OFFER, pinfo->num, sip_delay_sdp_changes, &setup_info);
+ DENDENT();
+ } else if (line_type == STATUS_LINE) {
+ if (stat_info->response_code >= 400) {
+ DPRINT(("calling setup_sdp_transport() SDP_EXCHANGE_ANSWER_REJECT "
+ "request_frame=%d, this=%d",
+ request_for_response, pinfo->num));
+ DINDENT();
+ /* SIP client request failed, so SDP offer should fail */
+ setup_sdp_transport(next_tvb, pinfo, SDP_EXCHANGE_ANSWER_REJECT, request_for_response, sip_delay_sdp_changes, &setup_info);
+ DENDENT();
+ }
+ else if ((stat_info->response_code >= 200) && (stat_info->response_code <= 299)) {
+ DPRINT(("calling setup_sdp_transport() SDP_EXCHANGE_ANSWER_ACCEPT "
+ "request_frame=%d, this=%d",
+ request_for_response, pinfo->num));
+ DINDENT();
+ /* SIP success request, so SDP offer should be accepted */
+ setup_sdp_transport(next_tvb, pinfo, SDP_EXCHANGE_ANSWER_ACCEPT, request_for_response, sip_delay_sdp_changes, &setup_info);
+ DENDENT();
+ }
+ }
+ } else {
+ DPRINT(("calling setup_sdp_transport() resend_for_packet "
+ "request_frame=%d, this=%d",
+ request_for_response, pinfo->num));
+ DINDENT();
+ setup_sdp_transport_resend(pinfo->num, resend_for_packet);
+ DENDENT();
+ }
+ }
+
+ /* XXX: why is this called even if setup_sdp_transport() was called before? That will
+ parse the SDP a second time, for 'application/sdp' media MIME bodies */
+ DPRINT(("calling dissector_try_string()"));
+ DINDENT();
+ found_match = dissector_try_string(media_type_dissector_table,
+ media_type_str_lower_case,
+ next_tvb, pinfo,
+ message_body_tree, &content_info);
+ DENDENT();
+ DPRINT(("done calling dissector_try_string() with found_match=%u", found_match));
+
+ if (!found_match &&
+ !strncmp(media_type_str_lower_case, "multipart/", sizeof("multipart/")-1)) {
+ DPRINT(("calling dissector_try_string() for multipart"));
+ DINDENT();
+ /* Try to decode the unknown multipart subtype anyway */
+ found_match = dissector_try_string(media_type_dissector_table,
+ "multipart/",
+ next_tvb, pinfo,
+ message_body_tree, &content_info);
+ DENDENT();
+ DPRINT(("done calling dissector_try_string() with found_match=%u", found_match));
+ }
+ /* If no match dump as text */
+ }
+ if ( found_match == 0 )
+ {
+ DPRINT(("calling dissector_try_heuristic() with found_match=0"));
+ DINDENT();
+ if (!(dissector_try_heuristic(heur_subdissector_list,
+ next_tvb, pinfo, message_body_tree, &hdtbl_entry, NULL))) {
+ int tmp_offset = 0;
+ while (tvb_offset_exists(next_tvb, tmp_offset)) {
+ tvb_find_line_end(next_tvb, tmp_offset, -1, &next_offset, FALSE);
+ linelen = next_offset - tmp_offset;
+ proto_tree_add_format_text(message_body_tree, next_tvb,
+ tmp_offset, linelen);
+ tmp_offset = next_offset;
+ }/* end while */
+ }
+ DENDENT();
+ }
+ offset += datalen;
+ }
+
+ /* And add the filterable field to the request/response line */
+ if (reqresp_tree)
+ {
+ proto_item *item;
+ item = proto_tree_add_boolean(reqresp_tree, hf_sip_resend, tvb, orig_offset, 0,
+ resend_for_packet > 0);
+ proto_item_set_generated(item);
+ if (resend_for_packet > 0)
+ {
+ item = proto_tree_add_uint(reqresp_tree, hf_sip_original_frame,
+ tvb, orig_offset, 0, resend_for_packet);
+ proto_item_set_generated(item);
+ }
+
+ if (request_for_response > 0)
+ {
+ item = proto_tree_add_uint(reqresp_tree, hf_sip_matching_request_frame,
+ tvb, orig_offset, 0, request_for_response);
+ proto_item_set_generated(item);
+ item = proto_tree_add_uint(reqresp_tree, hf_sip_response_time,
+ tvb, orig_offset, 0, response_time);
+ proto_item_set_generated(item);
+ if ((line_type == STATUS_LINE)&&(strcmp(cseq_method, "BYE") == 0)){
+ item = proto_tree_add_uint(reqresp_tree, hf_sip_release_time,
+ tvb, orig_offset, 0, response_time);
+ proto_item_set_generated(item);
+ }
+ }
+ }
+
+ if (ts != NULL)
+ proto_item_set_len(ts, offset - orig_offset);
+
+ if (global_sip_raw_text)
+ tvb_raw_text_add(tvb, orig_offset, offset - orig_offset, body_offset, pinfo, tree);
+
+ /* Append a brief summary to the SIP root item */
+ if (stat_info->request_method) {
+ proto_item_append_text(ts, " (%s)", stat_info->request_method);
+ }
+ else {
+ proto_item_append_text(ts, " (%u)", stat_info->response_code);
+ }
+ return offset - orig_offset;
+}
+
+/* Display filter for SIP Request-Line */
+static void
+dfilter_sip_request_line(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, gint offset, guint meth_len, gint linelen)
+{
+ const guint8 *value;
+ guint parameter_len = meth_len;
+ uri_offset_info uri_offsets;
+
+ /*
+ * We know we have the entire method; otherwise, "sip_parse_line()"
+ * would have returned OTHER_LINE.
+ * Request-Line = Method SP Request-URI SP SIP-Version CRLF
+ * SP = single space
+ * Request-URI = SIP-URI / SIPS-URI / absoluteURI
+ */
+
+ /* get method string*/
+ proto_tree_add_item_ret_string(tree, hf_sip_Method, tvb, offset, parameter_len, ENC_ASCII | ENC_NA,
+ wmem_packet_scope(), &value);
+
+ /* Copy request method for telling tap */
+ stat_info->request_method = value;
+
+ if (tree) {
+ /* build Request-URI tree*/
+ offset=offset + parameter_len+1;
+ sip_uri_offset_init(&uri_offsets);
+ /* calc R-URI len*/
+ uri_offsets.uri_end = tvb_find_guint8(tvb, offset, linelen, ' ')-1;
+ dissect_sip_uri(tvb, pinfo, offset, offset + linelen, &uri_offsets);
+ display_sip_uri(tvb, tree, pinfo, &uri_offsets, &sip_req_uri);
+ }
+}
+
+/* Display filter for SIP Status-Line */
+static void
+dfilter_sip_status_line(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, gint line_end, gint offset)
+{
+ gint response_code = 0;
+ gboolean response_code_valid;
+ proto_item* pi;
+ int diag_len;
+ tvbuff_t *next_tvb;
+
+ /*
+ * We know we have the entire status code; otherwise,
+ * "sip_parse_line()" would have returned OTHER_LINE.
+ * We also know that we have a version string followed by a
+ * space at the beginning of the line, for the same reason.
+ */
+ offset = offset + SIP2_HDR_LEN + 1;
+ response_code_valid = ws_strtoi32(tvb_get_string_enc(wmem_packet_scope(), tvb, offset, 3,
+ ENC_UTF_8|ENC_NA), NULL, &response_code);
+
+ /* Add numerical response code to tree */
+ pi = proto_tree_add_uint(tree, hf_sip_Status_Code, tvb, offset, 3, response_code);
+ if (!response_code_valid)
+ expert_add_info(pinfo, pi, &ei_sip_Status_Code_invalid);
+
+ /* Add response code for sending to tap */
+ stat_info->response_code = response_code;
+
+ /* Skip past the response code and possible trailing space */
+ offset = offset + 3 + 1;
+
+ /* Check for diagnostics */
+ diag_len = line_end - (SIP2_HDR_LEN + 1 + 3 + 1);
+ if((diag_len) <= 0)
+ return;
+
+ /* If we have a SIP diagnostics sub dissector call it */
+ if(sip_diag_handle){
+ next_tvb = tvb_new_subset_length(tvb, offset, diag_len);
+ call_dissector_only(sip_diag_handle, next_tvb, pinfo, tree, NULL);
+ }
+}
+
+/* From section 4.1 of RFC 2543:
+ *
+ * Request-Line = Method SP Request-URI SP SIP-Version CRLF
+ *
+ * From section 5.1 of RFC 2543:
+ *
+ * Status-Line = SIP-version SP Status-Code SP Reason-Phrase CRLF
+ *
+ * From section 7.1 of RFC 3261:
+ *
+ * Unlike HTTP, SIP treats the version number as a literal string.
+ * In practice, this should make no difference.
+ */
+static line_type_t
+sip_parse_line(tvbuff_t *tvb, int offset, gint linelen, guint *token_1_lenp)
+{
+ gint space_offset;
+ gint token_1_start;
+ guint token_1_len;
+ gint token_2_start;
+ guint token_2_len;
+ gint token_3_start;
+ guint token_3_len;
+ gint colon_pos;
+
+ token_1_start = offset;
+ space_offset = tvb_find_guint8(tvb, token_1_start, -1, ' ');
+ if ((space_offset == -1) || (space_offset == token_1_start)) {
+ /*
+ * Either there's no space in the line (which means
+ * the line is empty or doesn't have a token followed
+ * by a space; neither is valid for a request or status), or
+ * the first character in the line is a space (meaning
+ * the method is empty, which isn't valid for a request,
+ * or the SIP version is empty, which isn't valid for a
+ * status).
+ */
+ return OTHER_LINE;
+ }
+ token_1_len = space_offset - token_1_start;
+ token_2_start = space_offset + 1;
+ space_offset = tvb_find_guint8(tvb, token_2_start, -1, ' ');
+ if (space_offset == -1) {
+ /*
+ * There's no space after the second token, so we don't
+ * have a third token.
+ */
+ return OTHER_LINE;
+ }
+ token_2_len = space_offset - token_2_start;
+ token_3_start = space_offset + 1;
+ token_3_len = token_1_start + linelen - token_3_start;
+
+ *token_1_lenp = token_1_len;
+
+ /*
+ * Is the first token a version string?
+ */
+ if ( (strict_sip_version && (
+ token_1_len == SIP2_HDR_LEN
+ && tvb_strneql(tvb, token_1_start, SIP2_HDR, SIP2_HDR_LEN) == 0)
+ ) || (! strict_sip_version && (
+ tvb_strncaseeql(tvb, token_1_start, "SIP/", 4) == 0)
+ )) {
+ /*
+ * Yes, so this is either a Status-Line or something
+ * else other than a Request-Line. To be a Status-Line,
+ * the second token must be a 3-digit number.
+ */
+ if (token_2_len != 3) {
+ /*
+ * We don't have 3-character status code.
+ */
+ return OTHER_LINE;
+ }
+ if (!g_ascii_isdigit(tvb_get_guint8(tvb, token_2_start)) ||
+ !g_ascii_isdigit(tvb_get_guint8(tvb, token_2_start + 1)) ||
+ !g_ascii_isdigit(tvb_get_guint8(tvb, token_2_start + 2))) {
+ /*
+ * 3 characters yes, 3 digits no.
+ */
+ return OTHER_LINE;
+ }
+ return STATUS_LINE;
+ } else {
+ /*
+ * No, so this is either a Request-Line or something
+ * other than a Status-Line. To be a Request-Line, the
+ * second token must be a URI and the third token must
+ * be a version string.
+ */
+ if (token_2_len < 3) {
+ /*
+ * We don't have a URI consisting of at least 3
+ * characters.
+ */
+ return OTHER_LINE;
+ }
+ colon_pos = tvb_find_guint8(tvb, token_2_start + 1, -1, ':');
+ if (colon_pos == -1) {
+ /*
+ * There is no colon after the method, so the URI
+ * doesn't have a colon in it, so it's not valid.
+ */
+ return OTHER_LINE;
+ }
+ if (colon_pos >= token_3_start) {
+ /*
+ * The colon is in the version string, not the URI.
+ */
+ return OTHER_LINE;
+ }
+ /* XXX - Check for a proper URI prefix? */
+ if ( (strict_sip_version && (
+ token_3_len != SIP2_HDR_LEN
+ || tvb_strneql(tvb, token_3_start, SIP2_HDR, SIP2_HDR_LEN) == -1)
+ ) || (! strict_sip_version && (
+ tvb_strncaseeql(tvb, token_3_start, "SIP/", 4) == -1)
+ )) {
+ /*
+ * The version string isn't an SIP version 2.0 version
+ * string.
+ */
+ return OTHER_LINE;
+ }
+ return REQUEST_LINE;
+ }
+}
+
+static gboolean sip_is_known_request(tvbuff_t *tvb, int meth_offset,
+ guint meth_len, guint *meth_idx)
+{
+ guint i;
+ gchar *meth_name;
+
+ meth_name = tvb_get_string_enc(wmem_packet_scope(), tvb, meth_offset, meth_len, ENC_UTF_8|ENC_NA);
+
+ for (i = 1; i < array_length(sip_methods); i++) {
+ if (meth_len == strlen(sip_methods[i]) &&
+ strncmp(meth_name, sip_methods[i], meth_len) == 0)
+ {
+ *meth_idx = i;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ * Returns index of method in sip_headers
+ * Header namne should be in lower case
+ */
+static gint sip_is_known_sip_header(gchar *header_name, guint header_len)
+{
+ guint pos;
+
+ /* Compact name is one character long */
+ if(header_len>1){
+ pos = GPOINTER_TO_UINT(g_hash_table_lookup(sip_headers_hash, header_name));
+ if (pos!=0)
+ return pos;
+ }
+
+ /* Look for compact name match */
+ for (pos = 1; pos < array_length(sip_headers); pos++) {
+ if (sip_headers[pos].compact_name != NULL &&
+ header_len == strlen(sip_headers[pos].compact_name) &&
+ g_ascii_strncasecmp(header_name, sip_headers[pos].compact_name, header_len) == 0)
+ return pos;
+ }
+
+ return -1;
+}
+
+/*
+ * Display the entire message as raw text.
+ */
+static void
+tvb_raw_text_add(tvbuff_t *tvb, int offset, int length, int body_offset, packet_info* pinfo, proto_tree *tree)
+{
+ proto_tree *raw_tree;
+ proto_item *ti;
+ int next_offset, linelen, end_offset;
+ char *str;
+ tvbuff_t* body_tvb = NULL;
+
+ ti = proto_tree_add_item(tree, proto_raw_sip, tvb, offset, length, ENC_NA);
+ raw_tree = proto_item_add_subtree(ti, ett_raw_text);
+
+ end_offset = offset + length;
+
+ if (body_offset < end_offset
+ && global_sip_raw_text_body_default_encoding != IANA_CS_UTF_8
+ /* UTF-8 compatible with ASCII */
+ && global_sip_raw_text_body_default_encoding != IANA_CS_US_ASCII)
+ {
+ /* Create body tvb with new character encoding */
+ guint32 iana_charset_id = global_sip_raw_text_body_default_encoding;
+ guint ws_encoding_id = mibenum_charset_to_encoding((guint)iana_charset_id);
+
+ if (ws_encoding_id != (ENC_NA | ENC_ASCII) && ws_encoding_id != (ENC_NA | ENC_UTF_8)) {
+ /* Encoding body with the new encoding */
+ gchar* encoding_name = val_to_str_ext_wmem(pinfo->pool, iana_charset_id,
+ &mibenum_vals_character_sets_ext, "UNKNOWN");
+ const guint8* data_str = tvb_get_string_enc(wmem_packet_scope(), tvb, body_offset,
+ end_offset - body_offset, ws_encoding_id);
+ size_t l = strlen(data_str);
+ body_tvb = tvb_new_child_real_data(tvb, data_str, (guint)l, (gint)l);
+ add_new_data_source(pinfo, body_tvb, wmem_strdup_printf(pinfo->pool, "Decoded %s text", encoding_name));
+ }
+ }
+
+ /* Display the headers of SIP message as raw text */
+ while (offset < body_offset) {
+ tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
+ linelen = next_offset - offset;
+ if (raw_tree) {
+ if (global_sip_raw_text_without_crlf)
+ str = tvb_format_text_wsp(wmem_packet_scope(), tvb, offset, linelen);
+ else
+ str = tvb_format_text(wmem_packet_scope(), tvb, offset, linelen);
+ proto_tree_add_string_format(raw_tree, hf_sip_raw_line, tvb, offset, linelen,
+ str,
+ "%s",
+ str);
+ }
+ offset = next_offset;
+ }
+
+ DISSECTOR_ASSERT_HINT(offset == body_offset, "The offset must be equal to body_offset before dissect body as raw text.");
+
+ if (body_offset < end_offset) {
+ /* Dissect the body of SIP message as raw text */
+ if (body_tvb) {
+ offset = 0;
+ end_offset = tvb_captured_length_remaining(body_tvb, 0);
+ } else {
+ body_tvb = tvb; /* reuse old offset and end_offset */
+ }
+
+ while (offset < end_offset) {
+ tvb_find_line_end(body_tvb, offset, -1, &next_offset, FALSE);
+ linelen = next_offset - offset;
+ if (raw_tree) {
+ if (global_sip_raw_text_without_crlf)
+ str = tvb_format_text_wsp(wmem_packet_scope(), body_tvb, offset, linelen);
+ else
+ str = tvb_format_text(wmem_packet_scope(), body_tvb, offset, linelen);
+
+ proto_tree_add_string_format(raw_tree, hf_sip_raw_line, body_tvb, offset,
+ linelen, str, "%s", str);
+ }
+ offset = next_offset;
+ }
+ }
+}
+
+/* Check to see if this packet is a resent request. Return value is the frame number
+ of the original frame this packet seems to be resending (0 = no resend). */
+guint sip_is_packet_resend(packet_info *pinfo,
+ const char *cseq_method,
+ gchar *call_id,
+ guchar cseq_number_set,
+ guint32 cseq_number, line_type_t line_type)
+{
+ guint32 cseq_to_compare = 0;
+ sip_hash_key key;
+ sip_hash_key *p_key = 0;
+ sip_hash_value *p_val = 0;
+ sip_frame_result_value *sip_frame_result = NULL;
+ guint result = 0;
+
+ /* Only consider retransmission of UDP packets */
+ if (pinfo->ptype != PT_UDP)
+ {
+ return 0;
+ }
+
+ /* Don't consider packets that appear to be resent only because
+ they are e.g. returned in ICMP unreachable messages. */
+ if (pinfo->flags.in_error_pkt)
+ {
+ return 0;
+ }
+
+ /* A broken packet may have no cseq number set. Don't consider it as
+ a resend */
+ if (!cseq_number_set)
+ {
+ return 0;
+ }
+
+ /* Return any answer stored from previous dissection */
+ if (pinfo->fd->visited)
+ {
+ sip_frame_result = (sip_frame_result_value*)p_get_proto_data(wmem_file_scope(), pinfo, proto_sip, pinfo->curr_layer_num);
+ if (sip_frame_result != NULL)
+ {
+ return sip_frame_result->original_frame_num;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ /* No packet entry found, consult global hash table */
+
+ /* Prepare the key */
+ (void) g_strlcpy(key.call_id, call_id, MAX_CALL_ID_SIZE);
+
+ /* We're only using these addresses locally (for the hash lookup) so
+ * there is no need to make a (g_malloc'd) copy of them.
+ */
+ set_address(&key.dest_address, pinfo->net_dst.type, pinfo->net_dst.len,
+ pinfo->net_dst.data);
+ set_address(&key.source_address, pinfo->net_src.type,
+ pinfo->net_src.len, pinfo->net_src.data);
+ key.dest_port = pinfo->destport;
+ if (sip_retrans_the_same_sport) {
+ key.source_port = pinfo->srcport;
+ } else {
+ key.source_port = MAGIC_SOURCE_PORT;
+ }
+
+ /* Do the lookup */
+ p_val = (sip_hash_value*)g_hash_table_lookup(sip_hash, &key);
+
+ if (p_val)
+ {
+ /* Table entry found, we'll use its value for comparison */
+ cseq_to_compare = p_val->cseq;
+
+ /* First time through, must update value with current details if
+ cseq number has changed */
+ if (cseq_number != p_val->cseq)
+ {
+ p_val->cseq = cseq_number;
+ p_val->method = wmem_strdup(wmem_file_scope(), cseq_method);
+ p_val->transaction_state = nothing_seen;
+ p_val->frame_number = 0;
+ if (line_type == REQUEST_LINE)
+ {
+ p_val->request_time = pinfo->abs_ts;
+ }
+ }
+ }
+ else
+ {
+ /* Need to create a new table entry */
+
+ /* Allocate a new key and value */
+ p_key = wmem_new(wmem_file_scope(), sip_hash_key);
+ p_val = wmem_new0(wmem_file_scope(), sip_hash_value);
+
+ /* Fill in key and value details */
+ snprintf(p_key->call_id, MAX_CALL_ID_SIZE, "%s", call_id);
+ copy_address_wmem(wmem_file_scope(), &(p_key->dest_address), &pinfo->net_dst);
+ copy_address_wmem(wmem_file_scope(), &(p_key->source_address), &pinfo->net_src);
+ p_key->dest_port = pinfo->destport;
+ if (sip_retrans_the_same_sport) {
+ p_key->source_port = pinfo->srcport;
+ } else {
+ p_key->source_port = MAGIC_SOURCE_PORT;
+ }
+
+ p_val->cseq = cseq_number;
+ p_val->method = wmem_strdup(wmem_file_scope(), cseq_method);
+ p_val->transaction_state = nothing_seen;
+ if (line_type == REQUEST_LINE)
+ {
+ p_val->request_time = pinfo->abs_ts;
+ }
+
+ /* Add entry */
+ g_hash_table_insert(sip_hash, p_key, p_val);
+
+ /* Assume have seen no cseq yet */
+ cseq_to_compare = 0;
+ }
+
+
+ /******************************************/
+ /* Is it a resend??? */
+
+ /* Does this look like a resent request (discount ACK, CANCEL, or a
+ different method from the original one) ? */
+
+ if ((line_type == REQUEST_LINE) && (cseq_number == cseq_to_compare) &&
+ (p_val->transaction_state == request_seen) &&
+ (strcmp(cseq_method, p_val->method) == 0) &&
+ (strcmp(cseq_method, "ACK") != 0) &&
+ (strcmp(cseq_method, "CANCEL") != 0))
+ {
+ result = p_val->frame_number;
+ }
+
+ /* Does this look like a resent final response ? */
+ if ((line_type == STATUS_LINE) && (cseq_number == cseq_to_compare) &&
+ (p_val->transaction_state == final_response_seen) &&
+ (strcmp(cseq_method, p_val->method) == 0) &&
+ (stat_info->response_code >= 200) &&
+ (stat_info->response_code == p_val->response_code))
+ {
+ result = p_val->frame_number;
+ }
+
+ /* Update state for this entry */
+ p_val->cseq = cseq_number;
+
+ switch (line_type)
+ {
+ case REQUEST_LINE:
+ p_val->transaction_state = request_seen;
+ if (!result)
+ {
+ /* This frame is the original request */
+ p_val->frame_number = pinfo->num;
+ p_val->request_time = pinfo->abs_ts;
+ }
+ break;
+ case STATUS_LINE:
+ if (stat_info->response_code >= 200)
+ {
+ p_val->response_code = stat_info->response_code;
+ p_val->transaction_state = final_response_seen;
+ if (!result)
+ {
+ /* This frame is the original response */
+ p_val->frame_number = pinfo->num;
+ }
+ }
+ else
+ {
+ p_val->transaction_state = provisional_response_seen;
+ }
+ break;
+ default:
+ break;
+ }
+
+ sip_frame_result = (sip_frame_result_value *)p_get_proto_data(wmem_file_scope(), pinfo, proto_sip, pinfo->curr_layer_num);
+ if (sip_frame_result == NULL)
+ {
+ sip_frame_result = wmem_new0(wmem_file_scope(), sip_frame_result_value);
+ p_add_proto_data(wmem_file_scope(), pinfo, proto_sip, pinfo->curr_layer_num, sip_frame_result);
+ }
+
+ /* Store return value with this packet */
+ sip_frame_result->original_frame_num = result;
+
+ return result;
+}
+
+
+/* Check to see if this packet is a resent request. Return value is the frame number
+ of the original frame this packet seems to be resending (0 = no resend). */
+guint sip_find_request(packet_info *pinfo,
+ const char *cseq_method,
+ gchar *call_id,
+ guchar cseq_number_set,
+ guint32 cseq_number,
+ guint32 *response_time)
+{
+ guint32 cseq_to_compare = 0;
+ sip_hash_key key;
+ sip_hash_value *p_val = 0;
+ sip_frame_result_value *sip_frame_result = NULL;
+ guint result = 0;
+ gint seconds_between_packets;
+ gint nseconds_between_packets;
+
+ /* Only consider UDP */
+ if (pinfo->ptype != PT_UDP)
+ {
+ return 0;
+ }
+
+ /* Ignore error (usually ICMP) frames */
+ if (pinfo->flags.in_error_pkt)
+ {
+ return 0;
+ }
+
+ /* A broken packet may have no cseq number set. Ignore. */
+ if (!cseq_number_set)
+ {
+ return 0;
+ }
+
+ /* Return any answer stored from previous dissection */
+ if (pinfo->fd->visited)
+ {
+ sip_frame_result = (sip_frame_result_value*)p_get_proto_data(wmem_file_scope(), pinfo, proto_sip, pinfo->curr_layer_num);
+ if (sip_frame_result != NULL)
+ {
+ *response_time = sip_frame_result->response_time;
+ return sip_frame_result->response_request_frame_num;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ /* No packet entry found, consult global hash table */
+
+ /* Prepare the key */
+ (void) g_strlcpy(key.call_id, call_id, MAX_CALL_ID_SIZE);
+
+ /* Looking for matching request, so reverse addresses for this lookup */
+ set_address(&key.dest_address, pinfo->net_src.type, pinfo->net_src.len,
+ pinfo->net_src.data);
+ set_address(&key.source_address, pinfo->net_dst.type, pinfo->net_dst.len,
+ pinfo->net_dst.data);
+ key.dest_port = pinfo->srcport;
+ key.source_port = pinfo->destport;
+
+ /* Do the lookup */
+ p_val = (sip_hash_value*)g_hash_table_lookup(sip_hash, &key);
+
+ if (p_val)
+ {
+ /* Table entry found, we'll use its value for comparison */
+ cseq_to_compare = p_val->cseq;
+ }
+ else
+ {
+ /* We don't have the request */
+ return 0;
+ }
+
+
+ /**************************************************/
+ /* Is it a response to a request that we've seen? */
+ if ((cseq_number == cseq_to_compare) &&
+ (p_val->transaction_state == request_seen) &&
+ (strcmp(cseq_method, p_val->method) == 0))
+ {
+ result = p_val->frame_number;
+ }
+
+
+ /* Store return value with this packet */
+ sip_frame_result = (sip_frame_result_value *)p_get_proto_data(wmem_file_scope(), pinfo, proto_sip, pinfo->curr_layer_num);
+ if (sip_frame_result == NULL)
+ {
+ /* Allocate and set all values to zero */
+ sip_frame_result = wmem_new0(wmem_file_scope(), sip_frame_result_value);
+ p_add_proto_data(wmem_file_scope(), pinfo, proto_sip, pinfo->curr_layer_num, sip_frame_result);
+ }
+
+ sip_frame_result->response_request_frame_num = result;
+
+ /* Work out response time */
+ seconds_between_packets = (gint)
+ (pinfo->abs_ts.secs - p_val->request_time.secs);
+ nseconds_between_packets =
+ pinfo->abs_ts.nsecs - p_val->request_time.nsecs;
+ sip_frame_result->response_time = (seconds_between_packets*1000) +
+ (nseconds_between_packets / 1000000);
+ *response_time = sip_frame_result->response_time;
+
+ return result;
+}
+
+/*
+ * Find the initial INVITE to calculate the total setup time
+ */
+guint sip_find_invite(packet_info *pinfo,
+ const char *cseq_method _U_,
+ gchar *call_id,
+ guchar cseq_number_set,
+ guint32 cseq_number _U_,
+ guint32 *response_time)
+{
+#if 0
+ guint32 cseq_to_compare = 0;
+#endif
+ sip_hash_key key;
+ sip_hash_value *p_val = 0;
+ sip_frame_result_value *sip_frame_result = NULL;
+ guint result = 0;
+ gint seconds_between_packets;
+ gint nseconds_between_packets;
+
+ /* Only consider UDP */
+ if (pinfo->ptype != PT_UDP)
+ {
+ return 0;
+ }
+
+ /* Ignore error (usually ICMP) frames */
+ if (pinfo->flags.in_error_pkt)
+ {
+ return 0;
+ }
+
+ /* A broken packet may have no cseq number set. Ignore. */
+ if (!cseq_number_set)
+ {
+ return 0;
+ }
+
+ /* Return any answer stored from previous dissection */
+ if (pinfo->fd->visited)
+ {
+ sip_frame_result = (sip_frame_result_value*)p_get_proto_data(wmem_file_scope(), pinfo, proto_sip, pinfo->curr_layer_num);
+ if (sip_frame_result != NULL)
+ {
+ *response_time = sip_frame_result->response_time;
+ return sip_frame_result->response_request_frame_num;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ /* No packet entry found, consult global hash table */
+
+ /* Prepare the key */
+ (void) g_strlcpy(key.call_id, call_id, MAX_CALL_ID_SIZE);
+
+ /* Looking for matching INVITE */
+ set_address(&key.dest_address, pinfo->net_dst.type, pinfo->net_dst.len,
+ pinfo->net_dst.data);
+ set_address(&key.source_address, pinfo->net_src.type, pinfo->net_src.len,
+ pinfo->net_src.data);
+ key.dest_port = pinfo->destport;
+ key.source_port = pinfo->srcport;
+
+ /* Do the lookup */
+ p_val = (sip_hash_value*)g_hash_table_lookup(sip_hash, &key);
+
+ if (p_val)
+ {
+#if 0
+ /* Table entry found, we'll use its value for comparison */
+ cseq_to_compare = p_val->cseq;
+#endif
+ }
+ else
+ {
+ /* We don't have the request */
+ return 0;
+ }
+
+
+ /**************************************************/
+ /* Is it a response to a request that we've seen? */
+#if 0
+ if ((cseq_number == cseq_to_compare) &&
+ (p_val->transaction_state == request_seen) &&
+ (strcmp(cseq_method, p_val->method) == 0))
+ {
+ result = p_val->frame_number;
+ }
+#endif
+
+ result = p_val->frame_number;
+
+ /* Store return value with this packet */
+ sip_frame_result = (sip_frame_result_value *)p_get_proto_data(wmem_file_scope(), pinfo, proto_sip, pinfo->curr_layer_num);
+ if (sip_frame_result == NULL)
+ {
+ /* Allocate and set all values to zero */
+ sip_frame_result = wmem_new0(wmem_file_scope(), sip_frame_result_value);
+ p_add_proto_data(wmem_file_scope(), pinfo, proto_sip, pinfo->curr_layer_num, sip_frame_result);
+ }
+
+ sip_frame_result->response_request_frame_num = result;
+
+ /* Work out response time */
+ seconds_between_packets = (gint)
+ (pinfo->abs_ts.secs - p_val->request_time.secs);
+ nseconds_between_packets =
+ pinfo->abs_ts.nsecs - p_val->request_time.nsecs;
+ sip_frame_result->response_time = (seconds_between_packets*1000) +
+ (nseconds_between_packets / 1000000);
+ *response_time = sip_frame_result->response_time;
+
+
+ return result;
+}
+
+static gboolean sip_validate_authorization(sip_authorization_t *authorization_info, gchar *password) {
+ gchar ha1[33] = {0};
+ gchar ha2[33] = {0};
+ gchar response[33] = {0};
+ gcry_md_hd_t md5_handle;
+ if ( (authorization_info->qop == NULL) ||
+ (authorization_info->username == NULL) ||
+ (authorization_info->realm == NULL) ||
+ (authorization_info->method == NULL) ||
+ (authorization_info->uri == NULL) ||
+ (authorization_info->nonce == NULL) ) {
+ return TRUE; /* If no qop, discard */
+ }
+ if (strcmp(authorization_info->qop, "auth") ||
+ (authorization_info->nonce_count == NULL) ||
+ (authorization_info->cnonce == NULL) ||
+ (authorization_info->response == NULL) ||
+ (password == NULL)) {
+ return TRUE; /* Obsolete or not enough information, discard */
+ }
+
+ if (gcry_md_open(&md5_handle, GCRY_MD_MD5, 0)) {
+ return FALSE;
+ }
+
+ gcry_md_write(md5_handle, authorization_info->username, strlen(authorization_info->username));
+ gcry_md_putc(md5_handle, ':');
+ gcry_md_write(md5_handle, authorization_info->realm, strlen(authorization_info->realm));
+ gcry_md_putc(md5_handle, ':');
+ gcry_md_write(md5_handle, password, strlen(password));
+ /* Array is zeroed out so there is always a \0 at index 32 for string termination */
+ bytes_to_hexstr(ha1, gcry_md_read(md5_handle, 0), HASH_MD5_LENGTH);
+ gcry_md_reset(md5_handle);
+ gcry_md_write(md5_handle, authorization_info->method, strlen(authorization_info->method));
+ gcry_md_putc(md5_handle, ':');
+ gcry_md_write(md5_handle, authorization_info->uri, strlen(authorization_info->uri));
+ /* Array is zeroed out so there is always a \0 at index 32 for string termination */
+ bytes_to_hexstr(ha2, gcry_md_read(md5_handle, 0), HASH_MD5_LENGTH);
+ gcry_md_reset(md5_handle);
+ gcry_md_write(md5_handle, ha1, strlen(ha1));
+ gcry_md_putc(md5_handle, ':');
+ gcry_md_write(md5_handle, authorization_info->nonce, strlen(authorization_info->nonce));
+ gcry_md_putc(md5_handle, ':');
+ gcry_md_write(md5_handle, authorization_info->nonce_count, strlen(authorization_info->nonce_count));
+ gcry_md_putc(md5_handle, ':');
+ gcry_md_write(md5_handle, authorization_info->cnonce, strlen(authorization_info->cnonce));
+ gcry_md_putc(md5_handle, ':');
+ gcry_md_write(md5_handle, authorization_info->qop, strlen(authorization_info->qop));
+ gcry_md_putc(md5_handle, ':');
+ gcry_md_write(md5_handle, ha2, strlen(ha2));
+ /* Array is zeroed out so there is always a \0 at index 32 for string termination */
+ bytes_to_hexstr(response, gcry_md_read(md5_handle, 0), HASH_MD5_LENGTH);
+ gcry_md_close(md5_handle);
+ if (!strncmp(response, authorization_info->response, 32)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* TAP STAT INFO */
+
+/*
+ * Much of this is from ui/gtk/sip_stat.c:
+ * sip_stat 2004 Martin Mathieson
+ */
+
+/* TODO: extra codes to be added from SIP extensions?
+ * https://www.iana.org/assignments/sip-parameters/sip-parameters.xhtml#sip-parameters-6
+ */
+const value_string sip_response_code_vals[] = {
+ { 999, "Unknown response"}, /* Must be first */
+
+ { 100, "Trying"},
+ { 180, "Ringing"},
+ { 181, "Call Is Being Forwarded"},
+ { 182, "Queued"},
+ { 183, "Session Progress"},
+ { 199, "Informational - Others" },
+
+ { 200, "OK"},
+ { 202, "Accepted"},
+ { 204, "No Notification"},
+ { 299, "Success - Others"}, /* used to keep track of other Success packets */
+
+ { 300, "Multiple Choices"},
+ { 301, "Moved Permanently"},
+ { 302, "Moved Temporarily"},
+ { 305, "Use Proxy"},
+ { 380, "Alternative Service"},
+ { 399, "Redirection - Others"},
+
+ { 400, "Bad Request"},
+ { 401, "Unauthorized"},
+ { 402, "Payment Required"},
+ { 403, "Forbidden"},
+ { 404, "Not Found"},
+ { 405, "Method Not Allowed"},
+ { 406, "Not Acceptable"},
+ { 407, "Proxy Authentication Required"},
+ { 408, "Request Timeout"},
+ { 410, "Gone"},
+ { 412, "Conditional Request Failed"},
+ { 413, "Request Entity Too Large"},
+ { 414, "Request-URI Too Long"},
+ { 415, "Unsupported Media Type"},
+ { 416, "Unsupported URI Scheme"},
+ { 420, "Bad Extension"},
+ { 421, "Extension Required"},
+ { 422, "Session Timer Too Small"},
+ { 423, "Interval Too Brief"},
+ { 428, "Use Identity Header"},
+ { 429, "Provide Referrer Identity"},
+ { 430, "Flow Failed"},
+ { 433, "Anonymity Disallowed"},
+ { 436, "Bad Identity-Info"},
+ { 437, "Unsupported Certificate"},
+ { 438, "Invalid Identity Header"},
+ { 439, "First Hop Lacks Outbound Support"},
+ { 440, "Max-Breadth Exceeded"},
+ { 470, "Consent Needed"},
+ { 480, "Temporarily Unavailable"},
+ { 481, "Call/Transaction Does Not Exist"},
+ { 482, "Loop Detected"},
+ { 483, "Too Many Hops"},
+ { 484, "Address Incomplete"},
+ { 485, "Ambiguous"},
+ { 486, "Busy Here"},
+ { 487, "Request Terminated"},
+ { 488, "Not Acceptable Here"},
+ { 489, "Bad Event"},
+ { 491, "Request Pending"},
+ { 493, "Undecipherable"},
+ { 494, "Security Agreement Required"},
+ { 499, "Client Error - Others"},
+
+ { 500, "Server Internal Error"},
+ { 501, "Not Implemented"},
+ { 502, "Bad Gateway"},
+ { 503, "Service Unavailable"},
+ { 504, "Server Time-out"},
+ { 505, "Version Not Supported"},
+ { 513, "Message Too Large"},
+ { 599, "Server Error - Others"},
+
+ { 600, "Busy Everywhere"},
+ { 603, "Decline"},
+ { 604, "Does Not Exist Anywhere"},
+ { 606, "Not Acceptable"},
+ { 607, "Unwanted"},
+ { 608, "Rejected"},
+ { 699, "Global Failure - Others"},
+
+ { 0, NULL}
+};
+#define RESPONSE_CODE_MIN 100
+#define RESPONSE_CODE_MAX 699
+
+typedef enum
+{
+ REQ_RESP_METHOD_COLUMN,
+ COUNT_COLUMN,
+ RESENT_COLUMN,
+ MIN_SETUP_COLUMN,
+ AVG_SETUP_COLUMN,
+ MAX_SETUP_COLUMN
+} sip_stat_columns;
+
+static stat_tap_table_item sip_stat_fields[] = {
+ {TABLE_ITEM_STRING, TAP_ALIGN_LEFT, "Request Method / Response Code", "%-25s"},
+ {TABLE_ITEM_UINT, TAP_ALIGN_RIGHT, "Count", "%d"},
+ {TABLE_ITEM_UINT, TAP_ALIGN_RIGHT, "Resent", "%d"},
+ {TABLE_ITEM_FLOAT, TAP_ALIGN_RIGHT, "Min Setup (s)", "%8.2f"},
+ {TABLE_ITEM_FLOAT, TAP_ALIGN_RIGHT, "Avg Setup (s)", "%8.2f"},
+ {TABLE_ITEM_FLOAT, TAP_ALIGN_RIGHT, "Max Setup (s)", "%8.2f"},
+};
+
+static const char *req_table_name = "SIP Requests";
+static const char *resp_table_name = "SIP Responses";
+
+static void sip_stat_init(stat_tap_table_ui* new_stat)
+{
+ /* XXX Should we have a single request + response table instead? */
+ int num_fields = sizeof(sip_stat_fields)/sizeof(stat_tap_table_item);
+ stat_tap_table *req_table;
+ stat_tap_table *resp_table;
+ stat_tap_table_item_type items[sizeof(sip_stat_fields)/sizeof(stat_tap_table_item)];
+ guint i;
+
+ // These values are fixed for all entries.
+ items[REQ_RESP_METHOD_COLUMN].type = TABLE_ITEM_STRING;
+ items[COUNT_COLUMN].type = TABLE_ITEM_UINT;
+ items[COUNT_COLUMN].user_data.uint_value = 0;
+ items[COUNT_COLUMN].value.uint_value = 0;
+ items[RESENT_COLUMN].type = TABLE_ITEM_UINT;
+ items[RESENT_COLUMN].value.uint_value = 0;
+ items[MIN_SETUP_COLUMN].type = TABLE_ITEM_FLOAT;
+ items[MIN_SETUP_COLUMN].user_data.uint_value = 0;
+ items[MIN_SETUP_COLUMN].value.float_value = 0.0f;
+ items[AVG_SETUP_COLUMN].type = TABLE_ITEM_FLOAT;
+ items[AVG_SETUP_COLUMN].user_data.float_value = 0.0f;
+ items[AVG_SETUP_COLUMN].value.float_value = 0.0f;
+ items[MAX_SETUP_COLUMN].type = TABLE_ITEM_FLOAT;
+ items[MAX_SETUP_COLUMN].value.float_value = 0.0f;
+
+ req_table = stat_tap_find_table(new_stat, req_table_name);
+ if (req_table) {
+ if (new_stat->stat_tap_reset_table_cb)
+ new_stat->stat_tap_reset_table_cb(req_table);
+ }
+ else {
+ req_table = stat_tap_init_table(req_table_name, num_fields, 0, NULL);
+ stat_tap_add_table(new_stat, req_table);
+
+ // For req_table, first column value is method.
+ for (i = 1; i < array_length(sip_methods); i++) {
+ items[REQ_RESP_METHOD_COLUMN].value.string_value = g_strdup(sip_methods[i]);
+ stat_tap_init_table_row(req_table, i-1, num_fields, items);
+ }
+ }
+
+ resp_table = stat_tap_find_table(new_stat, resp_table_name);
+ if (resp_table) {
+ if (new_stat->stat_tap_reset_table_cb)
+ new_stat->stat_tap_reset_table_cb(resp_table);
+ }
+ else {
+ resp_table = stat_tap_init_table(resp_table_name, num_fields, 0, NULL);
+ stat_tap_add_table(new_stat, resp_table);
+
+ // For responses entries, first column gets code and description.
+ for (i = 1; sip_response_code_vals[i].strptr; i++) {
+ unsigned response_code = sip_response_code_vals[i].value;
+ items[REQ_RESP_METHOD_COLUMN].value.string_value =
+ ws_strdup_printf("%u %s", response_code, sip_response_code_vals[i].strptr);
+ items[REQ_RESP_METHOD_COLUMN].user_data.uint_value = response_code;
+ stat_tap_init_table_row(resp_table, i-1, num_fields, items);
+ }
+ }
+}
+
+static tap_packet_status
+sip_stat_packet(void *tapdata, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *siv_ptr, tap_flags_t flags _U_)
+{
+ stat_data_t* stat_data = (stat_data_t*) tapdata;
+ const sip_info_value_t *info_value = (const sip_info_value_t *) siv_ptr;
+ stat_tap_table *cur_table = NULL;
+ guint cur_row = 0; /* 0 = Unknown for both tables */
+
+ if (info_value->request_method && info_value->response_code < 1) {
+ /* Request table */
+ stat_tap_table *req_table = stat_tap_find_table(stat_data->stat_tap_data, req_table_name);
+ stat_tap_table_item_type *item_data;
+ guint element;
+
+ cur_table = req_table;
+ for (element = 0; element < req_table->num_elements; element++) {
+ item_data = stat_tap_get_field_data(req_table, element, REQ_RESP_METHOD_COLUMN);
+ if (g_ascii_strcasecmp(info_value->request_method, item_data->value.string_value) == 0) {
+ cur_row = element;
+ break;
+ }
+ }
+
+ } else if (info_value->response_code > 0) {
+ /* Response table */
+ stat_tap_table *resp_table = stat_tap_find_table(stat_data->stat_tap_data, resp_table_name);
+ guint response_code = info_value->response_code;
+ stat_tap_table_item_type *item_data;
+ guint element;
+
+ cur_table = resp_table;
+ if (response_code < RESPONSE_CODE_MIN || response_code > RESPONSE_CODE_MAX) {
+ response_code = 999;
+ } else if (!try_val_to_str(response_code, sip_response_code_vals)) {
+ response_code = ((response_code / 100) * 100) + 99;
+ }
+
+ for (element = 0; element < resp_table->num_elements; element++) {
+ item_data = stat_tap_get_field_data(resp_table, element, REQ_RESP_METHOD_COLUMN);
+ if (item_data->user_data.uint_value == response_code) {
+ cur_row = element;
+ break;
+ }
+ }
+
+ } else {
+ return TAP_PACKET_DONT_REDRAW;
+ }
+
+ if (cur_table) {
+ stat_tap_table_item_type *item_data;
+
+ item_data = stat_tap_get_field_data(cur_table, cur_row, COUNT_COLUMN);
+ item_data->value.uint_value++;
+ stat_tap_set_field_data(cur_table, cur_row, COUNT_COLUMN, item_data);
+
+ if (info_value->resend) {
+ item_data = stat_tap_get_field_data(cur_table, cur_row, RESENT_COLUMN);
+ item_data->value.uint_value++;
+ stat_tap_set_field_data(cur_table, cur_row, RESENT_COLUMN, item_data);
+ }
+
+ if (info_value->setup_time > 0) {
+ stat_tap_table_item_type *min_item_data = stat_tap_get_field_data(cur_table, cur_row, MIN_SETUP_COLUMN);
+ stat_tap_table_item_type *avg_item_data = stat_tap_get_field_data(cur_table, cur_row, AVG_SETUP_COLUMN);
+ stat_tap_table_item_type *max_item_data = stat_tap_get_field_data(cur_table, cur_row, MAX_SETUP_COLUMN);
+ double setup_time = (double) info_value->setup_time / 1000;
+ unsigned count;
+
+ min_item_data->user_data.uint_value++; /* We store the setup count in MIN_SETUP_COLUMN */
+ count = min_item_data->user_data.uint_value;
+ avg_item_data->user_data.float_value += setup_time; /* We store the total setup time in AVG_SETUP_COLUMN */
+
+ if (count <= 1) {
+ min_item_data->value.float_value = setup_time;
+ avg_item_data->value.float_value = setup_time;
+ max_item_data->value.float_value = setup_time;
+ } else {
+ if (setup_time < min_item_data->value.float_value) {
+ min_item_data->value.float_value = setup_time;
+ }
+ avg_item_data->value.float_value = avg_item_data->user_data.float_value / count;
+ if (setup_time > max_item_data->value.float_value) {
+ max_item_data->value.float_value = setup_time;
+ }
+ }
+
+ stat_tap_set_field_data(cur_table, cur_row, MIN_SETUP_COLUMN, min_item_data);
+ stat_tap_set_field_data(cur_table, cur_row, AVG_SETUP_COLUMN, avg_item_data);
+ stat_tap_set_field_data(cur_table, cur_row, MAX_SETUP_COLUMN, max_item_data);
+ }
+ }
+
+ return TAP_PACKET_REDRAW;
+}
+
+static void
+sip_stat_reset(stat_tap_table* table)
+{
+ guint element;
+ stat_tap_table_item_type* item_data;
+
+ for (element = 0; element < table->num_elements; element++)
+ {
+ item_data = stat_tap_get_field_data(table, element, COUNT_COLUMN);
+ item_data->user_data.uint_value = 0;
+ item_data->value.uint_value = 0;
+ stat_tap_set_field_data(table, element, COUNT_COLUMN, item_data);
+
+ item_data = stat_tap_get_field_data(table, element, RESENT_COLUMN);
+ item_data->value.uint_value = 0;
+ stat_tap_set_field_data(table, element, RESENT_COLUMN, item_data);
+
+ item_data = stat_tap_get_field_data(table, element, MIN_SETUP_COLUMN);
+ item_data->user_data.uint_value = 0;
+ item_data->value.float_value = 0.0f;
+ stat_tap_set_field_data(table, element, MIN_SETUP_COLUMN, item_data);
+
+ item_data = stat_tap_get_field_data(table, element, AVG_SETUP_COLUMN);
+ item_data->user_data.float_value = 0.0f;
+ item_data->value.float_value = 0.0f;
+ stat_tap_set_field_data(table, element, AVG_SETUP_COLUMN, item_data);
+
+ item_data = stat_tap_get_field_data(table, element, MAX_SETUP_COLUMN);
+ item_data->value.float_value = 0.0f;
+ stat_tap_set_field_data(table, element, MAX_SETUP_COLUMN, item_data);
+ }
+}
+
+static void
+sip_stat_free_table_item(stat_tap_table* table _U_, guint row _U_, guint column, stat_tap_table_item_type* field_data)
+{
+ if (column != REQ_RESP_METHOD_COLUMN) return;
+ g_free((char*)field_data->value.string_value);
+ field_data->value.string_value = NULL;
+}
+
+static gchar *sip_follow_conv_filter(epan_dissect_t *edt, packet_info *pinfo _U_, guint *stream _U_, guint *sub_stream _U_)
+{
+ gchar *filter = NULL;
+
+ /* Extract si.Call-ID from decoded tree in edt */
+ if (edt != NULL) {
+ int hfid = proto_registrar_get_id_byname("sip.Call-ID");
+ GPtrArray *gp = proto_find_first_finfo(edt->tree, hfid);
+ if (gp != NULL && gp->len != 0) {
+ filter = ws_strdup_printf("sip.Call-ID == \"%s\"", fvalue_get_string(((field_info *)gp->pdata[0])->value));
+ }
+ g_ptr_array_free(gp, TRUE);
+ } else {
+ filter = ws_strdup_printf("sip.Call-ID");
+ }
+
+ return filter;
+}
+
+static gchar *sip_follow_index_filter(guint stream _U_, guint sub_stream _U_)
+{
+ return NULL;
+}
+
+static gchar *sip_follow_address_filter(address *src_addr _U_, address *dst_addr _U_, int src_port _U_, int dst_port _U_)
+{
+ return NULL;
+}
+
+
+/* Register the protocol with Wireshark */
+void proto_register_sip(void)
+{
+
+ /* Setup list of header fields */
+ static hf_register_info hf[] = {
+
+ { &hf_sip_msg_hdr,
+ { "Message Header", "sip.msg_hdr",
+ FT_STRING, BASE_NONE, NULL, 0,
+ "Message Header in SIP message", HFILL }
+ },
+ { &hf_sip_Method,
+ { "Method", "sip.Method",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "SIP Method", HFILL }
+ },
+ { &hf_Request_Line,
+ { "Request-Line", "sip.Request-Line",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "SIP Request-Line", HFILL }
+ },
+ { &hf_sip_ruri_display,
+ { "Request-URI display info", "sip.r-uri.display.info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: SIP R-URI Display Info", HFILL }
+ },
+ { &hf_sip_ruri,
+ { "Request-URI", "sip.r-uri",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: SIP R-URI", HFILL }
+ },
+ { &hf_sip_ruri_user,
+ { "Request-URI User Part", "sip.r-uri.user",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: SIP R-URI User", HFILL }
+ },
+ { &hf_sip_ruri_host,
+ { "Request-URI Host Part", "sip.r-uri.host",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: SIP R-URI Host", HFILL }
+ },
+ { &hf_sip_ruri_port,
+ { "Request-URI Host Port", "sip.r-uri.port",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: SIP R-URI Port", HFILL }
+ },
+ { &hf_sip_ruri_param,
+ { "Request URI parameter", "sip.r-uri.param",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_Status_Code,
+ { "Status-Code", "sip.Status-Code",
+ FT_UINT32, BASE_DEC,NULL,0x0,
+ "SIP Status Code", HFILL }
+ },
+ { &hf_sip_Status_Line,
+ { "Status-Line", "sip.Status-Line",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "SIP Status-Line", HFILL }
+ },
+ { &hf_sip_display,
+ { "SIP Display info", "sip.display.info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Display info", HFILL }
+ },
+ { &hf_sip_to_display,
+ { "SIP to display info", "sip.to.display.info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: To Display info", HFILL }
+ },
+ { &hf_sip_to_addr,
+ { "SIP to address", "sip.to.addr",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: To Address", HFILL }
+ },
+ { &hf_sip_to_user,
+ { "SIP to address User Part", "sip.to.user",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: To Address User", HFILL }
+ },
+ { &hf_sip_to_host,
+ { "SIP to address Host Part", "sip.to.host",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: To Address Host", HFILL }
+ },
+ { &hf_sip_to_port,
+ { "SIP to address Host Port", "sip.to.port",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: To Address Port", HFILL }
+ },
+ { &hf_sip_to_param,
+ { "SIP To URI parameter", "sip.to.param",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_to_tag,
+ { "SIP to tag", "sip.to.tag",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: to tag", HFILL }
+ },
+ { &hf_sip_from_display,
+ { "SIP from display info", "sip.from.display.info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: From Display info", HFILL }
+ },
+ { &hf_sip_from_addr,
+ { "SIP from address", "sip.from.addr",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: From Address", HFILL }
+ },
+ { &hf_sip_from_user,
+ { "SIP from address User Part", "sip.from.user",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: From Address User", HFILL }
+ },
+ { &hf_sip_from_host,
+ { "SIP from address Host Part", "sip.from.host",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: From Address Host", HFILL }
+ },
+ { &hf_sip_from_port,
+ { "SIP from address Host Port", "sip.from.port",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: From Address Port", HFILL }
+ },
+ { &hf_sip_from_param,
+ { "SIP From URI parameter", "sip.from.param",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_from_tag,
+ { "SIP from tag", "sip.from.tag",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: from tag", HFILL }
+ },
+ { &hf_sip_curi_display,
+ { "SIP C-URI display info", "sip.contact.display.info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: SIP C-URI Display info", HFILL }
+ },
+ { &hf_sip_curi,
+ { "Contact URI", "sip.contact.uri",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: SIP C-URI", HFILL }
+ },
+ { &hf_sip_curi_user,
+ { "Contact URI User Part", "sip.contact.user",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: SIP C-URI User", HFILL }
+ },
+ { &hf_sip_curi_host,
+ { "Contact URI Host Part", "sip.contact.host",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: SIP C-URI Host", HFILL }
+ },
+ { &hf_sip_curi_port,
+ { "Contact URI Host Port", "sip.contact.port",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: SIP C-URI Port", HFILL }
+ },
+ { &hf_sip_curi_param,
+ { "Contact URI parameter", "sip.contact.param",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_route_display,
+ { "Route display info", "sip.Route.display.info",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_route,
+ { "Route URI", "sip.Route.uri",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_route_user,
+ { "Route Userinfo", "sip.Route.user",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_route_host,
+ { "Route Host Part", "sip.Route.host",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_route_port,
+ { "Route Host Port", "sip.Route.port",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_route_param,
+ { "Route URI parameter", "sip.Route.param",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_record_route_display,
+ { "Record-Route display info", "sip.Record-Route.display.info",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_record_route,
+ { "Record-Route URI", "sip.Record-Route.uri",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_record_route_user,
+ { "Record-Route Userinfo", "sip.Record-Route.user",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_record_route_host,
+ { "Record-Route Host Part", "sip.Record-Route.host",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_record_route_port,
+ { "Record-Route Host Port", "sip.Record-Route.port",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_record_route_param,
+ { "Record-Route URI parameter", "sip.Record-Route.param",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_service_route_display,
+ { "Service-Route display info", "sip.Service-Route.display.info",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_service_route,
+ { "Service-Route URI", "sip.Service-Route.uri",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_service_route_user,
+ { "Service-Route Userinfo", "sip.Service-Route.user",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_service_route_host,
+ { "Service-Route Host Part", "sip.Service-Route.host",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_service_route_port,
+ { "Service-Route Host Port", "sip.Service-Route.port",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_service_route_param,
+ { "Service-Route URI parameter", "sip.Service-Route.param",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_path_display,
+ { "Path URI", "sip.Path.display.info",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_path,
+ { "Path URI", "sip.Path.uri",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_path_user,
+ { "Path Userinfo", "sip.Path.user",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_path_host,
+ { "Path Host Part", "sip.Path.host",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_path_port,
+ { "Path Host Port", "sip.Path.port",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_path_param,
+ { "Path URI parameter", "sip.Path.param",
+ FT_STRING, BASE_NONE,NULL,0x0,NULL,HFILL }
+ },
+ { &hf_sip_contact_param,
+ { "Contact parameter", "sip.contact.parameter",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: one contact parameter", HFILL }
+ },
+ { &hf_sip_tag,
+ { "SIP tag", "sip.tag",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: tag", HFILL }
+ },
+ { &hf_sip_pai_display,
+ { "SIP PAI display info", "sip.pai.display.info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: P-Asserted-Identity Display info", HFILL }
+ },
+ { &hf_sip_pai_addr,
+ { "SIP PAI Address", "sip.pai.addr",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: P-Asserted-Identity Address", HFILL }
+ },
+ { &hf_sip_pai_user,
+ { "SIP PAI User Part", "sip.pai.user",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: P-Asserted-Identity User", HFILL }
+ },
+ { &hf_sip_pai_host,
+ { "SIP PAI Host Part", "sip.pai.host",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: P-Asserted-Identity Host", HFILL }
+ },
+ { &hf_sip_pai_port,
+ { "SIP PAI Host Port", "sip.pai.port",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: P-Asserted-Identity Port", HFILL }
+ },
+ { &hf_sip_pai_param,
+ { "SIP PAI URI parameter", "sip.pai.param",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_pmiss_display,
+ { "SIP PMISS display info", "sip.pmiss.display.info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: Permission Missing Display info", HFILL }
+ },
+ { &hf_sip_pmiss_addr,
+ { "SIP PMISS Address", "sip.pmiss.addr",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: Permission Missing Address", HFILL }
+ },
+ { &hf_sip_pmiss_user,
+ { "SIP PMISS User Part", "sip.pmiss.user",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: Permission Missing User", HFILL }
+ },
+ { &hf_sip_pmiss_host,
+ { "SIP PMISS Host Part", "sip.pmiss.host",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: Permission Missing Host", HFILL }
+ },
+ { &hf_sip_pmiss_port,
+ { "SIP PMISS Host Port", "sip.pmiss.port",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: Permission Missing Port", HFILL }
+ },
+ { &hf_sip_pmiss_param,
+ { "SIP PMISS URI parameter", "sip.pmiss.param",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_ppi_display,
+ { "SIP PPI display info", "sip.ppi.display.info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: P-Preferred-Identity Display info", HFILL }
+ },
+ { &hf_sip_ppi_addr,
+ { "SIP PPI Address", "sip.ppi.addr",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: P-Preferred-Identity Address", HFILL }
+ },
+ { &hf_sip_ppi_user,
+ { "SIP PPI User Part", "sip.ppi.user",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: P-Preferred-Identity User", HFILL }
+ },
+ { &hf_sip_ppi_host,
+ { "SIP PPI Host Part", "sip.ppi.host",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: P-Preferred-Identity Host", HFILL }
+ },
+ { &hf_sip_ppi_port,
+ { "SIP PPI Host Port", "sip.ppi.port",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: P-Preferred-Identity Port", HFILL }
+ },
+ { &hf_sip_ppi_param,
+ { "SIP PPI URI parameter", "sip.ppi.param",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_tc_display,
+ { "SIP TC display info", "sip.tc.display.info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: Trigger Consent Display info", HFILL }
+ },
+ { &hf_sip_tc_addr,
+ { "SIP TC Address", "sip.tc.addr",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: Trigger Consent Address", HFILL }
+ },
+ { &hf_sip_tc_user,
+ { "SIP TC User Part", "sip.tc.user",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: Trigger Consent User", HFILL }
+ },
+ { &hf_sip_tc_host,
+ { "SIP TC Host Part", "sip.tc.host",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: Trigger Consent Host", HFILL }
+ },
+ { &hf_sip_tc_port,
+ { "SIP TC Host Port", "sip.tc.port",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: Trigger Consent Port", HFILL }
+ },
+ { &hf_sip_tc_param,
+ { "SIP TC URI parameter", "sip.tc.param",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_tc_turi,
+ { "SIP TC Target URI", "sip.tc.target-uri",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: Trigger Consent Target URI", HFILL }
+ },
+ { &hf_header_array[POS_ACCEPT],
+ { "Accept", "sip.Accept",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Accept Header", HFILL }
+ },
+ { &hf_header_array[POS_ACCEPT_CONTACT],
+ { "Accept-Contact", "sip.Accept-Contact",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3841: Accept-Contact Header", HFILL }
+ },
+ { &hf_header_array[POS_ACCEPT_ENCODING],
+ { "Accept-Encoding", "sip.Accept-Encoding",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3841: Accept-Encoding Header", HFILL }
+ },
+ { &hf_header_array[POS_ACCEPT_LANGUAGE],
+ { "Accept-Language", "sip.Accept-Language",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Accept-Language Header", HFILL }
+ },
+ { &hf_header_array[POS_ACCEPT_RESOURCE_PRIORITY],
+ { "Accept-Resource-Priority", "sip.Accept-Resource-Priority",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "Draft: Accept-Resource-Priority Header", HFILL }
+ },
+ { &hf_header_array[POS_ADDITIONAL_IDENTITY],
+ { "Additional-Identity", "sip.Additional-Identity",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_ALERT_INFO],
+ { "Alert-Info", "sip.Alert-Info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Alert-Info Header", HFILL }
+ },
+ { &hf_header_array[POS_ALLOW],
+ { "Allow", "sip.Allow",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Allow Header", HFILL }
+ },
+ { &hf_header_array[POS_ALLOW_EVENTS],
+ { "Allow-Events", "sip.Allow-Events",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3265: Allow-Events Header", HFILL }
+ },
+ { &hf_header_array[POS_ANSWER_MODE],
+ { "Answer-Mode", "sip.Answer-Mode",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 5373: Answer-Mode Header", HFILL }
+ },
+ { &hf_header_array[POS_ATTESTATION_INFO],
+ { "Attestation-Info", "sip.Attestation-Info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_AUTHENTICATION_INFO],
+ { "Authentication-Info", "sip.Authentication-Info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Authentication-Info Header", HFILL }
+ },
+ { &hf_header_array[POS_AUTHORIZATION],
+ { "Authorization", "sip.Authorization",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Authorization Header", HFILL }
+ },
+ { &hf_header_array[POS_CALL_ID],
+ { "Call-ID", "sip.Call-ID",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Call-ID Header", HFILL }
+ },
+ { &hf_header_array[POS_CALL_INFO],
+ { "Call-Info", "sip.Call-Info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Call-Info Header", HFILL }
+ },
+ { &hf_header_array[POS_CELLULAR_NETWORK_INFO],
+ { "Cellular-Network-Info", "sip.Cellular-Network-Info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_CONTACT],
+ { "Contact", "sip.Contact",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Contact Header", HFILL }
+ },
+ { &hf_header_array[POS_CONTENT_DISPOSITION],
+ { "Content-Disposition", "sip.Content-Disposition",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Content-Disposition Header", HFILL }
+ },
+ { &hf_header_array[POS_CONTENT_ENCODING],
+ { "Content-Encoding", "sip.Content-Encoding",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Content-Encoding Header", HFILL }
+ },
+ { &hf_header_array[POS_CONTENT_LANGUAGE],
+ { "Content-Language", "sip.Content-Language",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Content-Language Header", HFILL }
+ },
+ { &hf_header_array[POS_CONTENT_LENGTH],
+ { "Content-Length", "sip.Content-Length",
+ FT_UINT32, BASE_DEC,NULL,0x0,
+ "RFC 3261: Content-Length Header", HFILL }
+ },
+ { &hf_header_array[POS_CONTENT_TYPE],
+ { "Content-Type", "sip.Content-Type",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Content-Type Header", HFILL }
+ },
+ { &hf_header_array[POS_CSEQ],
+ { "CSeq", "sip.CSeq",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: CSeq Header", HFILL }
+ },
+ { &hf_header_array[POS_DATE],
+ { "Date", "sip.Date",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Date Header", HFILL }
+ },
+ { &hf_header_array[POS_ERROR_INFO],
+ { "Error-Info", "sip.Error-Info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Error-Info Header", HFILL }
+ },
+ { &hf_header_array[POS_EVENT],
+ { "Event", "sip.Event",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3265: Event Header", HFILL }
+ },
+ { &hf_header_array[POS_EXPIRES],
+ { "Expires", "sip.Expires",
+ FT_UINT32, BASE_DEC,NULL,0x0,
+ "RFC 3261: Expires Header", HFILL }
+ },
+ { &hf_header_array[POS_FEATURE_CAPS],
+ { "Feature-Caps", "sip.Feature-Caps",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 6809: Feature-Caps", HFILL }
+ },
+ { &hf_header_array[POS_FLOW_TIMER],
+ { "Flow-Timer", "sip.Flow-Timer",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 5626: Flow-Timer", HFILL }
+ },
+ { &hf_header_array[POS_FROM],
+ { "From", "sip.From",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: From Header", HFILL }
+ },
+ { &hf_header_array[POS_GEOLOCATION],
+ { "Geolocation", "sip.Geolocation",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_GEOLOCATION_ERROR],
+ { "Geolocation-Error", "sip.Geolocation-Error",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_GEOLOCATION_ROUTING],
+ { "Geolocation-Routing", "sip.Geolocation-Routing",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_HISTORY_INFO],
+ { "History-Info", "sip.History-Info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 4244: Request History Information", HFILL }
+ },
+ { &hf_header_array[POS_IDENTITY],
+ { "Identity", "sip.Identity",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 4474: Request Identity", HFILL }
+ },
+ { &hf_header_array[POS_IDENTITY_INFO],
+ { "Identity-info", "sip.Identity-info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 4474: Request Identity-info", HFILL }
+ },
+ { &hf_header_array[POS_INFO_PKG],
+ { "Info-Package", "sip.Info-Package",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_IN_REPLY_TO],
+ { "In-Reply-To", "sip.In-Reply-To",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: In-Reply-To Header", HFILL }
+ },
+ { &hf_header_array[POS_JOIN],
+ { "Join", "sip.Join",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "Draft: Join Header", HFILL }
+ },
+ { &hf_header_array[POS_MAX_BREADTH],
+ { "Max-Breadth", "sip.Max-Breadth",
+ FT_UINT32, BASE_DEC,NULL,0x0,
+ "RFC 5393: Max-Breadth Header", HFILL }
+ },
+ { &hf_header_array[POS_MAX_FORWARDS],
+ { "Max-Forwards", "sip.Max-Forwards",
+ FT_UINT32, BASE_DEC,NULL,0x0,
+ "RFC 3261: Max-Forwards Header", HFILL }
+ },
+ { &hf_header_array[POS_MIME_VERSION],
+ { "MIME-Version", "sip.MIME-Version",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: MIME-Version Header", HFILL }
+ },
+ { &hf_header_array[POS_MIN_EXPIRES],
+ { "Min-Expires", "sip.Min-Expires",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Min-Expires Header", HFILL }
+ },
+ { &hf_header_array[POS_MIN_SE],
+ { "Min-SE", "sip.Min-SE",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "Draft: Min-SE Header", HFILL }
+ },
+ { &hf_header_array[POS_ORGANIZATION],
+ { "Organization", "sip.Organization",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Organization Header", HFILL }
+ },
+ { &hf_header_array[POS_ORIGINATION_ID],
+ { "Origination-Id", "sip.Origination-Id",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_P_ACCESS_NETWORK_INFO],
+ { "P-Access-Network-Info", "sip.P-Access-Network-Info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "P-Access-Network-Info Header", HFILL }
+ },
+ { &hf_header_array[POS_P_ANSWER_STATE],
+ { "P-Answer-State", "sip.P-Answer-State",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 4964: P-Answer-State Header", HFILL }
+ },
+ { &hf_header_array[POS_P_ASSERTED_IDENTITY],
+ { "P-Asserted-Identity", "sip.P-Asserted-Identity",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: P-Asserted-Identity Header", HFILL }
+ },
+ { &hf_header_array[POS_P_ASSERTED_SERV],
+ { "P-Asserted-Service", "sip.P-Asserted-Service",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_P_CHARGE_INFO],
+ { "P-Charge-Info", "sip.P-Charge-Info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_P_ASSOCIATED_URI],
+ { "P-Associated-URI", "sip.P-Associated-URI",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3455: P-Associated-URI Header", HFILL }
+ },
+
+ { &hf_header_array[POS_P_CALLED_PARTY_ID],
+ { "P-Called-Party-ID", "sip.P-Called-Party-ID",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3455: P-Called-Party-ID Header", HFILL }
+ },
+
+ { &hf_header_array[POS_P_CHARGING_FUNC_ADDRESSES],
+ { "P-Charging-Function-Addresses","sip.P-Charging-Function-Addresses",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+
+ { &hf_header_array[POS_P_CHARGING_VECTOR],
+ { "P-Charging-Vector", "sip.P-Charging-Vector",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "P-Charging-Vector Header", HFILL }
+ },
+
+ { &hf_header_array[POS_P_DCS_TRACE_PARTY_ID],
+ { "P-DCS-Trace-Party-ID", "sip.P-DCS-Trace-Party-ID",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "P-DCS-Trace-Party-ID Header", HFILL }
+ },
+
+ { &hf_header_array[POS_P_DCS_OSPS],
+ { "P-DCS-OSPS", "sip.P-DCS-OSPS",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "P-DCS-OSPS Header", HFILL }
+ },
+
+ { &hf_header_array[POS_P_DCS_BILLING_INFO],
+ { "P-DCS-Billing-Info", "sip.P-DCS-Billing-Info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "P-DCS-Billing-Info Header", HFILL }
+ },
+
+ { &hf_header_array[POS_P_DCS_LAES],
+ { "P-DCS-LAES", "sip.P-DCS-LAES",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "P-DCS-LAES Header", HFILL }
+ },
+
+ { &hf_header_array[POS_P_DCS_REDIRECT],
+ { "P-DCS-Redirect", "sip.P-DCS-Redirect",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "P-DCS-Redirect Header", HFILL }
+ },
+
+ { &hf_header_array[POS_P_EARLY_MEDIA],
+ { "P-Early-Media", "sip.P-Early-Media",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "P-Early-Media Header", HFILL }
+ },
+
+ { &hf_header_array[POS_P_MEDIA_AUTHORIZATION],
+ { "P-Media-Authorization", "sip.P-Media-Authorization",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3313: P-Media-Authorization Header", HFILL }
+ },
+
+ { &hf_header_array[POS_P_PREFERRED_IDENTITY],
+ { "P-Preferred-Identity", "sip.P-Preferred-Identity",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3325: P-Preferred-Identity Header", HFILL }
+ },
+ { &hf_header_array[POS_P_PREFERRED_SERV],
+ { "P-Preferred-Service", "sip.P-Preferred-Service",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_P_PROFILE_KEY],
+ { "P-Profile-Key", "sip.P-Profile-Key",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "P-Profile-Key Header", HFILL }
+ },
+ { &hf_header_array[POS_P_REFUSED_URI_LST],
+ { "P-Refused-URI-List", "sip.P-Refused-URI-List",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "P-Refused-URI-List Header", HFILL }
+ },
+ { &hf_header_array[POS_P_SERVED_USER],
+ { "P-Served-User", "sip.P-Served-User",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_P_USER_DATABASE],
+ { "P-User-Database", "sip.P-User-Database",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "P-User-Database Header", HFILL }
+ },
+
+ { &hf_header_array[POS_P_VISITED_NETWORK_ID],
+ { "P-Visited-Network-ID", "sip.P-Visited-Network-ID",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3455: P-Visited-Network-ID Header", HFILL }
+ },
+
+ { &hf_header_array[POS_PATH],
+ { "Path", "sip.Path",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3327: Path Header", HFILL }
+ },
+
+ { &hf_header_array[POS_PERMISSION_MISSING],
+ { "Permission-Missing", "sip.Permission-Missing",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 5360: Permission Missing Header", HFILL }
+ },
+ { &hf_header_array[POS_POLICY_CONTACT],
+ { "Policy-Contact", "sip.Policy_Contact",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_POLICY_ID],
+ { "Policy-ID", "sip.Policy_ID",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_PRIORITY],
+ { "Priority", "sip.Priority",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Priority Header", HFILL }
+ },
+ { &hf_header_array[POS_PRIORITY_SHARE],
+ { "Priority-Share", "sip.Priority-Share",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_PRIV_ANSWER_MODE],
+ { "Priv-Answer-mode", "sip.Priv-Answer-mode",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_PRIVACY],
+ { "Privacy", "sip.Privacy",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "Privacy Header", HFILL }
+ },
+
+ { &hf_header_array[POS_PROXY_AUTHENTICATE],
+ { "Proxy-Authenticate", "sip.Proxy-Authenticate",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Proxy-Authenticate Header", HFILL }
+ },
+ { &hf_header_array[POS_PROXY_AUTHORIZATION],
+ { "Proxy-Authorization", "sip.Proxy-Authorization",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Proxy-Authorization Header", HFILL }
+ },
+
+ { &hf_header_array[POS_PROXY_REQUIRE],
+ { "Proxy-Require", "sip.Proxy-Require",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Proxy-Require Header", HFILL }
+ },
+ { &hf_header_array[POS_RACK],
+ { "RAck", "sip.RAck",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3262: RAck Header", HFILL }
+ },
+ { &hf_header_array[POS_REASON],
+ { "Reason", "sip.Reason",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3326 Reason Header", HFILL }
+ },
+ { &hf_header_array[POS_REASON_PHRASE],
+ { "Reason-Phrase", "sip.Reason-Phrase",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_RECORD_ROUTE],
+ { "Record-Route", "sip.Record-Route",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Record-Route Header", HFILL }
+ },
+ { &hf_header_array[POS_RECV_INFO],
+ { "Recv-Info", "sip.Recv-Info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_REFER_SUB],
+ { "Refer-Sub", "sip.Refer-Sub",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 4488: Refer-Sub Header", HFILL }
+ },
+ { &hf_header_array[POS_REFER_TO],
+ { "Refer-To", "sip.Refer-To",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3515: Refer-To Header", HFILL }
+ },
+ { &hf_header_array[POS_REFERRED_BY],
+ { "Referred By", "sip.Referred-by",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3892: Referred-by Header", HFILL }
+ },
+ { &hf_header_array[POS_REJECT_CONTACT],
+ { "Reject-Contact", "sip.Reject-Contact",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3841: Reject-Contact Header", HFILL }
+ },
+ { &hf_header_array[POS_RELAYED_CHARGE],
+ { "Relayed-Charge", "sip.Relayed-Charge",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_REPLACES],
+ { "Replaces", "sip.Replaces",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3891: Replaces Header", HFILL }
+ },
+ { &hf_header_array[POS_REPLY_TO],
+ { "Reply-To", "sip.Reply-To",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Reply-To Header", HFILL }
+ },
+ { &hf_header_array[POS_REQUEST_DISPOSITION],
+ { "Request-Disposition", "sip.Request-Disposition",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3841: Request-Disposition Header", HFILL }
+ },
+ { &hf_header_array[POS_REQUIRE],
+ { "Require", "sip.Require",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Require Header", HFILL }
+ },
+ { &hf_header_array[POS_RESOURCE_PRIORITY],
+ { "Resource-Priority", "sip.Resource-Priority",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "Draft: Resource-Priority Header", HFILL }
+ },
+ { &hf_header_array[POS_RESOURCE_SHARE],
+ { "Resource-Share", "sip.Resource-Share",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_RESPONSE_SOURCE],
+ { "Response-Source", "sip.Response-Source",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_RESTORATION_INFO],
+ { "Restoration-Info", "sip.Restoration-Info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_RETRY_AFTER],
+ { "Retry-After", "sip.Retry-After",
+ FT_UINT32, BASE_DEC,NULL,0x0,
+ "RFC 3261: Retry-After Header", HFILL }
+ },
+ { &hf_header_array[POS_ROUTE],
+ { "Route", "sip.Route",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Route Header", HFILL }
+ },
+ { &hf_header_array[POS_RSEQ],
+ { "RSeq", "sip.RSeq",
+ FT_UINT32, BASE_DEC,NULL,0x0,
+ "RFC 3262: RSeq Header", HFILL }
+ },
+ { &hf_header_array[ POS_SECURITY_CLIENT],
+ { "Security-Client", "sip.Security-Client",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3329 Security-Client Header", HFILL }
+ },
+ { &hf_header_array[ POS_SECURITY_SERVER],
+ { "Security-Server", "sip.Security-Server",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3329 Security-Server Header", HFILL }
+ },
+ { &hf_header_array[ POS_SECURITY_VERIFY],
+ { "Security-Verify", "sip.Security-Verify",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3329 Security-Verify Header", HFILL }
+ },
+ { &hf_header_array[POS_SERVER],
+ { "Server", "sip.Server",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Server Header", HFILL }
+ },
+ { &hf_header_array[POS_SERVICE_INTERACT_INFO],
+ { "Service-Interact-Info", "sip.Service-Interact-Info",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_SERVICE_ROUTE],
+ { "Service-Route", "sip.Service-Route",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3608: Service-Route Header", HFILL }
+ },
+ { &hf_header_array[POS_SESSION_EXPIRES],
+ { "Session-Expires", "sip.Session-Expires",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 4028: Session-Expires Header", HFILL }
+ },
+ { &hf_header_array[POS_SESSION_ID],
+ { "Session-ID", "sip.Session-ID",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_SIP_ETAG],
+ { "ETag", "sip.ETag",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3903: SIP-ETag Header", HFILL }
+ },
+ { &hf_header_array[POS_SIP_IF_MATCH],
+ { "If_Match", "sip.If_Match",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3903: SIP-If-Match Header", HFILL }
+ },
+ { &hf_header_array[POS_SUBJECT],
+ { "Subject", "sip.Subject",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Subject Header", HFILL }
+ },
+ { &hf_header_array[POS_SUBSCRIPTION_STATE],
+ { "Subscription-State", "sip.Subscription-State",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3265: Subscription-State Header", HFILL }
+ },
+ { &hf_header_array[POS_SUPPORTED],
+ { "Supported", "sip.Supported",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Supported Header", HFILL }
+ },
+ { &hf_header_array[POS_SUPPRESS_IF_MATCH],
+ { "Suppress-If-Match", "sip.Suppress_If_Match",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ },
+ { &hf_header_array[POS_TARGET_DIALOG],
+ { "Target-Dialog", "sip.Target-Dialog",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 4538: Target-Dialog Header", HFILL }
+ },
+ { &hf_header_array[POS_TIMESTAMP],
+ { "Timestamp", "sip.Timestamp",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Timestamp Header", HFILL }
+ },
+ { &hf_header_array[POS_TO],
+ { "To", "sip.To",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: To Header", HFILL }
+ },
+
+ { &hf_header_array[POS_TRIGGER_CONSENT],
+ { "Trigger-Consent", "sip.Trigger-Consent",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 5380: Trigger Consent", HFILL }
+ },
+
+ { &hf_header_array[POS_UNSUPPORTED],
+ { "Unsupported", "sip.Unsupported",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Unsupported Header", HFILL }
+ },
+ { &hf_header_array[POS_USER_AGENT],
+ { "User-Agent", "sip.User-Agent",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: User-Agent Header", HFILL }
+ },
+ { &hf_header_array[POS_VIA],
+ { "Via", "sip.Via",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Via Header", HFILL }
+ },
+ { &hf_header_array[POS_WARNING],
+ { "Warning", "sip.Warning",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: Warning Header", HFILL }
+ },
+
+ { &hf_header_array[POS_WWW_AUTHENTICATE],
+ { "WWW-Authenticate", "sip.WWW-Authenticate",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 3261: WWW-Authenticate Header", HFILL }
+ },
+ { &hf_header_array[POS_DIVERSION],
+ { "Diversion", "sip.Diversion",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "RFC 5806: Diversion Header", HFILL }
+ },
+ { &hf_header_array[POS_USER_TO_USER],
+ { "User-to-User", "sip.uui",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "draft-johnston-sipping-cc-uui-09: User-to-User header", HFILL }
+ },
+ { &hf_sip_resend,
+ { "Resent Packet", "sip.resend",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_original_frame,
+ { "Suspected resend of frame", "sip.resend-original",
+ FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RETRANS_PREV), 0x0,
+ "Original transmission of frame", HFILL}
+ },
+ { &hf_sip_matching_request_frame,
+ { "Request Frame", "sip.response-request",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_response_time,
+ { "Response Time (ms)", "sip.response-time",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Response time since original request (in milliseconds)", HFILL}
+ },
+ { &hf_sip_release_time,
+ { "Release Time (ms)", "sip.release-time",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "release time since original BYE (in milliseconds)", HFILL}
+ },
+ { &hf_sip_auth,
+ { "Authentication", "sip.auth",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication", HFILL}
+ },
+ { &hf_sip_auth_scheme,
+ { "Authentication Scheme", "sip.auth.scheme",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication Scheme", HFILL}
+ },
+ { &hf_sip_auth_digest_response,
+ { "Digest Authentication Response", "sip.auth.digest.response",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Digest Authentication Response Value", HFILL}
+ },
+ { &hf_sip_auth_nc,
+ { "Nonce Count", "sip.auth.nc",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication Nonce count", HFILL}
+ },
+ { &hf_sip_auth_username,
+ { "Username", "sip.auth.username",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication Username", HFILL}
+ },
+ { &hf_sip_auth_realm,
+ { "Realm", "sip.auth.realm",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication Realm", HFILL}
+ },
+ { &hf_sip_auth_nonce,
+ { "Nonce Value", "sip.auth.nonce",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication Nonce", HFILL}
+ },
+ { &hf_sip_auth_algorithm,
+ { "Algorithm", "sip.auth.algorithm",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication Algorithm", HFILL}
+ },
+ { &hf_sip_auth_opaque,
+ { "Opaque Value", "sip.auth.opaque",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication Opaque value", HFILL}
+ },
+ { &hf_sip_auth_qop,
+ { "QOP", "sip.auth.qop",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication QOP", HFILL}
+ },
+ { &hf_sip_auth_cnonce,
+ { "CNonce Value", "sip.auth.cnonce",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication Client Nonce", HFILL}
+ },
+ { &hf_sip_auth_uri,
+ { "Authentication URI", "sip.auth.uri",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication URI", HFILL}
+ },
+ { &hf_sip_auth_domain,
+ { "Authentication Domain", "sip.auth.domain",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication Domain", HFILL}
+ },
+ { &hf_sip_auth_stale,
+ { "Stale Flag", "sip.auth.stale",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication Stale Flag", HFILL}
+ },
+ { &hf_sip_auth_auts,
+ { "Authentication Token", "sip.auth.auts",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication Token", HFILL}
+ },
+ { &hf_sip_auth_rspauth,
+ { "Response auth", "sip.auth.rspauth",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication Response auth", HFILL}
+ },
+ { &hf_sip_auth_nextnonce,
+ { "Next Nonce", "sip.auth.nextnonce",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication Next Nonce", HFILL}
+ },
+ { &hf_sip_auth_ik,
+ { "Integrity Key", "sip.auth.ik",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication Integrity Key", HFILL}
+ },
+ { &hf_sip_auth_ck,
+ { "Cyphering Key", "sip.auth.ck",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Authentication Cyphering Key", HFILL}
+ },
+ { &hf_sip_cseq_seq_no,
+ { "Sequence Number", "sip.CSeq.seq",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "CSeq header sequence number", HFILL}
+ },
+ { &hf_sip_cseq_method,
+ { "Method", "sip.CSeq.method",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "CSeq header method", HFILL}
+ },
+ { &hf_sip_via_transport,
+ { "Transport", "sip.Via.transport",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "Via header Transport", HFILL}
+ },
+ { &hf_sip_via_sent_by_address,
+ { "Sent-by Address", "sip.Via.sent-by.address",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "Via header Sent-by Address", HFILL}
+ },
+ { &hf_sip_via_sent_by_port,
+ { "Sent-by port", "sip.Via.sent-by.port",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Via header Sent-by Port", HFILL}
+ },
+ { &hf_sip_via_branch,
+ { "Branch", "sip.Via.branch",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Via Branch", HFILL},
+ },
+ { &hf_sip_via_maddr,
+ { "Maddr", "sip.Via.maddr",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Via Maddr", HFILL},
+ },
+ { &hf_sip_via_rport,
+ { "RPort", "sip.Via.rport",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Via RPort", HFILL},
+ },
+ { &hf_sip_via_received,
+ { "Received", "sip.Via.received",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Via Received", HFILL},
+ },
+ { &hf_sip_via_ttl,
+ { "TTL", "sip.Via.ttl",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Via TTL", HFILL}
+ },
+ { &hf_sip_via_comp,
+ { "Comp", "sip.Via.comp",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Via comp", HFILL}
+ },
+ { &hf_sip_via_sigcomp_id,
+ { "Sigcomp identifier", "sip.Via.sigcomp-id",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP Via sigcomp identifier", HFILL}
+ },
+ { &hf_sip_via_oc,
+ { "Overload Control", "sip.Via.oc",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_via_oc_val,
+ { "Overload Control Value", "sip.Via.oc_val",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_via_oc_validity,
+ { "Overload Control Validity", "sip.Via.oc_validity",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_via_oc_seq,
+ { "Overload Control Sequence", "sip.Via.oc_seq",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_oc_seq_timestamp,
+ { "Overload Control Sequence Time Stamp",
+ "sip.Via.oc_seq.ts",
+ FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_via_oc_algo,
+ { "Overload Control Algorithm", "sip.Via.oc_algo",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_via_be_route,
+ { "be-route", "sip.Via.be_route",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_p_acc_net_i_acc_type,
+ { "access-type", "sip.P-Access-Network-Info.access-type",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP P-Access-Network-Info access-type", HFILL}
+ },
+ { &hf_sip_p_acc_net_i_ucid_3gpp,
+ { "utran-cell-id-3gpp", "sip.P-Access-Network-Info.utran-cell-id-3gpp",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "SIP P-Access-Network-Info utran-cell-id-3gpp", HFILL}
+ },
+ { &hf_sip_rack_rseq_no,
+ { "RSeq Sequence Number", "sip.RAck.RSeq.seq",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "RAck RSeq header sequence number (from prov response)", HFILL}
+ },
+ { &hf_sip_rack_cseq_no,
+ { "CSeq Sequence Number", "sip.RAck.CSeq.seq",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "RAck CSeq header sequence number (from prov response)", HFILL}
+ },
+ { &hf_sip_rack_cseq_method,
+ { "CSeq Method", "sip.RAck.CSeq.method",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "RAck CSeq header method (from prov response)", HFILL}
+ },
+ { &hf_sip_reason_protocols,
+ { "Reason protocols", "sip.reason_protocols",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_reason_cause_q850,
+ { "Cause", "sip.reason_cause_q850",
+ FT_UINT32, BASE_DEC_HEX|BASE_EXT_STRING, &q850_cause_code_vals_ext, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_reason_cause_sip,
+ { "Cause", "sip.reason_cause_sip",
+ FT_UINT32, BASE_DEC, VALS(sip_response_code_vals), 0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_reason_cause_other,
+ { "Cause", "sip.reason_cause_other",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_reason_text,
+ { "Text", "sip.reason_text",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_msg_body,
+ { "Message Body", "sip.msg_body",
+ FT_BYTES, BASE_NONE|BASE_NO_DISPLAY_VALUE, NULL, 0x0,
+ "Message Body in SIP message", HFILL }
+ },
+ { &hf_sip_sec_mechanism,
+ { "[Security-mechanism]", "sip.sec_mechanism",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_sec_mechanism_alg,
+ { "alg", "sip.sec_mechanism.alg",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_sec_mechanism_ealg,
+ { "ealg", "sip.sec_mechanism.ealg",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_sec_mechanism_prot,
+ { "prot", "sip.sec_mechanism.prot",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_sec_mechanism_spi_c,
+ { "spi-c", "sip.sec_mechanism.spi_c",
+ FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_sec_mechanism_spi_s,
+ { "spi-s", "sip.sec_mechanism.spi_s",
+ FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_sec_mechanism_port1,
+ { "port1", "sip.sec_mechanism.port1",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_sec_mechanism_port_c,
+ { "port-c", "sip.sec_mechanism.port_c",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_sec_mechanism_port2,
+ { "port2", "sip.sec_mechanism.port2",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_sec_mechanism_port_s,
+ { "port-s", "sip.sec_mechanism.port_s",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_session_id_sess_id,
+ { "sess-id", "sip.Session-ID.sess_id",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_session_id_param,
+ { "param", "sip.Session-ID.param",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_session_id_local_uuid,
+ { "local-uuid", "sip.Session-ID.local_uuid",
+ FT_GUID, BASE_NONE, NULL, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_session_id_remote_uuid,
+ { "remote-uuid", "sip.Session-ID.remote_uuid",
+ FT_GUID, BASE_NONE, NULL, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_session_id_logme,
+ { "logme", "sip.Session-ID.logme",
+ FT_BOOLEAN, BASE_NONE, TFS(&tfs_set_notset), 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_continuation,
+ { "Continuation data", "sip.continuation",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL}
+ },
+ { &hf_sip_feature_cap,
+ { "Feature Cap", "sip.feature_cap",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_service_priority,
+ { "Service Priority", "sip.service_priority",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_icid_value,
+ { "icid-value", "sip.icid_value",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_icid_gen_addr,
+ { "icid-gen-addr", "sip.icid_gen_addr",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_sip_call_id_gen,
+ { "Generated Call-ID", "sip.call_id_generated",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ "Use to catch call id across protocols", HFILL }
+ },
+
+ };
+
+ /* raw_sip header field(s) */
+ static hf_register_info raw_hf[] = {
+
+ { &hf_sip_raw_line,
+ { "Raw SIP Line", "raw_sip.line",
+ FT_STRING, BASE_NONE,NULL,0x0,
+ NULL, HFILL }
+ }};
+
+ /* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_sip,
+ &ett_sip_reqresp,
+ &ett_sip_hdr,
+ &ett_sip_ext_hdr,
+ &ett_sip_element,
+ &ett_sip_hist,
+ &ett_sip_uri,
+ &ett_sip_contact_item,
+ &ett_sip_message_body,
+ &ett_sip_cseq,
+ &ett_sip_via,
+ &ett_sip_reason,
+ &ett_sip_security_client,
+ &ett_sip_security_server,
+ &ett_sip_security_verify,
+ &ett_sip_rack,
+ &ett_sip_record_route,
+ &ett_sip_service_route,
+ &ett_sip_route,
+ &ett_sip_path,
+ &ett_sip_ruri,
+ &ett_sip_pai_uri,
+ &ett_sip_pmiss_uri,
+ &ett_sip_ppi_uri,
+ &ett_sip_tc_uri,
+ &ett_sip_to_uri,
+ &ett_sip_from_uri,
+ &ett_sip_curi,
+ &ett_sip_session_id,
+ &ett_sip_p_access_net_info,
+ &ett_sip_p_charging_vector,
+ &ett_sip_feature_caps,
+ &ett_sip_via_be_route
+ };
+ static gint *ett_raw[] = {
+ &ett_raw_text,
+ };
+
+ static ei_register_info ei[] = {
+ { &ei_sip_unrecognized_header, { "sip.unrecognized_header", PI_UNDECODED, PI_NOTE, "Unrecognised SIP header", EXPFILL }},
+ { &ei_sip_header_no_colon, { "sip.header_no_colon", PI_MALFORMED, PI_WARN, "Header has no colon after the name", EXPFILL }},
+ { &ei_sip_header_not_terminated, { "sip.header_not_terminated", PI_MALFORMED, PI_WARN, "Header not terminated by empty line (CRLF)", EXPFILL }},
+#if 0
+ { &ei_sip_odd_register_response, { "sip.response.unusual", PI_RESPONSE_CODE, PI_WARN, "SIP Response is unusual", EXPFILL }},
+#endif
+ { &ei_sip_call_id_invalid, { "sip.Call-ID.invalid", PI_PROTOCOL, PI_WARN, "Call ID is mandatory", EXPFILL }},
+ { &ei_sip_sipsec_malformed, { "sip.sec_mechanism.malformed", PI_MALFORMED, PI_WARN, "SIP Security-mechanism header malformed", EXPFILL }},
+ { &ei_sip_via_sent_by_port, { "sip.Via.sent-by.port.invalid", PI_MALFORMED, PI_NOTE, "Invalid SIP Via sent-by-port", EXPFILL }},
+ { &ei_sip_content_length_invalid, { "sip.content_length.invalid", PI_MALFORMED, PI_NOTE, "Invalid content_length", EXPFILL }},
+ { &ei_sip_retry_after_invalid, { "sip.retry_after.invalid", PI_MALFORMED, PI_NOTE, "Invalid retry_after value", EXPFILL }},
+ { &ei_sip_Status_Code_invalid, { "sip.Status-Code.invalid", PI_MALFORMED, PI_NOTE, "Invalid Status-Code", EXPFILL }},
+ { &ei_sip_authorization_invalid, { "sip.authorization.invalid", PI_PROTOCOL, PI_WARN, "Invalid authorization response for known credentials", EXPFILL }},
+ { &ei_sip_session_id_sess_id,{ "sip.Session-ID.sess_id.invalid", PI_PROTOCOL, PI_WARN, "Session ID cannot be empty", EXPFILL }}
+ };
+
+ module_t *sip_module;
+ expert_module_t* expert_sip;
+ uat_t* sip_custom_headers_uat;
+ uat_t* sip_authorization_users_uat;
+
+ static tap_param sip_stat_params[] = {
+ { PARAM_FILTER, "filter", "Filter", NULL, TRUE }
+ };
+
+ static stat_tap_table_ui sip_stat_table = {
+ REGISTER_STAT_GROUP_TELEPHONY,
+ "SIP Statistics",
+ "sip",
+ "sip,stat",
+ sip_stat_init,
+ sip_stat_packet,
+ sip_stat_reset,
+ sip_stat_free_table_item,
+ NULL,
+ sizeof(sip_stat_fields)/sizeof(stat_tap_table_item), sip_stat_fields,
+ sizeof(sip_stat_params)/sizeof(tap_param), sip_stat_params,
+ NULL,
+ 0
+ };
+
+ /* UAT for header fields */
+ static uat_field_t sip_custom_header_uat_fields[] = {
+ UAT_FLD_CSTRING(sip_custom_header_fields, header_name, "Header name", "SIP header name"),
+ UAT_FLD_CSTRING(sip_custom_header_fields, header_desc, "Field desc", "Description of the value contained in the header"),
+ UAT_END_FIELDS
+ };
+
+ static uat_field_t sip_authorization_users_uat_fields[] = {
+ UAT_FLD_CSTRING(sip_authorization_users, username, "Username", "SIP authorization username"),
+ UAT_FLD_CSTRING(sip_authorization_users, realm, "Realm", "SIP authorization realm"),
+ UAT_FLD_CSTRING(sip_authorization_users, password, "Password", "SIP authorization password"),
+ UAT_END_FIELDS
+ };
+
+ /* Register the protocol name and description */
+ proto_sip = proto_register_protocol("Session Initiation Protocol", "SIP", "sip");
+ proto_raw_sip = proto_register_protocol("Session Initiation Protocol (SIP as raw text)",
+ "Raw_SIP", "raw_sip");
+ sip_handle = register_dissector("sip", dissect_sip, proto_sip);
+ sip_tcp_handle = register_dissector("sip.tcp", dissect_sip_tcp, proto_sip);
+
+ /* Required function calls to register the header fields and subtrees used */
+ proto_register_field_array(proto_sip, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+ expert_sip = expert_register_protocol(proto_sip);
+ expert_register_field_array(expert_sip, ei, array_length(ei));
+ proto_register_subtree_array(ett_raw, array_length(ett_raw));
+
+ /* Register raw_sip field(s) */
+ proto_register_field_array(proto_raw_sip, raw_hf, array_length(raw_hf));
+
+ sip_module = prefs_register_protocol(proto_sip, proto_reg_handoff_sip);
+
+ prefs_register_uint_preference(sip_module, "tls.port",
+ "SIP TLS Port",
+ "SIP Server TLS Port",
+ 10, &sip_tls_port);
+
+ prefs_register_bool_preference(sip_module, "display_raw_text",
+ "Display raw text for SIP message",
+ "Specifies that the raw text of the "
+ "SIP message should be displayed "
+ "in addition to the dissection tree",
+ &global_sip_raw_text);
+
+ prefs_register_bool_preference(sip_module, "display_raw_text_without_crlf",
+ "Don't show '\\r\\n' in raw SIP messages",
+ "If the raw text of the SIP message "
+ "is displayed, the trailing carriage "
+ "return and line feed are not shown",
+ &global_sip_raw_text_without_crlf);
+
+ prefs_register_enum_preference(sip_module, "raw_text_body_default_encoding",
+ "Default charset of raw SIP messages",
+ "Display sip body of raw text by using this charset. The default is UTF-8.",
+ &global_sip_raw_text_body_default_encoding,
+ ws_supported_mibenum_vals_character_sets_ev_array, FALSE);
+
+ prefs_register_bool_preference(sip_module, "strict_sip_version",
+ "Enforce strict SIP version check (" SIP2_HDR ")",
+ "If enabled, only " SIP2_HDR " traffic will be dissected as SIP. "
+ "Disable it to allow SIP traffic with a different version "
+ "to be dissected as SIP.",
+ &strict_sip_version);
+
+ prefs_register_bool_preference(sip_module, "desegment_headers",
+ "Reassemble SIP headers spanning multiple TCP segments",
+ "Whether the SIP dissector should reassemble headers "
+ "of a request spanning multiple TCP segments. "
+ "To use this option, you must also enable "
+ "\"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
+ &sip_desegment_headers);
+
+ prefs_register_bool_preference(sip_module, "desegment_body",
+ "Reassemble SIP bodies spanning multiple TCP segments",
+ "Whether the SIP dissector should use the "
+ "\"Content-length:\" value, if present, to reassemble "
+ "the body of a request spanning multiple TCP segments, "
+ "and reassemble chunked data spanning multiple TCP segments. "
+ "To use this option, you must also enable "
+ "\"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
+ &sip_desegment_body);
+
+ prefs_register_bool_preference(sip_module, "retrans_the_same_sport",
+ "Retransmissions always use the same source port",
+ "Whether retransmissions are detected coming from the same source port only.",
+ &sip_retrans_the_same_sport);
+
+ prefs_register_bool_preference(sip_module, "delay_sdp_changes",
+ "Delay SDP changes for tracking media",
+ "Whether SIP should delay tracking the media (e.g., RTP/RTCP) until an SDP offer "
+ "is answered. If enabled, mid-dialog changes to SDP and media state only take "
+ "effect if and when an SDP offer is successfully answered; however enabling this "
+ "prevents tracking media in early-media call scenarios",
+ &sip_delay_sdp_changes);
+
+ prefs_register_bool_preference(sip_module, "hide_generatd_call_id",
+ "Hide the generated Call Id",
+ "Whether the generated call id should be hidden(not displayed) in the tree or not.",
+ &sip_hide_generatd_call_ids);
+
+ /* UAT */
+ sip_custom_headers_uat = uat_new("Custom SIP Header Fields",
+ sizeof(header_field_t),
+ "custom_sip_header_fields",
+ TRUE,
+ &sip_custom_header_fields,
+ &sip_custom_num_header_fields,
+ /* specifies named fields, so affects dissection
+ and the set of named fields */
+ UAT_AFFECTS_DISSECTION|UAT_AFFECTS_FIELDS,
+ NULL,
+ header_fields_copy_cb,
+ header_fields_update_cb,
+ header_fields_free_cb,
+ header_fields_post_update_cb,
+ header_fields_reset_cb,
+ sip_custom_header_uat_fields
+ );
+
+ prefs_register_uat_preference(sip_module, "custom_sip_header_fields", "Custom SIP header fields",
+ "A table to define custom SIP header for which fields can be setup and used for filtering/data extraction etc.",
+ sip_custom_headers_uat);
+
+ prefs_register_bool_preference(sip_module, "validate_authorization",
+ "Validate SIP authorization",
+ "Validate SIP authorizations with known credentials",
+ &global_sip_validate_authorization);
+
+ sip_authorization_users_uat = uat_new("SIP authorization users",
+ sizeof(authorization_user_t),
+ "authorization_users_sip",
+ TRUE,
+ &sip_authorization_users,
+ &sip_authorization_num_users,
+ /* specifies named fields, so affects dissection
+ and the set of named fields */
+ UAT_AFFECTS_DISSECTION|UAT_AFFECTS_FIELDS,
+ NULL,
+ authorization_users_copy_cb,
+ authorization_users_update_cb,
+ authorization_users_free_cb,
+ NULL,
+ NULL,
+ sip_authorization_users_uat_fields
+ );
+
+ prefs_register_uat_preference(sip_module, "authorization_users_sip", "SIP authorization users",
+ "A table to define user credentials used for validating authorization attempts",
+ sip_authorization_users_uat);
+
+ register_init_routine(&sip_init_protocol);
+ register_cleanup_routine(&sip_cleanup_protocol);
+ heur_subdissector_list = register_heur_dissector_list("sip", proto_sip);
+ /* Register for tapping */
+ sip_tap = register_tap("sip");
+ sip_follow_tap = register_tap("sip_follow");
+
+ ext_hdr_subdissector_table = register_dissector_table("sip.hdr", "SIP Extension header", proto_sip, FT_STRING, STRING_CASE_SENSITIVE);
+
+ register_stat_tap_table_ui(&sip_stat_table);
+
+ /* compile patterns */
+ ws_mempbrk_compile(&pbrk_comma_semi, ",;");
+ ws_mempbrk_compile(&pbrk_whitespace, " \t\r\n");
+ ws_mempbrk_compile(&pbrk_param_end, ">,;? \r");
+ ws_mempbrk_compile(&pbrk_param_end_colon_brackets, ">,;? \r:[]");
+ ws_mempbrk_compile(&pbrk_header_end_dquote, "\r\n,;\"");
+ ws_mempbrk_compile(&pbrk_tab_sp_fslash, "\t /");
+ ws_mempbrk_compile(&pbrk_addr_end, "[] \t:;");
+ ws_mempbrk_compile(&pbrk_via_param_end, "\t;, ");
+
+ register_follow_stream(proto_sip, "sip_follow", sip_follow_conv_filter, sip_follow_index_filter, sip_follow_address_filter,
+ udp_port_to_display, follow_tvb_tap_listener, NULL, NULL);
+}
+
+void
+proto_reg_handoff_sip(void)
+{
+ static guint saved_sip_tls_port;
+ static gboolean sip_prefs_initialized = FALSE;
+
+ if (!sip_prefs_initialized) {
+ sigcomp_handle = find_dissector_add_dependency("sigcomp", proto_sip);
+ sip_diag_handle = find_dissector("sip.diagnostic");
+ sip_uri_userinfo_handle = find_dissector("sip.uri_userinfo");
+ sip_via_branch_handle = find_dissector("sip.via_branch");
+ sip_via_be_route_handle = find_dissector("sip.via_be_route");
+ /* Check for a dissector to parse Reason Code texts */
+ sip_reason_code_handle = find_dissector("sip.reason_code");
+ /* SIP content type and internet media type used by other dissectors are the same */
+ media_type_dissector_table = find_dissector_table("media_type");
+
+ dissector_add_uint_range_with_preference("udp.port", DEFAULT_SIP_PORT_RANGE, sip_handle);
+ dissector_add_string("media_type", "message/sip", sip_handle);
+ dissector_add_string("ws.protocol", "sip", sip_handle); /* RFC 7118 */
+
+ dissector_add_uint_range_with_preference("tcp.port", DEFAULT_SIP_PORT_RANGE, sip_tcp_handle);
+
+ heur_dissector_add("udp", dissect_sip_heur, "SIP over UDP", "sip_udp", proto_sip, HEURISTIC_ENABLE);
+ heur_dissector_add("tcp", dissect_sip_tcp_heur, "SIP over TCP", "sip_tcp", proto_sip, HEURISTIC_ENABLE);
+ heur_dissector_add("sctp", dissect_sip_heur, "SIP over SCTP", "sip_sctp", proto_sip, HEURISTIC_ENABLE);
+ heur_dissector_add("stun", dissect_sip_heur, "SIP over TURN", "sip_stun", proto_sip, HEURISTIC_ENABLE);
+
+ dissector_add_uint("acdr.tls_application_port", 5061, sip_handle);
+ dissector_add_uint("acdr.tls_application", TLS_APP_SIP, sip_handle);
+ dissector_add_string("protobuf_field", "adc.sip.ResponsePDU.body", sip_handle);
+ dissector_add_string("protobuf_field", "adc.sip.RequestPDU.body", sip_handle);
+
+ exported_pdu_tap = find_tap_id(EXPORT_PDU_TAP_NAME_LAYER_7);
+
+ sip_prefs_initialized = TRUE;
+ } else {
+ ssl_dissector_delete(saved_sip_tls_port, sip_tcp_handle);
+ }
+ /* Set our port number for future use */
+ ssl_dissector_add(sip_tls_port, sip_tcp_handle);
+ saved_sip_tls_port = sip_tls_port;
+
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */