From Didier Gautheron:
[obnox/wireshark/wip.git] / epan / dissectors / packet-pw-fr.c
1 /* packet-pw-fr.c
2  * Routines for Frame Relay MPLS PW dissection as per RFC4619.
3  * Copyright 2009, Dmitry Trebich, Artem Tamazov <artem.tamazov@tellabs.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  * History:
26  * ---------------------------------
27  * 18.03.2009 initial implementation
28  * - FR DLCI mode
29  * Not supported yet:
30  * - Correct FR decode for encapsulations which contain fragmented FR frames.
31  * - FR DLCI Martini (legacy) mode (i.e. legacy CW).
32  */
33
34 #ifdef HAVE_CONFIG_H
35 # include "config.h"
36 #endif
37
38 #include <glib.h>
39 #include <epan/packet.h>
40 #include <epan/expert.h>
41
42 #include "packet-mpls.h"
43
44 static gint proto_encaps = -1;
45 static gint ett_encaps = -1;
46
47 /*static int hf_pw_fr = -1;*/
48 static int hf_cw_bits03 = -1;
49 static int hf_cw_fecn = -1;
50 static int hf_cw_becn = -1;
51 static int hf_cw_de = -1;
52 static int hf_cw_cr = -1;
53 static int hf_cw_frg = -1;
54 static int hf_cw_len = -1;
55 static int hf_cw_seq = -1;
56
57 static const value_string vals_frg[] = {
58         { 0x0,  "Unfragmented" },
59         { 0x1,  "First fragment" },
60         { 0x2,  "Last fragment" },
61         { 0x3,  "Intermediate fragment" },
62         { 0,    NULL }
63 };
64
65
66 static dissector_handle_t fr_stripped_address_handle;
67
68
69 static void
70 dissect_pw_fr( tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree )
71 {
72         gint packet_size;
73         gint payload_size;
74         gint payload_padding;
75         const int encaps_size = 4; /*encapsulation consists of mandatory CW only*/
76         enum {
77                 PQ_CW_BAD                               = 0x001
78                     ,PQ_CW_BAD_BITS03                   = 0x002
79                     ,PQ_CW_BAD_LEN_GT_PACKET            = 0x004
80                     ,PQ_CW_BAD_LEN_MUST_BE_ZERO         = 0x008
81                     ,PQ_CW_BAD_LEN_MUST_BE_NONZERO      = 0x010
82                 ,PQ_PAYLOAD_SIZE_ZERO                   = 0x020
83         } packet_quality;
84         
85         packet_size = tvb_reported_length_remaining(tvb, 0);
86         if (packet_size < encaps_size)
87         {
88                 if (tree)
89                 {
90                         proto_item  *item;
91                         item = proto_tree_add_item(tree, proto_encaps, tvb, 0, -1, FALSE); 
92                         expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR,
93                                 "PW packet (%d) is smaller than PW encapsulation header (%d)"
94                                 ,(int)packet_size,(int)encaps_size);
95                 }
96                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "FR PW");
97                 col_set_str(pinfo->cinfo, COL_INFO, "Malformed: PW packet < PW encapsulation header");
98                 return;
99         }
100
101         if (dissect_try_cw_first_nibble(tvb,pinfo,tree))
102         {
103                 return;
104         }
105
106         /* check how "good" is this packet */   
107         /* also decide payload length from packet size and CW */
108         packet_quality = 0;
109         if (0 != (tvb_get_guint8(tvb, 0) & 0xf0 /*bits03*/))
110         {
111                 packet_quality |= PQ_CW_BAD + PQ_CW_BAD_BITS03;
112         }
113         {
114                 /* RFC4619:
115                  * [ If the frame's length (defined as the
116                  * length of the layer 2 payload plus the length of the control word)
117                  * is less than 64 octets, the length field MUST be set to the PW
118                  * payload length.  Otherwise, the length field MUST be set to zero. ] 
119                  * 
120                  * Note difference from RFC4385 which states that:  
121                  * [..the length field MUST be set to the length of the PW payload 
122                  * *plus* the length of the *PWMCW*. ]
123                  */
124                 int cw_len;
125                 gint payload_size_packet; /*derived from packet size*/
126
127                 cw_len = tvb_get_guint8(tvb, 1) & 0x3f; 
128                 payload_size_packet = packet_size - encaps_size;
129                 
130                 /* 
131                  * Initial assumptions.
132                  */
133                 payload_size = payload_size_packet; 
134                 payload_padding = 0;  
135                 
136                 if (payload_size_packet < 64)
137                 {
138                         gint payload_size_cw; /*derived from cw*/
139                         payload_size_cw = cw_len; /*RFC4619-specific*/ 
140                         if (payload_size_cw == 0)
141                         {
142                                 packet_quality |= PQ_CW_BAD + PQ_CW_BAD_LEN_MUST_BE_NONZERO;
143                         }
144                         else if (payload_size_cw > payload_size_packet)
145                         {
146                                 packet_quality |= PQ_CW_BAD + PQ_CW_BAD_LEN_GT_PACKET;
147                         }
148                         else /* ok */
149                         {
150                                 payload_size = payload_size_cw;
151                                 payload_padding = payload_size_packet - payload_size_cw; /* >=0 */
152                         }
153                 }
154                 else /* payload_size_packet >= 64 */
155                 {          
156                         if (cw_len != 0)
157                         {
158                                 packet_quality |= PQ_CW_BAD + PQ_CW_BAD_LEN_MUST_BE_ZERO;
159                         }
160                 }
161         }
162         if ((payload_size == 0))
163         {               
164                 packet_quality |= PQ_PAYLOAD_SIZE_ZERO;
165         }
166
167         col_set_str(pinfo->cinfo, COL_PROTOCOL, "FR PW");  
168         if (check_col(pinfo->cinfo, COL_INFO))
169         {
170                 col_clear(pinfo->cinfo, COL_INFO);
171                 if (packet_quality & PQ_CW_BAD) 
172                 {
173                         col_append_str(pinfo->cinfo, COL_INFO, "CW:Malformed, ");
174                 }
175                 col_append_fstr(pinfo->cinfo, COL_INFO, "%d payload octets", (int)payload_size);
176         
177                 if (payload_padding != 0)
178                 {
179                         col_append_fstr(pinfo->cinfo, COL_INFO, ", %d padding", (int)payload_padding);
180                 }
181         }
182
183         if (tree)
184         {
185                 proto_tree* subtree;
186                 proto_item* item_headline;
187                 proto_item* item;
188                 
189                 item_headline = proto_tree_add_item(tree, proto_encaps, tvb, 0, 4, FALSE); 
190                 proto_item_append_text(item_headline, ": 0x%.8" G_GINT32_MODIFIER "x", tvb_get_ntohl(tvb, 0));
191                 subtree = proto_item_add_subtree(item_headline, ett_encaps);
192                 
193                 if (packet_quality & PQ_CW_BAD_BITS03) /*display only if value is wrong*/
194                 {
195                         item = proto_tree_add_item(subtree, hf_cw_bits03, tvb, 0, 1, FALSE);
196                         expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR,
197                                 "Bits 0..3 of Control Word must be 0");
198                 }
199                 
200                 (void)proto_tree_add_item( subtree, hf_cw_fecn, tvb, 0, 1, FALSE );
201                 (void)proto_tree_add_item( subtree, hf_cw_becn, tvb, 0, 1, FALSE );
202                 (void)proto_tree_add_item( subtree, hf_cw_de, tvb, 0, 1, FALSE );
203                 (void)proto_tree_add_item( subtree, hf_cw_cr, tvb, 0, 1, FALSE );
204                 (void)proto_tree_add_item( subtree, hf_cw_frg, tvb, 1, 1, FALSE );
205                 
206                 item = proto_tree_add_item( subtree, hf_cw_len, tvb, 1, 1, FALSE );
207                 if (packet_quality & PQ_CW_BAD_LEN_GT_PACKET)
208                 {
209                         expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR,
210                                 "Bad Length: greater than FR payload size (%d)", 
211                                 (int)payload_size);
212                 }  
213                 if (packet_quality & PQ_CW_BAD_LEN_MUST_BE_NONZERO)
214                 {
215                         expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR,
216                                 "Bad Length: must be non-zero if FR PW packet size (%d) is < 64",
217                                 (int)(payload_size+encaps_size));
218                 }
219                 if (packet_quality & PQ_CW_BAD_LEN_MUST_BE_ZERO)
220                 {
221                         expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR,
222                                 "Bad Length: must be 0 if FR PW packet size (%d) is >= 64",
223                                 (int)(payload_size+encaps_size));
224                 }
225                 
226                 proto_tree_add_item( subtree, hf_cw_seq, tvb, 2, 2, FALSE );
227
228                 if (payload_padding > 0)
229                 {
230                         proto_tree_add_text(subtree, tvb, 
231                                 encaps_size+payload_size, payload_padding, 
232                                 "[Padding: %d octets]",(int)payload_padding);
233                 }               
234
235                 if (packet_quality & PQ_PAYLOAD_SIZE_ZERO)
236                 {
237                         expert_add_info_format(pinfo, item_headline, PI_MALFORMED, PI_WARN,
238                                 "FR payload size must be non-zero");
239                 }
240
241         }
242         if (payload_size > 0)
243         {
244                 tvbuff_t *tvb_payload;
245                 tvb_payload = tvb_new_subset(tvb, encaps_size, payload_size, payload_size);
246                 call_dissector( fr_stripped_address_handle, tvb_payload, pinfo, tree );
247         } 
248         return;
249 }
250
251
252 void
253 proto_register_pw_fr(void)
254 {
255         static hf_register_info hf[] = {
256                 {&hf_cw_bits03  ,{"Bits 0 to 3"         ,"pwfr.bits03"  ,FT_UINT8       ,BASE_HEX
257                                   ,NULL                 ,0xf0           ,NULL
258                                   ,HFILL }}
259                 ,{&hf_cw_fecn   ,{"FR FECN"             ,"pwfr.fecn"    ,FT_UINT8       ,BASE_DEC
260                                   ,NULL                 ,0x08           ,"FR Forward Explicit Congestion Notification bit"
261                                   ,HFILL}}
262                 ,{&hf_cw_becn   ,{"FR BECN"             ,"pwfr.becn"    ,FT_UINT8       ,BASE_DEC
263                                   ,NULL                 ,0x04           ,"FR Backward Explicit Congestion Notification bit"
264                                   ,HFILL}}
265                 ,{&hf_cw_de     ,{"FR DE bit"           ,"pwfr.de"      ,FT_UINT8       ,BASE_DEC
266                                   ,NULL                 ,0x02           ,"FR Discard Eligibility bit"
267                                   ,HFILL}}
268                 ,{&hf_cw_cr     ,{"FR Frame C/R"        ,"pwfr.cr"      ,FT_UINT8       ,BASE_DEC
269                                   ,NULL                 ,0x01           ,"FR frame Command/Response bit"
270                                   ,HFILL}}
271                 ,{&hf_cw_frg    ,{"Fragmentation"       ,"pwfr.frag"    ,FT_UINT8       ,BASE_DEC
272                                   ,vals_frg             ,0xc0           ,NULL
273                                   ,HFILL}}
274                 ,{&hf_cw_len    ,{"Length"              ,"pwfr.length"  ,FT_UINT8       ,BASE_DEC
275                                   ,NULL                 ,0x3f           ,NULL
276                                   ,HFILL}}
277                 ,{&hf_cw_seq    ,{"Sequence number"     ,"pwfr.length"  ,FT_UINT16      ,BASE_DEC
278                                   ,NULL                 ,0              ,NULL
279                                   ,HFILL}}
280         };
281
282         static gint *ett[] = {
283                 &ett_encaps
284         };
285
286         proto_encaps = proto_register_protocol( "PW Frame Relay DLCI Control Word",
287                                                 "Frame Relay DLCI PW",
288                                                 "pwfr");
289         proto_register_field_array(proto_encaps, hf, array_length(hf));
290         proto_register_subtree_array(ett, array_length(ett));
291         register_dissector("pw_fr", dissect_pw_fr, proto_encaps );
292 }
293
294
295 void
296 proto_reg_handoff_pw_fr(void)
297 {
298         dissector_handle_t h;
299         h = find_dissector("pw_fr");
300         dissector_add("mpls.label", LABEL_INVALID, h);
301         fr_stripped_address_handle = find_dissector("fr_stripped_address");
302 }