#include <string.h> and/or #include <stdio.h> not needed.
[obnox/wireshark/wip.git] / epan / dissectors / packet-gprs-ns.c
1 /* packet-gprs-ns.c
2  * Routines for GPRS Network Service (ETSI GSM 08.16 version 6.3.0)
3  * dissection
4  * Copyright 2003, Josef Korelus <jkor@quick.cz>
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <glib.h>
32 #include <epan/packet.h>
33
34 /*ETSI  GSM08.16 Network Service */
35 #define NS_UNITDATA     0x00
36 #define NS_RESET        0x02
37 #define NS_RESET_ACK    0x03
38 #define NS_BLOCK        0x04
39 #define NS_BLOCK_ACK    0x05
40 #define NS_UNBLOCK      0x06
41 #define NS_UNBLOCK_ACK  0x07
42 #define NS_STATUS       0x08
43 #define NS_ALIVE        0x0a
44 #define NS_ALIVE_ACK    0x0b
45
46 /*ETSI  GSM 08.16 IEI coding */
47 #define Cause           0x00
48 #define NS_VCI          0x01
49 #define NS_PDU          0x02
50 #define BVCI            0x03
51 #define NSEI            0x04
52
53 static int proto_gprs_ns = -1;
54 static gint ett_gprs_ns = -1;
55 static int hf_gprs_ns_pdutype = -1;
56 static int hf_gprs_ns_ie_type = -1;
57 static int hf_gprs_ns_ie_length = -1;
58 static int hf_gprs_ns_cause = -1;
59 static int hf_gprs_ns_vci = -1;
60 static int hf_gprs_ns_nsei = -1;
61 static int hf_gprs_ns_bvci = -1;
62 static int hf_gprs_ns_spare = -1;
63  
64 static const value_string ns_pdu_type[]= {
65         { NS_UNITDATA,    "NS-UNITDATA" },
66         { NS_RESET,       "NS-RESET" },
67         { NS_RESET_ACK,   "NS-RESET-ACK" },
68         { NS_BLOCK,       "NS-BLOCK" },
69         { NS_BLOCK_ACK,   "NS-BLOCK-ACK" },
70         { NS_UNBLOCK,     "NS-UNBLOCK" },
71         { NS_UNBLOCK_ACK, "NS-UNBLOCK-ACK" },
72         { NS_STATUS,      "NS-STATUS" },
73         { NS_ALIVE,       "NS-ALIVE" },
74         { NS_ALIVE_ACK,   "NS-ALIVE-ACK" },
75         { 0,               NULL },
76 };
77
78 static const value_string ns_ie_type[]= {
79         {  Cause,   "Cause" },
80         {  NS_VCI,  "NS-VCI"},  
81         {  NS_PDU,  "NS PDU"},  
82         {  BVCI,    "BVCI"}, 
83         {  NSEI,    "NSEI"},
84         {  0,        NULL },
85 };
86
87 static const value_string cause_val[]= {
88         { 0x0,    "Transit network failure" },
89         { 0x1,    "O&M intervention" },
90         { 0x2,    "Equipment failure" },
91         { 0x3,    "NS-VC blocked " },
92         { 0x4,    "NS-VC unknown" },
93         { 0x5,    "NS-VC unknown on that NSE" },
94         { 0x8,    "Semantically incorrect PDU" },
95         { 0xa,    "PDU not compatible with protocol state" },
96         { 0xb,    "Protocol error - unspecified" },
97         { 0xc,    "Invalid essential IE" },
98         { 0xd,    "Missing essential IE" },
99         { 0,      NULL },       
100 };
101  
102 static dissector_handle_t bssgp_handle;
103
104 static void
105 process_tlvs(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
106 {
107         guint8 type;
108         int length_len;
109         guint16 length;
110         guint8 cause;
111         guint16 nsvc, bvc, nsei;
112
113         while (tvb_reported_length_remaining(tvb, offset) > 0) {
114                 type = tvb_get_guint8(tvb, offset);
115                 proto_tree_add_uint(tree, hf_gprs_ns_ie_type,
116                     tvb, offset, 1, type);
117                 offset++;
118
119                 length_len = 1;
120                 length = tvb_get_guint8(tvb, offset);
121                 if (length & 0x80) {
122                         /*
123                          * This is the final octet of the length.
124                          */
125                         length &= 0x7F;
126                 } else {
127                         /*
128                          * One more octet.
129                          */
130                         length_len++;
131                         length = (length << 8) | tvb_get_guint8(tvb, offset);
132                 }
133                 proto_tree_add_uint(tree, hf_gprs_ns_ie_length,
134                     tvb, offset, length_len, length);
135                 offset += length_len;
136
137                 switch (type) {
138
139                 case Cause:
140                         if (length == 1) {
141                                 cause = tvb_get_guint8(tvb, offset);
142                                 if (tree) {
143                                         proto_tree_add_uint(tree,
144                                             hf_gprs_ns_cause, tvb, offset, 1,
145                                             cause);
146                                 }
147                                 if (check_col(pinfo->cinfo, COL_INFO)) {
148                                         col_append_fstr(pinfo->cinfo, COL_INFO,
149                                             "  Cause: %s",
150                                             val_to_str(cause, cause_val, "Unknown (0x%02x)"));
151                                 }
152                         } else {
153                                 if (tree) {
154                                         proto_tree_add_text(tree,
155                                             tvb, offset, length,
156                                             "Bad cause length %u, should be 1",
157                                             length);
158                                 }
159                         }
160                         break;
161
162                 case NS_VCI:
163                         if (length == 2) {
164                                 nsvc = tvb_get_ntohs(tvb, offset);
165                                 if (tree) {
166                                         proto_tree_add_uint(tree,
167                                             hf_gprs_ns_vci, tvb, offset, 2,
168                                             nsvc);
169                                 }
170                                 if (check_col(pinfo->cinfo, COL_INFO)) {
171                                         col_append_fstr(pinfo->cinfo, COL_INFO,
172                                             " NSVCI: %u", nsvc);
173                                 }
174                         } else {
175                                 if (tree) {
176                                         proto_tree_add_text(tree,
177                                             tvb, offset, length,
178                                             "Bad NS-VCI length %u, should be 2",
179                                             length);
180                                 }
181                         }
182                         break;
183
184                 case NS_PDU:
185                         /*
186                          * XXX - dissect as a GPRS NS PDU.
187                          * Do the usual "error packet" stuff.
188                          */
189                         if (tree) {
190                                 proto_tree_add_text(tree,
191                                     tvb, offset, length,
192                                     "Error PDU");
193                         }
194                         break;
195
196                 case BVCI:
197                         if (length == 2) {
198                                 bvc = tvb_get_ntohs(tvb, offset);
199                                 if (tree) {
200                                         proto_tree_add_uint(tree,
201                                             hf_gprs_ns_bvci, tvb, offset, 2,
202                                             bvc);
203                                 }
204                                 if (check_col(pinfo->cinfo, COL_INFO)) {
205                                         col_append_fstr(pinfo->cinfo, COL_INFO,
206                                             " BVCI: %u", bvc);
207                                 }
208                         } else {
209                                 if (tree) {
210                                         proto_tree_add_text(tree,
211                                             tvb, offset, length,
212                                             "Bad BVCI length %u, should be 2",
213                                             length);
214                                 }
215                         }
216                         break;
217
218                 case NSEI:
219                         if (length == 2) {
220                                 nsei = tvb_get_ntohs(tvb, offset);
221                                 if (tree) {
222                                         proto_tree_add_uint(tree,
223                                             hf_gprs_ns_nsei, tvb, offset, 2,
224                                             nsei);
225                                 }
226                                 if (check_col(pinfo->cinfo, COL_INFO)) {
227                                         col_append_fstr(pinfo->cinfo, COL_INFO,
228                                             " NSEI: %u", nsei);
229                                 }
230                         } else {
231                                 if (tree) {
232                                         proto_tree_add_text(tree,
233                                             tvb, offset, length,
234                                             "Bad NSEI length %u, should be 2",
235                                             length);
236                                 }
237                         }
238                         break;
239
240                 default:
241                         if (tree) {
242                                 proto_tree_add_text(tree,
243                                     tvb, offset, length,
244                                     "Unknown IE contents");
245                         }
246                         break;
247                 }
248                 offset += length;       
249         }
250 }
251
252 static void
253 dissect_gprs_ns(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
254 {
255         int offset = 0;
256         proto_item *ti = NULL;
257         proto_tree *gprs_ns_tree = NULL;
258         guint8 nspdu;
259         guint16 bvc;
260         tvbuff_t *next_tvb;
261   
262         col_set_str(pinfo->cinfo, COL_PROTOCOL, "GPRS NS");
263         col_clear(pinfo->cinfo, COL_INFO);
264
265         nspdu = tvb_get_guint8(tvb,offset);
266         if (check_col(pinfo->cinfo, COL_INFO)) {
267                 col_add_str(pinfo->cinfo, COL_INFO,
268                     val_to_str(nspdu, ns_pdu_type, "Unknown PDU type (0x%02x)"));
269         }
270         if (tree) {
271                 ti = proto_tree_add_item(tree, proto_gprs_ns, tvb, 0, -1, FALSE);
272                 gprs_ns_tree = proto_item_add_subtree(ti, ett_gprs_ns);
273                 proto_tree_add_uint(gprs_ns_tree, hf_gprs_ns_pdutype, tvb, 0, 1, nspdu);
274         }
275         offset++;
276
277         switch (nspdu) {
278
279         case NS_ALIVE:
280         case NS_ALIVE_ACK:
281         case NS_UNBLOCK:
282         case NS_UNBLOCK_ACK:
283                 break;
284
285         case NS_BLOCK:
286         case NS_BLOCK_ACK:
287         case NS_RESET:
288         case NS_RESET_ACK:
289         case NS_STATUS:
290                 /*
291                  * Process TLVs.
292                  */
293                 process_tlvs(tvb, offset, pinfo, gprs_ns_tree);
294                 break;
295
296         case NS_UNITDATA:
297                 if (tree)
298                         proto_tree_add_item(gprs_ns_tree, hf_gprs_ns_spare, tvb, offset, 1, FALSE);
299                 offset++;
300                 bvc = tvb_get_ntohs(tvb,offset);
301                 if (check_col(pinfo->cinfo, COL_INFO))
302                         col_append_fstr(pinfo->cinfo, COL_INFO, " BVCI: %u", bvc);
303                 if (tree)
304                         proto_tree_add_uint(gprs_ns_tree, hf_gprs_ns_bvci, tvb, offset, 2, bvc);
305                 offset=offset+2;
306                 next_tvb = tvb_new_subset_remaining(tvb, offset);
307                 call_dissector(bssgp_handle, next_tvb, pinfo, tree);
308                 break;
309
310         default:
311                 break;
312         }
313 }
314
315 /* Register the protocol with Wireshark */
316 void
317 proto_register_gprs_ns(void)
318 {
319         static hf_register_info hf[] = {
320                 { &hf_gprs_ns_pdutype, {
321                   "PDU Type", "gprs_ns.pdutype", FT_UINT8, BASE_HEX,
322                   VALS(ns_pdu_type), 0x0, "NS Command", HFILL}},
323                 { &hf_gprs_ns_ie_type, {
324                   "IE Type", "gprs_ns.ietype", FT_UINT8, BASE_HEX,
325                   VALS(ns_ie_type), 0x0, NULL, HFILL}},
326                 { &hf_gprs_ns_ie_length, {
327                   "IE Length", "gprs_ns.ielength", FT_UINT16, BASE_DEC,
328                   NULL, 0x0, NULL, HFILL}},
329                 { &hf_gprs_ns_cause, {
330                   "Cause", "gprs_ns.cause", FT_UINT8, BASE_HEX,
331                   VALS(cause_val), 0x0, NULL, HFILL}},
332                 { &hf_gprs_ns_vci, {
333                   "NSVCI", "gprs_ns.nsvci", FT_UINT16, BASE_DEC,
334                   NULL, 0x0, "Network Service Virtual Connection id", HFILL}},
335                 { &hf_gprs_ns_nsei, {
336                   "NSEI", "gprs_ns.nsei", FT_UINT16, BASE_DEC,
337                   NULL, 0x0, "Network Service Entity Id", HFILL}},
338                 { &hf_gprs_ns_bvci, {
339                   "BVCI", "gprs_ns.bvci", FT_UINT16, BASE_DEC,
340                   NULL, 0x0, "Cell ID", HFILL}},
341                 { &hf_gprs_ns_spare, {
342                   "Spare octet", "gprs_ns.spare", FT_UINT8, BASE_HEX,
343                   NULL, 0x0, NULL, HFILL}},
344         };
345
346         /* Setup protocol subtree array */
347         static gint *ett[] = {
348                  &ett_gprs_ns,
349         };
350
351         proto_gprs_ns = proto_register_protocol("GPRS Network service",
352             "GPRS NS","gprs_ns");
353         proto_register_field_array(proto_gprs_ns, hf, array_length(hf));
354         proto_register_subtree_array(ett, array_length(ett));
355
356         register_dissector("gprs_ns", dissect_gprs_ns, proto_gprs_ns);
357 }
358
359 void
360 proto_reg_handoff_gprs_ns(void)
361 {
362         bssgp_handle = find_dissector("bssgp");
363 }