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