Sanitize epan includes
[obnox/wireshark/wip.git] / epan / dissectors / packet-msrp.c
1 /* packet-msrp.c
2  * Routines for Message Session Relay Protocol(MSRP) dissection
3  * Copyright 2005, Anders Broman <anders.broman[at]ericsson.com>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  *
25  * References:
26  * http://www.ietf.org/internet-drafts/draft-ietf-simple-message-sessions-10.txt
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37
38 #include <glib.h>
39
40 #include <wsutil/str_util.h>
41
42 #include <epan/conversation.h>
43 #include <epan/strutil.h>
44 #include <epan/packet.h>
45 #include <epan/emem.h>
46 #include <epan/prefs.h>
47
48 #include "packet-msrp.h"
49
50 #define TCP_PORT_MSRP 0
51
52 #define MSRP_HDR "MSRP"
53 #define MSRP_HDR_LEN ((gint) strlen (MSRP_HDR))
54
55 /* Initialize the protocol and registered fields */
56 static int proto_msrp           = -1;
57
58 /* Initialize the subtree pointers */
59 static int ett_msrp                                     = -1;
60 static int ett_raw_text                         = -1;
61 static int ett_msrp_reqresp                     = -1;
62 static int ett_msrp_hdr                         = -1;
63 static int ett_msrp_element                     = -1;
64 static int ett_msrp_data                        = -1;
65 static int ett_msrp_end_line            = -1;
66 static int ett_msrp_setup                       = -1;
67
68 static int hf_msrp_response_line        = -1;
69 static int hf_msrp_request_line         = -1;
70 static int hf_msrp_transactionID        = -1;
71 static int hf_msrp_method                       = -1;
72 static int hf_msrp_status_code          = -1;
73 static int hf_msrp_msg_hdr                      = -1;
74 static int hf_msrp_end_line                     = -1;
75 static int hf_msrp_cnt_flg                      = -1;
76
77 static int hf_msrp_data                         = -1;
78
79 /* MSRP setup fields */
80 static int hf_msrp_setup        = -1;
81 static int hf_msrp_setup_frame  = -1;
82 static int hf_msrp_setup_method = -1;
83
84 typedef struct {
85         const char *name;
86 } msrp_header_t;
87
88 static const msrp_header_t msrp_headers[] = {
89         { "Unknown-header"},
90         { "From-Path"},                         /*  1 */
91         { "To-Path"},                           /*  2 */
92         { "Message-ID"},                        /*  3 */
93         { "Success-Report"},            /*  4 */
94         { "Failure-Report"},            /*  5 */
95         { "Byte-Range"},                        /*  6 */
96         { "Status"},                            /*  7 */
97         { "Content-Type"},                      /*  8 */
98         { "Content-ID"},                        /*  9 */
99         { "Content-Description"},       /*  10 */
100         { "Content-Disposition"},       /*  11 */
101         { "Use-Path"},                          /*  12 */
102         { "WWW-Authenticate"},          /*  13 */
103         { "Authorization"},                     /*  14 */
104         { "Authentication-Info"},       /*  15 */
105 };
106
107 static gint hf_header_array[] = {
108         -1, /* 0"Unknown-header" - Pad so that the real headers start at index 1 */
109         -1, /* 1"From-Path                                                                                                               */
110         -1, /* 2"To-Path                                                                                                                 */
111         -1, /* 3"Message-ID"                                                                                                     */
112         -1, /* 4"Success-Report"                                                                                                 */
113         -1, /* 5"Failure-Report"                                                                                                 */
114         -1, /* 6"Byte-Range"                                                                                                     */
115         -1, /* 7"Status"                                                                                                                 */
116         -1, /* 8"Content-Type"                                                                                                   */
117         -1, /* 9"Content-ID"                                                                                                     */
118         -1, /* 10"Content-Description"                                                                                   */
119         -1, /* 11"Content-Disposition"                                                                                   */
120         -1, /* 12"Use-Path"                                                                                                              */
121         -1, /* 13"WWW-Authenticate"                                                                                              */
122         -1, /* 14"Authorization"                                                                                                 */
123         -1, /* 15"Authentication-Info"                                                                                   */
124 };
125
126 #define MSRP_FROM_PATH                                                  1
127 #define MSRP_TO_PATH                                                    2
128 #define MSRP_MESSAGE_ID                                                 3
129 #define MSRP_SUCCESS_REPORT                                             4
130 #define MSRP_FAILURE_REPORT                                             5
131 #define MSRP_BYTE_RANGE                                                 6
132 #define MSRP_STATUS                                                             7
133 #define MSRP_CONTENT_TYPE                                               8
134 #define MSRP_CONTENT_ID                                                 9
135 #define MSRP_CONTENT_DISCRIPTION                                10
136 #define MSRP_CONTENT_DISPOSITION                                11
137 #define MSRP_USE_PATH                                                   12
138 #define MSRP_WWW_AUTHENTICATE                                   13
139 #define MSRP_AUTHORIZATION                                              14
140 #define MSRP_AUTHENTICATION_INFO                                15
141
142 static dissector_handle_t msrp_handle;
143 gboolean global_msrp_raw_text = TRUE;
144
145 /* MSRP content type and internet media type used by other dissectors
146  * are the same.  List of media types from IANA at:
147  * http://www.iana.org/assignments/media-types/index.html */
148 static dissector_table_t media_type_dissector_table;
149
150 static int dissect_msrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
151
152
153 /* Displaying conversation setup info */
154 static gboolean global_msrp_show_setup_info = TRUE;
155 static void show_setup_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
156
157 /* Set up an MSRP conversation using the info given */
158 void msrp_add_address( packet_info *pinfo,
159                        address *addr, int port,
160                        const gchar *setup_method, guint32 setup_frame_number)
161 {
162         address null_addr;
163         conversation_t* p_conv;
164         struct _msrp_conversation_info *p_conv_data = NULL;
165
166         /*
167          * If this isn't the first time this packet has been processed,
168          * we've already done this work, so we don't need to do it
169          * again.
170          */
171         if (pinfo->fd->flags.visited)
172         {
173                 return;
174         }
175
176         SET_ADDRESS(&null_addr, AT_NONE, 0, NULL);
177
178         /*
179          * Check if the ip address and port combination is not
180          * already registered as a conversation.
181          */
182         p_conv = find_conversation( pinfo->fd->num, addr, &null_addr, PT_TCP, port, 0,
183                                     NO_ADDR_B | NO_PORT_B);
184
185         /*
186          * If not, create a new conversation.
187          */
188         if (!p_conv) {
189                 p_conv = conversation_new( pinfo->fd->num, addr, &null_addr, PT_TCP,
190                                            (guint32)port, 0,
191                                            NO_ADDR2 | NO_PORT2);
192         }
193
194         /* Set dissector */
195         conversation_set_dissector(p_conv, msrp_handle);
196
197         /*
198          * Check if the conversation has data associated with it.
199          */
200         p_conv_data = conversation_get_proto_data(p_conv, proto_msrp);
201
202         /*
203          * If not, add a new data item.
204          */
205         if (!p_conv_data) {
206                 /* Create conversation data */
207                 p_conv_data = se_alloc(sizeof(struct _msrp_conversation_info));
208                 if (!p_conv_data)
209                 {
210                         return;
211                 }
212                 memset(p_conv_data, 0, sizeof(struct _msrp_conversation_info));
213                 conversation_add_proto_data(p_conv, proto_msrp, p_conv_data);
214         }
215
216         /*
217          * Update the conversation data.
218          */
219         p_conv_data->setup_method_set = TRUE;
220         g_strlcpy(p_conv_data->setup_method, setup_method, MAX_MSRP_SETUP_METHOD_SIZE);
221         p_conv_data->setup_frame_number = setup_frame_number;
222 }
223
224
225
226 /* Look for conversation info and display any setup info found */
227 void show_setup_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
228 {
229         /* Conversation and current data */
230         conversation_t *p_conv = NULL;
231         struct _msrp_conversation_info *p_conv_data = NULL;
232
233         /* Use existing packet data if available */
234         p_conv_data = p_get_proto_data(pinfo->fd, proto_msrp);
235
236         if (!p_conv_data)
237         {
238                 /* First time, get info from conversation */
239                 p_conv = find_conversation(pinfo->fd->num, &pinfo->net_dst, &pinfo->net_src,
240                                            PT_TCP,
241                                            pinfo->destport, pinfo->srcport, 0);
242
243                 if (p_conv)
244                 {
245                         /* Look for data in conversation */
246                         struct _msrp_conversation_info *p_conv_packet_data;
247                         p_conv_data = conversation_get_proto_data(p_conv, proto_msrp);
248
249                         if (p_conv_data)
250                         {
251                                 /* Save this conversation info into packet info */
252                                 p_conv_packet_data = se_alloc(sizeof(struct _msrp_conversation_info));
253                                 if (!p_conv_packet_data)
254                                 {
255                                         return;
256                                 }
257                                 memcpy(p_conv_packet_data, p_conv_data,
258                                        sizeof(struct _msrp_conversation_info));
259
260                                 p_add_proto_data(pinfo->fd, proto_msrp, p_conv_packet_data);
261                         }
262                 }
263         }
264
265         /* Create setup info subtree with summary info. */
266         if (p_conv_data && p_conv_data->setup_method_set)
267         {
268                 proto_tree *msrp_setup_tree;
269                 proto_item *ti =  proto_tree_add_string_format(tree, hf_msrp_setup, tvb, 0, 0,
270                                                                "",
271                                                                "Stream setup by %s (frame %u)",
272                                                                p_conv_data->setup_method,
273                                                                p_conv_data->setup_frame_number);
274                 PROTO_ITEM_SET_GENERATED(ti);
275                 msrp_setup_tree = proto_item_add_subtree(ti, ett_msrp_setup);
276                 if (msrp_setup_tree)
277                 {
278                         /* Add details into subtree */
279                         proto_item* item = proto_tree_add_uint(msrp_setup_tree, hf_msrp_setup_frame,
280                                                                tvb, 0, 0, p_conv_data->setup_frame_number);
281                         PROTO_ITEM_SET_GENERATED(item);
282                         item = proto_tree_add_string(msrp_setup_tree, hf_msrp_setup_method,
283                                                      tvb, 0, 0, p_conv_data->setup_method);
284                         PROTO_ITEM_SET_GENERATED(item);
285                 }
286         }
287 }
288
289
290
291 /* Returns index of headers */
292 static gint msrp_is_known_msrp_header(tvbuff_t *tvb, int offset, guint header_len)
293 {
294         guint i;
295
296         for (i = 1; i < array_length(msrp_headers); i++) {
297                 if (header_len == strlen(msrp_headers[i].name) &&
298                     tvb_strncaseeql(tvb, offset, msrp_headers[i].name, header_len) == 0)
299                 {
300                         return i;
301                 }
302         }
303
304         return -1;
305 }
306
307
308 /*
309  * Display the entire message as raw text.
310  */
311 static void
312 tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree)
313 {
314         int offset, next_offset, linelen;
315         offset = 0;
316
317         while (tvb_offset_exists(tvb, offset)) {
318                 /* 'desegment' is FALSE so will set next_offset to beyond the end of
319                    the buffer if no line ending is found */
320                 tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
321                 linelen = next_offset - offset;
322                 if(tree) {
323                         proto_tree_add_text(tree, tvb, offset, linelen,
324                                             "%s", tvb_format_text(tvb, offset, linelen));
325                 }
326                 offset = next_offset;
327         }
328 }
329
330 /* This code is modeled on the code in packet-sip.c
331  *  ABNF code for the MSRP header:
332  *  The following syntax specification uses the augmented Backus-Naur
333  *  Form (BNF) as described in RFC-2234 [6].
334  *
335  *
336  *  msrp-req-or-resp = msrp-request / msrp-response
337  *  msrp-request = req-start headers [content-stuff] end-line
338  *  msrp-response = resp-start headers end-line
339  *
340  *  req-start  = pMSRP SP transact-id SP method CRLF
341  *  resp-start = pMSRP SP transact-id SP status-code [SP phrase] CRLF
342  *  phrase = utf8text
343  *
344  *  pMSRP = %x4D.53.52.50 ; MSRP in caps
345  *  transact-id = ident
346  *  method = mSEND / mREPORT / other-method
347  *  mSEND = %x53.45.4e.44 ; SEND in caps
348  *  mREPORT = %x52.45.50.4f.52.54; REPORT in caps
349  *  other-method = 1*UPALPHA
350  *  Examples:
351  *  "MSRP 1234 SEND(CRLF)"
352  *      "MSRP 1234 200 OK(CRLF)
353  */
354 static gboolean
355 check_msrp_header(tvbuff_t *tvb)
356 {
357         gint offset = 0;
358         gint linelen;
359         gint space_offset;
360         gint next_offset = 0;
361         guint token_1_len;
362         gint token_2_start;
363
364         /*
365          * Note that "tvb_find_line_end()" will return a value that
366          * is not longer than what's in the buffer, so the
367          * "tvb_get_ptr()" calls below won't throw exceptions.   *
368          */
369         offset = 0;
370         if(tvb_length(tvb) < 4 ||  tvb_get_ntohl(tvb, 0) != 0x4d535250 /* MSRP */){
371                 return FALSE;
372         }
373
374         linelen = tvb_find_line_end(tvb, 0, -1, &next_offset, FALSE);
375         /* Find the first SP */
376         space_offset = tvb_find_guint8(tvb, 0, -1, ' ');
377
378         if (space_offset <= 0) {
379                 /*
380                  * Either there's no space in the line (which means
381                  * the line is empty or doesn't have a token followed
382                  * by a space; neither is valid for a request or response), or
383                  * the first character in the line is a space ( which isn't valid
384                  * for a MSRP header.)
385                  */
386                 return FALSE;
387         }
388
389         token_1_len = space_offset;
390         token_2_start = space_offset + 1;
391         space_offset = tvb_find_guint8(tvb, token_2_start, -1, ' ');
392         if (space_offset == -1) {
393                 /*
394                  * There's no space after the second token, so we don't
395                  * have a third token.
396                  */
397                 return FALSE;
398         }
399         /*
400          * Is the first token "MSRP"?
401          */
402         if (token_1_len == MSRP_HDR_LEN) { /*  && tvb_strneql(tvb, 0, MSRP_HDR, MSRP_HDR_LEN) == 0){ */
403                 /* This check can be made more strict but accept we do have MSRP for now */
404                 return TRUE;
405
406         }
407         return FALSE;
408 }
409
410 /* ABNF of line-end:
411  * end-line = "-------" transact-id continuation-flag CRLF
412  * This code is modeled on the code in packet-multipart.c
413  */
414 static int
415 find_end_line(tvbuff_t *tvb, gint start)
416 {
417         gint offset = start, next_offset, linelen;
418
419         while (tvb_length_remaining(tvb, offset) > 0) {
420                 /* 'desegment' is FALSE so will set next_offset to beyond the end of
421                    the buffer if no line ending is found */
422                 linelen =  tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
423                 if (linelen == -1) {
424                         return -1;
425                 }
426                 if (tvb_strneql(tvb, next_offset, (const gchar *)"-------", 7) == 0)
427                         return next_offset;
428                 offset = next_offset;
429         }
430
431         return -1;
432 }
433
434 static gboolean
435 dissect_msrp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
436 {
437         gint offset = 0;
438         conversation_t* conversation;
439
440         if ( check_msrp_header(tvb)){
441                 /*
442                  * TODO Set up conversation here
443                  */
444                 if (pinfo->fd->flags.visited){
445                         /* Look for existing conversation */
446                         conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
447                                 pinfo->srcport, pinfo->destport, 0);
448                         /* Create new one if not found */
449                         if (conversation == NULL){
450                                 conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst,
451                                         pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
452                                 /* Set dissector */
453                                 conversation_set_dissector(conversation, msrp_handle);
454                         }
455                 }
456                 offset = dissect_msrp(tvb, pinfo, tree);
457                 return TRUE;
458         }
459         return FALSE;
460 }
461
462 /* Code to actually dissect the packets */
463 static int
464 dissect_msrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
465 {
466         gint offset = 0;
467         gint next_offset = 0;
468         proto_item *ti, *th, *msrp_headers_item, *msrp_element_item;
469         proto_tree *msrp_tree, *reqresp_tree, *raw_tree, *msrp_hdr_tree, *msrp_end_tree;
470         proto_tree *msrp_element_tree, *msrp_data_tree;
471         gint linelen;
472         gint space_offset;
473         gint token_2_start;
474         guint token_2_len;
475         gint token_3_start;
476         guint token_3_len;
477         gint token_4_start = 0;
478         guint token_4_len = 0;
479         gboolean is_msrp_response;
480         gint end_line_offset;
481         gint end_line_len;
482         gint line_end_offset;
483         gint message_end_offset;
484         gint colon_offset;
485         char *transaction_id_str = NULL;
486         gint header_len;
487         gint hf_index;
488         gint value_offset;
489         guchar c;
490         gint value_len;
491         char *value;
492         gboolean have_body = FALSE;
493         gboolean found_match = FALSE;
494         gint content_type_len, content_type_parameter_str_len;
495         gchar *media_type_str_lower_case = NULL;
496         char *content_type_parameter_str = NULL;
497         tvbuff_t *next_tvb;
498         gint parameter_offset;
499         gint semi_colon_offset;
500
501         if ( !check_msrp_header(tvb)){
502                 return 0;
503         }
504         /* We have a MSRP header with at least three tokens
505          *
506          * Note that "tvb_find_line_end()" will return a value that
507          * is not longer than what's in the buffer, so the
508          * "tvb_get_ptr()" calls below won't throw exceptions.   *
509          */
510         offset = 0;
511         linelen = tvb_find_line_end(tvb, 0, -1, &next_offset, FALSE);
512
513         /* Find the first SP and skip the first token */
514         token_2_start = tvb_find_guint8(tvb, 0, linelen, ' ') + 1;
515
516         /* Work out 2nd token's length by finding next space */
517         space_offset = tvb_find_guint8(tvb, token_2_start, linelen-token_2_start, ' ');
518         token_2_len = space_offset - token_2_start;
519
520         /* Transaction ID found store it for later use */
521         transaction_id_str = tvb_get_ephemeral_string(tvb, token_2_start, token_2_len);
522
523         /* Look for another space in this line to indicate a 4th token */
524         token_3_start = space_offset + 1;
525         space_offset = tvb_find_guint8(tvb, token_3_start,linelen-token_3_start, ' ');
526         if ( space_offset == -1){
527                 /* 3rd token runs to the end of the line */
528                 token_3_len = linelen - token_3_start;
529         }else{
530                 /* We have a fourth token */
531                 token_3_len = space_offset - token_3_start;
532                 token_4_start = space_offset + 1;
533                 token_4_len = linelen - token_4_start;
534         }
535
536         /*
537          * Yes, so this is either a msrp-request or msrp-response.
538          * To be a msrp-response, the second token must be
539          * a 3-digit number.
540          */
541         is_msrp_response = FALSE;
542         if (token_3_len == 3) {
543                         if (isdigit(tvb_get_guint8(tvb, token_3_start)) &&
544                             isdigit(tvb_get_guint8(tvb, token_3_start + 1)) &&
545                             isdigit(tvb_get_guint8(tvb, token_3_start + 2))) {
546                                 is_msrp_response = TRUE;
547                         }
548         }
549
550         /* Make entries in Protocol column and Info column on summary display */
551         col_set_str(pinfo->cinfo, COL_PROTOCOL, "MSRP");
552         if (is_msrp_response){
553                 if (check_col(pinfo->cinfo, COL_INFO)) {
554                         col_add_fstr(pinfo->cinfo, COL_INFO, "Response: %s ",
555                                         tvb_format_text(tvb, token_3_start, token_3_len));
556
557                         if (token_4_len )
558                                 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
559                                         tvb_format_text(tvb, token_4_start, token_4_len));
560
561                         col_append_fstr(pinfo->cinfo, COL_INFO, "Transaction ID: %s",
562                                         tvb_format_text(tvb, token_2_start, token_2_len));
563                 }
564         }else{
565                 if (check_col(pinfo->cinfo, COL_INFO)) {
566                         proto_tree_add_text(tree, tvb, token_3_start, token_3_len,
567                                         "Col %s L=%u", tvb_format_text(tvb, token_3_start, token_3_len),token_3_len);
568
569                         col_add_fstr(pinfo->cinfo, COL_INFO, "Request: %s ",
570                                         tvb_format_text(tvb, token_3_start, token_3_len));
571
572                         col_append_fstr(pinfo->cinfo, COL_INFO, "Transaction ID: %s",
573                                         tvb_format_text(tvb, token_2_start, token_2_len));
574                 }
575         }
576
577         /* Find the end line to be able to process the headers
578          * Note that in case of [content-stuff] headers and [content-stuff] is separated by CRLF
579          */
580
581         offset = next_offset;
582         end_line_offset = find_end_line(tvb,offset);
583         /* TODO if -1 (No end line found, is returned do something) */
584         end_line_len =  tvb_find_line_end(tvb, end_line_offset, -1, &next_offset, FALSE);
585         message_end_offset = end_line_offset + end_line_len + 2;
586
587
588         if (tree) {
589                 ti = proto_tree_add_item(tree, proto_msrp, tvb, 0, message_end_offset, FALSE);
590                 msrp_tree = proto_item_add_subtree(ti, ett_msrp);
591
592                 if (is_msrp_response){
593                         th = proto_tree_add_item(msrp_tree,hf_msrp_response_line,tvb,0,linelen,FALSE);
594                         reqresp_tree = proto_item_add_subtree(th, ett_msrp_reqresp);
595                         proto_tree_add_item(reqresp_tree,hf_msrp_transactionID,tvb,token_2_start,token_2_len,FALSE);
596                         proto_tree_add_uint(reqresp_tree,hf_msrp_status_code,tvb,token_3_start,token_3_len,
597                                             atoi(tvb_get_ephemeral_string(tvb, token_3_start, token_3_len)));
598
599                 }else{
600                         th = proto_tree_add_item(msrp_tree,hf_msrp_request_line,tvb,0,linelen,FALSE);
601                         reqresp_tree = proto_item_add_subtree(th, ett_msrp_reqresp);
602                         proto_tree_add_item(reqresp_tree,hf_msrp_transactionID,tvb,token_2_start,token_2_len,FALSE);
603                         proto_tree_add_item(reqresp_tree,hf_msrp_method,tvb,token_3_start,token_3_len,FALSE);
604                 }
605
606                 /* Conversation setup info */
607                 if (global_msrp_show_setup_info)
608                 {
609                         show_setup_info(tvb, pinfo, msrp_tree);
610                 }
611
612                 /* Headers */
613                 msrp_headers_item = proto_tree_add_item(msrp_tree, hf_msrp_msg_hdr, tvb, offset,(end_line_offset - offset), FALSE);
614                 msrp_hdr_tree = proto_item_add_subtree(msrp_headers_item, ett_msrp_hdr);
615
616                 /*
617                  * Process the headers
618                  */
619                 while (tvb_reported_length_remaining(tvb, offset) > 0 && offset < end_line_offset  ) {
620                         /* 'desegment' is FALSE so will set next_offset to beyond the end of
621                            the buffer if no line ending is found */
622                         linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
623                         if (linelen == 0) {
624                                 /*
625                                  * This is a blank line separating the
626                                  * message header from the message body.
627                                  */
628                                 have_body = TRUE;
629                                 break;
630                         }
631                         line_end_offset = offset + linelen;
632                         colon_offset = tvb_find_guint8(tvb, offset, linelen, ':');
633                         if (colon_offset == -1) {
634                                 /*
635                                  * Malformed header - no colon after the name.
636                                  */
637                                 proto_tree_add_text(msrp_hdr_tree, tvb, offset,
638                                                         next_offset - offset, "%s",
639                                                             tvb_format_text(tvb, offset, linelen));
640                         } else {
641                                 header_len = colon_offset - offset;
642                                 hf_index = msrp_is_known_msrp_header(tvb, offset, header_len);
643
644                                 if (hf_index == -1) {
645                                         proto_tree_add_text(msrp_hdr_tree, tvb,
646                                                     offset, next_offset - offset, "%s",
647                                                     tvb_format_text(tvb, offset, linelen));
648                                 } else {
649                                         /*
650                                          * Skip whitespace after the colon.
651                                          */
652                                         value_offset = colon_offset + 1;
653                                         while (value_offset < line_end_offset &&
654                                                ((c = tvb_get_guint8(tvb, value_offset)) == ' ' ||
655                                                  c == '\t'))
656                                                 value_offset++;
657                                         /*
658                                          * Fetch the value.
659                                          */
660                                         value_len = line_end_offset - value_offset;
661                                         value = tvb_get_ephemeral_string(tvb, value_offset,
662                                                        value_len);
663
664                                         /*
665                                          * Add it to the protocol tree,
666                                          * but display the line as is.
667                                          */
668                                         msrp_element_item = proto_tree_add_string_format(msrp_hdr_tree,
669                                                    hf_header_array[hf_index], tvb,
670                                                    offset, next_offset - offset,
671                                                    value, "%s",
672                                                    tvb_format_text(tvb, offset, linelen));
673                                         msrp_element_tree = proto_item_add_subtree( msrp_element_item, ett_msrp_element);
674
675                                         switch ( hf_index ) {
676
677                                                 case MSRP_CONTENT_TYPE :
678                                                         content_type_len = value_len;
679                                                         semi_colon_offset = tvb_find_guint8(tvb, value_offset,linelen, ';');
680                                                         if ( semi_colon_offset != -1) {
681                                                                 parameter_offset = semi_colon_offset +1;
682                                                                 /*
683                                                                  * Skip whitespace after the semicolon.
684                                                                  */
685                                                                 while (parameter_offset < line_end_offset
686                                                                        && ((c = tvb_get_guint8(tvb, parameter_offset)) == ' '
687                                                                          || c == '\t'))
688                                                                         parameter_offset++;
689                                                                 content_type_len = semi_colon_offset - value_offset;
690                                                                 content_type_parameter_str_len = line_end_offset - parameter_offset;
691                                                                 content_type_parameter_str = tvb_get_ephemeral_string(tvb,
692                                                                                      parameter_offset, content_type_parameter_str_len);
693                                                         }
694                                                         media_type_str_lower_case = ascii_strdown_inplace(
695                                                             (gchar *)tvb_get_ephemeral_string(tvb, value_offset, content_type_len));
696                                                         break;
697
698                                                 default:
699                                                         break;
700                                         }
701                                 }
702                         }
703                         offset = next_offset;
704                 }/* End while */
705
706                 if ( have_body ){
707                         /*
708                          * There's a message body starting at "next_offset".
709                          * Set the length of the header item.
710                          */
711                         proto_item_set_end(msrp_headers_item, tvb, next_offset);
712
713                         /* Create new tree & tvb for data */
714                         next_tvb = tvb_new_subset_remaining(tvb, next_offset);
715                         ti = proto_tree_add_item(msrp_tree, hf_msrp_data, tvb,
716                                                  next_offset, -1, FALSE);
717                         msrp_data_tree = proto_item_add_subtree(ti, ett_msrp_data);
718
719                         /* give the content type parameters to sub dissectors */
720
721                         if ( media_type_str_lower_case != NULL ) {
722                                 void *save_private_data = pinfo->private_data;
723                                 pinfo->private_data = content_type_parameter_str;
724                                 found_match = dissector_try_string(media_type_dissector_table,
725                                                            media_type_str_lower_case,
726                                                            next_tvb, pinfo,
727                                                            msrp_data_tree);
728                                 pinfo->private_data = save_private_data;
729                                 /* If no match dump as text */
730                         }
731                         if ( found_match != TRUE )
732                         {
733                                 offset = 0;
734                                 while (tvb_offset_exists(next_tvb, offset)) {
735                                         tvb_find_line_end(next_tvb, offset, -1, &next_offset, FALSE);
736                                         linelen = next_offset - offset;
737                                         proto_tree_add_text(msrp_data_tree, next_tvb, offset, linelen,
738                                                     "%s", tvb_format_text(next_tvb, offset, linelen));
739                                         offset = next_offset;
740                                 }/* end while */
741                         }
742
743                 }
744
745
746
747                 /* End line */
748                 ti = proto_tree_add_item(msrp_tree,hf_msrp_end_line,tvb,end_line_offset,end_line_len,FALSE);
749                 msrp_end_tree = proto_item_add_subtree(ti, ett_msrp_end_line);
750
751                 proto_tree_add_item(msrp_end_tree,hf_msrp_transactionID,tvb,end_line_offset + 7,token_2_len,FALSE);
752                 /* continuation-flag */
753                 proto_tree_add_item(msrp_end_tree,hf_msrp_cnt_flg,tvb,end_line_offset+end_line_len-1,1,FALSE);
754
755                 if (global_msrp_raw_text){
756                         ti = proto_tree_add_text(tree, tvb, 0, -1,"Message Session Relay Protocol(as raw text)");
757                         raw_tree = proto_item_add_subtree(ti, ett_msrp);
758                         tvb_raw_text_add(tvb,raw_tree);
759                 }
760
761         }/* if tree */
762         return message_end_offset;
763         /*      return tvb_length(tvb); */
764
765 /* If this protocol has a sub-dissector call it here, see section 1.8 */
766 }
767
768
769 /* Register the protocol with Wireshark */
770 /* If this dissector uses sub-dissector registration add a registration routine.
771    This format is required because a script is used to find these routines and
772    create the code that calls these routines.
773 */
774 void
775 proto_reg_handoff_msrp(void)
776 {
777         msrp_handle = find_dissector("msrp");
778         dissector_add_handle("tcp.port", msrp_handle);   /* for "decode-as" */
779         heur_dissector_add("tcp", dissect_msrp_heur, proto_msrp);
780         media_type_dissector_table = find_dissector_table("media_type");
781 }
782
783 void
784 proto_register_msrp(void)
785 {
786 /* Setup protocol subtree array */
787         static gint *ett[] = {
788                 &ett_msrp,
789                 &ett_raw_text,
790                 &ett_msrp_reqresp,
791                 &ett_msrp_hdr,
792                 &ett_msrp_element,
793                 &ett_msrp_data,
794                 &ett_msrp_end_line,
795                 &ett_msrp_setup
796         };
797
798         /* Setup list of header fields */
799         static hf_register_info hf[] = {
800                 { &hf_msrp_request_line,
801                         { "Request Line",               "msrp.request.line",
802                         FT_STRING, BASE_NONE,NULL,0x0,
803                         NULL, HFILL }
804                 },
805                 { &hf_msrp_response_line,
806                         { "Response Line",              "msrp.response.line",
807                         FT_STRING, BASE_NONE,NULL,0x0,
808                         NULL, HFILL }
809                 },
810                 { &hf_msrp_transactionID,
811                         { "Transaction Id",             "msrp.transaction.id",
812                         FT_STRING, BASE_NONE,NULL,0x0,
813                         NULL, HFILL }
814                 },
815                 { &hf_msrp_method,
816                         { "Method",                             "msrp.method",
817                         FT_STRING, BASE_NONE,NULL,0x0,
818                         NULL, HFILL }
819                 },
820                 { &hf_msrp_status_code,
821                         { "Status code",                "msrp.status.code",
822                         FT_UINT16, BASE_DEC,NULL,0x0,
823                         NULL, HFILL }
824                 },
825                 { &hf_msrp_msg_hdr,
826                         { "Message Header",             "msrp.msg.hdr",
827                         FT_NONE, BASE_NONE,NULL,0x0,
828                         NULL, HFILL }
829                 },
830                 { &hf_msrp_end_line,
831                         { "End Line",           "msrp.end.line",
832                         FT_STRING, BASE_NONE,NULL,0x0,
833                         NULL, HFILL }
834                 },
835                 { &hf_msrp_cnt_flg,
836                         { "Continuation-flag",          "msrp.cnt.flg",
837                         FT_STRING, BASE_NONE,NULL,0x0,
838                         NULL, HFILL }
839                 },
840                 { &hf_header_array[MSRP_FROM_PATH],
841                         { "From Path",          "msrp.from.path",
842                         FT_STRING, BASE_NONE,NULL,0x0,
843                         NULL, HFILL }
844                 },
845                 { &hf_header_array[MSRP_TO_PATH],
846                         { "To Path",            "msrp.to.path",
847                         FT_STRING, BASE_NONE,NULL,0x0,
848                         NULL, HFILL }
849                 },
850                 { &hf_header_array[MSRP_MESSAGE_ID],
851                         { "Message ID",                 "msrp.messageid",
852                         FT_STRING, BASE_NONE,NULL,0x0,
853                         NULL, HFILL }
854                 },
855                 { &hf_header_array[MSRP_SUCCESS_REPORT],
856                         { "Success Report",             "msrp.success.report",
857                         FT_STRING, BASE_NONE,NULL,0x0,
858                         NULL, HFILL }
859                 },
860                 { &hf_header_array[MSRP_FAILURE_REPORT],
861                         { "Failure Report",             "msrp.failure.report",
862                         FT_STRING, BASE_NONE,NULL,0x0,
863                         NULL, HFILL }
864                 },
865                 { &hf_header_array[MSRP_BYTE_RANGE],
866                         { "Byte Range",                 "msrp.byte.range",
867                         FT_STRING, BASE_NONE,NULL,0x0,
868                         NULL, HFILL }
869                 },
870                 { &hf_header_array[MSRP_STATUS],
871                         { "Status",             "msrp.status",
872                         FT_STRING, BASE_NONE,NULL,0x0,
873                         NULL, HFILL }
874                 },
875                 { &hf_header_array[MSRP_CONTENT_TYPE],
876                         { "Content-Type",               "msrp.content.type",
877                         FT_STRING, BASE_NONE,NULL,0x0,
878                         NULL, HFILL }
879                 },
880                 { &hf_header_array[MSRP_CONTENT_ID],
881                         { "Content-ID",                 "msrp.content.id",
882                         FT_STRING, BASE_NONE,NULL,0x0,
883                         NULL, HFILL }
884                 },
885                 { &hf_header_array[MSRP_CONTENT_DISCRIPTION],
886                         { "Content-Description",                "msrp.content.description",
887                         FT_STRING, BASE_NONE,NULL,0x0,
888                         NULL, HFILL }
889                 },
890                 { &hf_header_array[MSRP_CONTENT_DISPOSITION],
891                         { "Content-Disposition",                "msrp.content.disposition",
892                         FT_STRING, BASE_NONE,NULL,0x0,
893                         NULL, HFILL }
894                 },
895                 { &hf_header_array[MSRP_USE_PATH],
896                         { "Use-Path",           "msrp.use.path",
897                         FT_STRING, BASE_NONE,NULL,0x0,
898                         NULL, HFILL }
899                 },
900                 { &hf_header_array[MSRP_WWW_AUTHENTICATE],
901                         { "WWW-Authenticate",           "msrp.www.authenticate",
902                         FT_STRING, BASE_NONE,NULL,0x0,
903                         NULL, HFILL }
904                 },
905                 { &hf_header_array[MSRP_AUTHORIZATION],
906                         { "Authorization",              "msrp.authorization",
907                         FT_STRING, BASE_NONE,NULL,0x0,
908                         NULL, HFILL }
909                 },
910                 { &hf_header_array[MSRP_AUTHENTICATION_INFO],
911                         { "Authentication-Info",                "msrp.authentication.info",
912                         FT_STRING, BASE_NONE,NULL,0x0,
913                         NULL, HFILL }
914                 },
915                 { &hf_msrp_data,
916                         { "Data", "msrp.data",
917                         FT_STRING, BASE_NONE, NULL, 0x0,
918                         NULL, HFILL}
919         },
920                 { &hf_msrp_setup,
921                         { "Stream setup", "msrp.setup",
922                         FT_STRING, BASE_NONE, NULL, 0x0,
923                         "Stream setup, method and frame number", HFILL}
924                 },
925                 { &hf_msrp_setup_frame,
926                         { "Setup frame", "msrp.setup-frame",
927                         FT_FRAMENUM, BASE_NONE, NULL, 0x0,
928                         "Frame that set up this stream", HFILL}
929                 },
930                 { &hf_msrp_setup_method,
931                         { "Setup Method", "msrp.setup-method",
932                         FT_STRING, BASE_NONE, NULL, 0x0,
933                         "Method used to set up this stream", HFILL}
934                 },
935         };
936
937         module_t *msrp_module;
938         /* Register the protocol name and description */
939         proto_msrp = proto_register_protocol("Message Session Relay Protocol","MSRP", "msrp");
940
941         /* Required function calls to register the header fields and subtrees used */
942         proto_register_field_array(proto_msrp, hf, array_length(hf));
943         proto_register_subtree_array(ett, array_length(ett));
944
945         msrp_module = prefs_register_protocol(proto_msrp, NULL);
946
947         prefs_register_bool_preference(msrp_module, "display_raw_text",
948                 "Display raw text for MSRP message",
949                 "Specifies that the raw text of the "
950                 "MSRP message should be displayed "
951                 "in addition to the dissection tree",
952                 &global_msrp_raw_text);
953
954         prefs_register_bool_preference(msrp_module, "show_setup_info",
955                 "Show stream setup information",
956                 "Where available, show which protocol and frame caused "
957                 "this MSRP stream to be created",
958                 &global_msrp_show_setup_info);
959
960
961         /*
962          * Register the dissector by name, so other dissectors can
963          * grab it by name rather than just referring to it directly.
964          */
965         new_register_dissector("msrp", dissect_msrp, proto_msrp);
966 }
967
968