Fix up a bunch of arguments to "dissect_ber_identifier()" to match its
[obnox/wireshark/wip.git] / epan / dissectors / packet-sip.c
1 /* packet-sip.c
2  * Routines for the Session Initiation Protocol (SIP) dissection.
3  * RFCs 3261-3264
4  *
5  * TODO: Pay attention to Content-Type: It might not always be SDP.
6  *      Content-Type is fixed, mixed/mode is not handled though.
7  *       hf_ display filters for headers of SIP extension RFCs:
8  *              Done for RFC 3265, RFC 3262
9  *              Use hash table for list of headers
10  *       Add sip msg body dissection based on Content-Type for:
11  *                SDP, MIME, and other types
12  *       Align SIP methods with recent Internet Drafts or RFC
13  *               (SIP INFO, rfc2976 - done)
14  *               (SIP SUBSCRIBE-NOTIFY - done)
15  *               (SIP REFER - done)
16  *               check for other
17  *
18  * Copyright 2000, Heikki Vatiainen <hessu@cs.tut.fi>
19  * Copyright 2001, Jean-Francois Mule <jfm@cablelabs.com>
20  * Copyright 2004, Anders Broman <anders.broman@ericsson.com>
21  *
22  * $Id$
23  *
24  * Ethereal - Network traffic analyzer
25  * By Gerald Combs <gerald@ethereal.com>
26  * Copyright 1998 Gerald Combs
27  *
28  * Copied from packet-cops.c
29  *
30  * This program is free software; you can redistribute it and/or
31  * modify it under the terms of the GNU General Public License
32  * as published by the Free Software Foundation; either version 2
33  * of the License, or (at your option) any later version.
34  *
35  * This program is distributed in the hope that it will be useful,
36  * but WITHOUT ANY WARRANTY; without even the implied warranty of
37  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38  * GNU General Public License for more details.
39  *
40  * You should have received a copy of the GNU General Public License
41  * along with this program; if not, write to the Free Software
42  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
43  */
44
45 #ifdef HAVE_CONFIG_H
46 # include "config.h"
47 #endif
48
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <ctype.h>
53
54 #include <epan/prefs.h>
55
56 #include <glib.h>
57 #include <epan/packet.h>
58
59 #include "packet-sip.h"
60 #include <epan/tap.h>
61
62 #define TCP_PORT_SIP 5060
63 #define UDP_PORT_SIP 5060
64
65 static gint sip_tap = -1;
66 static dissector_handle_t sigcomp_handle;
67
68 /* Initial size of hash table tracking state of calls */
69 #define SIP_INIT_HASH_TABLE_SIZE 50
70
71 /* Initialize the protocol and registered fields */
72 static gint proto_sip                           = -1;
73 static gint proto_raw_sip                       = -1;
74 static gint hf_msg_hdr                          = -1;
75 static gint hf_Method                           = -1;
76 static gint hf_Request_Line                     = -1;
77 static gint hf_Status_Code                      = -1;
78 static gint hf_Status_Line                      = -1;
79 static gint hf_sip_display                      = -1;
80 static gint hf_sip_to_addr                      = -1;
81 static gint hf_sip_from_addr            = -1;
82 static gint hf_sip_tag                          = -1;
83 static gint hf_sip_uri                          = -1;
84 static gint hf_sip_contact_addr         = -1;
85 static gint hf_sip_contact_item         = -1;
86 static gint hf_sip_resend                       = -1;
87 static gint hf_sip_original_frame       = -1;
88
89 /* Initialize the subtree pointers */
90 static gint ett_sip                             = -1;
91 static gint ett_sip_reqresp             = -1;
92 static gint ett_sip_hdr                         = -1;
93 static gint ett_raw_text                        = -1;
94 static gint ett_sip_element             = -1;
95 static gint ett_sip_uri                         = -1;
96 static gint ett_sip_contact_item        = -1;
97 static gint ett_sip_message_body        = -1;
98
99 /* PUBLISH method added as per http://www.ietf.org/internet-drafts/draft-ietf-sip-publish-01.txt */
100 static const char *sip_methods[] = {
101         "<Invalid method>",      /* Pad so that the real methods start at index 1 */
102         "ACK",
103         "BYE",
104         "CANCEL",
105         "DO",
106         "INFO",
107         "INVITE",
108         "MESSAGE",
109         "NOTIFY",
110         "OPTIONS",
111         "PRACK",
112         "QAUTH",
113         "REFER",
114         "REGISTER",
115         "SPRACK",
116         "SUBSCRIBE",
117         "UPDATE",
118         "PUBLISH"
119 };
120
121 /* from RFC 3261
122  * Updated with info from http://www.iana.org/assignments/sip-parameters
123  * (last updated 2004-10-17)
124  * Updated with: http://www.ietf.org/internet-drafts/draft-ietf-sip-resource-priority-05.txt
125  */
126 typedef struct {
127         char *name;
128         char *compact_name;
129 } sip_header_t;
130 static const sip_header_t sip_headers[] = {
131                 { "Unknown-header",                     NULL }, /* 0 Pad so that the real headers start at index 1 */
132                 { "Accept",                                     NULL }, /* 1 */
133                 { "Accept-Contact",                             "a"      }, /* 2 RFC3841  */
134                 { "Accept-Encoding",                    NULL }, /* 3 */
135                 { "Accept-Language",                    NULL }, /* 4 */
136                                 { "Accept-Resource-Priority",   NULL }, /* 5 draft-ietf-sip-resource-priority-05.txt */
137                 { "Alert-Info",                                 NULL },
138                 { "Allow",                                              NULL },
139                 { "Allow-Events",                               "u"  }, /* 8 RFC3265  */
140                 { "Authentication-Info",                NULL },
141                 { "Authorization",                              NULL }, /* 10 */
142                 { "Call-ID",                                    "i"  },
143                 { "Call-Info",                                  NULL },
144                 { "Contact",                                    "m"  },
145                 { "Content-Disposition",                NULL },
146                 { "Content-Encoding",                   "e"  }, /* 15 */
147                 { "Content-Language",                   NULL },
148                 { "Content-Length",                     "l"  },
149                 { "Content-Type",                               "c"  },
150                 { "CSeq",                                               NULL },
151                 { "Date",                                               NULL }, /* 20 */
152                 { "Error-Info",                                 NULL },
153                 { "Event",                                              "o"  },
154                 { "Expires",                                    NULL },
155                 { "From",                                               "f"  },
156                 { "In-Reply-To",                                NULL }, /*  25 RFC3261  */
157                 { "Join",                                               NULL }, /*  26 RFC-ietf-sip-join-03.txt  */
158                 { "Max-Forwards",                               NULL },
159                 { "MIME-Version",                               NULL },
160                 { "Min-Expires",                                NULL },
161                 { "Min-SE",                                             NULL },  /*  30 RFC-ietf-sip-session-timer-15.txt  */
162                 { "Organization",                               NULL },
163                 { "P-Access-Network-Info",              NULL },  /*  32 RFC3455  */
164                 { "P-Asserted-Identity",        NULL },  /*  33 RFC3325  */
165                 { "P-Associated-URI",           NULL },  /*  34 RFC3455  */
166                 { "P-Called-Party-ID",          NULL },  /*  35 RFC3455  */
167                 { "P-Charging-Function-Addresses",NULL },/*  36 RFC3455  */
168                 { "P-Charging-Vector",          NULL },  /*  37 RFC3455  */
169                 { "P-DCS-Trace-Party-ID",       NULL },  /*  38 RFC3603  */
170                 { "P-DCS-OSPS",                 NULL },  /*  39 RFC3603  */
171                 { "P-DCS-Billing-Info",         NULL },  /*  40 RFC3603  */
172                 { "P-DCS-LAES",                 NULL },  /*  41 RFC3603  */
173                 { "P-DCS-Redirect",             NULL },  /*  42 RFC3603  */
174                 { "P-Media-Authorization",      NULL },  /*  43 RFC3313  */
175                 { "P-Preferred-Identity",       NULL },  /*  44 RFC3325  */
176                 { "P-Visited-Network-ID",       NULL },  /*  45 RFC3455  */
177                 { "Path",                       NULL },  /*  46 RFC3327  */
178                 { "Priority",                                   NULL },
179                 { "Privacy",                    NULL },  /*  48 RFC3323  */
180                 { "Proxy-Authenticate",                 NULL },
181                 { "Proxy-Authorization",                NULL },  /* 50 */
182                 { "Proxy-Require",                              NULL },
183                 { "RAck",                                               NULL },
184                 { "Reason",                     NULL },  /*  53 RFC3326  */
185                 { "Record-Route",                               NULL },
186                 { "Referred-By",                                "b"  },  /*  55 RFC3892  */
187                 { "Reject-Contact",                             "j"  },  /*  56 RFC3841  */
188                 { "Replaces",                                   NULL },  /*  57 RFC3891  */
189                 { "Reply-To",                                   NULL },  /*  58 RFC3261  */
190                 { "Request-Disposition",                "d"  },  /*  59 RFC3841  */
191                 { "Require",                                    NULL },  /*  60 RFC3261  */
192                                 { "Resource-Priority",                  NULL },  /*  61 draft-ietf-sip-resource-priority-05.txt */
193                 { "Retry-After",                                NULL },  /*  62 RFC3261  */
194                 { "Route",                                              NULL },  /*  63 RFC3261  */
195                 { "RSeq",                                               NULL },  /*  64 RFC3841  */
196                 { "Security-Client",                    NULL },  /*  65 RFC3329  */
197                 { "Security-Server",                    NULL },  /*  66 RFC3329  */
198                 { "Security-Verify",                    NULL },  /*  67 RFC3329  */
199                 { "Server",                                             NULL },  /*  68 RFC3261  */
200                 { "Service-Route",                              NULL },  /*  69 RFC3608  */
201                 { "Session-Expires",                    "x"  },  /*  70 RFC-ietf-sip-session-timer-15.txt  */
202                 { "SIP-ETag",                                   NULL },  /*  71 draft-ietf-sip-publish-03  */
203                 { "SIP-If-Match",                               NULL },  /*  72 draft-ietf-sip-publish-03  */
204                 { "Subject",                                    "s"  },  /*  73 RFC3261  */
205                 { "Subscription-State",                 NULL },  /*  74 RFC3265  */
206                 { "Supported",                                  "k"      },  /*  75 RFC3261  */
207                 { "Timestamp",                                  NULL },  /*  76 RFC3261  */
208                 { "To",                                                 "t"  },  /*  77 RFC3261  */
209                 { "Unsupported",                                NULL },  /*  78 RFC3261  */
210                 { "User-Agent",                                 NULL },  /*  79 RFC3261  */
211                 { "Via",                                                "v"  },  /*  80 RFC3261  */
212                 { "Warning",                                    NULL },  /*  81 RFC3261  */
213                 { "WWW-Authenticate",                   NULL },  /*  82 RFC3261  */
214                 { "Refer-To",                                   "r"  },  /*  83 RFC3515  */
215
216 };
217
218
219 #define POS_ACCEPT                                                      1
220 #define POS_ACCEPT_CONTACT                                      2
221 #define POS_ACCEPT_ENCODING                                     3
222 #define POS_ACCEPT_LANGUAGE                                     4
223 #define POS_ACCEPT_RESOURCE_PRIORITY            5
224 #define POS_ALERT_INFO                                          6
225 #define POS_ALLOW                                                       7
226 #define POS_ALLOW_EVENTS                                        8
227 #define POS_AUTHENTICATION_INFO                         9
228 #define POS_AUTHORIZATION                                       10
229 #define POS_CALL_ID                                                     11
230 #define POS_CALL_INFO                                           12
231 #define POS_CONTACT                                                     13
232 #define POS_CONTENT_DISPOSITION                         14
233 #define POS_CONTENT_ENCODING                            15
234 #define POS_CONTENT_LANGUAGE                            16
235 #define POS_CONTENT_LENGTH                                      17
236 #define POS_CONTENT_TYPE                                        18
237 #define POS_CSEQ                                                        19
238 #define POS_DATE                                                        20
239 #define POS_ERROR_INFO                                          21
240 #define POS_EVENT                                                       22
241 #define POS_EXPIRES                                                     23
242 #define POS_FROM                                                        24
243 #define POS_IN_REPLY_TO                                         25
244 #define POS_JOIN                                                        26
245 #define POS_MAX_FORWARDS                                        27
246 #define POS_MIME_VERSION                                        28
247 #define POS_MIN_EXPIRES                                         29
248 #define POS_MIN_SE                                                      30
249 #define POS_ORGANIZATION                                        31
250 #define POS_P_ACCESS_NETWORK_INFO                       32
251 #define POS_P_ASSERTED_IDENTITY                         33
252 #define POS_P_ASSOCIATED_URI                            34
253 #define POS_P_CALLED_PARTY_ID                           35
254 #define POS_P_CHARGING_FUNCTION_ADDRESSES       36
255 #define POS_P_CHARGING_VECTOR                           37
256 #define POS_P_DCS_TRACE_PARTY_ID                        38
257 #define POS_P_DCS_OSPS                                          39
258 #define POS_P_DCS_BILLING_INFO                          40
259 #define POS_P_DCS_LAES                                          41
260 #define POS_P_DCS_REDIRECT                                      42
261 #define POS_P_MEDIA_AUTHORIZATION                       43
262 #define POS_P_PREFERRED_IDENTITY                        44
263 #define POS_P_VISITED_NETWORK_ID                        45
264 #define POS_PATH                                                        46
265 #define POS_PRIORITY                                            47
266 #define POS_PRIVACY                                                     48
267 #define POS_PROXY_AUTHENTICATE                          49
268 #define POS_PROXY_AUTHORIZATION                         50
269 #define POS_PROXY_REQUIRE                                       51
270 #define POS_RACK                                                        52
271 #define POS_REASON                                                      53
272 #define POS_RECORD_ROUTE                                        54
273 #define POS_REFERED_BY                                          55
274 #define POS_REJECT_CONTACT                                      56
275 #define POS_REPLACES                                            57
276 #define POS_REPLY_TO                                            58
277 #define POS_REQUEST_DISPOSITION                         59
278 #define POS_REQUIRE                                                     60
279 #define POS_RESOURCE_PRIORITY                           61
280 #define POS_RETRY_AFTER                                         62
281 #define POS_ROUTE                                                       63
282 #define POS_RSEQ                                                        64
283 #define POS_SECURITY_CLIENT                                     65
284 #define POS_SECURITY_SERVER                                     66
285 #define POS_SECURITY_VERIFY                                     67
286 #define POS_SERVER                                                      68
287 #define POS_SERVICE_ROUTE                                       69
288 #define POS_SESSION_EXPIRES                                     70
289 #define POS_SIP_ETAG                                            71
290 #define POS_SIP_IF_MATCH                                        72
291 #define POS_SUBJECT                                                     73
292 #define POS_SUBSCRIPTION_STATE                          74
293 #define POS_SUPPORTED                                           75
294 #define POS_TIMESTAMP                                           76
295 #define POS_TO                                                          77
296 #define POS_UNSUPPORTED                                         78
297 #define POS_USER_AGENT                                          79
298 #define POS_VIA                                                         80
299 #define POS_WARNING                                                     81
300 #define POS_WWW_AUTHENTICATE                            82
301 #define POS_REFER_TO                                            83
302
303 static gint hf_header_array[] = {
304                 -1, /* 0"Unknown-header" - Pad so that the real headers start at index 1 */
305                 -1, /* 1"Accept"                                                                                */
306                 -1, /* 2"Accept-Contact"                                        RFC3841         */
307                 -1, /* 3"Accept-Encoding"                                                               */
308                 -1, /* 4"Accept-Language"                                                               */
309                 -1, /* 5"Accept-Resource-Priority"  draft-ietf-sip-resource-priority-05.txt     */
310                 -1, /* 6"Alert-Info",                                                                   */
311                 -1, /* 7"Allow",                                                                                */
312                 -1, /* 8"Allow-Events",                                         RFC3265         */
313                 -1, /* 9"Authentication-Info"                                                   */
314                 -1, /* 10"Authorization",                                                               */
315                 -1, /* 11"Call-ID",                                                                             */
316                 -1, /* 12"Call-Info"                                                                    */
317                 -1, /* 13"Contact",                                                                             */
318                 -1, /* 14"Content-Disposition",                                                 */
319                 -1, /* 15"Content-Encoding",                                                    */
320                 -1, /* 16"Content-Language",                                                    */
321                 -1, /* 17"Content-Length",                                                              */
322                 -1, /* 18"Content-Type",                                                                */
323                 -1, /* 19"CSeq",                                                                                */
324                 -1, /* 20"Date",                                                                                */
325                 -1, /* 21"Error-Info",                                                                  */
326                 -1, /* 22"Event",                                                                               */
327                 -1, /* 23"Expires",                                                                             */
328                 -1, /* 24"From",                                                                                */
329                 -1, /* 25"In-Reply-To",                                         RFC3261         */
330                 -1, /* 26"Join",                                                        RFC-ietf-sip-join-03.txt  */
331                 -1, /* 27"Max-Forwards",                                                                */
332                 -1, /* 28"MIME-Version",                                                                */
333                 -1, /* 29"Min-Expires",                                                                 */
334                 -1, /* 30"Min-SE",                                                      RFC-ietf-sip-session-timer-15.txt  */
335                 -1, /* 31"Organization",                                                                */
336                 -1, /* 32"P-Access-Network-Info",                               RFC3455 */
337                 -1, /* 33"P-Asserted-Identity",                                 RFC3325 */
338                 -1, /* 34"P-Associated-URI",                                    RFC3455 */
339                 -1, /* 35"P-Called-Party-ID",                                   RFC3455 */
340                 -1, /* 36"P-Charging-Function-Addresses",               RFC3455 */
341                 -1, /* 37"P-Charging-Vector",                                   RFC3455 */
342                 -1, /* 38"P-DCS-Trace-Party-ID",                                RFC3603 */
343                 -1, /* 39"P-DCS-OSPS",                                                  RFC3603 */
344                 -1, /* 40"P-DCS-Billing-Info",                                  RFC3603 */
345                 -1, /* 41"P-DCS-LAES",                                                  RFC3603 */
346                 -1, /* 42"P-DCS-Redirect",                                              RFC3603 */
347                 -1, /* 43"P-Media-Authorization",                               RFC3313 */
348                 -1, /* 44"P-Preferred-Identity",                                RFC3325 */
349                 -1, /* 45"P-Visited-Network-ID",                                RFC3455 */
350                 -1, /* 46"Path",                                                                RFC3327 */
351                 -1, /* 47"Priority"                                                                             */
352                 -1, /* 48"Privacy",                                                             RFC3323 */
353                 -1, /* 49"Proxy-Authenticate",                                                  */
354                 -1, /* 50"Proxy-Authorization",                                                 */
355                 -1, /* 51"Proxy-Require",                                                               */
356                 -1, /* 52"RAck",                                                                                */
357                 -1, /* 53"Reason",                                                              RFC3326 */
358                 -1, /* 54"Record-Route",                                                                */
359                 -1, /* 55"Referred-By",                                                                 */
360                 -1, /* 56"Reject-Contact",                                              RFC3841 */
361                 -1, /* 57"Replaces",                                                    RFC3891 */
362                 -1, /* 58"Reply-To",                                                    RFC3261 */
363                 -1, /* 59"Request-Disposition",                                 RFC3841 */
364                 -1, /* 60"Require",                                                             RFC3261 */
365                                 -1, /* 61"Resource-Priority",draft-ietf-sip-resource-priority-05.txt */
366                                 -1, /* 62"Retry-After",                                                 RFC3261 */
367                 -1, /* 63"Route",                                                               RFC3261 */
368                 -1, /* 64"RSeq",                                                                RFC3841 */
369                 -1, /* 65"Security-Client",                                             RFC3329 */
370                 -1, /* 66"Security-Server",                                             RFC3329 */
371                 -1, /* 67"Security-Verify",                                             RFC3329 */
372                 -1, /* 68"Server",                                                              RFC3261 */
373                 -1, /* 69"Service-Route",                                               RFC3608 */
374                 -1, /* 70"Session-Expires",     RFC-ietf-sip-session-timer-15.txt  */
375                 -1, /* 71"SIP-ETag",                      draft-ietf-sip-publish-04  */
376                 -1, /* 72"SIP-If-Match",                  draft-ietf-sip-publish-04  */
377                 -1, /* 73"Subject",                                                             RFC3261 */
378                 -1, /* 74"Subscription-State",                                  RFC3265 */
379                 -1, /* 75"Supported",                                                   RFC3261 */
380                 -1, /* 76"Timestamp",                                                   RFC3261 */
381                 -1, /* 77"To",                                                                  RFC3261 */
382                 -1, /* 78"Unsupported",                                                 RFC3261 */
383                 -1, /* 79"User-Agent",                                                  RFC3261 */
384                 -1, /* 80"Via",                                                                 RFC3261 */
385                 -1, /* 81"Warning",                                                             RFC3261 */
386                 -1, /* 82"WWW-Authenticate",                                    RFC3261 */
387                 -1, /* 83"Refer-To",                                                    RFC3515 */
388
389 };
390
391 /*
392  * Type of line.  It's either a SIP Request-Line, a SIP Status-Line, or
393  * another type of line.
394  */
395 typedef enum {
396         REQUEST_LINE,
397         STATUS_LINE,
398         OTHER_LINE
399 } line_type_t;
400
401 /* global_sip_raw_text determines whether we are going to display               */
402 /* the raw text of the SIP message, much like the MEGACO dissector does.        */
403 static gboolean global_sip_raw_text = FALSE;
404 /* strict_sip_version determines whether the SIP dissector enforces
405  * the SIP version to be "SIP/2.0". */
406 static gboolean strict_sip_version = TRUE;
407
408 static gboolean dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo,
409     proto_tree *tree, gboolean is_heur);
410 static line_type_t sip_parse_line(tvbuff_t *tvb, gint linelen,
411     guint *token_1_len);
412 static gboolean sip_is_known_request(tvbuff_t *tvb, int meth_offset,
413     guint meth_len, guint *meth_idx);
414 static gint sip_is_known_sip_header(tvbuff_t *tvb, int offset,
415     guint header_len);
416 static void dfilter_sip_request_line(tvbuff_t *tvb, proto_tree *tree,
417     guint meth_len);
418 static void dfilter_sip_status_line(tvbuff_t *tvb, proto_tree *tree);
419 static void tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree);
420 static guint sip_is_packet_resend(packet_info *pinfo,
421                                 gchar* cseq_method,
422                                 gchar* call_id,
423                                 guchar cseq_number_set, guint32 cseq_number,
424                                 line_type_t line_type);
425
426
427 /* SIP content type and internet media type used by other dissectors
428  * are the same.  List of media types from IANA at:
429  * http://www.iana.org/assignments/media-types/index.html */
430 static dissector_table_t media_type_dissector_table;
431
432 #define SIP2_HDR "SIP/2.0"
433 #define SIP2_HDR_LEN (strlen (SIP2_HDR))
434
435 /* Store the info needed by the SIP tap for one packet */
436 static sip_info_value_t *stat_info;
437
438 /* The buffer size for the cseq_method name */
439 #define MAX_CSEQ_METHOD_SIZE 16
440
441 /****************************************************************************
442  * Conversation-type definitions
443  *
444  * For each call, keep track of the current cseq number and state of
445  * transaction, in order to be able to detect retransmissions.
446  *
447  * Don't use the conservation mechanism, but instead:
448  * - store with each dissected packet original frame (if any)
449  * - maintain a global hash table of
450  *   (call_id, source_addr, dest_addr) -> (cseq, transaction_state, frame)
451  ****************************************************************************/
452
453 static GHashTable *sip_hash = NULL;           /* Hash table */
454 static GMemChunk  *sip_hash_keys = NULL;      /* Hash key chunk */
455 static GMemChunk  *sip_hash_values = NULL;    /* Hash value chunk */
456
457 /* Types for hash table keys and values */
458 #define MAX_CALL_ID_SIZE 128
459 typedef struct
460 {
461         char call_id[MAX_CALL_ID_SIZE];
462         address source_address;
463         guint32 source_port;
464         address dest_address;
465         guint32 dest_port;
466 } sip_hash_key;
467
468
469 typedef enum
470 {
471         nothing_seen,
472         request_seen,
473         provisional_response_seen,
474         final_response_seen
475 } transaction_state_t;
476
477 typedef struct
478 {
479         guint32 cseq;
480         transaction_state_t transaction_state;
481         guint32 response_code;
482         gint frame_number;
483 } sip_hash_value;
484
485
486 /************************/
487 /* Hash table functions */
488
489 /* Equal keys */
490 gint sip_equal(gconstpointer v, gconstpointer v2)
491 {
492         const sip_hash_key* val1 = v;
493         const sip_hash_key* val2 = v2;
494
495         /* Call id must match */
496         if (strcmp(val1->call_id, val2->call_id) != 0)
497         {
498                 return 0;
499         }
500
501         /* Addresses must match */
502         return  (ADDRESSES_EQUAL(&(val1->source_address), &(val2->source_address))) &&
503                 (val1->source_port == val2->source_port) &&
504                 (ADDRESSES_EQUAL(&(val1->dest_address), &(val2->dest_address))) &&
505                 (val1->dest_port == val2->dest_port);
506 }
507
508 /* Compute a hash value for a given key. */
509 /* Don't try to use addresses here, call-id should be almost unique. */
510 guint sip_hash_func(gconstpointer v)
511 {
512         gint n;
513         const sip_hash_key *key = v;
514         guint value = strlen(key->call_id);
515         gint chars_to_use = value / 4;
516
517         /* First few characters from the call-id should be enough... */
518         for (n=0; n < chars_to_use; n++)
519         {
520                 value += key->call_id[n];
521         }
522
523         return value;
524 }
525
526
527 /* Initializes the hash table and the mem_chunk area each time a new
528  * file is loaded or re-loaded in ethereal */
529 static void
530 sip_init_protocol(void)
531 {
532         /* Destroy any existing memory chunks / hashes. */
533         if (sip_hash)
534                 g_hash_table_destroy(sip_hash);
535         if (sip_hash_keys)
536                 g_mem_chunk_destroy(sip_hash_keys);
537         if (sip_hash_values)
538                 g_mem_chunk_destroy(sip_hash_values);
539
540         /* Now create them over */
541         sip_hash = g_hash_table_new(sip_hash_func, sip_equal);
542         sip_hash_keys = g_mem_chunk_new("sip_hash_keys",
543                                         sizeof(sip_hash_key),
544                                         SIP_INIT_HASH_TABLE_SIZE * sizeof(sip_hash_key),
545                                         G_ALLOC_ONLY);
546         sip_hash_values = g_mem_chunk_new("sip_hash_values",
547                                         sizeof(sip_hash_value),
548                                         SIP_INIT_HASH_TABLE_SIZE * sizeof(sip_hash_value),
549                                         G_ALLOC_ONLY);
550 }
551
552 /*
553  * Copied from the mgcp dissector. (This function should be moved to /epan )
554  * tvb_skip_wsp - Returns the position in tvb of the first non-whitespace
555  *                character following offset or offset + maxlength -1 whichever
556  *                is smaller.
557  *
558  * Parameters:
559  * tvb - The tvbuff in which we are skipping whitespace.
560  * offset - The offset in tvb from which we begin trying to skip whitespace.
561  * maxlength - The maximum distance from offset that we may try to skip
562  * whitespace.
563  *
564  * Returns: The position in tvb of the first non-whitespace
565  *          character following offset or offset + maxlength -1 whichever
566  *          is smaller.
567  */
568 static gint tvb_skip_wsp(tvbuff_t* tvb, gint offset, gint maxlength)
569 {
570         gint counter = offset;
571         gint end = offset + maxlength,tvb_len;
572         guint8 tempchar;
573
574         /* Get the length remaining */
575         tvb_len = tvb_length(tvb);
576         end = offset + maxlength;
577         if (end >= tvb_len)
578         {
579                 end = tvb_len;
580         }
581
582         /* Skip past spaces and tabs until run out or meet something else */
583         for (counter = offset;
584              counter < end &&
585               ((tempchar = tvb_get_guint8(tvb,counter)) == ' ' ||
586               tempchar == '\t');
587              counter++);
588
589         return (counter);
590 }
591
592 /* Structure to collect info about a sip uri */
593 typedef struct _uri_offset_info
594 {
595         gint display_name_start;
596         gint display_name_end;
597         gint uri_start;
598         gint uri_end;
599         gint uri_parameters_start;
600         gint uri_parameters_end;
601         gint name_addr_start;
602         gint name_addr_end;
603 } uri_offset_info;
604
605 /* Code to parse a sip uri.
606  * Returns Offset end off parsing or -1 for unsuccessful parsing
607  */
608 static gint
609 dissect_sip_uri(tvbuff_t *tvb, packet_info *pinfo _U_, gint start_offset,
610                 gint line_end_offset, uri_offset_info *uri_offsets)
611 {
612         gchar c;
613         gint i;
614         gint current_offset;
615         gint queried_offset;
616         gint colon_offset;
617         gint comma_offset;
618         gint semicolon_offset;
619         gint question_mark_offset;
620         gboolean uri_without_angle_quotes = FALSE;
621
622         /* skip Spaces and Tabs */
623         current_offset = tvb_skip_wsp(tvb, start_offset, line_end_offset - start_offset);
624
625         if(current_offset >= line_end_offset) {
626                 /* Nothing to parse */
627                 return -1;
628         }
629
630         uri_offsets->name_addr_start = current_offset;
631
632         /* First look, if we have a display name */
633         c=tvb_get_guint8(tvb, current_offset);
634         switch(c)
635         {
636                 case '"':
637                         /* We have a display name, look for the next unescaped '"' */
638                         uri_offsets->display_name_start = current_offset;
639                         do
640                         {
641                                 queried_offset = tvb_find_guint8(tvb, current_offset + 1, line_end_offset - (current_offset + 1), '"');
642                                 if(queried_offset == -1)
643                                 {
644                                         /* malformed URI */
645                                         return -1;
646                                 }
647                                 current_offset = queried_offset;
648
649                                 /* Is it escaped? */
650                                 /* count back slashes before '"' */
651                                 for(i=1;tvb_get_guint8(tvb, queried_offset - i) == '\\';i++);
652                                 i--;
653
654                                 if(i % 2 == 0)
655                                 {
656                                         /* not escaped */
657                                         break;
658                                 }
659                         } while (current_offset < line_end_offset);
660                         if(current_offset >= line_end_offset)
661                         {
662                                 /* malformed URI */
663                                 return -1;
664                         }
665
666                         uri_offsets->display_name_end = current_offset;
667
668                         /* find start of the URI */
669                         queried_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, '<');
670                         if(queried_offset == -1)
671                         {
672                                 /* malformed Uri */
673                                 return -1;
674                         }
675                         current_offset = queried_offset + 1;
676                         break;
677
678                 case '<':
679                         /* We don't have a display name */
680                         current_offset++;
681                         break;
682
683                 default:
684                         /* We have either an URI without angles or a display name with a limited character set */
685                         /* Look for the right angle quote or colon */
686                         queried_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, '<');
687                         colon_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, ':');
688                         if(queried_offset != -1 && colon_offset != -1)
689                         {
690                                 if(queried_offset < colon_offset)
691                                 {
692                                         /* we have an URI with angle quotes */
693                                         uri_offsets->display_name_start = current_offset;
694                                         uri_offsets->display_name_end = queried_offset - 1;
695                                         current_offset = queried_offset + 1;
696                                 }
697                                 else
698                                 {
699                                         /* we have an URI without angle quotes */
700                                         uri_without_angle_quotes = TRUE;
701                                 }
702                         }
703                         else
704                         {
705                                 if(queried_offset != -1)
706                                 {
707                                         /* we have an URI with angle quotes */
708                                         uri_offsets->display_name_start = current_offset;
709                                         uri_offsets->display_name_end = queried_offset - 1;
710                                         current_offset = queried_offset + 1;
711                                         break;
712                                 }
713                                 if(colon_offset != -1)
714                                 {
715                                         /* we have an URI without angle quotes */
716                                         uri_without_angle_quotes = TRUE;
717                                         break;
718                                 }
719                                 /* If this point is reached, we can't parse the URI */
720                                 return -1;
721                         }
722                         break;
723         }
724
725         /* Start parsing of URI */
726         uri_offsets->uri_start = current_offset;
727         if(uri_without_angle_quotes == TRUE)
728         {
729                 /* look for the first ',' or ';' which will mark the end of this URI
730                  * In this case a semicolon indicates a header field parameter, and not an uri parameter.
731                  */
732                 comma_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, ',');
733                 semicolon_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, ';');
734
735                 if (semicolon_offset != -1 && comma_offset != -1)
736                 {
737                         if(semicolon_offset < comma_offset)
738                         {
739                                 uri_offsets->uri_end = semicolon_offset - 1;
740                         }
741                         else
742                         {
743                                 uri_offsets->uri_end = comma_offset - 1;
744                         }
745                 }
746                 else
747                 {
748                         if (semicolon_offset != -1)
749                         {
750                                 uri_offsets->uri_end = semicolon_offset - 1;
751                         }
752                         if (comma_offset != -1)
753                         {
754                                 uri_offsets->uri_end = comma_offset - 1;
755                         }
756                         /* If both offsets are equal to -1, we don't have a semicolon or a comma.
757                          * In that case, we assume that the end of the URI is at the line end
758                          */
759                         uri_offsets->uri_end = line_end_offset - 2;
760                 }
761                 uri_offsets->name_addr_end = uri_offsets->uri_end;
762                 current_offset = uri_offsets->uri_end + 1; /* Now save current_offset, as it is the value to be returned now */
763         }
764         else
765         {
766                 /* look for closing angle quote */
767                 queried_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, '>');
768                 if(queried_offset == -1)
769                 {
770                         /* malformed Uri */
771                         return -1;
772                 }
773                 uri_offsets->name_addr_end = queried_offset;
774                 uri_offsets->uri_end = queried_offset - 1;
775                 current_offset = queried_offset; /* Now save current_offset. It contains the value we have to return */
776
777                 /* Look for '@' within URI */
778                 queried_offset = tvb_find_guint8(tvb, uri_offsets->uri_start, uri_offsets->uri_end - uri_offsets->uri_start, '@');
779                 if(queried_offset == -1)
780                 {
781                         /* no '@': look for the first ';' or '?' in the URI */
782                         question_mark_offset = tvb_find_guint8(tvb, uri_offsets->uri_start, uri_offsets->uri_end - uri_offsets->uri_start, '?');
783                         semicolon_offset = tvb_find_guint8(tvb, uri_offsets->uri_start, uri_offsets->uri_end - uri_offsets->uri_start, ';');
784                 }
785                 else
786                 {
787                         /* with '@': look for the first ';' or '?' behind the '@' */
788                         question_mark_offset = tvb_find_guint8(tvb, queried_offset, uri_offsets->uri_end - queried_offset, '?');
789                         semicolon_offset = tvb_find_guint8(tvb, queried_offset, uri_offsets->uri_end - queried_offset, ';');
790                 }
791
792                 /* Set Parameter*/
793                 if (semicolon_offset != -1 && question_mark_offset != -1)
794                 {
795                         if(semicolon_offset < question_mark_offset)
796                         {
797                                 uri_offsets->uri_parameters_start = semicolon_offset;
798                         }
799                         else
800                         {
801                                 uri_offsets->uri_parameters_start = question_mark_offset;
802                         }
803                         uri_offsets->uri_parameters_end = uri_offsets->uri_end;
804                         uri_offsets->uri_end = uri_offsets->uri_parameters_start - 1;
805                 }
806                 else
807                 {
808                         if (semicolon_offset != -1)
809                         {
810                                 uri_offsets->uri_parameters_start = semicolon_offset;
811                                 uri_offsets->uri_parameters_end = uri_offsets->uri_end;
812                                 uri_offsets->uri_end = uri_offsets->uri_parameters_start - 1;
813                         }
814                         if (question_mark_offset != -1)
815                         {
816                                 uri_offsets->uri_parameters_start = question_mark_offset;
817                                 uri_offsets->uri_parameters_end = uri_offsets->uri_end;
818                                 uri_offsets->uri_end = uri_offsets->uri_parameters_start - 1;
819                         }
820                         /* If both offsets are equal to -1, we don't have a semicolon or a question mark.
821                          * In that case, we don't have to save any offsets.
822                          */
823                 }
824
825         }
826
827         return current_offset;
828 }
829
830
831 /* Code to parse a contact header item
832  * Returns Offset end off parsing or -1 for unsuccessful parsing
833  */
834 static gint
835 dissect_sip_contact_item(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint start_offset, gint line_end_offset)
836 {
837         gchar c;
838         proto_item *ti = NULL;
839         proto_tree *contact_item_tree = NULL, *uri_tree = NULL;
840
841         gint current_offset;
842         gint queried_offset;
843         gint contact_params_start_offset = -1;
844         gint contact_item_end_offset = -1;
845         uri_offset_info uri_offsets;
846
847         uri_offsets.display_name_start = -1;
848         uri_offsets.display_name_end = -1;
849         uri_offsets.uri_start = -1;
850         uri_offsets.uri_end = -1;
851         uri_offsets.uri_parameters_start = -1;
852         uri_offsets.uri_parameters_end = -1;
853         uri_offsets.name_addr_start = -1;
854         uri_offsets.name_addr_end = -1;
855
856         /* skip Spaces and Tabs */
857         start_offset = tvb_skip_wsp(tvb, start_offset, line_end_offset - start_offset);
858
859         if(start_offset >= line_end_offset) {
860                 /* Nothing to parse */
861                 return -1;
862         }
863
864         current_offset = dissect_sip_uri(tvb, pinfo, start_offset, line_end_offset, &uri_offsets);
865         if(current_offset == -1)
866         {
867                 /* Parsing failed */
868                 return -1;
869         }
870
871         /* Now look for the end of the contact item */
872         while (current_offset < line_end_offset)
873         {
874                 c=tvb_get_guint8(tvb, current_offset);
875
876                 if(c == ';' && contact_params_start_offset == -1)
877                 {
878                         /* here we start with contact parameters */
879                         contact_params_start_offset = current_offset;
880                 }
881
882                 if(c == '"')
883                 {
884                         /* look for the next unescaped '"' */
885                         do
886                         {
887                                 queried_offset = tvb_find_guint8(tvb, current_offset + 1, line_end_offset - (current_offset + 1), '"');
888                                 if(queried_offset == -1)
889                                 {
890                                         /* malformed URI */
891                                         return -1;
892                                 }
893                                 current_offset = queried_offset;
894
895                                 /* Is it escaped? */
896                         } while (tvb_get_guint8(tvb, queried_offset - 1) == '\\');
897                 }
898
899                 if(c == ',')
900                 {
901                         /* end of contact item found. */
902                         contact_item_end_offset = current_offset - 1; /* remove ',' */
903                         break;
904                 }
905
906                 current_offset++;
907         }
908
909         if(contact_item_end_offset == -1)
910                 contact_item_end_offset = line_end_offset - 3;  /* remove '\r\n' */
911
912         /* Build the tree, now */
913         if(tree)
914         {
915                 ti = proto_tree_add_string(tree, hf_sip_contact_item, tvb, start_offset, contact_item_end_offset - start_offset + 1,
916                                            tvb_format_text(tvb, start_offset, contact_item_end_offset - start_offset + 1));
917                 contact_item_tree = proto_item_add_subtree(ti, ett_sip_contact_item);
918
919                 ti = proto_tree_add_string(contact_item_tree, hf_sip_uri, tvb, uri_offsets.name_addr_start, uri_offsets.name_addr_end - uri_offsets.name_addr_start + 1,
920                                            tvb_format_text(tvb, uri_offsets.name_addr_start, uri_offsets.name_addr_end - uri_offsets.name_addr_start + 1));
921                 uri_tree = proto_item_add_subtree(ti, ett_sip_uri);
922
923                 if(uri_offsets.display_name_start != -1 && uri_offsets.display_name_end != -1)
924                 {
925                         proto_tree_add_string(uri_tree, hf_sip_display, tvb, uri_offsets.display_name_start,
926                                               uri_offsets.display_name_end - uri_offsets.display_name_start + 1,
927                                               tvb_format_text(tvb, uri_offsets.display_name_start,
928                                                               uri_offsets.display_name_end - uri_offsets.display_name_start + 1));
929                 }
930
931                 if(uri_offsets.uri_start != -1 && uri_offsets.uri_end != -1)
932                 {
933                         proto_tree_add_string(uri_tree, hf_sip_contact_addr, tvb, uri_offsets.uri_start,
934                                               uri_offsets.uri_end - uri_offsets.uri_start + 1,
935                                               tvb_format_text(tvb, uri_offsets.uri_start,
936                                                               uri_offsets.uri_end - uri_offsets.uri_start + 1));
937                 }
938
939                 /* Parse URI and Contact header Parameters now */
940                 /* TODO */
941         }
942
943         return current_offset;
944 }
945
946 /* Code to actually dissect the packets */
947 static int
948 dissect_sip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
949 {
950         guint8 octet;
951
952         octet = tvb_get_guint8(tvb,0);
953         if ((octet  & 0xf8) == 0xf8){
954                 call_dissector(sigcomp_handle, tvb, pinfo, tree);
955                 return tvb_length(tvb);
956         }
957
958
959         if (!dissect_sip_common(tvb, pinfo, tree, FALSE))
960                 return 0;
961
962         return tvb_length(tvb);
963 }
964
965 static void
966 dissect_sip_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
967 {
968         guint8 octet;
969
970         octet = tvb_get_guint8(tvb,0);
971         if ((octet  & 0xf8) == 0xf8){
972                 call_dissector(sigcomp_handle, tvb, pinfo, tree);
973                 return;
974         }
975         dissect_sip_common(tvb, pinfo, tree, TRUE);
976 }
977
978 static gboolean
979 dissect_sip_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
980 {
981         return dissect_sip_common(tvb, pinfo, tree, FALSE);
982 }
983
984 static gboolean
985 dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
986     gboolean dissect_other_as_continuation)
987 {
988         int offset;
989         gint next_offset, linelen;
990         line_type_t line_type;
991         tvbuff_t *next_tvb;
992         gboolean is_known_request;
993         gboolean found_match = FALSE;
994         char *descr;
995         guint token_1_len = 0;
996         guint current_method_idx = 0;
997         proto_item *ts = NULL, *ti = NULL, *th = NULL, *sip_element_item = NULL;
998         proto_tree *sip_tree = NULL, *reqresp_tree = NULL , *hdr_tree = NULL, *sip_element_tree = NULL, *message_body_tree = NULL;
999         guchar contacts = 0, contact_is_star = 0, expires_is_0 = 0;
1000         guint32 cseq_number = 0;
1001         guchar  cseq_number_set = 0;
1002         char    cseq_method[MAX_CSEQ_METHOD_SIZE] = "";
1003         char    call_id[MAX_CALL_ID_SIZE] = "";
1004         char *media_type_str = NULL;
1005         char *media_type_str_lower_case = NULL;
1006         char *content_type_parameter_str = NULL;
1007         guint resend_for_packet = 0;
1008         char  *string;
1009         int strlen_to_copy;
1010
1011         /* Initialise stat info for passing to tap */
1012         stat_info = g_malloc(sizeof(sip_info_value_t));
1013         stat_info->response_code = 0;
1014         stat_info->request_method = NULL;
1015         stat_info->reason_phrase = NULL;
1016         stat_info->resend = 0;
1017         stat_info->tap_call_id = NULL;
1018         stat_info->tap_from_addr = NULL;
1019         stat_info->tap_to_addr = NULL;
1020
1021         /*
1022          * Note that "tvb_find_line_end()" will return a value that
1023          * is not longer than what's in the buffer, so the
1024          * "tvb_get_ptr()" calls below won't throw exceptions.
1025          *
1026          * Note that "tvb_strneql()" doesn't throw exceptions, so
1027          * "sip_parse_line()" won't throw an exception.
1028          */
1029         offset = 0;
1030         linelen = tvb_find_line_end(tvb, 0, -1, &next_offset, FALSE);
1031         line_type = sip_parse_line(tvb, linelen, &token_1_len);
1032         if (line_type == OTHER_LINE) {
1033                 /*
1034                  * This is neither a SIP request nor response.
1035                  */
1036                 if (!dissect_other_as_continuation) {
1037                         /*
1038                          * We were asked to reject this.
1039                          */
1040                         return FALSE;
1041                 }
1042
1043                 /*
1044                  * Just dissect it as a continuation.
1045                  */
1046         }
1047
1048         if (check_col(pinfo->cinfo, COL_PROTOCOL))
1049                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SIP");
1050
1051         switch (line_type) {
1052
1053         case REQUEST_LINE:
1054                         is_known_request = sip_is_known_request(tvb, 0, token_1_len, &current_method_idx);
1055                         descr = is_known_request ? "Request" : "Unknown request";
1056                         if (check_col(pinfo->cinfo, COL_INFO)) {
1057                                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s",
1058                                              descr,
1059                                              tvb_format_text(tvb, 0, linelen - SIP2_HDR_LEN - 1));
1060                         }
1061                 break;
1062
1063                 case STATUS_LINE:
1064                         descr = "Status";
1065                         if (check_col(pinfo->cinfo, COL_INFO)) {
1066                                 col_add_fstr(pinfo->cinfo, COL_INFO, "Status: %s",
1067                                              tvb_format_text(tvb, SIP2_HDR_LEN + 1, linelen - SIP2_HDR_LEN - 1));
1068                         }
1069                         string = tvb_get_string(tvb, SIP2_HDR_LEN + 5, linelen - (SIP2_HDR_LEN + 5));
1070                         stat_info->reason_phrase = g_malloc(linelen - (SIP2_HDR_LEN + 5) + 1);
1071                         strncpy(stat_info->reason_phrase, string, linelen - (SIP2_HDR_LEN + 5) + 1);
1072                         /* String no longer needed */
1073                         g_free(string);
1074                 break;
1075
1076                 case OTHER_LINE:
1077                 default: /* Squelch compiler complaints */
1078                         descr = "Continuation";
1079                         if (check_col(pinfo->cinfo, COL_INFO))
1080                                 col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
1081                 break;
1082         }
1083
1084         if (tree) {
1085                 ts = proto_tree_add_item(tree, proto_sip, tvb, 0, -1, FALSE);
1086                 sip_tree = proto_item_add_subtree(ts, ett_sip);
1087         }
1088
1089         switch (line_type) {
1090
1091                 case REQUEST_LINE:
1092                         if (sip_tree) {
1093                                 ti = proto_tree_add_string(sip_tree, hf_Request_Line, tvb, 0, linelen,
1094                                                            tvb_format_text(tvb, 0, linelen));
1095                                 reqresp_tree = proto_item_add_subtree(ti, ett_sip_reqresp);
1096                         }
1097                         dfilter_sip_request_line(tvb, reqresp_tree, token_1_len);
1098                 break;
1099
1100                 case STATUS_LINE:
1101                         if (sip_tree) {
1102                                 ti = proto_tree_add_string(sip_tree, hf_Status_Line, tvb, 0, linelen,
1103                                                            tvb_format_text(tvb, 0, linelen));
1104                                 reqresp_tree = proto_item_add_subtree(ti, ett_sip_reqresp);
1105                         }
1106                         dfilter_sip_status_line(tvb, reqresp_tree);
1107                 break;
1108
1109                 case OTHER_LINE:
1110                         if (sip_tree) {
1111                                 ti = proto_tree_add_text(sip_tree, tvb, 0, next_offset,
1112                                                          "%s line: %s", descr,
1113                                                          tvb_format_text(tvb, 0, linelen));
1114                                 reqresp_tree = proto_item_add_subtree(ti, ett_sip_reqresp);
1115                                 proto_tree_add_text(sip_tree, tvb, 0, -1,
1116                                                     "Continuation data");
1117                         }
1118                 return TRUE;
1119         }
1120
1121         offset = next_offset;
1122         if (sip_tree) {
1123                 th = proto_tree_add_item(sip_tree, hf_msg_hdr, tvb, offset, -1, FALSE);
1124                 hdr_tree = proto_item_add_subtree(th, ett_sip_hdr);
1125         }
1126
1127         /*
1128          * Process the headers - if we're not building a protocol tree,
1129          * we just do this to find the blank line separating the
1130          * headers from the message body.
1131          */
1132         next_offset = offset;
1133         while (tvb_reported_length_remaining(tvb, offset) > 0) {
1134                 gint line_end_offset;
1135                 gint colon_offset;
1136                 gint semi_colon_offset;
1137                 gint len;
1138                 gint parameter_offset;
1139                 gint parameter_end_offset;
1140                 gint parameter_len;
1141                 gint content_type_len, content_type_parameter_str_len;
1142                 gint header_len;
1143                 gint hf_index;
1144                 gint value_offset;
1145                 gint comma_offset;
1146                 guchar c;
1147                 size_t value_len;
1148                 char *value;
1149
1150                 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
1151                 if (linelen == 0) {
1152                         /*
1153                          * This is a blank line separating the
1154                          * message header from the message body.
1155                          */
1156                         break;
1157                 }
1158                 line_end_offset = offset + linelen;
1159                 colon_offset = tvb_find_guint8(tvb, offset, linelen, ':');
1160                 if (colon_offset == -1) {
1161                         /*
1162                          * Malformed header - no colon after the name.
1163                          */
1164                         if(hdr_tree) {
1165                                 proto_tree_add_text(hdr_tree, tvb, offset,
1166                                                     next_offset - offset, "%s",
1167                                                     tvb_format_text(tvb, offset, linelen));
1168                         }
1169                 } else {
1170                         header_len = colon_offset - offset;
1171                         hf_index = sip_is_known_sip_header(tvb, offset, header_len);
1172
1173                         if (hf_index == -1) {
1174                                 if(hdr_tree) {
1175                                         proto_tree_add_text(hdr_tree, tvb,
1176                                                             offset, next_offset - offset, "%s",
1177                                                             tvb_format_text(tvb, offset, linelen));
1178                                 }
1179                         } else {
1180                                 /*
1181                                  * Skip whitespace after the colon.
1182                                  */
1183                                 value_offset = colon_offset + 1;
1184                                 while (value_offset < line_end_offset &&
1185                                        ((c = tvb_get_guint8(tvb, value_offset)) == ' ' ||
1186                                          c == '\t'))
1187                                         value_offset++;
1188                                 /*
1189                                  * Fetch the value.
1190                                  */
1191                                 value_len = line_end_offset - value_offset;
1192                                 value = tvb_get_string(tvb, value_offset,
1193                                                        value_len);
1194
1195                                 /*
1196                                  * Add it to the protocol tree,
1197                                  * but display the line as is.
1198                                  */
1199                                 switch ( hf_index ) {
1200
1201                                         case POS_TO :
1202                                                 if(hdr_tree) {
1203                                                         sip_element_item = proto_tree_add_string_format(hdr_tree,
1204                                                                            hf_header_array[hf_index], tvb,
1205                                                                            offset, next_offset - offset,
1206                                                                            value, "%s",
1207                                                                            tvb_format_text(tvb, offset, linelen));
1208                                                         sip_element_tree = proto_item_add_subtree( sip_element_item,
1209                                                                            ett_sip_element);
1210                                                 }
1211                                                 /* See if we have a SIP/SIPS uri enclosed in <>, if so anything in front is
1212                                                  * display info.
1213                                                  */
1214                                                 parameter_offset = tvb_find_guint8(tvb, value_offset,value_len, '<');
1215                                                 if ( parameter_offset != -1){
1216                                                         len = parameter_offset - value_offset;
1217                                                         if ( len > 1){
1218                                                                 /* Something in front, must be display info
1219                                                                  * TODO: Get rid of trailing space(s)
1220                                                                  */
1221                                                                 proto_tree_add_item(sip_element_tree, hf_sip_display, tvb, value_offset,
1222                                                                                     len, FALSE);
1223                                                         }
1224                                                         parameter_offset ++;
1225                                                         parameter_end_offset = parameter_offset;
1226                                                         /* RFC3261 paragraph 20
1227                                                          * The Contact, From, and To header fields contain a URI.  If the URI
1228                                                          * contains a comma, question mark or semicolon, the URI MUST be
1229                                                          * enclosed in angle brackets (< and >).  Any URI parameters are
1230                                                          * contained within these brackets.  If the URI is not enclosed in angle
1231                                                          * brackets, any semicolon-delimited parameters are header-parameters,
1232                                                          * not URI parameters.
1233                                                          */
1234                                                         while (parameter_end_offset < line_end_offset){
1235                                                                 parameter_end_offset++;
1236                                                                 c = tvb_get_guint8(tvb, parameter_end_offset);
1237                                                                 switch (c) {
1238                                                                         case '>':
1239                                                                         case ',':
1240                                                                         case ';':
1241                                                                         case '?':
1242                                                                                 goto separator_found;
1243                                                                         default :
1244                                                                         break;
1245                                                                 }
1246                                                         }
1247 separator_found:
1248                                                         parameter_len = parameter_end_offset - parameter_offset;
1249                                                         proto_tree_add_item(sip_element_tree, hf_sip_to_addr, tvb, parameter_offset,
1250                                                                             parameter_len, FALSE);
1251                                                         /*info for the tap for voip_calls.c*/
1252                                                         stat_info->tap_to_addr=tvb_get_string(tvb, parameter_offset, parameter_len);
1253
1254                                                         parameter_offset = parameter_end_offset + 1;
1255                                                         /*
1256                                                          * URI parameters ?
1257                                                          */
1258                                                         parameter_end_offset = tvb_find_guint8(tvb, parameter_offset,( line_end_offset - parameter_offset), ';');
1259                                                         if ( parameter_end_offset == -1)
1260                                                                 parameter_end_offset = line_end_offset;
1261
1262                                                         offset = parameter_end_offset;
1263                                                 }
1264                                                 else
1265                                                 {
1266                                                         /* Extract SIP/SIPS URI */
1267                                                         parameter_offset = value_offset;
1268                                                         while (parameter_offset < line_end_offset
1269                                                                && (tvb_strneql(tvb, parameter_offset, "sip", 3) != 0))
1270                                                                 parameter_offset++;
1271                                                         len = parameter_offset - value_offset;
1272                                                         if ( len > 1){
1273                                                                 /* Something in front, must be display info
1274                                                                  * TODO: Get rid of trailing space(s)
1275                                                                  */
1276                                                                 proto_tree_add_item(sip_element_tree, hf_sip_display, tvb, value_offset,
1277                                                                                     len, FALSE);
1278                                                         }
1279                                                         parameter_end_offset = tvb_find_guint8(tvb, parameter_offset,
1280                                                                                                (line_end_offset - parameter_offset), ';');
1281                                                         if ( parameter_end_offset == -1)
1282                                                                 parameter_end_offset = line_end_offset;
1283                                                         parameter_len = parameter_end_offset - parameter_offset;
1284                                                         proto_tree_add_item(sip_element_tree, hf_sip_to_addr, tvb, parameter_offset,
1285                                                                             parameter_len, FALSE);
1286                                                         /*info for the tap for voip_calls.c*/
1287                                                         stat_info->tap_to_addr=tvb_get_string(tvb, parameter_offset, parameter_len);
1288                                                         offset = parameter_end_offset;
1289                                                 }
1290                                                 /* Find parameter tag if present.
1291                                                  * TODO make this generic to find any interesting parameter
1292                                                  * use the same method as for SIP headers ?
1293                                                  */
1294
1295                                                 parameter_offset = offset;
1296                                                 while (parameter_offset < line_end_offset
1297                                                        && (tvb_strneql(tvb, parameter_offset, "tag=", 4) != 0))
1298                                                         parameter_offset++;
1299                                                 if ( parameter_offset < line_end_offset ){ /* Tag found */
1300                                                         parameter_offset = parameter_offset + 4;
1301                                                         parameter_end_offset = tvb_find_guint8(tvb, parameter_offset,
1302                                                                                                (line_end_offset - parameter_offset), ';');
1303                                                         if ( parameter_end_offset == -1)
1304                                                                 parameter_end_offset = line_end_offset;
1305                                                         parameter_len = parameter_end_offset - parameter_offset;
1306                                                         proto_tree_add_item(sip_element_tree, hf_sip_tag, tvb, parameter_offset,
1307                                                                             parameter_len, FALSE);
1308
1309                                                 }
1310                                         break;
1311
1312                                         case POS_FROM :
1313                                                 if(hdr_tree) {
1314                                                         sip_element_item = proto_tree_add_string_format(hdr_tree,
1315                                                                            hf_header_array[hf_index], tvb,
1316                                                                            offset, next_offset - offset,
1317                                                                            value, "%s",
1318                                                                            tvb_format_text(tvb, offset, linelen));
1319                                                         sip_element_tree = proto_item_add_subtree( sip_element_item, ett_sip_element);
1320                                                 }
1321                                                 /* See if we have a SIP/SIPS uri enclosed in <>, if so anything in front is
1322                                                  * display info.
1323                                                  */
1324                                                 parameter_offset = tvb_find_guint8(tvb, value_offset,value_len, '<');
1325                                                 if ( parameter_offset != -1){
1326                                                         len = parameter_offset - value_offset;
1327                                                         if ( len > 1){
1328                                                                 /* Something in front, must be display info
1329                                                                  * TODO: Get rid of trailing space(s)
1330                                                                  */
1331                                                                 proto_tree_add_item(sip_element_tree, hf_sip_display, tvb, value_offset,
1332                                                                                     len, FALSE);
1333                                                         }
1334                                                         parameter_offset ++;
1335                                                         parameter_end_offset = parameter_offset;
1336                                                         /* RFC3261 paragraph 20
1337                                                          * The Contact, From, and To header fields contain a URI.  If the URI
1338                                                          * contains a comma, question mark or semicolon, the URI MUST be
1339                                                          * enclosed in angle brackets (< and >).  Any URI parameters are
1340                                                          * contained within these brackets.  If the URI is not enclosed in angle
1341                                                          * brackets, any semicolon-delimited parameters are header-parameters,
1342                                                          * not URI parameters.
1343                                                          */
1344                                                         while (parameter_end_offset < line_end_offset){
1345                                                                 parameter_end_offset++;
1346                                                                 c = tvb_get_guint8(tvb, parameter_end_offset);
1347                                                                 switch (c) {
1348                                                                         case '>':
1349                                                                         case ',':
1350                                                                         case ';':
1351                                                                         case '?':
1352                                                                                 goto separator_found2;
1353                                                                         default :
1354                                                                         break;
1355                                                                 }
1356                                                         }
1357 separator_found2:
1358                                                         parameter_len = parameter_end_offset - parameter_offset;
1359                                                         dfilter_store_sip_from_addr(tvb, sip_element_tree,
1360                                                                                     parameter_offset, parameter_len);
1361                                                         /*info for the tap for voip_calls.c*/
1362                                                         stat_info->tap_from_addr=tvb_get_string(tvb, parameter_offset, parameter_len);
1363                                                         parameter_offset = parameter_end_offset + 1;
1364                                                         /*
1365                                                          * URI parameters ?
1366                                                          */
1367                                                         parameter_end_offset = tvb_find_guint8(tvb, parameter_offset,( line_end_offset - parameter_offset), ';');
1368                                                         if ( parameter_end_offset == -1)
1369                                                                 parameter_end_offset = line_end_offset;
1370
1371                                                         offset = parameter_end_offset;
1372                                                 }
1373                                                 else
1374                                                 {
1375                                                         /* Extract SIP/SIPS URI */
1376                                                         parameter_offset = value_offset;
1377                                                         while (parameter_offset < line_end_offset
1378                                                                && (tvb_strneql(tvb, parameter_offset, "sip", 3) != 0))
1379                                                                 parameter_offset++;
1380                                                         len = parameter_offset - value_offset;
1381                                                         if ( len > 1){
1382                                                                 /* Something in front, must be display info
1383                                                                  * TODO: Get rid of trailing space(s)
1384                                                                  */
1385                                                                 proto_tree_add_item(sip_element_tree, hf_sip_display, tvb, value_offset,
1386                                                                                     len, FALSE);
1387                                                         }
1388                                                         parameter_end_offset = tvb_find_guint8(tvb, parameter_offset,
1389                                                                                                (line_end_offset - parameter_offset), ';');
1390                                                         if ( parameter_end_offset == -1)
1391                                                                 parameter_end_offset = line_end_offset;
1392                                                         parameter_len = parameter_end_offset - parameter_offset;
1393                                                         proto_tree_add_item(sip_element_tree, hf_sip_from_addr, tvb, parameter_offset,
1394                                                                             parameter_len, FALSE);
1395                                                         /*info for the tap for voip_calls.c*/
1396                                                         stat_info->tap_from_addr=tvb_get_string(tvb, parameter_offset, parameter_len);
1397                                                         offset = parameter_end_offset;
1398                                                 }
1399                                                 /* Find parameter tag if present.
1400                                                  * TODO make this generic to find any interesting parameter
1401                                                  * use the same method as for SIP headers ?
1402                                                  */
1403
1404                                                 parameter_offset = offset;
1405                                                 while (parameter_offset < line_end_offset
1406                                                        && (tvb_strneql(tvb, parameter_offset, "tag=", 4) != 0))
1407                                                         parameter_offset++;
1408                                                 if ( parameter_offset < line_end_offset ){ /* Tag found */
1409                                                         parameter_offset = parameter_offset + 4;
1410                                                         parameter_end_offset = tvb_find_guint8(tvb, parameter_offset,
1411                                                                                                (line_end_offset - parameter_offset), ';');
1412                                                         if ( parameter_end_offset == -1)
1413                                                                 parameter_end_offset = line_end_offset;
1414                                                         parameter_len = parameter_end_offset - parameter_offset;
1415                                                         proto_tree_add_item(sip_element_tree, hf_sip_tag, tvb, parameter_offset,
1416                                                                             parameter_len, FALSE);
1417
1418                                                 }
1419                                         break;
1420
1421                                         case POS_CSEQ :
1422                                                 /* Store the sequence number */
1423                                                 cseq_number = atoi(value);
1424                                                 cseq_number_set = 1;
1425                                                 stat_info->tap_cseq_number=cseq_number;
1426
1427                                                 /* Walk past number and spaces characters to get to start
1428                                                    of method name */
1429                                                 for (value_offset=0; value_offset < (gint)strlen(value); value_offset++)
1430                                                 {
1431                                                         if (isalpha((guchar)value[value_offset]))
1432                                                         {
1433                                                                 break;
1434                                                         }
1435                                                 }
1436                                                 if (value_offset == (gint)strlen(value))
1437                                                 {
1438                                                         THROW(ReportedBoundsError);
1439                                                         return TRUE;
1440                                                 }
1441
1442                                                 /* Extract method name from value */
1443                                                 strlen_to_copy = strlen(value)-value_offset+1;
1444                                                 if (strlen_to_copy > MAX_CSEQ_METHOD_SIZE) {
1445                                                         /* Note the error in the protocol tree */
1446                                                         if(hdr_tree) {
1447                                                                 proto_tree_add_string_format(hdr_tree,
1448                                                                                              hf_header_array[hf_index], tvb,
1449                                                                                              offset, next_offset - offset,
1450                                                                                              value+value_offset, "%s String too big: %d bytes",
1451                                                                                              sip_headers[POS_CSEQ].name,
1452                                                                                              strlen_to_copy);
1453                                                         }
1454                                                         THROW(ReportedBoundsError);
1455                                                         return TRUE;
1456                                                 }
1457                                                 else {
1458                                                         strncpy(cseq_method, value+value_offset, MIN(strlen_to_copy, MAX_CSEQ_METHOD_SIZE));
1459
1460                                                         /* Add 'CSeq' string item to tree */
1461                                                         if(hdr_tree) {
1462                                                                 proto_tree_add_string_format(hdr_tree,
1463                                                                                              hf_header_array[hf_index], tvb,
1464                                                                                              offset, next_offset - offset,
1465                                                                                              value, "%s",
1466                                                                                              tvb_format_text(tvb, offset, linelen));
1467                                                         }
1468                                                 }
1469                                         break;
1470
1471                                         case POS_CALL_ID :
1472                                                 /* Store the Call-id */
1473                                                 strncpy(call_id, value,
1474                                                         strlen(value)+1 < MAX_CALL_ID_SIZE ?
1475                                                         strlen(value)+1 :
1476                                                         MAX_CALL_ID_SIZE);
1477                                                 stat_info->tap_call_id = g_strdup(call_id);
1478
1479                                                 /* Add 'Call-id' string item to tree */
1480                                                 if(hdr_tree) {
1481                                                         proto_tree_add_string_format(hdr_tree,
1482                                                                                      hf_header_array[hf_index], tvb,
1483                                                                                      offset, next_offset - offset,
1484                                                                                      value, "%s",
1485                                                                                      tvb_format_text(tvb, offset, linelen));
1486                                                 }
1487                                         break;
1488
1489                                         case POS_EXPIRES :
1490                                                 if (strcmp(value, "0") == 0)
1491                                                 {
1492                                                         expires_is_0 = 1;
1493                                                 }
1494                                                 /* Add 'Expires' string item to tree */
1495                                                 if(hdr_tree) {
1496                                                         proto_tree_add_string_format(hdr_tree,
1497                                                                                      hf_header_array[hf_index], tvb,
1498                                                                                      offset, next_offset - offset,
1499                                                                                      value, "%s",
1500                                                                                      tvb_format_text(tvb, offset, linelen));
1501                                                 }
1502                                         break;
1503
1504                                         /*
1505                                          * Content-Type is the same as Internet
1506                                          * media type used by other dissectors,
1507                                          * appropriate dissector found by
1508                                          * lookup in "media_type" dissector table.
1509                                          */
1510                                         case POS_CONTENT_TYPE :
1511                                                 if(hdr_tree) {
1512                                                         proto_tree_add_string_format(hdr_tree,
1513                                                                                      hf_header_array[hf_index], tvb,
1514                                                                                      offset, next_offset - offset,
1515                                                                                      value, "%s",
1516                                                                                      tvb_format_text(tvb, offset, linelen));
1517                                                 }
1518                                                 content_type_len = value_len;
1519                                                 semi_colon_offset = tvb_find_guint8(tvb, value_offset,linelen, ';');
1520                                                 if ( semi_colon_offset != -1) {
1521                                                         parameter_offset = semi_colon_offset +1;
1522                                                         /*
1523                                                          * Skip whitespace after the semicolon.
1524                                                          */
1525                                                         while (parameter_offset < line_end_offset
1526                                                                && ((c = tvb_get_guint8(tvb, parameter_offset)) == ' '
1527                                                                  || c == '\t'))
1528                                                                 parameter_offset++;
1529                                                         content_type_len = semi_colon_offset - value_offset;
1530                                                         content_type_parameter_str_len = line_end_offset - parameter_offset;
1531                                                         content_type_parameter_str = tvb_get_string(tvb, parameter_offset,
1532                                                                                      content_type_parameter_str_len);
1533                                                 }
1534                                                 media_type_str = tvb_get_string(tvb, value_offset, content_type_len);
1535 #if GLIB_MAJOR_VERSION < 2
1536                                                 media_type_str_lower_case = g_strdup(media_type_str);
1537                                                 g_strdown(media_type_str_lower_case);
1538 #else
1539                                                 media_type_str_lower_case = g_ascii_strdown(media_type_str, -1);
1540 #endif
1541                                                 g_free(media_type_str);
1542                                         break;
1543
1544                                         case POS_CONTACT :
1545                                                 if(hdr_tree) {
1546                                                         sip_element_item = proto_tree_add_string_format(hdr_tree,
1547                                                                            hf_header_array[hf_index], tvb,
1548                                                                            offset, next_offset - offset,
1549                                                                            value, "%s",
1550                                                                            tvb_format_text(tvb, offset, linelen));
1551                                                         sip_element_tree = proto_item_add_subtree( sip_element_item,
1552                                                                            ett_sip_element);
1553                                                 }
1554                                                 if (strcmp(value, "*") == 0)
1555                                                 {
1556                                                         contact_is_star = 1;
1557                                                         break;
1558                                                 }
1559
1560                                                 comma_offset = value_offset;
1561                                                 while((comma_offset = dissect_sip_contact_item(tvb, pinfo, sip_element_tree, comma_offset, next_offset)) != -1)
1562                                                 {
1563                                                         contacts++;
1564                                                         if(comma_offset == next_offset)
1565                                                         {
1566                                                                 /* Line End reached: Stop Parsing */
1567                                                                 break;
1568                                                         }
1569
1570                                                         if(tvb_get_guint8(tvb, comma_offset) != ',')
1571                                                         {
1572                                                                 /* Undefined value reached: Stop Parsing */
1573                                                                 break;
1574                                                         }
1575                                                         comma_offset++; /* skip comma */
1576                                                 }
1577                                         break;
1578
1579                                         default :
1580                                                 if(hdr_tree) {
1581                                                         proto_tree_add_string_format(hdr_tree,
1582                                                                                      hf_header_array[hf_index], tvb,
1583                                                                                      offset, next_offset - offset,
1584                                                                                      value, "%s",
1585                                                                                      tvb_format_text(tvb, offset, linelen));
1586                                                 }
1587                                         break;
1588                                 }/* end switch */
1589                                 g_free(value);
1590                         }/*if HF_index */
1591                 }/* if colon_offset */
1592                 offset = next_offset;
1593         }/* End while */
1594
1595         if (tvb_offset_exists(tvb, next_offset)) {
1596
1597                 /*
1598                  * There's a message body starting at "next_offset".
1599                  * Set the length of the header item.
1600                  */
1601                 proto_item_set_end(th, tvb, next_offset);
1602                 next_tvb = tvb_new_subset(tvb, next_offset, -1, -1);
1603                 if(sip_tree) {
1604                         ti = proto_tree_add_text(sip_tree, next_tvb, 0, -1,
1605                                                  "Message body");
1606                         message_body_tree = proto_item_add_subtree(ti, ett_sip_message_body);
1607                 }
1608
1609                 /* give the content type parameters to sub dissectors */
1610
1611                 if ( media_type_str_lower_case != NULL ) {
1612                         void *save_private_data = pinfo->private_data;
1613                         pinfo->private_data = content_type_parameter_str;
1614                         found_match = dissector_try_string(media_type_dissector_table,
1615                                                            media_type_str_lower_case,
1616                                                            next_tvb, pinfo,
1617                                                            message_body_tree);
1618                         g_free(media_type_str_lower_case);
1619                         pinfo->private_data = save_private_data;
1620                         /* If no match dump as text */
1621                 }
1622                 g_free(content_type_parameter_str);
1623                 if ( found_match != TRUE )
1624                 {
1625                         offset = 0;
1626                         while (tvb_offset_exists(next_tvb, offset)) {
1627                                 tvb_find_line_end(next_tvb, offset, -1, &next_offset, FALSE);
1628                                 linelen = next_offset - offset;
1629                                 if(message_body_tree) {
1630                                         proto_tree_add_text(message_body_tree, next_tvb, offset, linelen,
1631                                                             "%s", tvb_format_text(next_tvb, offset, linelen));
1632                                 }
1633                                 offset = next_offset;
1634                         }/* end while */
1635                 }
1636         }
1637
1638
1639         /* Add to info column interesting things learned from header fields. */
1640         if (check_col(pinfo->cinfo, COL_INFO))
1641         {
1642                 /* Registration requests */
1643                 if (strcmp(sip_methods[current_method_idx], "REGISTER") == 0)
1644                 {
1645                         if (contact_is_star && expires_is_0)
1646                         {
1647                                 col_append_str(pinfo->cinfo, COL_INFO, "    (remove all bindings)");
1648                         }
1649                         else
1650                         if (!contacts)
1651                         {
1652                                 col_append_str(pinfo->cinfo, COL_INFO, "    (fetch bindings)");
1653                         }
1654                 }
1655
1656                 /* Registration responses */
1657                 if (line_type == STATUS_LINE && (strcmp(cseq_method, "REGISTER") == 0))
1658                 {
1659                         col_append_fstr(pinfo->cinfo, COL_INFO, "    (%d bindings)", contacts);
1660                 }
1661         }
1662
1663         /* Check if this packet is a resend. */
1664         resend_for_packet = sip_is_packet_resend(pinfo, cseq_method, call_id,
1665                                                  cseq_number_set, cseq_number,
1666                                                  line_type);
1667         /* Mark whether this is a resend for the tap */
1668         stat_info->resend = (resend_for_packet > 0);
1669
1670         /* And add the filterable field to the request/response line */
1671         if (reqresp_tree)
1672         {
1673                 proto_item *item;
1674                 item = proto_tree_add_boolean(reqresp_tree, hf_sip_resend, tvb, 0, 0,
1675                                               resend_for_packet > 0);
1676                 PROTO_ITEM_SET_GENERATED(item);
1677                 if (resend_for_packet > 0)
1678                 {
1679                         item = proto_tree_add_uint(reqresp_tree, hf_sip_original_frame,
1680                                                    tvb, 0, 0, resend_for_packet);
1681                         PROTO_ITEM_SET_GENERATED(item);
1682                 }
1683         }
1684
1685
1686         if (global_sip_raw_text)
1687                 tvb_raw_text_add(tvb, tree);
1688
1689         /* Report this packet to the tap */
1690         if (!pinfo->in_error_pkt)
1691         {
1692                 tap_queue_packet(sip_tap, pinfo, stat_info);
1693         }
1694
1695         return TRUE;
1696 }
1697
1698 /* Display filter for SIP Request-Line */
1699 static void
1700 dfilter_sip_request_line(tvbuff_t *tvb, proto_tree *tree, guint meth_len)
1701 {
1702         char    *string;
1703
1704         /*
1705          * We know we have the entire method; otherwise, "sip_parse_line()"
1706          * would have returned OTHER_LINE.
1707          */
1708         string = tvb_get_string(tvb, 0, meth_len);
1709         if (tree) {
1710                 proto_tree_add_string(tree, hf_Method, tvb, 0, meth_len, string);
1711         }
1712         /* Copy request method for telling tap */
1713         stat_info->request_method = g_malloc(meth_len+1);
1714         strncpy(stat_info->request_method, string, meth_len+1);
1715
1716         /* String no longer needed */
1717         g_free(string);
1718 }
1719
1720 /* Display filter for SIP Status-Line */
1721 static void
1722 dfilter_sip_status_line(tvbuff_t *tvb, proto_tree *tree)
1723 {
1724         char string[3+1];
1725         gint response_code = 0;
1726
1727         /*
1728          * We know we have the entire status code; otherwise,
1729          * "sip_parse_line()" would have returned OTHER_LINE.
1730          * We also know that we have a version string followed by a
1731          * space at the beginning of the line, for the same reason.
1732          */
1733         tvb_memcpy(tvb, (guint8 *)string, SIP2_HDR_LEN + 1, 3);
1734         string[3] = '\0';
1735         response_code = atoi(string);
1736
1737         /* Add numerical response code to tree */
1738         if (tree) {
1739                 proto_tree_add_uint(tree, hf_Status_Code, tvb, SIP2_HDR_LEN + 1,
1740                                     3, response_code);
1741         }
1742
1743         /* Add response code for sending to tap */
1744         stat_info->response_code = response_code;
1745 }
1746
1747 void dfilter_store_sip_from_addr(tvbuff_t *tvb,proto_tree *tree,guint parameter_offset,
1748                                           guint parameter_len)
1749 {
1750         proto_tree_add_item(tree, hf_sip_from_addr, tvb, parameter_offset,
1751                                                         parameter_len, FALSE);
1752
1753 }
1754 /* From section 4.1 of RFC 2543:
1755  *
1756  * Request-Line  =  Method SP Request-URI SP SIP-Version CRLF
1757  *
1758  * From section 5.1 of RFC 2543:
1759  *
1760  * Status-Line  =  SIP-version SP Status-Code SP Reason-Phrase CRLF
1761  *
1762  * From section 7.1 of RFC 3261:
1763  *
1764  * Unlike HTTP, SIP treats the version number as a literal string.
1765  * In practice, this should make no difference.
1766  */
1767 static line_type_t
1768 sip_parse_line(tvbuff_t *tvb, gint linelen, guint *token_1_lenp)
1769 {
1770         gint space_offset;
1771         guint token_1_len;
1772         gint token_2_start;
1773         guint token_2_len;
1774         gint token_3_start;
1775         guint token_3_len;
1776         gint colon_pos;
1777
1778         space_offset = tvb_find_guint8(tvb, 0, -1, ' ');
1779         if (space_offset <= 0) {
1780                 /*
1781                  * Either there's no space in the line (which means
1782                  * the line is empty or doesn't have a token followed
1783                  * by a space; neither is valid for a request or status), or
1784                  * the first character in the line is a space (meaning
1785                  * the method is empty, which isn't valid for a request,
1786                  * or the SIP version is empty, which isn't valid for a
1787                  * status).
1788                  */
1789                 return OTHER_LINE;
1790         }
1791         token_1_len = space_offset;
1792         token_2_start = space_offset + 1;
1793         space_offset = tvb_find_guint8(tvb, token_2_start, -1, ' ');
1794         if (space_offset == -1) {
1795                 /*
1796                  * There's no space after the second token, so we don't
1797                  * have a third token.
1798                  */
1799                 return OTHER_LINE;
1800         }
1801         token_2_len = space_offset - token_2_start;
1802         token_3_start = space_offset + 1;
1803         token_3_len = linelen - token_3_start;
1804
1805         *token_1_lenp = token_1_len;
1806
1807         /*
1808          * Is the first token a version string?
1809          */
1810         if ( (strict_sip_version && (
1811                 token_1_len == SIP2_HDR_LEN
1812                 && tvb_strneql(tvb, 0, SIP2_HDR, SIP2_HDR_LEN) == 0)
1813         ) || (! strict_sip_version && (
1814                 tvb_strneql(tvb, 0, "SIP/", 4) == 0)
1815         )) {
1816                 /*
1817                  * Yes, so this is either a Status-Line or something
1818                  * else other than a Request-Line.  To be a Status-Line,
1819                  * the second token must be a 3-digit number.
1820                  */
1821                 if (token_2_len != 3) {
1822                         /*
1823                          * We don't have 3-character status code.
1824                          */
1825                         return OTHER_LINE;
1826                 }
1827                 if (!isdigit(tvb_get_guint8(tvb, token_2_start)) ||
1828                     !isdigit(tvb_get_guint8(tvb, token_2_start + 1)) ||
1829                     !isdigit(tvb_get_guint8(tvb, token_2_start + 2))) {
1830                         /*
1831                          * 3 characters yes, 3 digits no.
1832                          */
1833                         return OTHER_LINE;
1834                 }
1835                 return STATUS_LINE;
1836         } else {
1837                 /*
1838                  * No, so this is either a Request-Line or something
1839                  * other than a Status-Line.  To be a Request-Line, the
1840                  * second token must be a URI and the third token must
1841                  * be a version string.
1842                  */
1843                 if (token_2_len < 3) {
1844                         /*
1845                          * We don't have a URI consisting of at least 3
1846                          * characters.
1847                          */
1848                         return OTHER_LINE;
1849                 }
1850                 colon_pos = tvb_find_guint8(tvb, token_2_start + 1, -1, ':');
1851                 if (colon_pos == -1) {
1852                         /*
1853                          * There is no colon after the method, so the URI
1854                          * doesn't have a colon in it, so it's not valid.
1855                          */
1856                         return OTHER_LINE;
1857                 }
1858                 if (colon_pos >= token_3_start) {
1859                         /*
1860                          * The colon is in the version string, not the URI.
1861                          */
1862                         return OTHER_LINE;
1863                 }
1864                 /* XXX - Check for a proper URI prefix? */
1865                 if ( (strict_sip_version && (
1866                         token_3_len != SIP2_HDR_LEN
1867                         || tvb_strneql(tvb, token_3_start, SIP2_HDR, SIP2_HDR_LEN) == -1)
1868                 ) || (! strict_sip_version && (
1869                         tvb_strneql(tvb, token_3_start, "SIP/", 4) == -1)
1870                 )) {
1871                         /*
1872                          * The version string isn't an SIP version 2.0 version
1873                          * string.
1874                          */
1875                         return OTHER_LINE;
1876                 }
1877                 return REQUEST_LINE;
1878         }
1879 }
1880
1881 static gboolean sip_is_known_request(tvbuff_t *tvb, int meth_offset,
1882     guint meth_len, guint *meth_idx)
1883 {
1884         guint i;
1885
1886         for (i = 1; i < array_length(sip_methods); i++) {
1887                 if (meth_len == strlen(sip_methods[i]) &&
1888                     tvb_strneql(tvb, meth_offset, sip_methods[i], meth_len) == 0)
1889                 {
1890                      *meth_idx = i;
1891                      return TRUE;
1892                 }
1893         }
1894
1895         return FALSE;
1896 }
1897
1898 /* Returns index of method in sip_headers */
1899 static gint sip_is_known_sip_header(tvbuff_t *tvb, int offset, guint header_len)
1900 {
1901         guint i;
1902
1903         for (i = 1; i < array_length(sip_headers); i++) {
1904                 if (header_len == strlen(sip_headers[i].name) &&
1905                     tvb_strncaseeql(tvb, offset, sip_headers[i].name, header_len) == 0)
1906                         return i;
1907                 if (sip_headers[i].compact_name != NULL &&
1908                     header_len == strlen(sip_headers[i].compact_name) &&
1909                     tvb_strncaseeql(tvb, offset, sip_headers[i].compact_name, header_len) == 0)
1910                         return i;
1911         }
1912
1913         return -1;
1914 }
1915
1916 /*
1917  * Display the entire message as raw text.
1918  */
1919 static void
1920 tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree)
1921 {
1922         proto_tree *raw_tree = NULL;
1923         proto_item *ti = NULL;
1924         int offset, next_offset, linelen;
1925
1926         if(tree) {
1927                 ti = proto_tree_add_item(tree, proto_raw_sip, tvb, 0, -1, FALSE);
1928                 raw_tree = proto_item_add_subtree(ti, ett_raw_text);
1929         }
1930
1931         offset = 0;
1932
1933         while (tvb_offset_exists(tvb, offset)) {
1934                 tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
1935                 linelen = next_offset - offset;
1936                 if(raw_tree) {
1937                         proto_tree_add_text(raw_tree, tvb, offset, linelen,
1938                             "%s", tvb_format_text(tvb, offset, linelen));
1939                 }
1940                 offset = next_offset;
1941         }
1942 }
1943
1944 /* Check to see if this packet is a resent request.  Return value is number
1945    of the original frame this packet seems to be resending (0 = no resend). */
1946 guint sip_is_packet_resend(packet_info *pinfo,
1947                         gchar *cseq_method,
1948                         gchar *call_id,
1949                         guchar cseq_number_set,
1950                         guint32 cseq_number, line_type_t line_type)
1951 {
1952         guint32 cseq_to_compare = 0;
1953         sip_hash_key   key;
1954         sip_hash_key   *p_key = 0;
1955         sip_hash_value *p_val = 0;
1956         guint result = 0;
1957
1958         /* Only consider retransmission of UDP packets */
1959         if (pinfo->ptype != PT_UDP)
1960         {
1961                 return 0;
1962         }
1963
1964         /* Don't consider packets that appear to be resent only because
1965            they are e.g. returned in ICMP unreachable messages. */
1966         if (pinfo->in_error_pkt)
1967         {
1968                 return 0;
1969         }
1970
1971         /* A broken packet may have no cseq number set. Don't consider it as
1972            a resend */
1973         if (!cseq_number_set)
1974         {
1975                 return 0;
1976         }
1977
1978         /* Return any answer stored from previous dissection */
1979         if (pinfo->fd->flags.visited)
1980         {
1981                 return GPOINTER_TO_UINT(p_get_proto_data(pinfo->fd, proto_sip));
1982         }
1983
1984         /* No packet entry found, consult global hash table */
1985
1986         /* Prepare the key */
1987         strncpy(key.call_id, call_id,
1988                 (strlen(call_id)+1 <= MAX_CALL_ID_SIZE) ?
1989                         strlen(call_id)+1 :
1990                         MAX_CALL_ID_SIZE);
1991         COPY_ADDRESS(&key.dest_address, &pinfo->net_dst);
1992         COPY_ADDRESS(&key.source_address, &pinfo->net_src);
1993         key.dest_port = pinfo->destport;
1994         key.source_port = pinfo->srcport;
1995
1996         /* Do the lookup */
1997         p_val = (sip_hash_value*)g_hash_table_lookup(sip_hash, &key);
1998
1999         if (p_val)
2000         {
2001                 /* Table entry found, we'll use its value for comparison */
2002                 cseq_to_compare = p_val->cseq;
2003         }
2004         else
2005         {
2006                 /* Need to create a new table entry */
2007
2008                 /* Allocate a new key and value */
2009                 p_key = g_mem_chunk_alloc(sip_hash_keys);
2010                 p_val = g_mem_chunk_alloc(sip_hash_values);
2011
2012                 /* Just give up if allocations failed */
2013                 if (!p_key || !p_val)
2014                 {
2015                         return 0;
2016                 }
2017
2018                 /* Fill in key and value details */
2019                 strcpy(p_key->call_id, call_id);
2020                 COPY_ADDRESS(&(p_key->dest_address), &pinfo->net_dst);
2021                 COPY_ADDRESS(&(p_key->source_address), &pinfo->net_src);
2022                 p_key->dest_port = pinfo->destport;
2023                 p_key->source_port = pinfo->srcport;
2024
2025                 p_val->cseq = cseq_number;
2026                 p_val->transaction_state = nothing_seen;
2027                 p_val->frame_number = 0;
2028
2029                 /* Add entry */
2030                 g_hash_table_insert(sip_hash, p_key, p_val);
2031
2032                 /* Assume have seen no cseq yet */
2033                 cseq_to_compare = 0;
2034         }
2035
2036
2037         /******************************************/
2038         /* Is it a resend???                      */
2039
2040         /* Does this look like a resent request (discount ACK, CANCEL) ? */
2041         if ((line_type == REQUEST_LINE) && (cseq_number == cseq_to_compare) &&
2042                 (p_val->transaction_state == request_seen) &&
2043                 (strcmp(cseq_method, "ACK") != 0) &&
2044                 (strcmp(cseq_method, "CANCEL") != 0))
2045         {
2046                 result = p_val->frame_number;
2047         }
2048
2049         /* Does this look like a resent final response ? */
2050         if ((line_type == STATUS_LINE) && (cseq_number == cseq_to_compare) &&
2051                 (p_val->transaction_state == final_response_seen) &&
2052                 (stat_info->response_code >= 200) &&
2053                 (stat_info->response_code == p_val->response_code))
2054         {
2055                 result = p_val->frame_number;
2056         }
2057
2058         /* Update state for this entry */
2059         p_val->cseq = cseq_number;
2060
2061         switch (line_type)
2062         {
2063                 case REQUEST_LINE:
2064                         p_val->transaction_state = request_seen;
2065                         if (!result)
2066                         {
2067                                 p_val->frame_number = pinfo->fd->num;
2068                         }
2069                         break;
2070                 case STATUS_LINE:
2071                         if (stat_info->response_code >= 200)
2072                         {
2073                                 p_val->response_code = stat_info->response_code;
2074                                 p_val->transaction_state = final_response_seen;
2075                                 if (!result)
2076                                 {
2077                                         p_val->frame_number = pinfo->fd->num;
2078                                 }
2079                         }
2080                         else
2081                         {
2082                                 p_val->transaction_state = provisional_response_seen;
2083                         }
2084                         break;
2085                 default:
2086                         break;
2087         }
2088
2089         /* Store return value with this packet */
2090         p_add_proto_data(pinfo->fd, proto_sip, GUINT_TO_POINTER(result));
2091
2092         return result;
2093 }
2094
2095
2096 /* Register the protocol with Ethereal */
2097 void proto_register_sip(void)
2098 {
2099
2100         /* Setup list of header fields */
2101         static hf_register_info hf[] = {
2102
2103                 { &hf_msg_hdr,
2104                                 { "Message Header",           "sip.msg_hdr",
2105                         FT_NONE, 0, NULL, 0,
2106                         "Message Header in SIP message", HFILL }
2107                 },
2108                 { &hf_Method,
2109                        { "Method",              "sip.Method",
2110                        FT_STRING, BASE_NONE,NULL,0x0,
2111                         "SIP Method", HFILL }
2112                 },
2113                 { &hf_Request_Line,
2114                                 { "Request-Line",                "sip.Request-Line",
2115                                         FT_STRING, BASE_NONE,NULL,0x0,
2116                        "SIP Request-Line", HFILL }
2117                 },
2118                 { &hf_Status_Code,
2119                        { "Status-Code",                 "sip.Status-Code",
2120                        FT_UINT32, BASE_DEC,NULL,0x0,
2121                         "SIP Status Code", HFILL }
2122                 },
2123                 { &hf_Status_Line,
2124                        { "Status-Line",                 "sip.Status-Line",
2125                        FT_STRING, BASE_NONE,NULL,0x0,
2126                        "SIP Status-Line", HFILL }
2127                 },
2128                 { &hf_sip_display,
2129                         { "SIP Display info",           "sip.display.info",
2130                        FT_STRING, BASE_NONE,NULL,0x0,
2131                         "RFC 3261: Display info", HFILL }
2132                 },
2133                 { &hf_sip_to_addr,
2134                                 { "SIP to address",             "sip.to.addr",
2135                        FT_STRING, BASE_NONE,NULL,0x0,
2136                         "RFC 3261: to addr", HFILL }
2137                 },
2138                 { &hf_sip_from_addr,
2139                        { "SIP from address",            "sip.from.addr",
2140                        FT_STRING, BASE_NONE,NULL,0x0,
2141                         "RFC 3261: from addr", HFILL }
2142                 },
2143                 { &hf_sip_contact_addr,
2144                        { "SIP contact address",         "sip.contact.addr",
2145                        FT_STRING, BASE_NONE,NULL,0x0,
2146                         "RFC 3261: contact addr", HFILL }
2147                 },
2148                 { &hf_sip_uri,
2149                                 { "URI",                "sip.uri",
2150                        FT_STRING, BASE_NONE,NULL,0x0,
2151                         "RFC 3261: SIP Uri", HFILL }
2152                 },
2153                 { &hf_sip_contact_item,
2154                        { "Contact Binding",             "sip.contact.binding",
2155                        FT_STRING, BASE_NONE,NULL,0x0,
2156                         "RFC 3261: one contact binding", HFILL }
2157                 },
2158                 { &hf_sip_tag,
2159                        { "SIP tag",             "sip.tag",
2160                        FT_STRING, BASE_NONE,NULL,0x0,
2161                         "RFC 3261: tag", HFILL }
2162                 },
2163                 { &hf_header_array[POS_ACCEPT],
2164                        { "Accept",              "sip.Accept",
2165                        FT_STRING, BASE_NONE,NULL,0x0,
2166                         "RFC 3261: Accept Header", HFILL }
2167                 },
2168                 { &hf_header_array[POS_ACCEPT_CONTACT],
2169                        { "Accept-Contact",              "sip.Accept-Contact",
2170                        FT_STRING, BASE_NONE,NULL,0x0,
2171                         "RFC 3841: Accept-Contact Header", HFILL }
2172                 },
2173                 { &hf_header_array[POS_ACCEPT_ENCODING],
2174                        { "Accept-Encoding",             "sip.Accept-Encoding",
2175                        FT_STRING, BASE_NONE,NULL,0x0,
2176                         "RFC 3841: Accept-Encoding Header", HFILL }
2177                 },
2178                 { &hf_header_array[POS_ACCEPT_LANGUAGE],
2179                        { "Accept-Language",             "sip.Accept-Language",
2180                        FT_STRING, BASE_NONE,NULL,0x0,
2181                         "RFC 3261: Accept-Language Header", HFILL }
2182                 },
2183                 { &hf_header_array[POS_ACCEPT_RESOURCE_PRIORITY],
2184                        { "Accept-Resource-Priority",            "sip.Accept-Resource-Priority",
2185                        FT_STRING, BASE_NONE,NULL,0x0,
2186                         "Draft: Accept-Resource-Priority Header", HFILL }
2187                 },
2188                 { &hf_header_array[POS_ALERT_INFO],
2189                        { "Alert-Info",          "sip.Alert-Info",
2190                        FT_STRING, BASE_NONE,NULL,0x0,
2191                         "RFC 3261: Alert-Info Header", HFILL }
2192                 },
2193                 { &hf_header_array[POS_ALLOW],
2194                        { "Allow",               "sip.Allow",
2195                        FT_STRING, BASE_NONE,NULL,0x0,
2196                         "RFC 3261: Allow Header", HFILL }
2197                 },
2198                 { &hf_header_array[POS_ALLOW_EVENTS],
2199                        { "Allow-Events",                "sip.Allow-Events",
2200                        FT_STRING, BASE_NONE,NULL,0x0,
2201                         "RFC 3265: Allow-Events Header", HFILL }
2202                 },
2203                 { &hf_header_array[POS_AUTHENTICATION_INFO],
2204                        { "Authentication-Info",                 "sip.Authentication-Info",
2205                        FT_STRING, BASE_NONE,NULL,0x0,
2206                         "RFC 3261: Authentication-Info Header", HFILL }
2207                 },
2208                 { &hf_header_array[POS_AUTHORIZATION],
2209                        { "Authorization",               "sip.Authorization",
2210                        FT_STRING, BASE_NONE,NULL,0x0,
2211                         "RFC 3261: Authorization Header", HFILL }
2212                 },
2213                 { &hf_header_array[POS_CALL_ID],
2214                        { "Call-ID",             "sip.Call-ID",
2215                        FT_STRING, BASE_NONE,NULL,0x0,
2216                         "RFC 3261: Call-ID Header", HFILL }
2217                 },
2218                 { &hf_header_array[POS_CALL_INFO],
2219                        { "Call-Info",           "sip.Call-Info",
2220                        FT_STRING, BASE_NONE,NULL,0x0,
2221                         "RFC 3261: Call-Info Header", HFILL }
2222                 },
2223                 { &hf_header_array[POS_CONTACT],
2224                        { "Contact",             "sip.Contact",
2225                        FT_STRING, BASE_NONE,NULL,0x0,
2226                         "RFC 3261: Contact Header", HFILL }
2227                 },
2228                 { &hf_header_array[POS_CONTENT_DISPOSITION],
2229                        { "Content-Disposition",                 "sip.Content-Disposition",
2230                        FT_STRING, BASE_NONE,NULL,0x0,
2231                         "RFC 3261: Content-Disposition Header", HFILL }
2232                 },
2233                 { &hf_header_array[POS_CONTENT_ENCODING],
2234                        { "Content-Encoding",            "sip.Content-Encoding",
2235                        FT_STRING, BASE_NONE,NULL,0x0,
2236                         "RFC 3261: Content-Encoding Header", HFILL }
2237                 },
2238                 { &hf_header_array[POS_CONTENT_LANGUAGE],
2239                        { "Content-Language",            "sip.Content-Language",
2240                        FT_STRING, BASE_NONE,NULL,0x0,
2241                         "RFC 3261: Content-Language Header", HFILL }
2242                 },
2243                 { &hf_header_array[POS_CONTENT_LENGTH],
2244                        { "Content-Length",              "sip.Content-Length",
2245                        FT_STRING, BASE_NONE,NULL,0x0,
2246                         "RFC 3261: Content-Length Header", HFILL }
2247                 },
2248                 { &hf_header_array[POS_CONTENT_TYPE],
2249                        { "Content-Type",                "sip.Content-Type",
2250                        FT_STRING, BASE_NONE,NULL,0x0,
2251                         "RFC 3261: Content-Type Header", HFILL }
2252                 },
2253                 { &hf_header_array[POS_CSEQ],
2254                        { "CSeq",                "sip.CSeq",
2255                        FT_STRING, BASE_NONE,NULL,0x0,
2256                         "RFC 3261: CSeq Header", HFILL }
2257                 },
2258                 { &hf_header_array[POS_DATE],
2259                        { "Date",                "sip.Date",
2260                        FT_STRING, BASE_NONE,NULL,0x0,
2261                         "RFC 3261: Date Header", HFILL }
2262                 },
2263                 { &hf_header_array[POS_ERROR_INFO],
2264                        { "Error-Info",          "sip.Error-Info",
2265                        FT_STRING, BASE_NONE,NULL,0x0,
2266                         "RFC 3261: Error-Info Header", HFILL }
2267                 },
2268                 { &hf_header_array[POS_EVENT],
2269                        { "Event",               "sip.Event",
2270                        FT_STRING, BASE_NONE,NULL,0x0,
2271                         "RFC 3265: Event Header", HFILL }
2272                 },
2273                 { &hf_header_array[POS_EXPIRES],
2274                        { "Expires",             "sip.Expires",
2275                        FT_STRING, BASE_NONE,NULL,0x0,
2276                         "RFC 3261: Expires Header", HFILL }
2277                 },
2278                 { &hf_header_array[POS_FROM],
2279                        { "From",                "sip.From",
2280                        FT_STRING, BASE_NONE,NULL,0x0,
2281                         "RFC 3261: From Header", HFILL }
2282                 },
2283                 { &hf_header_array[POS_IN_REPLY_TO],
2284                        { "In-Reply-To",                 "sip.In-Reply-To",
2285                        FT_STRING, BASE_NONE,NULL,0x0,
2286                         "RFC 3261: In-Reply-To Header", HFILL }
2287                 },
2288                 { &hf_header_array[POS_JOIN],
2289                        { "Join",                "sip.Join",
2290                        FT_STRING, BASE_NONE,NULL,0x0,
2291                         "Draft: Join Header", HFILL }
2292                 },
2293                 { &hf_header_array[POS_MAX_FORWARDS],
2294                        { "Max-Forwards",                "sip.Max-Forwards",
2295                        FT_STRING, BASE_NONE,NULL,0x0,
2296                         "RFC 3261: Max-Forwards Header", HFILL }
2297                 },
2298                 { &hf_header_array[POS_MIME_VERSION],
2299                        { "MIME-Version",                "sip.MIME-Version",
2300                        FT_STRING, BASE_NONE,NULL,0x0,
2301                         "RFC 3261: MIME-Version Header", HFILL }
2302                 },
2303                 { &hf_header_array[POS_MIN_EXPIRES],
2304                        { "Min-Expires",                 "sip.Min-Expires",
2305                        FT_STRING, BASE_NONE,NULL,0x0,
2306                         "RFC 3261: Min-Expires Header", HFILL }
2307                 },
2308                 { &hf_header_array[POS_MIN_SE],
2309                        { "Min-SE",              "sip.Min-SE",
2310                        FT_STRING, BASE_NONE,NULL,0x0,
2311                         "Draft: Min-SE Header", HFILL }
2312                 },
2313                 { &hf_header_array[POS_ORGANIZATION],
2314                        { "Organization",                "sip.Organization",
2315                        FT_STRING, BASE_NONE,NULL,0x0,
2316                         "RFC 3261: Organization Header", HFILL }
2317                 },
2318                 { &hf_header_array[POS_P_ACCESS_NETWORK_INFO],
2319                        { "P-Access-Network-Info",       "sip.P-Access-Network-Info",
2320                        FT_STRING, BASE_NONE,NULL,0x0,
2321                         "P-Access-Network-Info Header", HFILL }
2322                 },
2323
2324                 { &hf_header_array[POS_P_ASSERTED_IDENTITY],
2325                        { "P-Asserted-Identity",         "sip.P-Asserted-Identity",
2326                        FT_STRING, BASE_NONE,NULL,0x0,
2327                         "P-Asserted-Identity Header", HFILL }
2328                 },
2329
2330                 { &hf_header_array[POS_P_ASSOCIATED_URI],
2331                        { "P-Associated-URI",            "sip.P-Associated-URI",
2332                        FT_STRING, BASE_NONE,NULL,0x0,
2333                         "P-Associated-URI Header", HFILL }
2334                 },
2335
2336                 { &hf_header_array[POS_P_CALLED_PARTY_ID],
2337                        { "P-Called-Party-ID",           "sip.P-Called-Party-ID",
2338                        FT_STRING, BASE_NONE,NULL,0x0,
2339                         "P-Called-Party-ID Header", HFILL }
2340                 },
2341
2342                 { &hf_header_array[POS_P_CHARGING_FUNCTION_ADDRESSES],
2343                        { "P-Charging-Function-Addresses","sip.P-Charging-Function-Addresses",
2344                        FT_STRING, BASE_NONE,NULL,0x0,
2345                         "P-Charging-Function-Addresses", HFILL }
2346                 },
2347
2348                 { &hf_header_array[POS_P_CHARGING_VECTOR],
2349                        { "P-Charging-Vector",           "sip.P-Charging-Vector",
2350                        FT_STRING, BASE_NONE,NULL,0x0,
2351                         "P-Charging-Vector Header", HFILL }
2352                 },
2353
2354                 { &hf_header_array[POS_P_DCS_TRACE_PARTY_ID],
2355                        { "P-DCS-Trace-Party-ID",        "sip.P-DCS-Trace-Party-ID",
2356                        FT_STRING, BASE_NONE,NULL,0x0,
2357                         "P-DCS-Trace-Party-ID Header", HFILL }
2358                 },
2359
2360                 { &hf_header_array[POS_P_DCS_OSPS],
2361                        { "P-DCS-OSPS",                  "sip.P-DCS-OSPS",
2362                        FT_STRING, BASE_NONE,NULL,0x0,
2363                         "P-DCS-OSPS Header", HFILL }
2364                 },
2365
2366                 { &hf_header_array[POS_P_DCS_BILLING_INFO],
2367                        { "P-DCS-Billing-Info",          "sip.P-DCS-Billing-Info",
2368                        FT_STRING, BASE_NONE,NULL,0x0,
2369                         "P-DCS-Billing-Info Header", HFILL }
2370                 },
2371
2372                 { &hf_header_array[POS_P_DCS_LAES],
2373                        { "P-DCS-LAES",                  "sip.P-DCS-LAES",
2374                        FT_STRING, BASE_NONE,NULL,0x0,
2375                         "P-DCS-LAES Header", HFILL }
2376                 },
2377
2378                 { &hf_header_array[POS_P_DCS_REDIRECT],
2379                        { "P-DCS-Redirect",              "sip.P-DCS-Redirect",
2380                        FT_STRING, BASE_NONE,NULL,0x0,
2381                         "P-DCS-Redirect Header", HFILL }
2382                 },
2383
2384                 { &hf_header_array[POS_P_MEDIA_AUTHORIZATION],
2385                        { "P-Media-Authorization",       "sip.P-Media-Authorization",
2386                        FT_STRING, BASE_NONE,NULL,0x0,
2387                         "P-Media-Authorization Header", HFILL }
2388                 },
2389
2390                 { &hf_header_array[POS_P_PREFERRED_IDENTITY],
2391                        { "P-Preferred-Identity",        "sip.P-Preferred-Identity",
2392                        FT_STRING, BASE_NONE,NULL,0x0,
2393                         "P-Preferred-Identity Header", HFILL }
2394                 },
2395
2396                 { &hf_header_array[POS_P_VISITED_NETWORK_ID],
2397                        { "P-Visited-Network-ID",        "sip.P-Visited-Network-ID",
2398                        FT_STRING, BASE_NONE,NULL,0x0,
2399                         "P-Visited-Network-ID Header", HFILL }
2400                 },
2401
2402                 { &hf_header_array[POS_PATH],
2403                        { "Path",                        "sip.Path",
2404                        FT_STRING, BASE_NONE,NULL,0x0,
2405                         "Path Header", HFILL }
2406                 },
2407
2408         { &hf_header_array[POS_PRIORITY],
2409                        { "Priority",            "sip.Priority",
2410                        FT_STRING, BASE_NONE,NULL,0x0,
2411                         "RFC 3261: Priority Header", HFILL }
2412                 },
2413                 { &hf_header_array[POS_PRIVACY],
2414                        { "Privacy",                     "sip.Privacy",
2415                        FT_STRING, BASE_NONE,NULL,0x0,
2416                         "Privacy Header", HFILL }
2417                 },
2418
2419         { &hf_header_array[POS_PROXY_AUTHENTICATE],
2420                        { "Proxy-Authenticate",          "sip.Proxy-Authenticate",
2421                        FT_STRING, BASE_NONE,NULL,0x0,
2422                         "RFC 3261: Proxy-Authenticate Header", HFILL }
2423                 },
2424                 { &hf_header_array[POS_PROXY_AUTHORIZATION],
2425                        { "Proxy-Authorization",                 "sip.Proxy-Authorization",
2426                        FT_STRING, BASE_NONE,NULL,0x0,
2427                         "RFC 3261: Proxy-Authorization Header", HFILL }
2428                 },
2429
2430         { &hf_header_array[POS_PROXY_REQUIRE],
2431                        { "Proxy-Require",               "sip.Proxy-Require",
2432                        FT_STRING, BASE_NONE,NULL,0x0,
2433                         "RFC 3261: Proxy-Require Header", HFILL }
2434                 },
2435                 { &hf_header_array[POS_RACK],
2436                        { "RAck",                "sip.RAck",
2437                        FT_STRING, BASE_NONE,NULL,0x0,
2438                         "RFC 3262: RAck Header", HFILL }
2439                 },
2440                 { &hf_header_array[POS_REASON],
2441                        { "Reason",                      "sip.Reason",
2442                        FT_STRING, BASE_NONE,NULL,0x0,
2443                         "RFC 3326 Reason Header", HFILL }
2444                 },
2445                 { &hf_header_array[POS_RECORD_ROUTE],
2446                        { "Record-Route",                "sip.Record-Route",
2447                        FT_STRING, BASE_NONE,NULL,0x0,
2448                         "RFC 3261: Record-Route Header", HFILL }
2449                 },
2450                 { &hf_header_array[POS_REFERED_BY],
2451                        { "Refered By",          "sip.Refered-by",
2452                        FT_STRING, BASE_NONE,NULL,0x0,
2453                         "RFC 3892: Refered-by Header", HFILL }
2454                 },
2455                 { &hf_header_array[POS_REJECT_CONTACT],
2456                         { "Reject-Contact",             "sip.Reject-Contact",
2457                         FT_STRING, BASE_NONE,NULL,0x0,
2458                         "RFC 3841: Reject-Contact Header", HFILL }
2459                 },
2460                 { &hf_header_array[POS_REPLACES],
2461                         { "Replaces",           "sip.Replaces",
2462                         FT_STRING, BASE_NONE,NULL,0x0,
2463                         "RFC 3891: Replaces Header", HFILL }
2464                 },
2465                 { &hf_header_array[POS_REPLY_TO],
2466                        { "Reply-To",            "sip.Reply-To",
2467                        FT_STRING, BASE_NONE,NULL,0x0,
2468                         "RFC 3261: Reply-To Header", HFILL }
2469                 },
2470                 { &hf_header_array[POS_REQUEST_DISPOSITION],
2471                        { "Request-Disposition",         "sip.Request-Disposition",
2472                        FT_STRING, BASE_NONE,NULL,0x0,
2473                         "RFC 3841: Request-Disposition Header", HFILL }
2474                 },
2475                 { &hf_header_array[POS_REQUIRE],
2476                         { "Require",            "sip.Require",
2477                        FT_STRING, BASE_NONE,NULL,0x0,
2478                         "RFC 3261: Require Header", HFILL }
2479                 },
2480                 { &hf_header_array[POS_RESOURCE_PRIORITY],
2481                         { "Resource-Priority",          "sip.Resource-Priority",
2482                        FT_STRING, BASE_NONE,NULL,0x0,
2483                         "Draft: Resource-Priority Header", HFILL }
2484                 },
2485                 { &hf_header_array[POS_RETRY_AFTER],
2486                         { "Retry-After",                "sip.Retry-After",
2487                        FT_STRING, BASE_NONE,NULL,0x0,
2488                         "RFC 3261: Retry-After Header", HFILL }
2489                 },
2490                 { &hf_header_array[POS_ROUTE],
2491                        { "Route",               "sip.Route",
2492                        FT_STRING, BASE_NONE,NULL,0x0,
2493                         "RFC 3261: Route Header", HFILL }
2494                 },
2495         { &hf_header_array[POS_RSEQ],
2496                        { "RSeq",                "sip.RSeq",
2497                        FT_STRING, BASE_NONE,NULL,0x0,
2498                         "RFC 3262: RSeq Header", HFILL }
2499                 },
2500                 { &hf_header_array[ POS_SECURITY_CLIENT],
2501                        { "Security-Client",             "sip.Security-Client",
2502                        FT_STRING, BASE_NONE,NULL,0x0,
2503                         "RFC 3329 Security-Client Header", HFILL }
2504                 },
2505                 { &hf_header_array[ POS_SECURITY_SERVER],
2506                        { "Security-Server",             "sip.Security-Server",
2507                        FT_STRING, BASE_NONE,NULL,0x0,
2508                         "RFC 3329 Security-Server Header", HFILL }
2509                 },
2510                 { &hf_header_array[ POS_SECURITY_VERIFY],
2511                        { "Security-Verify",             "sip.Security-Verify",
2512                        FT_STRING, BASE_NONE,NULL,0x0,
2513                         "RFC 3329 Security-Verify Header", HFILL }
2514                 },
2515                 { &hf_header_array[POS_SERVER],
2516                         { "Server",             "sip.Server",
2517                        FT_STRING, BASE_NONE,NULL,0x0,
2518                         "RFC 3261: Server Header", HFILL }
2519                 },
2520                 { &hf_header_array[POS_SERVICE_ROUTE],
2521                        { "Service-Route",               "sip.Service-Route",
2522                        FT_STRING, BASE_NONE,NULL,0x0,
2523                         "Service-Route Header", HFILL }
2524                 },
2525                 { &hf_header_array[POS_SESSION_EXPIRES],
2526                        { "Session-Expires",             "sip.Session-Expires",
2527                        FT_STRING, BASE_NONE,NULL,0x0,
2528                         "Session-Expires Header", HFILL }
2529                 },
2530                 { &hf_header_array[POS_SIP_ETAG],
2531                        { "ETag",                "sip.ETag",
2532                        FT_STRING, BASE_NONE,NULL,0x0,
2533                         "SIP-ETag Header", HFILL }
2534                 },
2535                 { &hf_header_array[POS_SIP_IF_MATCH],
2536                        { "If_Match",            "sip.If_Match",
2537                        FT_STRING, BASE_NONE,NULL,0x0,
2538                         "SIP-If-Match Header", HFILL }
2539                 },
2540                 { &hf_header_array[POS_SUBJECT],
2541                        { "Subject",             "sip.Subject",
2542                        FT_STRING, BASE_NONE,NULL,0x0,
2543                         "RFC 3261: Subject Header", HFILL }
2544                 },
2545                 { &hf_header_array[POS_SUBSCRIPTION_STATE],
2546                        { "Subscription-State",          "sip.Subscription-State",
2547                        FT_STRING, BASE_NONE,NULL,0x0,
2548                         "RFC 3265: Subscription-State Header", HFILL }
2549                 },
2550                 { &hf_header_array[POS_SUPPORTED],
2551                         { "Supported",          "sip.Supported",
2552                        FT_STRING, BASE_NONE,NULL,0x0,
2553                         "RFC 3261: Supported Header", HFILL }
2554                 },
2555                 { &hf_header_array[POS_TIMESTAMP],
2556                         { "Timestamp",          "sip.Timestamp",
2557                        FT_STRING, BASE_NONE,NULL,0x0,
2558                         "RFC 3261: Timestamp Header", HFILL }
2559                 },
2560                 { &hf_header_array[POS_TO],
2561                         { "To",                 "sip.To",
2562                        FT_STRING, BASE_NONE,NULL,0x0,
2563                         "RFC 3261: To Header", HFILL }
2564                 },
2565
2566                 { &hf_header_array[POS_UNSUPPORTED],
2567                         { "Unsupported",                "sip.Unsupported",
2568                        FT_STRING, BASE_NONE,NULL,0x0,
2569                         "RFC 3261: Unsupported Header", HFILL }
2570                 },
2571                 { &hf_header_array[POS_USER_AGENT],
2572                         { "User-Agent",                 "sip.User-Agent",
2573                        FT_STRING, BASE_NONE,NULL,0x0,
2574                         "RFC 3261: User-Agent Header", HFILL }
2575                 },
2576                 { &hf_header_array[POS_VIA],
2577                         { "Via",                "sip.Via",
2578                        FT_STRING, BASE_NONE,NULL,0x0,
2579                         "RFC 3261: Via Header", HFILL }
2580                 },
2581                 { &hf_header_array[POS_WARNING],
2582                         { "Warning",            "sip.Warning",
2583                        FT_STRING, BASE_NONE,NULL,0x0,
2584                         "RFC 3261: Warning Header", HFILL }
2585                 },
2586
2587                 { &hf_header_array[POS_WWW_AUTHENTICATE],
2588                         { "WWW-Authenticate",           "sip.WWW-Authenticate",
2589                        FT_STRING, BASE_NONE,NULL,0x0,
2590                         "RFC 3261: WWW-Authenticate Header", HFILL }
2591                 },
2592                 { &hf_header_array[POS_REFER_TO],
2593                        { "Refer-To",                    "sip.Refer-To",
2594                        FT_STRING, BASE_NONE,NULL,0x0,
2595                         "Refer-To Header", HFILL }
2596                 },
2597                 { &hf_sip_resend,
2598                         { "Resent Packet", "sip.resend",
2599                         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2600                         "", HFILL }
2601                 },
2602                 { &hf_sip_original_frame,
2603                         { "Suspected resend of frame",  "sip.resend-original",
2604                         FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2605                         "Original transmission of frame", HFILL}}
2606                 };
2607
2608         /* Setup protocol subtree array */
2609         static gint *ett[] = {
2610                 &ett_sip,
2611                 &ett_sip_reqresp,
2612                 &ett_sip_hdr,
2613                 &ett_sip_element,
2614                 &ett_sip_uri,
2615                 &ett_sip_contact_item,
2616                 &ett_sip_message_body,
2617         };
2618         static gint *ett_raw[] = {
2619                 &ett_raw_text,
2620         };
2621
2622         module_t *sip_module;
2623
2624         /* Register the protocol name and description */
2625         proto_sip = proto_register_protocol("Session Initiation Protocol",
2626                                             "SIP", "sip");
2627         proto_raw_sip = proto_register_protocol("Session Initiation Protocol (SIP as raw text)",
2628                                                 "Raw_SIP", "raw_sip");
2629         new_register_dissector("sip", dissect_sip, proto_sip);
2630
2631         /* Required function calls to register the header fields and subtrees used */
2632         proto_register_field_array(proto_sip, hf, array_length(hf));
2633         proto_register_subtree_array(ett, array_length(ett));
2634         proto_register_subtree_array(ett_raw, array_length(ett_raw));
2635
2636         /* SIP content type and internet media type used by other dissectors are the same */
2637         media_type_dissector_table = find_dissector_table("media_type");
2638
2639         sip_module = prefs_register_protocol(proto_sip, NULL);
2640
2641         prefs_register_bool_preference(sip_module, "display_raw_text",
2642                 "Display raw text for SIP message",
2643                 "Specifies that the raw text of the "
2644                 "SIP message should be displayed "
2645                 "in addition to the dissection tree",
2646                 &global_sip_raw_text);
2647         prefs_register_bool_preference(sip_module, "strict_sip_version",
2648                 "Enforce strict SIP version check (" SIP2_HDR ")",
2649                 "If enabled, only " SIP2_HDR " traffic will be dissected as SIP. "
2650                 "Disable it to allow SIP traffic with a different version "
2651                 "to be dissected as SIP.",
2652                 &strict_sip_version);
2653
2654         register_init_routine(&sip_init_protocol);
2655
2656         /* Register for tapping */
2657         sip_tap = register_tap("sip");
2658 }
2659
2660 void
2661 proto_reg_handoff_sip(void)
2662 {
2663         dissector_handle_t sip_handle, sip_tcp_handle;
2664
2665         sip_handle = new_create_dissector_handle(dissect_sip, proto_sip);
2666         dissector_add("udp.port", UDP_PORT_SIP, sip_handle);
2667         dissector_add_string("media_type", "message/sip", sip_handle);
2668         sigcomp_handle = find_dissector("sigcomp");
2669
2670         sip_tcp_handle = create_dissector_handle(dissect_sip_tcp, proto_sip);
2671         dissector_add("tcp.port", TCP_PORT_SIP, sip_tcp_handle);
2672
2673         heur_dissector_add("udp", dissect_sip_heur, proto_sip);
2674         heur_dissector_add("tcp", dissect_sip_heur, proto_sip);
2675         heur_dissector_add("sctp", dissect_sip_heur, proto_sip);
2676 }