AODV dissection support, from Erik Nordstr�m.
[obnox/wireshark/wip.git] / packet-mtp2.c
1 /* packet-mtp2.c
2  * Routines for MTP2 dissection
3  * It is hopefully (needs testing) compliant to
4  * ITU-T Q.703
5  *
6  * Copyright 2001, Michael Tuexen <michael.tuexen[AT]icn.siemens.de>
7  *
8  * $Id: packet-mtp2.c,v 1.3 2002/01/21 07:36:37 guy Exp $
9  *
10  * Ethereal - Network traffic analyzer
11  * By Gerald Combs <gerald@ethereal.com>
12  * Copyright 1998 Gerald Combs
13  *
14  * Copied from packet-m2pa.c
15  * 
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  * 
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  * 
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <glib.h>
36
37 #include <epan/packet.h>
38
39 /* Initialize the protocol and registered fields */
40 static int proto_mtp2      = -1;
41 static int hf_mtp2_bsn     = -1;
42 static int hf_mtp2_bib     = -1;
43 static int hf_mtp2_fsn     = -1;
44 static int hf_mtp2_fib     = -1;
45 static int hf_mtp2_li      = -1;
46 static int hf_mtp2_spare   = -1;
47 static int hf_mtp2_sf      = -1;
48 static int hf_mtp2_long_sf = -1;
49
50 /* Initialize the subtree pointers */
51 static gint ett_mtp2       = -1;
52
53 static dissector_handle_t mtp3_handle;
54 static int mtp3_proto_id;
55
56 #define BSN_BIB_LENGTH 1
57 #define FSN_FIB_LENGTH 1
58 #define LI_LENGTH      1
59 #define HEADER_LENGTH  (BSN_BIB_LENGTH + FSN_FIB_LENGTH + LI_LENGTH)
60 #define SF_LENGTH      1
61 #define LONG_SF_LENGTH 2
62
63 #define BSN_BIB_OFFSET 0
64 #define FSN_FIB_OFFSET (BSN_BIB_OFFSET + BSN_BIB_LENGTH)
65 #define LI_OFFSET      (FSN_FIB_OFFSET + FSN_FIB_LENGTH)
66 #define SIO_OFFSET     (LI_OFFSET + LI_LENGTH)
67 #define SF_OFFSET      (LI_OFFSET + LI_LENGTH)
68
69 #define BSN_MASK       0x7f
70 #define BIB_MASK       0x80
71 #define FSN_MASK       0x7f
72 #define FIB_MASK       0x80
73 #define LI_MASK        0x3f
74 #define SPARE_MASK     0xc0
75
76 #define STATUS_O       0x0
77 #define STATUS_N       0x1
78 #define STATUS_E       0x2
79 #define STATUS_OS      0x3
80 #define STATUS_PO      0x4
81 #define STATUS_B       0x5
82
83 static const value_string status_field_vals[] = {
84         { STATUS_O,      "Status Indication O" },
85   { STATUS_N,  "Status Indication N" },
86         { STATUS_E,      "Status Indication E" },
87         { STATUS_OS, "Status Indication OS" },
88         { STATUS_PO, "Status Indication PO" },
89         { STATUS_B,  "Status Indication BO" },
90   { 0,         NULL} 
91 };
92
93 static void
94 dissect_mtp2_header(tvbuff_t *su_tvb, proto_item *mtp2_tree)
95 {  
96   guint8 bsn_bib, fsn_fib, li;
97   
98   bsn_bib = tvb_get_guint8(su_tvb, BSN_BIB_OFFSET);
99   fsn_fib = tvb_get_guint8(su_tvb, FSN_FIB_OFFSET);
100   li      = tvb_get_guint8(su_tvb, LI_OFFSET);
101   
102   if (mtp2_tree) {
103     proto_tree_add_uint(mtp2_tree, hf_mtp2_bsn, su_tvb, BSN_BIB_OFFSET, BSN_BIB_LENGTH, bsn_bib);
104     proto_tree_add_uint(mtp2_tree, hf_mtp2_bib, su_tvb, BSN_BIB_OFFSET, BSN_BIB_LENGTH, bsn_bib);
105     proto_tree_add_uint(mtp2_tree, hf_mtp2_fsn, su_tvb, FSN_FIB_OFFSET, FSN_FIB_LENGTH, fsn_fib);
106     proto_tree_add_uint(mtp2_tree, hf_mtp2_fib, su_tvb, FSN_FIB_OFFSET, FSN_FIB_LENGTH, fsn_fib);
107     proto_tree_add_uint(mtp2_tree, hf_mtp2_li, su_tvb, LI_OFFSET, LI_LENGTH, li);
108     proto_tree_add_uint(mtp2_tree, hf_mtp2_spare, su_tvb, LI_OFFSET, LI_LENGTH, li);
109   }
110 }
111
112 static void
113 dissect_mtp2_fisu(packet_info *pinfo)
114 {  
115   if (check_col(pinfo->cinfo, COL_INFO))
116     col_append_str(pinfo->cinfo, COL_INFO, "FISU");
117 }
118
119 static void
120 dissect_mtp2_lssu(tvbuff_t *su_tvb, packet_info *pinfo, proto_item *mtp2_tree)
121 {  
122   guint8  li, sf;
123   guint16 long_sf;
124
125   if (check_col(pinfo->cinfo, COL_INFO))
126     col_append_str(pinfo->cinfo, COL_INFO, "LSSU");
127
128   if (mtp2_tree) {
129     li = tvb_get_guint8(su_tvb, LI_OFFSET);
130     if ((li & LI_MASK) == 1) {
131       sf = tvb_get_guint8(su_tvb, SF_OFFSET);
132       proto_tree_add_uint(mtp2_tree, hf_mtp2_sf, su_tvb, SF_OFFSET, SF_LENGTH, sf);
133     } else {
134       long_sf = tvb_get_letohs(su_tvb, SF_OFFSET);
135       proto_tree_add_uint(mtp2_tree, hf_mtp2_long_sf, su_tvb, SF_OFFSET, LONG_SF_LENGTH, long_sf);
136     }
137   }
138 }
139
140 static void
141 dissect_mtp2_msu(tvbuff_t *su_tvb, packet_info *pinfo, proto_item *mtp2_item, proto_item *tree)
142 {  
143   gint sif_sio_length;
144   tvbuff_t *sif_sio_tvb;
145
146   if ((check_col(pinfo->cinfo, COL_INFO)) && (!proto_is_protocol_enabled(mtp3_proto_id)))
147     col_append_str(pinfo->cinfo, COL_INFO, "MSU");
148     
149   sif_sio_length = tvb_length(su_tvb) - HEADER_LENGTH;
150   sif_sio_tvb = tvb_new_subset(su_tvb, SIO_OFFSET, sif_sio_length, sif_sio_length);
151   call_dissector(mtp3_handle, sif_sio_tvb, pinfo, tree);
152   
153   if (tree)
154     proto_item_set_len(mtp2_item, HEADER_LENGTH);
155
156 }
157
158 static void
159 dissect_mtp2_su(tvbuff_t *su_tvb, packet_info *pinfo, proto_item *mtp2_item, proto_item *mtp2_tree, proto_tree *tree)
160 {
161   guint8 li;
162   
163   dissect_mtp2_header(su_tvb, mtp2_tree);
164   li = tvb_get_guint8(su_tvb, LI_OFFSET);
165   switch(li & LI_MASK) {
166   case 0:
167     dissect_mtp2_fisu(pinfo);
168     break;
169   case 1:
170   case 2:
171     dissect_mtp2_lssu(su_tvb, pinfo, mtp2_tree);
172     break;
173   default:
174     dissect_mtp2_msu(su_tvb, pinfo, mtp2_item, tree);
175     break;
176   }
177 }
178
179 static void
180 dissect_mtp2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
181 {
182   proto_item *mtp2_item = NULL;
183   proto_tree *mtp2_tree = NULL;
184
185   if (check_col(pinfo->cinfo, COL_PROTOCOL))
186     col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP2");
187
188   if (tree) {
189     mtp2_item = proto_tree_add_item(tree, proto_mtp2, tvb, 0, -1, FALSE);
190     mtp2_tree = proto_item_add_subtree(mtp2_item, ett_mtp2);
191   };
192
193   dissect_mtp2_su(tvb, pinfo, mtp2_item, mtp2_tree, tree);
194 }
195
196 void
197 proto_register_mtp2(void)
198 {
199
200   static hf_register_info hf[] = {
201     { &hf_mtp2_bsn,
202       { "Backward sequence number", "mtp2.bsn",
203               FT_UINT8, BASE_DEC, NULL, BSN_MASK,          
204               "", HFILL }
205     },
206     { &hf_mtp2_bib,
207       { "Backward indicator bit", "mtp2.bib",
208               FT_UINT8, BASE_DEC, NULL, BIB_MASK,          
209               "", HFILL }
210     },
211     { &hf_mtp2_fsn,
212       { "Forward sequence number", "mtp2.fsn",
213               FT_UINT8, BASE_DEC, NULL, FSN_MASK,          
214               "", HFILL }
215     },
216     { &hf_mtp2_fib,
217       { "Forward indicator bit", "mtp2.fib",
218               FT_UINT8, BASE_DEC, NULL, FIB_MASK,          
219               "", HFILL }
220     },
221     { &hf_mtp2_li,
222       { "Length Indicator", "mtp2.li",
223               FT_UINT8, BASE_DEC, NULL, LI_MASK,          
224               "", HFILL }
225     },
226     { &hf_mtp2_spare,
227       { "Spare", "mtp2.spare",
228               FT_UINT8, BASE_DEC, NULL, SPARE_MASK,          
229               "", HFILL }
230     },
231     { &hf_mtp2_sf,
232       { "Status field", "mtp2.sf",
233               FT_UINT8, BASE_DEC, VALS(status_field_vals), 0x0,          
234               "", HFILL }
235     },
236     { &hf_mtp2_long_sf,
237       { "Status field", "mtp2.long_sf",
238               FT_UINT16, BASE_HEX, NULL, 0x0,          
239               "", HFILL }
240     }
241   };
242
243   static gint *ett[] = {
244     &ett_mtp2
245   };
246
247   proto_mtp2 = proto_register_protocol("Message Transfer Part Level 2", "MTP2", "mtp2");
248   register_dissector("mtp2", dissect_mtp2, proto_mtp2);
249
250   proto_register_field_array(proto_mtp2, hf, array_length(hf));
251   proto_register_subtree_array(ett, array_length(ett));
252
253 };
254
255 void
256 proto_reg_handoff_mtp2(void)
257 {
258   mtp3_handle   = find_dissector("mtp3");
259   mtp3_proto_id = proto_get_id_by_filter_name("mtp3");
260 }