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