Note that for THE3GPP_IPV6_DNS_SERVERS we probably *do* need to handle
[obnox/wireshark/wip.git] / 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  *
21  * $Id: packet-sip.c,v 1.60 2004/02/18 20:55:57 guy Exp $
22  *
23  * Ethereal - Network traffic analyzer
24  * By Gerald Combs <gerald@ethereal.com>
25  * Copyright 1998 Gerald Combs
26  *
27  * Copied from packet-cops.c
28  *
29  * This program is free software; you can redistribute it and/or
30  * modify it under the terms of the GNU General Public License
31  * as published by the Free Software Foundation; either version 2
32  * of the License, or (at your option) any later version.
33  *
34  * This program is distributed in the hope that it will be useful,
35  * but WITHOUT ANY WARRANTY; without even the implied warranty of
36  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37  * GNU General Public License for more details.
38  *
39  * You should have received a copy of the GNU General Public License
40  * along with this program; if not, write to the Free Software
41  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
42  */
43
44 #ifdef HAVE_CONFIG_H
45 # include "config.h"
46 #endif
47
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <ctype.h>
52
53 #include "prefs.h"
54
55 #include <glib.h>
56 #include <epan/packet.h>
57
58 #define TCP_PORT_SIP 5060
59 #define UDP_PORT_SIP 5060
60
61 /* Initialize the protocol and registered fields */
62 static gint proto_sip = -1;
63 static gint proto_raw_sip = -1;
64 static gint hf_msg_hdr = -1;
65 static gint hf_Method = -1;
66 static gint hf_Request_Line = -1;
67 static gint hf_Status_Code = -1;
68 static gint hf_Status_Line = -1;
69 static gint hf_sip_to_addr = -1;
70 static gint hf_sip_from_addr = -1;
71 static gint hf_sip_tag = -1;
72
73 /* Initialize the subtree pointers */
74 static gint ett_sip             = -1;
75 static gint ett_sip_reqresp     = -1;
76 static gint ett_sip_hdr         = -1;
77 static gint ett_raw_text        = -1;
78 static gint ett_sip_element     = -1;
79 static gint ett_sip_message_body = -1;
80
81 /* PUBLISH method added as per http://www.ietf.org/internet-drafts/draft-ietf-sip-publish-01.txt */
82 static const char *sip_methods[] = {
83         "<Invalid method>",      /* Pad so that the real methods start at index 1 */
84         "ACK",
85         "BYE",
86         "CANCEL",
87         "DO",
88         "INFO",
89         "INVITE",
90         "MESSAGE",
91         "NOTIFY",
92         "OPTIONS",
93         "PRACK",
94         "QAUTH",
95         "REFER",
96         "REGISTER",
97         "SPRACK",
98         "SUBSCRIBE",
99         "UPDATE",
100         "PUBLISH"
101 };
102
103 /* from RFC 3261 */
104 /* Updated with info from http://www.iana.org/assignments/sip-parameters */
105 /* (last updated 2003-10-31) */
106 /* Added two headsers ( Etag and If-Match )from http://www.ietf.org/internet-drafts/draft-ietf-sip-publish-01.txt */
107 typedef struct {
108         char *name;
109         char *compact_name;
110 } sip_header_t;
111 static const sip_header_t sip_headers[] = {
112                 { "Unknown-header",             NULL }, /* Pad so that the real headers start at index 1 */
113                 { "Accept",                     NULL },
114                 { "Accept-Encoding",            NULL },
115                 { "Accept-Language",            NULL },
116                 { "Alert-Info",                 NULL },
117                 { "Allow",                      NULL },
118                 { "Allow-Events",               NULL },
119                 { "Authentication-Info",        NULL },
120                 { "Authorization",              NULL },
121                 { "Call-ID",                    "i"  },
122                 { "Call-Info",                  NULL },
123                 { "Contact",                    "m"  },
124                 { "Content-Disposition",        NULL },
125                 { "Content-Encoding",           "e"  },
126                 { "Content-Language",           NULL },
127                 { "Content-Length",             "l"  },
128                 { "Content-Type",               "c"  },
129                 { "CSeq",                       NULL },
130                 { "Date",                       NULL },
131                 { "Error-Info",                 NULL },
132                 { "Event",                      "o"  },
133                 { "Expires",                    NULL },
134                 { "From",                       "f"  },
135                 { "In-Reply-To",                NULL },
136                 { "Max-Forwards",               NULL },
137                 { "MIME-Version",               NULL },
138                 { "Min-Expires",                NULL },
139                 { "Organization",               NULL },
140                 { "Priority",                   NULL },
141                 { "Proxy-Authenticate",         NULL },
142                 { "Proxy-Authorization",        NULL },
143                 { "Proxy-Require",              NULL },
144                 { "RAck",                       NULL },
145                 { "RSeq",                       NULL },
146                 { "Record-Route",               NULL },
147                 { "Reply-To",                   NULL },
148                 { "Require",                    NULL },
149                 { "Retry-After",                NULL },
150                 { "Route",                      NULL },
151                 { "Server",                     NULL },
152                 { "Subject",                    "s"  },
153                 { "Subscription-State",         NULL },
154                 { "Supported",                  "k" },
155                 { "Timestamp",                  NULL },
156                 { "To",                         "t"  },
157                 { "Unsupported",                NULL },
158                 { "User-Agent",                 NULL },
159                 { "Via",                        "v" },
160                 { "Warning",                    NULL },
161                 { "WWW-Authenticate",           NULL },
162                 { "P-Access-Network-Info",      NULL },  /*  RFC3455  */  
163                 { "P-Asserted-Identity",        NULL },  /*  RFC3325  */  
164                 { "P-Associated-URI",           NULL },  /*  RFC3455  */  
165                 { "P-Called-Party-ID",          NULL },  /*  RFC3455  */  
166                 { "P-Charging-Function-Addresses",NULL }, /*  RFC3455  */  
167                 { "P-Charging-Vector",          NULL },  /*  RFC3455  */  
168                 { "P-DCS-Trace-Party-ID",       NULL },  /*  RFC3603  */  
169                 { "P-DCS-OSPS",                 NULL },  /*  RFC3603  */  
170                 { "P-DCS-Billing-Info",         NULL },  /*  RFC3603  */  
171                 { "P-DCS-LAES",                 NULL },  /*  RFC3603  */  
172                 { "P-DCS-Redirect",             NULL },  /*  RFC3603  */  
173                 { "P-Media-Authorization",      NULL },  /*  RFC3313  */  
174                 { "P-Preferred-Identity",       NULL },  /*  RFC3325  */  
175                 { "P-Visited-Network-ID",       NULL },  /*  RFC3455  */  
176                 { "Path",                       NULL },  /*  RFC3327  */  
177                 { "Privacy",                    NULL },  /*  RFC3323  */  
178                 { "Reason",                     NULL },  /*  RFC3326  */  
179                 { "Refer-To",                   "r"  },  /*  RFC3515  */  
180                 { "Service-Route",              NULL },  /*  RFC3608  */  
181                 { "ETag",                       NULL },  /*  draft-ietf-sip-publish-01  */  
182                 { "If-Match",                   NULL },  /*  draft-ietf-sip-publish-01  */  
183
184 };
185
186
187 #define POS_ACCEPT                      1
188 #define POS_ACCEPT_ENCODING             2
189 #define POS_ACCEPT_LANGUAGE             3
190 #define POS_ALERT_INFO                  4
191 #define POS_ALLOW                       5
192 #define POS_ALLOW_EVENTS                6
193 #define POS_AUTHENTICATION_INFO         7
194 #define POS_AUTHORIZATION               8
195 #define POS_CALL_ID                     9
196 #define POS_CALL_INFO                   10
197 #define POS_CONTACT                     11
198 #define POS_CONTENT_DISPOSITION         12
199 #define POS_CONTENT_ENCODING            13
200 #define POS_CONTENT_LANGUAGE            14
201 #define POS_CONTENT_LENGTH              15
202 #define POS_CONTENT_TYPE                16
203 #define POS_CSEQ                        17
204 #define POS_DATE                        18
205 #define POS_ERROR_INFO                  19
206 #define POS_EVENT                       20
207 #define POS_EXPIRES                     21
208 #define POS_FROM                        22
209 #define POS_IN_REPLY_TO                 23
210 #define POS_MAX_FORWARDS                24
211 #define POS_MIME_VERSION                25
212 #define POS_MIN_EXPIRES                 26
213 #define POS_ORGANIZATION                27
214 #define POS_PRIORITY                    28
215 #define POS_PROXY_AUTHENTICATE          29
216 #define POS_PROXY_AUTHORIZATION         30
217 #define POS_PROXY_REQUIRE               31
218 #define POS_RACK                        32
219 #define POS_RSEQ                        33
220 #define POS_RECORD_ROUTE                34
221 #define POS_REPLY_TO                    35
222 #define POS_REQUIRE                     36
223 #define POS_RETRY_AFTER                 37
224 #define POS_ROUTE                       38
225 #define POS_SERVER                      39
226 #define POS_SUBJECT                     40
227 #define POS_SUBSCRIPTION_STATE          41
228 #define POS_SUPPORTED                   42
229 #define POS_TIMESTAMP                   43
230 #define POS_TO                          44
231 #define POS_UNSUPPORTED                 45
232 #define POS_USER_AGENT                  46
233 #define POS_VIA                         47
234 #define POS_WARNING                     48
235 #define POS_WWW_AUTHENTICATE            49
236
237 #define POS_P_ACCESS_NETWORK_INFO       50  
238 #define POS_P_ASSERTED_IDENTITY         51    
239 #define POS_P_ASSOCIATED_URI            52  
240 #define POS_P_CALLED_PARTY_ID           53  
241 #define POS_P_CHARGING_FUNCTION_ADDRESSES 54  
242 #define POS_P_CHARGING_VECTOR           55
243 #define POS_P_DCS_TRACE_PARTY_ID        56 
244 #define POS_P_DCS_OSPS                  57  
245 #define POS_P_DCS_BILLING_INFO          58  
246 #define POS_P_DCS_LAES                  59  
247 #define POS_P_DCS_REDIRECT              60  
248 #define POS_P_MEDIA_AUTHORIZATION       61  
249 #define POS_P_PREFERRED_IDENTITY        62  
250 #define POS_P_VISITED_NETWORK_ID        63  
251 #define POS_PATH                        64  
252 #define POS_PRIVACY                     65  
253 #define POS_REASON                      66 
254 #define POS_REFER_TO                    67 
255 #define POS_SERVICE_ROUTE               68 
256 #define POS_ETAG                        69 
257 #define POS_IF_MATCH                    70  
258
259 static gint hf_header_array[] = {
260                 -1, /* "Unknown-header" - Pad so that the real headers start at index 1 */
261                 -1, /* "Accept" */
262                 -1, /* "Accept-Encoding" */
263                 -1, /* "Accept-Language" */
264                 -1, /* "Alert-Info" */
265                 -1, /* "Allow" */
266                 -1, /* "Allow-Events" - RFC 3265 */
267                 -1, /* "Authentication-Info" */
268                 -1, /* "Authorization" */
269                 -1, /* "Call-ID" */
270                 -1, /* "Call-Info" */
271                 -1, /* "Contact" */
272                 -1, /* "Content-Disposition" */
273                 -1, /* "Content-Encoding" */
274                 -1, /* "Content-Language" */
275                 -1, /* "Content-Length" */
276                 -1, /* "Content-Type" */
277                 -1, /* "CSeq" */
278                 -1, /* "Date" */
279                 -1, /* "Error-Info" */
280                 -1, /* "Expires" */
281                 -1, /* "Event" - RFC 3265 */
282                 -1, /* "From" */
283                 -1, /* "In-Reply-To" */
284                 -1, /* "Max-Forwards" */
285                 -1, /* "MIME-Version" */
286                 -1, /* "Min-Expires" */
287                 -1, /* "Organization" */
288                 -1, /* "Priority" */
289                 -1, /* "Proxy-Authenticate" */
290                 -1, /* "Proxy-Authorization" */
291                 -1, /* "Proxy-Require" */
292                 -1, /* "RAck" - RFC 3262 */
293                 -1, /* "RSeq" - RFC 3261 */
294                 -1, /* "Record-Route" */
295                 -1, /* "Reply-To" */
296                 -1, /* "Require" */
297                 -1, /* "Retry-After" */
298                 -1, /* "Route" */
299                 -1, /* "Server" */
300                 -1, /* "Subject" */
301                 -1, /* "Subscription-State" - RFC 3265 */
302                 -1, /* "Supported" */
303                 -1, /* "Timestamp" */
304                 -1, /* "To" */
305                 -1, /* "Unsupported" */
306                 -1, /* "User-Agent" */
307                 -1, /* "Via" */
308                 -1, /* "Warning" */
309                 -1,  /* "WWW-Authenticate" */
310                 -1,  /* "P-Access-Network-Info" -   RFC3455  */  
311                 -1,  /* "P-Asserted-Identity"   -   RFC3325  */  
312                 -1,  /* "P-Associated-URI"      -   RFC3455  */  
313                 -1,  /* "P-Called-Party-ID"     -   RFC3455  */  
314                 -1,  /* "P-Charging-Function-Addresses" -   RFC3455  */  
315                 -1,  /* "P-Charging-Vector"     -   RFC3455  */  
316                 -1,  /* "P-DCS-Trace-Party-ID"  -   RFC3603  */  
317                 -1,  /* "P-DCS-OSPS"            -   RFC3603  */  
318                 -1,  /* "P-DCS-Billing-Info"    -   RFC3603  */  
319                 -1,  /* "P-DCS-LAES"            -   RFC3603  */  
320                 -1,  /* "P-DCS-Redirect"        -   RFC3603  */  
321                 -1,  /* "P-Media-Authorization"         -   RFC3313  */  
322                 -1,  /* "P-Preferred-Identity"  -   RFC3325  */  
323                 -1,  /* "P-Visited-Network-ID"  -   RFC3455  */  
324                 -1,  /* "Path"                  -   RFC3327  */  
325                 -1,  /* "Privacy"               -   RFC3323  */  
326                 -1,  /* "Reason"                -   RFC3326  */  
327                 -1,  /* "Refer-To"              -   RFC3515  */  
328                 -1,  /* "Service-Route"                 -   RFC3608  */  
329                 -1,  /* "ETag"     draft-ietf-sip-publish-01  */  
330                 -1,  /* "If-Match  draft-ietf-sip-publish-01  */  
331
332 };
333
334 /*
335  * Type of line.  It's either a SIP Request-Line, a SIP Status-Line, or
336  * another type of line.
337  */
338 typedef enum {
339         REQUEST_LINE,
340         STATUS_LINE,
341         OTHER_LINE
342 } line_type_t;
343
344 /* global_sip_raw_text determines whether we are going to display               */
345 /* the raw text of the SIP message, much like the MEGACO dissector does.        */
346 static gboolean global_sip_raw_text = FALSE;
347 /* strict_sip_version determines whether the SIP dissector enforces
348  * the SIP version to be "SIP/2.0". */
349 static gboolean strict_sip_version = TRUE;
350
351 static gboolean dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo,
352     proto_tree *tree, gboolean is_heur);
353 static line_type_t sip_parse_line(tvbuff_t *tvb, gint linelen,
354     guint *token_1_len);
355 static gboolean sip_is_known_request(tvbuff_t *tvb, int meth_offset,
356     guint meth_len, guint *meth_idx);
357 static gint sip_is_known_sip_header(tvbuff_t *tvb, int offset,
358     guint header_len);
359 static void dfilter_sip_request_line(tvbuff_t *tvb, proto_tree *tree,
360     guint meth_len);
361 static void dfilter_sip_status_line(tvbuff_t *tvb, proto_tree *tree);
362 static void tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree);
363
364 /* SIP content type and internet media type used by other dissectors
365  * are the same.  List of media types from IANA at:
366  * http://www.iana.org/assignments/media-types/index.html */
367 static dissector_table_t media_type_dissector_table;
368
369 #define SIP2_HDR "SIP/2.0"
370 #define SIP2_HDR_LEN (strlen (SIP2_HDR))
371
372 /* Code to actually dissect the packets */
373 static int
374 dissect_sip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
375 {
376         if (!dissect_sip_common(tvb, pinfo, tree, FALSE))
377                 return 0;
378         return tvb_length(tvb);
379 }
380
381 static void
382 dissect_sip_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
383 {
384         dissect_sip_common(tvb, pinfo, tree, TRUE);
385 }
386
387 static gboolean
388 dissect_sip_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
389 {
390         return dissect_sip_common(tvb, pinfo, tree, FALSE);
391 }
392
393 static gboolean
394 dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
395     gboolean dissect_other_as_continuation)
396 {
397         int offset;
398         gint next_offset, linelen;
399         line_type_t line_type;
400         tvbuff_t *next_tvb;
401         gboolean is_known_request;
402         gboolean found_match = FALSE;
403         char *descr;
404         guint token_1_len;
405         guint current_method_idx = 0;
406         proto_item *ts = NULL, *ti, *th = NULL, *sip_element_item;
407         proto_tree *sip_tree = NULL, *reqresp_tree, *hdr_tree = NULL, *sip_element_tree, *message_body_tree;
408         guchar contacts = 0, contact_is_star = 0, expires_is_0 = 0;     
409         char csec_method[16] = "";
410         char *media_type_str = NULL;
411         char *media_type_str_lower_case = NULL;
412         char *content_type_parameter_str = NULL;
413
414         /*
415          * Note that "tvb_find_line_end()" will return a value that
416          * is not longer than what's in the buffer, so the
417          * "tvb_get_ptr()" calls below won't throw exceptions.
418          *
419          * Note that "tvb_strneql()" doesn't throw exceptions, so
420          * "sip_parse_line()" won't throw an exception.
421          */
422         offset = 0;
423         linelen = tvb_find_line_end(tvb, 0, -1, &next_offset, FALSE);
424         line_type = sip_parse_line(tvb, linelen, &token_1_len);
425         if (line_type == OTHER_LINE) {
426                 /*
427                  * This is neither a SIP request nor response.
428                  */
429                 if (!dissect_other_as_continuation) {
430                         /*
431                          * We were asked to reject this.
432                          */
433                         return FALSE;
434                 }
435
436                 /*
437                  * Just dissect it as a continuation.
438                  */
439         }
440
441         if (check_col(pinfo->cinfo, COL_PROTOCOL))
442                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SIP");
443
444         switch (line_type) {
445
446         case REQUEST_LINE:
447                 is_known_request = sip_is_known_request(tvb, 0, token_1_len, &current_method_idx);
448                 descr = is_known_request ? "Request" : "Unknown request";
449                 if (check_col(pinfo->cinfo, COL_INFO)) {
450                         col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s",
451                              descr,
452                              tvb_format_text(tvb, 0, linelen - SIP2_HDR_LEN - 1));
453                 }
454                 break;
455
456         case STATUS_LINE:
457                 descr = "Status";
458                 if (check_col(pinfo->cinfo, COL_INFO)) {
459                         col_add_fstr(pinfo->cinfo, COL_INFO, "Status: %s",
460                              tvb_format_text(tvb, SIP2_HDR_LEN + 1, linelen - SIP2_HDR_LEN - 1));
461                 }
462                 break;
463
464         case OTHER_LINE:
465         default: /* Squelch compiler complaints */
466                 descr = "Continuation";
467                 if (check_col(pinfo->cinfo, COL_INFO))
468                         col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
469                 break;
470         }
471         if (tree) {
472                 ts = proto_tree_add_item(tree, proto_sip, tvb, 0, -1, FALSE);
473                 sip_tree = proto_item_add_subtree(ts, ett_sip);
474
475                 switch (line_type) {
476
477                 case REQUEST_LINE:
478                         ti = proto_tree_add_string(sip_tree, hf_Request_Line, tvb, 0, linelen,
479                                               tvb_format_text(tvb, 0, linelen));
480                         reqresp_tree = proto_item_add_subtree(ti, ett_sip_reqresp);
481                         dfilter_sip_request_line(tvb, reqresp_tree, token_1_len);
482                         break;
483
484                 case STATUS_LINE:
485                         ti = proto_tree_add_string(sip_tree, hf_Status_Line, tvb, 0, linelen,
486                                               tvb_format_text(tvb, 0, linelen));
487                         reqresp_tree = proto_item_add_subtree(ti, ett_sip_reqresp);
488                         dfilter_sip_status_line(tvb, reqresp_tree);
489                         break;
490
491                 case OTHER_LINE:
492                         ti = proto_tree_add_text(sip_tree, tvb, 0, next_offset,
493                                                  "%s line: %s", descr,
494                                                  tvb_format_text(tvb, 0, linelen));
495                         reqresp_tree = proto_item_add_subtree(ti, ett_sip_reqresp);
496                         proto_tree_add_text(sip_tree, tvb, 0, -1,
497                             "Continuation data");
498                         return TRUE;
499                 }
500
501                 offset = next_offset;
502                 th = proto_tree_add_item(sip_tree, hf_msg_hdr, tvb, offset, -1,
503                     FALSE);
504                 hdr_tree = proto_item_add_subtree(th, ett_sip_hdr);
505         }
506
507         /*
508          * Process the headers - if we're not building a protocol tree,
509          * we just do this to find the blank line separating the
510          * headers from the message body.
511          */
512         next_offset = offset;
513         while (tvb_reported_length_remaining(tvb, offset) > 0) {
514                 gint line_end_offset;
515                 gint colon_offset;
516                 gint semicolon_offset;
517                 gint content_type_len, content_type_parameter_str_len;
518                 gint header_len;
519                 gint hf_index;
520                 gint value_offset,tag_offset;
521                 guchar c;
522                 size_t value_len;
523                 char *value;
524
525                 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset,
526                     FALSE);
527                 if (linelen == 0) {
528                         /*
529                          * This is a blank line separating the
530                          * message header from the message body.
531                          */
532                         break;
533                 }
534                 line_end_offset = offset + linelen;
535                 colon_offset = tvb_find_guint8(tvb, offset, linelen, ':');
536                 if (colon_offset == -1) {
537                         /*
538                          * Malformed header - no colon after the name.
539                          */
540                         proto_tree_add_text(hdr_tree, tvb, offset,
541                             next_offset - offset, "%s",
542                             tvb_format_text(tvb, offset, linelen));
543                 } else {
544                         header_len = colon_offset - offset;
545                         hf_index = sip_is_known_sip_header(tvb,
546                             offset, header_len);
547
548                         if (hf_index == -1) {
549                                 proto_tree_add_text(hdr_tree, tvb,
550                                     offset, next_offset - offset, "%s",
551                                     tvb_format_text(tvb, offset, linelen));
552                         } else {
553                                 /*
554                                  * Skip whitespace after the colon.
555                                  */
556                                 value_offset = colon_offset + 1;
557                                 while (value_offset < line_end_offset
558                                     && ((c = tvb_get_guint8(tvb,
559                                             value_offset)) == ' '
560                                       || c == '\t'))
561                                         value_offset++;
562                                 /*
563                                  * Fetch the value.
564                                  */
565                                 value_len = line_end_offset - value_offset;
566                                 value = tvb_get_string(tvb, value_offset,
567                                     value_len);
568
569                                 /*
570                                  * Add it to the protocol tree,
571                                  * but display the line as is.
572                                  */
573                                 switch ( hf_index ) {
574
575                                 case POS_TO :
576                                         sip_element_item = proto_tree_add_string_format(hdr_tree,
577                                             hf_header_array[hf_index], tvb,
578                                             offset, next_offset - offset,
579                                             value, "%s",
580                                             tvb_format_text(tvb, offset, linelen));
581                                         sip_element_tree = proto_item_add_subtree( sip_element_item,
582                                                  ett_sip_element);
583                                         tag_offset = tvb_find_guint8(tvb, offset,linelen, ';');
584                                         if ( tag_offset != -1){
585                                                 tag_offset = tag_offset + 1;
586                                                 c = tvb_get_guint8(tvb,tag_offset);
587                                                 if ( c == 't' ){/* tag found */
588                                                         proto_tree_add_string(sip_element_tree,
589                                                             hf_sip_to_addr, tvb,
590                                                             value_offset, (tag_offset - value_offset - 1),
591                                                         tvb_format_text(tvb, value_offset,
592                                                         ( tag_offset - value_offset - 1)));
593                                                         tag_offset = tvb_find_guint8(tvb, tag_offset,linelen, '=') + 1;
594                                                         proto_tree_add_string(sip_element_tree,
595                                                             hf_sip_tag, tvb,
596                                                             tag_offset, (line_end_offset - tag_offset),
597                                                         tvb_format_text(tvb, tag_offset, (line_end_offset - tag_offset)));
598                                                 
599                                                 }
600                                                 else {
601                                                         proto_tree_add_string_format(sip_element_tree,
602                                                             hf_sip_to_addr, tvb,
603                                                             offset, line_end_offset - offset,
604                                                             value, "%s",
605                                                             tvb_format_text(tvb, offset, linelen));
606                                                 }/* if c= t */
607                                         } /* if tag offset */
608                                         break;  
609
610                                 case POS_FROM :
611                                         sip_element_item = proto_tree_add_string_format(hdr_tree,
612                                             hf_header_array[hf_index], tvb,
613                                             offset, next_offset - offset,
614                                             value, "%s",
615                                             tvb_format_text(tvb, offset, linelen));
616                                         sip_element_tree = proto_item_add_subtree( sip_element_item, ett_sip_element);
617                                         tag_offset = tvb_find_guint8(tvb, offset,linelen, ';');
618                                         if ( tag_offset != -1){
619                                                 tag_offset = tag_offset + 1;
620                                                 c = tvb_get_guint8(tvb,tag_offset);
621                                                 if ( c == 't' ){/* tag found */
622                                                         proto_tree_add_string(sip_element_tree,
623                                                             hf_sip_from_addr, tvb,
624                                                             value_offset, (tag_offset - value_offset - 1),
625                                                             tvb_format_text(tvb, value_offset, ( tag_offset - value_offset - 1)));
626                                                         tag_offset = tvb_find_guint8(tvb, offset,linelen, '=') + 1;
627                                                         proto_tree_add_string(sip_element_tree,
628                                                             hf_sip_tag, tvb,
629                                                             tag_offset, (line_end_offset - tag_offset),
630                                                             tvb_format_text(tvb, tag_offset, (line_end_offset - tag_offset)));
631                                                 }
632                                                 else {
633                                                         tag_offset = tvb_find_guint8(tvb, tag_offset,linelen, ';');
634                                                         if ( tag_offset != -1){
635                                                                 tag_offset = tag_offset + 1;
636                                                                 c = tvb_get_guint8(tvb,tag_offset);
637                                                                 if ( c == 't' ){/* tag found */
638                                                                         proto_tree_add_string(sip_element_tree,
639                                                                            hf_sip_from_addr, tvb,
640                                                                            value_offset, (tag_offset - value_offset - 1),
641                                                                            tvb_format_text(tvb, value_offset, ( tag_offset - value_offset - 1)));
642                                                                         tag_offset = tvb_find_guint8(tvb, tag_offset,linelen, '=') + 1;
643                                                                         proto_tree_add_string(sip_element_tree,
644                                                                             hf_sip_tag, tvb,
645                                                                             tag_offset, (line_end_offset - tag_offset),
646                                                                             tvb_format_text(tvb, tag_offset, (line_end_offset - tag_offset)));
647                                                                 }
648                                                         }
649                                                 }/* if c= t */
650                                         } /* if tag offset */
651                                         break;
652
653                                 case POS_CSEQ :
654                                         /* Extract method name from value */
655                                         for (value_offset = 0; value_offset < (gint)strlen(value); value_offset++)
656                                         {
657                                                 if (isalpha((guchar)value[value_offset]))
658                                                 {
659                                                         strcpy(csec_method,value+value_offset);
660                                                         break;
661                                                 }
662                                         }
663                                         /* Add 'CSeq' string item to tree */
664                                         proto_tree_add_string_format(hdr_tree,
665                                             hf_header_array[hf_index], tvb,
666                                             offset, next_offset - offset,
667                                             value, "%s",
668                                             tvb_format_text(tvb, offset, linelen));
669                                         break;
670
671                                 case POS_EXPIRES :
672                                         if (strcmp(value, "0") == 0)
673                                         {
674                                                 expires_is_0 = 1;
675                                         }
676                                         /* Add 'Expires' string item to tree */
677                                         proto_tree_add_string_format(hdr_tree,
678                                             hf_header_array[hf_index], tvb,
679                                             offset, next_offset - offset,
680                                             value, "%s",
681                                             tvb_format_text(tvb, offset, linelen));
682                                         break;
683
684                                 /*
685                                  * Content-Type is the same as Internet
686                                  * media type used by other dissectors,
687                                  * appropriate dissector found by
688                                  * lookup in "media_type" dissector table.
689                                  */
690                                 case POS_CONTENT_TYPE :
691                                         proto_tree_add_string_format(hdr_tree,
692                                             hf_header_array[hf_index], tvb,
693                                             offset, next_offset - offset,
694                                             value, "%s",
695                                             tvb_format_text(tvb, offset, linelen));
696                                         content_type_len = value_len;
697                                         semicolon_offset = tvb_find_guint8(tvb, value_offset,linelen, ';');
698                                         if ( semicolon_offset != -1) {
699                                                 content_type_len = semicolon_offset - value_offset;
700                                                 content_type_parameter_str_len = line_end_offset - (semicolon_offset + 1); 
701                                                 content_type_parameter_str = tvb_get_string(tvb, semicolon_offset + 1,
702                                                                 content_type_parameter_str_len);
703                                         }
704                                         media_type_str = tvb_get_string(tvb, value_offset, content_type_len);
705 #if GLIB_MAJOR_VERSION < 2
706                                         media_type_str_lower_case = g_strdup(media_type_str);
707                                         g_strdown(media_type_str_lower_case);
708 #else
709                                         media_type_str_lower_case = g_ascii_strdown(media_type_str, -1);
710 #endif
711                                         g_free(media_type_str);
712                                         break;
713
714                                 case POS_CONTACT :
715                                         contacts++;
716                                         if (strcmp(value, "*") == 0)
717                                         {
718                                                 contact_is_star = 1;
719                                         }
720                                         /* Fall through to default case to add string to tree */
721
722                                 default :       
723                                         proto_tree_add_string_format(hdr_tree,
724                                             hf_header_array[hf_index], tvb,
725                                             offset, next_offset - offset,
726                                             value, "%s",
727                                             tvb_format_text(tvb, offset, linelen));
728                                 break;
729                                 }/* end switch */
730                                 g_free(value);
731                         }/*if HF_index */
732                 }/* if colon_offset */ 
733                 offset = next_offset;
734         }/* End while */
735
736         if (tvb_offset_exists(tvb, next_offset)) {
737
738                 /*
739                  * There's a message body starting at "next_offset".
740                  * Set the length of the header item.
741                  */
742                 proto_item_set_end(th, tvb, next_offset);
743                 next_tvb = tvb_new_subset(tvb, next_offset, -1, -1);
744                 ti = proto_tree_add_text(sip_tree, next_tvb, 0, -1,
745                                          "Message body");
746                 message_body_tree = proto_item_add_subtree(ti, ett_sip_message_body);
747
748                 /* give the content type parameters to sub dissectors */
749                 
750                 if ( media_type_str_lower_case != NULL ) {
751                         void *save_private_data = pinfo->private_data;
752                         pinfo->private_data = content_type_parameter_str;
753                         found_match = dissector_try_string(media_type_dissector_table,
754                                                            media_type_str_lower_case,
755                                                            next_tvb, pinfo,
756                                                            message_body_tree);
757                         g_free(media_type_str_lower_case);
758                         g_free(content_type_parameter_str);
759                         pinfo->private_data = save_private_data;
760                         /* If no match dump as text */
761                 }
762                 if ( found_match != TRUE )
763                 {
764                         offset = 0;
765                         while (tvb_offset_exists(next_tvb, offset)) {
766                                 tvb_find_line_end(next_tvb, offset, -1, &next_offset, FALSE);
767                                 linelen = next_offset - offset;
768                                 proto_tree_add_text(message_body_tree, next_tvb, offset, linelen,
769                                         "%s", tvb_format_text(next_tvb, offset, linelen));
770                                 offset = next_offset;
771                         }/* end while */
772                 }
773         }
774
775
776         /* Add to info column interesting things learned from header fields. */
777         if (check_col(pinfo->cinfo, COL_INFO))
778         {
779                 /* Registration requests */
780                 if (strcmp(sip_methods[current_method_idx], "REGISTER") == 0)
781                 {
782                         if (contact_is_star && expires_is_0)
783                         {
784                                 col_append_str(pinfo->cinfo, COL_INFO, "    (remove all bindings)");
785                         }
786                         else
787                         if (!contacts)
788                         {
789                                 col_append_str(pinfo->cinfo, COL_INFO, "    (fetch bindings)");
790                         }
791                 }
792
793                 /* Registration responses */
794                 if (line_type == STATUS_LINE && (strcmp(csec_method, "REGISTER") == 0))
795                 {
796                         col_append_fstr(pinfo->cinfo, COL_INFO, "    (%d bindings)", contacts);
797                 }
798         }
799
800         if (global_sip_raw_text)
801                 tvb_raw_text_add(tvb, tree);
802
803         return TRUE;
804 }
805
806 /* Display filter for SIP Request-Line */
807 static void
808 dfilter_sip_request_line(tvbuff_t *tvb, proto_tree *tree, guint meth_len)
809 {
810         char    *string;
811
812         /*
813          * We know we have the entire method; otherwise, "sip_parse_line()"
814          * would have returned OTHER_LINE.
815          */
816         string = tvb_get_string(tvb, 0, meth_len);
817         proto_tree_add_string(tree, hf_Method, tvb, 0, meth_len, string);
818         g_free(string);
819 }
820
821 /* Display filter for SIP Status-Line */
822 static void
823 dfilter_sip_status_line(tvbuff_t *tvb, proto_tree *tree)
824 {
825         char string[3+1];
826
827         /*
828          * We know we have the entire status code; otherwise,
829          * "sip_parse_line()" would have returned OTHER_LINE.
830          * We also know that we have a version string followed by a
831          * space at the beginning of the line, for the same reason.
832          */
833         tvb_memcpy(tvb, (guint8 *)string, SIP2_HDR_LEN + 1, 3);
834         string[3] = '\0';
835         proto_tree_add_string(tree, hf_Status_Code, tvb, SIP2_HDR_LEN + 1,
836             3, string);
837 }
838
839 /* From section 4.1 of RFC 2543:
840  *
841  * Request-Line  =  Method SP Request-URI SP SIP-Version CRLF
842  *
843  * From section 5.1 of RFC 2543:
844  *
845  * Status-Line  =  SIP-version SP Status-Code SP Reason-Phrase CRLF
846  *
847  * From section 7.1 of RFC 3261:
848  *
849  * Unlike HTTP, SIP treats the version number as a literal string.
850  * In practice, this should make no difference.
851  */
852 static line_type_t
853 sip_parse_line(tvbuff_t *tvb, gint linelen, guint *token_1_lenp)
854 {
855         gint space_offset;
856         guint token_1_len;
857         gint token_2_start;
858         guint token_2_len;
859         gint token_3_start;
860         guint token_3_len;
861         gint colon_pos;
862
863         space_offset = tvb_find_guint8(tvb, 0, -1, ' ');
864         if (space_offset <= 0) {
865                 /*
866                  * Either there's no space in the line (which means
867                  * the line is empty or doesn't have a token followed
868                  * by a space; neither is valid for a request or status), or
869                  * the first character in the line is a space (meaning
870                  * the method is empty, which isn't valid for a request,
871                  * or the SIP version is empty, which isn't valid for a
872                  * status).
873                  */
874                 return OTHER_LINE;
875         }
876         token_1_len = space_offset;
877         token_2_start = space_offset + 1;
878         space_offset = tvb_find_guint8(tvb, token_2_start, -1, ' ');
879         if (space_offset == -1) {
880                 /*
881                  * There's no space after the second token, so we don't
882                  * have a third token.
883                  */
884                 return OTHER_LINE;
885         }
886         token_2_len = space_offset - token_2_start;
887         token_3_start = space_offset + 1;
888         token_3_len = linelen - token_3_start;
889         
890         *token_1_lenp = token_1_len;
891
892         /*
893          * Is the first token a version string?
894          */
895         if ( (strict_sip_version && (
896                 token_1_len == SIP2_HDR_LEN
897                 && tvb_strneql(tvb, 0, SIP2_HDR, SIP2_HDR_LEN) == 0)
898         ) || (! strict_sip_version && (
899                 tvb_strneql(tvb, 0, "SIP/", 4) == 0)
900         )) {
901                 /*
902                  * Yes, so this is either a Status-Line or something
903                  * else other than a Request-Line.  To be a Status-Line,
904                  * the second token must be a 3-digit number.
905                  */
906                 if (token_2_len != 3) {
907                         /*
908                          * We don't have 3-character status code.
909                          */
910                         return OTHER_LINE;
911                 }
912                 if (!isdigit(tvb_get_guint8(tvb, token_2_start)) ||
913                     !isdigit(tvb_get_guint8(tvb, token_2_start + 1)) ||
914                     !isdigit(tvb_get_guint8(tvb, token_2_start + 2))) {
915                         /*
916                          * 3 characters yes, 3 digits no.
917                          */
918                         return OTHER_LINE;
919                 }
920                 return STATUS_LINE;
921         } else {
922                 /*
923                  * No, so this is either a Request-Line or something
924                  * other than a Status-Line.  To be a Request-Line, the
925                  * second token must be a URI and the third token must
926                  * be a version string.
927                  */
928                 if (token_2_len < 3) {
929                         /*
930                          * We don't have a URI consisting of at least 3
931                          * characters.
932                          */
933                         return OTHER_LINE;
934                 }
935                 colon_pos = tvb_find_guint8(tvb, token_2_start + 1, -1, ':');
936                 if (colon_pos == -1) {
937                         /*
938                          * There is no colon after the method, so the URI
939                          * doesn't have a colon in it, so it's not valid.
940                          */
941                         return OTHER_LINE;
942                 }
943                 if (colon_pos >= token_3_start) {
944                         /*
945                          * The colon is in the version string, not the URI.
946                          */
947                         return OTHER_LINE;
948                 }
949                 /* XXX - Check for a proper URI prefix? */
950                 if ( (strict_sip_version && (
951                         token_3_len != SIP2_HDR_LEN
952                         || tvb_strneql(tvb, token_3_start, SIP2_HDR, SIP2_HDR_LEN) == -1)
953                 ) || (! strict_sip_version && (
954                         tvb_strneql(tvb, token_3_start, "SIP/", 4) == -1)
955                 )) {
956                         /*
957                          * The version string isn't an SIP version 2.0 version
958                          * string.
959                          */
960                         return OTHER_LINE;
961                 }
962                 return REQUEST_LINE;
963         }
964 }
965
966 static gboolean sip_is_known_request(tvbuff_t *tvb, int meth_offset,
967     guint meth_len, guint *meth_idx)
968 {
969         guint i;
970
971         for (i = 1; i < array_length(sip_methods); i++) {
972                 if (meth_len == strlen(sip_methods[i]) &&
973                     tvb_strneql(tvb, meth_offset, sip_methods[i], meth_len) == 0)
974                 {
975                      *meth_idx = i;
976                      return TRUE;
977                 }
978         }
979
980         return FALSE;
981 }
982
983 /* Returns index of method in sip_headers */
984 static gint sip_is_known_sip_header(tvbuff_t *tvb, int offset, guint header_len)
985 {
986         guint i;
987
988         for (i = 1; i < array_length(sip_headers); i++) {
989                 if (header_len == strlen(sip_headers[i].name) &&
990                     tvb_strncaseeql(tvb, offset, sip_headers[i].name, header_len) == 0)
991                         return i;
992                 if (sip_headers[i].compact_name != NULL &&
993                     header_len == strlen(sip_headers[i].compact_name) &&
994                     tvb_strncaseeql(tvb, offset, sip_headers[i].compact_name, header_len) == 0)
995                         return i;
996         }
997
998         return -1;
999 }
1000
1001 /*
1002  * Display the entire message as raw text.
1003  */
1004 static void
1005 tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree)
1006 {
1007         proto_tree *raw_tree;
1008         proto_item *ti;
1009         int offset, next_offset, linelen;
1010
1011         ti = proto_tree_add_item(tree, proto_raw_sip, tvb, 0, -1, FALSE);
1012         raw_tree = proto_item_add_subtree(ti, ett_raw_text);
1013
1014         offset = 0;
1015
1016         while (tvb_offset_exists(tvb, offset)) {
1017                 tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
1018                 linelen = next_offset - offset;
1019                 proto_tree_add_text(raw_tree, tvb, offset, linelen,
1020                     "%s", tvb_format_text(tvb, offset, linelen));
1021                 offset = next_offset;
1022         }
1023 }
1024
1025 /* Register the protocol with Ethereal */
1026 void proto_register_sip(void)
1027 {
1028
1029         /* Setup list of header fields */
1030         static hf_register_info hf[] = {
1031
1032                 { &hf_msg_hdr,
1033                         { "Message Header",           "sip.msg_hdr",
1034                         FT_NONE, 0, NULL, 0,
1035                         "Message Header in SIP message", HFILL }
1036                 },
1037                 { &hf_Method,
1038                        { "Method",              "sip.Method", 
1039                        FT_STRING, BASE_NONE,NULL,0x0,
1040                         "SIP Method", HFILL }
1041                 },
1042                 { &hf_Request_Line,
1043                        { "Request-Line",                "sip.Request-Line",
1044                        FT_STRING, BASE_NONE,NULL,0x0,
1045                        "SIP Request-Line", HFILL }
1046                 },
1047                 { &hf_Status_Code,
1048                        { "Status-Code",                 "sip.Status-Code", 
1049                        FT_STRING, BASE_NONE,NULL,0x0,
1050                         "SIP Status Code", HFILL }
1051                 },
1052                 { &hf_Status_Line,
1053                        { "Status-Line",                 "sip.Status-Line",
1054                        FT_STRING, BASE_NONE,NULL,0x0,
1055                        "SIP Status-Line", HFILL }
1056                 },
1057                 { &hf_sip_to_addr,
1058                        { "SIP to address",              "sip.from_addr", 
1059                        FT_STRING, BASE_NONE,NULL,0x0,
1060                         "RFC 3261: from addr", HFILL }
1061                 },
1062                 { &hf_sip_from_addr,
1063                        { "SIP from address",            "sip.to_addr", 
1064                        FT_STRING, BASE_NONE,NULL,0x0,
1065                         "RFC 3261: to addr", HFILL }
1066                 },
1067                 { &hf_sip_tag,
1068                        { "SIP tag",             "sip.tag", 
1069                        FT_STRING, BASE_NONE,NULL,0x0,
1070                         "RFC 3261: tag", HFILL }
1071                 },
1072                 { &hf_header_array[POS_ACCEPT],
1073                        { "Accept",              "sip.Accept", 
1074                        FT_STRING, BASE_NONE,NULL,0x0,
1075                         "RFC 3261: Accept Header", HFILL }
1076                 },
1077                 { &hf_header_array[POS_ACCEPT_ENCODING],
1078                        { "Accept-Encoding",             "sip.Accept-Encoding", 
1079                        FT_STRING, BASE_NONE,NULL,0x0,
1080                         "RFC 3261: Accept-Encoding Header", HFILL }
1081                 },
1082                 { &hf_header_array[POS_ACCEPT_LANGUAGE],
1083                        { "Accept-Language",             "sip.Accept-Language", 
1084                        FT_STRING, BASE_NONE,NULL,0x0,
1085                         "RFC 3261: Accept-Language Header", HFILL }
1086                 },
1087                 { &hf_header_array[POS_ALERT_INFO],
1088                        { "Alert-Info",          "sip.Alert-Info", 
1089                        FT_STRING, BASE_NONE,NULL,0x0,
1090                         "RFC 3261: Alert-Info Header", HFILL }
1091                 },
1092                 { &hf_header_array[POS_ALLOW],
1093                        { "Allow",               "sip.Allow", 
1094                        FT_STRING, BASE_NONE,NULL,0x0,
1095                         "RFC 3261: Allow Header", HFILL }
1096                 },
1097                 { &hf_header_array[POS_ALLOW_EVENTS],
1098                        { "Allow-Events",                "sip.Allow-Events", 
1099                        FT_STRING, BASE_NONE,NULL,0x0,
1100                         "RFC 3265: Allow-Events Header", HFILL }
1101                 },
1102                 { &hf_header_array[POS_AUTHENTICATION_INFO],
1103                        { "Authentication-Info",                 "sip.Authentication-Info", 
1104                        FT_STRING, BASE_NONE,NULL,0x0,
1105                         "RFC 3261: Authentication-Info Header", HFILL }
1106                 },
1107                 { &hf_header_array[POS_AUTHORIZATION],
1108                        { "Authorization",               "sip.Authorization", 
1109                        FT_STRING, BASE_NONE,NULL,0x0,
1110                         "RFC 3261: Authorization Header", HFILL }
1111                 },
1112                 { &hf_header_array[POS_CALL_ID],
1113                        { "Call-ID",             "sip.Call-ID", 
1114                        FT_STRING, BASE_NONE,NULL,0x0,
1115                         "RFC 3261: Call-ID Header", HFILL }
1116                 },
1117                 { &hf_header_array[POS_CALL_INFO],
1118                        { "Call-Info",           "sip.Call-Info", 
1119                        FT_STRING, BASE_NONE,NULL,0x0,
1120                         "RFC 3261: Call-Info Header", HFILL }
1121                 },
1122                 { &hf_header_array[POS_CONTACT],
1123                        { "Contact",             "sip.Contact", 
1124                        FT_STRING, BASE_NONE,NULL,0x0,
1125                         "RFC 3261: Contact Header", HFILL }
1126                 },
1127                 { &hf_header_array[POS_CONTENT_DISPOSITION],
1128                        { "Content-Disposition",                 "sip.Content-Disposition", 
1129                        FT_STRING, BASE_NONE,NULL,0x0,
1130                         "RFC 3261: Content-Disposition Header", HFILL }
1131                 },
1132                 { &hf_header_array[POS_CONTENT_ENCODING],
1133                        { "Content-Encoding",            "sip.Content-Encoding", 
1134                        FT_STRING, BASE_NONE,NULL,0x0,
1135                         "RFC 3261: Content-Encoding Header", HFILL }
1136                 },
1137                 { &hf_header_array[POS_CONTENT_LANGUAGE],
1138                        { "Content-Language",            "sip.Content-Language", 
1139                        FT_STRING, BASE_NONE,NULL,0x0,
1140                         "RFC 3261: Content-Language Header", HFILL }
1141                 },
1142                 { &hf_header_array[POS_CONTENT_LENGTH],
1143                        { "Content-Length",              "sip.Content-Length", 
1144                        FT_STRING, BASE_NONE,NULL,0x0,
1145                         "RFC 3261: Content-Length Header", HFILL }
1146                 },
1147                 { &hf_header_array[POS_CONTENT_TYPE],
1148                        { "Content-Type",                "sip.Content-Type", 
1149                        FT_STRING, BASE_NONE,NULL,0x0,
1150                         "RFC 3261: Content-Type Header", HFILL }
1151                 },
1152                 { &hf_header_array[POS_CSEQ],
1153                        { "CSeq",                "sip.CSeq", 
1154                        FT_STRING, BASE_NONE,NULL,0x0,
1155                         "RFC 3261: CSeq Header", HFILL }
1156                 },
1157                 { &hf_header_array[POS_DATE],
1158                        { "Date",                "sip.Date", 
1159                        FT_STRING, BASE_NONE,NULL,0x0,
1160                         "RFC 3261: Date Header", HFILL }
1161                 },
1162                 { &hf_header_array[POS_ERROR_INFO],
1163                        { "Error-Info",          "sip.Error-Info", 
1164                        FT_STRING, BASE_NONE,NULL,0x0,
1165                         "RFC 3261: Error-Info Header", HFILL }
1166                 },
1167                 { &hf_header_array[POS_EVENT],
1168                        { "Event",               "sip.Event", 
1169                        FT_STRING, BASE_NONE,NULL,0x0,
1170                         "RFC 3265: Event Header", HFILL }
1171                 },
1172                 { &hf_header_array[POS_EXPIRES],
1173                        { "Expires",             "sip.Expires", 
1174                        FT_STRING, BASE_NONE,NULL,0x0,
1175                         "RFC 3261: Expires Header", HFILL }
1176                 },
1177                 { &hf_header_array[POS_FROM],
1178                        { "From",                "sip.From", 
1179                        FT_STRING, BASE_NONE,NULL,0x0,
1180                         "RFC 3261: From Header", HFILL }
1181                 },
1182                 { &hf_header_array[POS_IN_REPLY_TO],
1183                        { "In-Reply-To",                 "sip.In-Reply-To", 
1184                        FT_STRING, BASE_NONE,NULL,0x0,
1185                         "RFC 3261: In-Reply-To Header", HFILL }
1186                 },
1187                 { &hf_header_array[POS_MAX_FORWARDS],
1188                        { "Max-Forwards",                "sip.Max-Forwards", 
1189                        FT_STRING, BASE_NONE,NULL,0x0,
1190                         "RFC 3261: Max-Forwards Header", HFILL }
1191                 },
1192                 { &hf_header_array[POS_MIME_VERSION],
1193                        { "MIME-Version",                "sip.MIME-Version", 
1194                        FT_STRING, BASE_NONE,NULL,0x0,
1195                         "RFC 3261: MIME-Version Header", HFILL }
1196                 },
1197                 { &hf_header_array[POS_MIN_EXPIRES],
1198                        { "Min-Expires",                 "sip.Min-Expires", 
1199                        FT_STRING, BASE_NONE,NULL,0x0,
1200                         "RFC 3261: Min-Expires Header", HFILL }
1201                 },
1202                 { &hf_header_array[POS_ORGANIZATION],
1203                        { "Organization",                "sip.Organization", 
1204                        FT_STRING, BASE_NONE,NULL,0x0,
1205                         "RFC 3261: Organization Header", HFILL }
1206                 },
1207                 { &hf_header_array[POS_PRIORITY],
1208                        { "Priority",            "sip.Priority", 
1209                        FT_STRING, BASE_NONE,NULL,0x0,
1210                         "RFC 3261: Priority Header", HFILL }
1211                 },
1212                 { &hf_header_array[POS_PROXY_AUTHENTICATE],
1213                        { "Proxy-Authenticate",          "sip.Proxy-Authenticate", 
1214                        FT_STRING, BASE_NONE,NULL,0x0,
1215                         "RFC 3261: Proxy-Authenticate Header", HFILL }
1216                 },
1217                 { &hf_header_array[POS_PROXY_AUTHORIZATION],
1218                        { "Proxy-Authorization",                 "sip.Proxy-Authorization", 
1219                        FT_STRING, BASE_NONE,NULL,0x0,
1220                         "RFC 3261: Proxy-Authorization Header", HFILL }
1221                 },
1222                 { &hf_header_array[POS_RACK],
1223                        { "RAck",                "sip.RAck", 
1224                        FT_STRING, BASE_NONE,NULL,0x0,
1225                         "RFC 3262: RAck Header", HFILL }
1226                 },
1227                 { &hf_header_array[POS_RSEQ],
1228                        { "RSeq",                "sip.RSeq", 
1229                        FT_STRING, BASE_NONE,NULL,0x0,
1230                         "RFC 3262: RSeq Header", HFILL }
1231                 },
1232                 { &hf_header_array[POS_PROXY_REQUIRE],
1233                        { "Proxy-Require",               "sip.Proxy-Require", 
1234                        FT_STRING, BASE_NONE,NULL,0x0,
1235                         "RFC 3261: Proxy-Require Header", HFILL }
1236                 },
1237                 { &hf_header_array[POS_RECORD_ROUTE],
1238                        { "Record-Route",                "sip.Record-Route", 
1239                        FT_STRING, BASE_NONE,NULL,0x0,
1240                         "RFC 3261: Record-Route Header", HFILL }
1241                 },
1242                 { &hf_header_array[POS_REPLY_TO],
1243                        { "Reply-To",            "sip.Reply-To", 
1244                        FT_STRING, BASE_NONE,NULL,0x0,
1245                         "RFC 3261: Reply-To Header", HFILL }
1246                 },
1247                 { &hf_header_array[POS_REQUIRE],
1248                        { "Require",             "sip.Require", 
1249                        FT_STRING, BASE_NONE,NULL,0x0,
1250                         "RFC 3261: Require Header", HFILL }
1251                 },
1252                 { &hf_header_array[POS_RETRY_AFTER],
1253                        { "Retry-After",                 "sip.Retry-After", 
1254                        FT_STRING, BASE_NONE,NULL,0x0,
1255                         "RFC 3261: Retry-After Header", HFILL }
1256                 },
1257                 { &hf_header_array[POS_ROUTE],
1258                        { "Route",               "sip.Route", 
1259                        FT_STRING, BASE_NONE,NULL,0x0,
1260                         "RFC 3261: Route Header", HFILL }
1261                 },
1262                 { &hf_header_array[POS_SERVER],
1263                        { "Server",              "sip.Server", 
1264                        FT_STRING, BASE_NONE,NULL,0x0,
1265                         "RFC 3261: Server Header", HFILL }
1266                 },
1267                 { &hf_header_array[POS_SUBJECT],
1268                        { "Subject",             "sip.Subject", 
1269                        FT_STRING, BASE_NONE,NULL,0x0,
1270                         "RFC 3261: Subject Header", HFILL }
1271                 },
1272                 { &hf_header_array[POS_SUBSCRIPTION_STATE],
1273                        { "Subscription-State",          "sip.Subscription-State", 
1274                        FT_STRING, BASE_NONE,NULL,0x0,
1275                         "RFC 3265: Subscription-State Header", HFILL }
1276                 },
1277                 { &hf_header_array[POS_SUPPORTED],
1278                        { "Supported",           "sip.Supported", 
1279                        FT_STRING, BASE_NONE,NULL,0x0,
1280                         "RFC 3261: Supported Header", HFILL }
1281                 },
1282                 { &hf_header_array[POS_TIMESTAMP],
1283                        { "Timestamp",           "sip.Timestamp", 
1284                        FT_STRING, BASE_NONE,NULL,0x0,
1285                         "RFC 3261: Timestamp Header", HFILL }
1286                 },
1287                 { &hf_header_array[POS_TO],
1288                        { "To",          "sip.To", 
1289                        FT_STRING, BASE_NONE,NULL,0x0,
1290                         "RFC 3261: To Header", HFILL }
1291                 },
1292                 { &hf_header_array[POS_UNSUPPORTED],
1293                        { "Unsupported",                 "sip.Unsupported", 
1294                        FT_STRING, BASE_NONE,NULL,0x0,
1295                         "RFC 3261: Unsupported Header", HFILL }
1296                 },
1297                 { &hf_header_array[POS_USER_AGENT],
1298                        { "User-Agent",          "sip.User-Agent", 
1299                        FT_STRING, BASE_NONE,NULL,0x0,
1300                         "RFC 3261: User-Agent Header", HFILL }
1301                 },
1302                 { &hf_header_array[POS_VIA],
1303                        { "Via",                 "sip.Via", 
1304                        FT_STRING, BASE_NONE,NULL,0x0,
1305                         "RFC 3261: Via Header", HFILL }
1306                 },
1307                 { &hf_header_array[POS_WARNING],
1308                        { "Warning",             "sip.Warning", 
1309                        FT_STRING, BASE_NONE,NULL,0x0,
1310                         "RFC 3261: Warning Header", HFILL }
1311                 },
1312                 { &hf_header_array[POS_WWW_AUTHENTICATE],
1313                        { "WWW-Authenticate",            "sip.WWW-Authenticate", 
1314                        FT_STRING, BASE_NONE,NULL,0x0,
1315                         "RFC 3261: WWW-Authenticate Header", HFILL }
1316                 },
1317                 { &hf_header_array[POS_P_ACCESS_NETWORK_INFO],  
1318                        { "P-Access-Network-Info",       "sip.P-Access-Network-Info",  
1319                        FT_STRING, BASE_NONE,NULL,0x0,
1320                         "P-Access-Network-Info Header", HFILL }
1321                 },
1322
1323                 { &hf_header_array[POS_P_ASSERTED_IDENTITY],    
1324                        { "P-Asserted-Identity",         "sip.P-Asserted-Identity",  
1325                        FT_STRING, BASE_NONE,NULL,0x0,
1326                         "P-Asserted-Identity Header", HFILL }
1327                 },
1328
1329                 { &hf_header_array[POS_P_ASSOCIATED_URI],  
1330                        { "P-Associated-URI",            "sip.P-Associated-URI", 
1331                        FT_STRING, BASE_NONE,NULL,0x0,
1332                         "P-Associated-URI Header", HFILL }
1333                 },
1334
1335                 { &hf_header_array[POS_P_CALLED_PARTY_ID],  
1336                        { "P-Called-Party-ID",           "sip.P-Called-Party-ID", 
1337                        FT_STRING, BASE_NONE,NULL,0x0,
1338                         "P-Called-Party-ID Header", HFILL }
1339                 },
1340
1341                 { &hf_header_array[POS_P_CHARGING_FUNCTION_ADDRESSES],  
1342                        { "P-Charging-Function-Addresses","sip.P-Charging-Function-Addresses",  
1343                        FT_STRING, BASE_NONE,NULL,0x0,
1344                         "P-Charging-Function-Addresses", HFILL }
1345                 },
1346
1347                 { &hf_header_array[POS_P_CHARGING_VECTOR],
1348                        { "P-Charging-Vector",           "sip.P-Charging-Vector", 
1349                        FT_STRING, BASE_NONE,NULL,0x0,
1350                         "P-Charging-Vector Header", HFILL }
1351                 },
1352
1353                 { &hf_header_array[POS_P_DCS_TRACE_PARTY_ID], 
1354                        { "P-DCS-Trace-Party-ID",        "sip.P-DCS-Trace-Party-ID", 
1355                        FT_STRING, BASE_NONE,NULL,0x0,
1356                         "P-DCS-Trace-Party-ID Header", HFILL }
1357                 },
1358
1359                 { &hf_header_array[POS_P_DCS_OSPS],  
1360                        { "P-DCS-OSPS",                  "sip.P-DCS-OSPS", 
1361                        FT_STRING, BASE_NONE,NULL,0x0,
1362                         "P-DCS-OSPS Header", HFILL }
1363                 },
1364
1365                 { &hf_header_array[POS_P_DCS_BILLING_INFO],  
1366                        { "P-DCS-Billing-Info",          "sip.P-DCS-Billing-Info", 
1367                        FT_STRING, BASE_NONE,NULL,0x0,
1368                         "P-DCS-Billing-Info Header", HFILL }
1369                 },
1370
1371                 { &hf_header_array[POS_P_DCS_LAES],  
1372                        { "P-DCS-LAES",                  "sip.P-DCS-LAES", 
1373                        FT_STRING, BASE_NONE,NULL,0x0,
1374                         "P-DCS-LAES Header", HFILL }
1375                 },
1376
1377                 { &hf_header_array[POS_P_DCS_REDIRECT],  
1378                        { "P-DCS-Redirect",              "sip.P-DCS-Redirect", 
1379                        FT_STRING, BASE_NONE,NULL,0x0,
1380                         "P-DCS-Redirect Header", HFILL }
1381                 },
1382
1383                 { &hf_header_array[POS_P_MEDIA_AUTHORIZATION],  
1384                        { "P-Media-Authorization",       "sip.P-Media-Authorization", 
1385                        FT_STRING, BASE_NONE,NULL,0x0,
1386                         "P-Media-Authorization Header", HFILL }
1387                 },
1388
1389                 { &hf_header_array[POS_P_PREFERRED_IDENTITY],  
1390                        { "P-Preferred-Identity",        "sip.P-Preferred-Identity", 
1391                        FT_STRING, BASE_NONE,NULL,0x0,
1392                         "P-Preferred-Identity Header", HFILL }
1393                 },
1394
1395                 { &hf_header_array[POS_P_VISITED_NETWORK_ID],  
1396                        { "P-Visited-Network-ID",        "sip.P-Visited-Network-ID",  
1397                        FT_STRING, BASE_NONE,NULL,0x0,
1398                         "P-Visited-Network-ID Header", HFILL }
1399                 },
1400
1401                 { &hf_header_array[POS_PATH],  
1402                        { "Path",                        "sip.Path", 
1403                        FT_STRING, BASE_NONE,NULL,0x0,
1404                         "Path Header", HFILL }
1405                 },
1406
1407                 { &hf_header_array[POS_PRIVACY],  
1408                        { "Privacy",                     "sip.Privacy", 
1409                        FT_STRING, BASE_NONE,NULL,0x0,
1410                         "Privacy Header", HFILL }
1411                 },
1412
1413                 { &hf_header_array[POS_REASON], 
1414                        { "Reason",                      "sip.Reason", 
1415                        FT_STRING, BASE_NONE,NULL,0x0,
1416                         "Reason Header", HFILL }
1417                 },
1418
1419                 { &hf_header_array[POS_REFER_TO], 
1420                        { "Refer-To",                    "sip.Refer-To", 
1421                        FT_STRING, BASE_NONE,NULL,0x0,
1422                         "Refer-To Header", HFILL }
1423                 },
1424
1425                 { &hf_header_array[POS_SERVICE_ROUTE],                  
1426                        { "Service-Route",               "sip.Service-Route", 
1427                        FT_STRING, BASE_NONE,NULL,0x0,
1428                         "Service-Route Header", HFILL }
1429                 },
1430
1431                 { &hf_header_array[POS_ETAG],                  
1432                        { "ETag",                "sip.ETag", 
1433                        FT_STRING, BASE_NONE,NULL,0x0,
1434                         "ETag Header", HFILL }
1435                 },
1436                 { &hf_header_array[POS_IF_MATCH],                  
1437                        { "If_Match",            "sip.If_Match", 
1438                        FT_STRING, BASE_NONE,NULL,0x0,
1439                         "If-Match Header", HFILL }
1440                 },
1441         };
1442
1443         /* Setup protocol subtree array */
1444         static gint *ett[] = {
1445                 &ett_sip,
1446                 &ett_sip_reqresp,
1447                 &ett_sip_hdr,
1448                 &ett_sip_element,
1449                 &ett_sip_message_body,
1450         };
1451         static gint *ett_raw[] = {
1452                 &ett_raw_text,
1453         };
1454
1455         module_t *sip_module;
1456
1457         /* Register the protocol name and description */
1458         proto_sip = proto_register_protocol("Session Initiation Protocol",
1459             "SIP", "sip");
1460         proto_raw_sip = proto_register_protocol("Session Initiation Protocol (SIP as raw text)",
1461             "Raw_SIP", "raw_sip");
1462
1463         /* Required function calls to register the header fields and subtrees used */
1464         proto_register_field_array(proto_sip, hf, array_length(hf));
1465         proto_register_subtree_array(ett, array_length(ett));
1466         proto_register_subtree_array(ett_raw, array_length(ett_raw));
1467
1468         /* SIP content type and internet media type used by other dissectors are the same */
1469
1470         media_type_dissector_table = find_dissector_table("media_type");
1471
1472
1473         sip_module = prefs_register_protocol(proto_sip, NULL);
1474
1475         prefs_register_bool_preference(sip_module, "display_raw_text",
1476                 "Display raw text for SIP message",
1477                 "Specifies that the raw text of the "
1478                 "SIP message should be displayed "
1479                 "in addition to the dissection tree",
1480                 &global_sip_raw_text);
1481         prefs_register_bool_preference(sip_module, "strict_sip_version",
1482                 "Enforce strict SIP version check (" SIP2_HDR ")",
1483                 "If enabled, only " SIP2_HDR " traffic will be dissected as SIP. "
1484                 "Disable it to allow SIP traffic with a different version "
1485                 "to be dissected as SIP.",
1486                 &strict_sip_version);
1487 }
1488
1489 void
1490 proto_reg_handoff_sip(void)
1491 {
1492         dissector_handle_t sip_handle, sip_tcp_handle;
1493
1494         sip_handle = new_create_dissector_handle(dissect_sip, proto_sip);
1495         dissector_add("udp.port", UDP_PORT_SIP, sip_handle);
1496         dissector_add_string("media_type", "message/sip", sip_handle);
1497
1498         sip_tcp_handle = create_dissector_handle(dissect_sip_tcp, proto_sip);
1499         dissector_add("tcp.port", TCP_PORT_SIP, sip_tcp_handle);
1500
1501         heur_dissector_add("udp", dissect_sip_heur, proto_sip);
1502         heur_dissector_add("tcp", dissect_sip_heur, proto_sip);
1503         heur_dissector_add("sctp", dissect_sip_heur, proto_sip);
1504 }