Move 3 ASN1 dissectors to 'clean' group; move 1 PIDL dissector to 'dirty' group.
[metze/wireshark/wip.git] / epan / dissectors / packet-gsm_ipa.c
1 /* packet-gsm_ipa.c
2  * Routines for packet dissection of ip.access GSM A-bis over IP
3  * Copyright 2009 by Harald Welte <laforge@gnumonks.org>
4  * Copyright 2009, 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25  */
26
27 #include "config.h"
28
29 #include <glib.h>
30
31 #include <epan/packet.h>
32 #include <epan/ipproto.h>
33 #include <epan/prefs.h>
34
35 /*
36  * Protocol used by ip.access's nanoBTS/nanoGSM GSM picocells:
37  *
38  *      http://www.ipaccess.com/en/nanoGSM-picocell
39  *
40  * to transport the GSM A-bis interface over TCP and UDP.
41  *
42  * See
43  *
44  *      http://openbsc.osmocom.org/trac/wiki/nanoBTS
45  *
46  * for some information about this protocol determined by reverse-
47  * engineering.
48  */
49
50 /*
51  * These ports are also registered for other protocols, as per
52  *
53  * http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml
54  *
55  * exlm-agent     3002
56  * cgms           3003
57  * ii-admin       3006
58  * vrml-multi-use 4200-4299
59  * commplex-main  5000
60  *
61  * But, as that document says:
62  *
63  ************************************************************************
64  * PLEASE NOTE THE FOLLOWING:                                           *
65  *                                                                      *
66  * ASSIGNMENT OF A PORT NUMBER DOES NOT IN ANY WAY IMPLY AN             *
67  * ENDORSEMENT OF AN APPLICATION OR PRODUCT, AND THE FACT THAT NETWORK  *
68  * TRAFFIC IS FLOWING TO OR FROM A REGISTERED PORT DOES NOT MEAN THAT   *
69  * IT IS "GOOD" TRAFFIC, NOR THAT IT NECESSARILY CORRESPONDS TO THE     *
70  * ASSIGNED SERVICE. FIREWALL AND SYSTEM ADMINISTRATORS SHOULD          *
71  * CHOOSE HOW TO CONFIGURE THEIR SYSTEMS BASED ON THEIR KNOWLEDGE OF    *
72  * THE TRAFFIC IN QUESTION, NOT WHETHER THERE IS A PORT NUMBER          *
73  * REGISTERED OR NOT.                                                   *
74  ************************************************************************
75  */
76 #define IPA_TCP_PORTS "3002,3003,3006,4249,4250,5000"
77 #define IPA_UDP_PORTS "3006"
78
79 static dissector_handle_t ipa_handle;
80 static range_t *global_ipa_tcp_ports = NULL;
81 static range_t *global_ipa_udp_ports = NULL;
82 static gboolean global_ipa_in_root = FALSE;
83 static gboolean global_ipa_in_info = FALSE;
84
85 /* Initialize the protocol and registered fields */
86 static int proto_ipa = -1;
87 static int proto_ipaccess = -1;
88
89 static int hf_ipa_data_len = -1;
90 static int hf_ipa_protocol = -1;
91 static int hf_ipa_hsl_debug = -1;
92 static int hf_ipa_osmo_proto = -1;
93 static int hf_ipa_osmo_ctrl_data = -1;
94
95 static int hf_ipaccess_msgtype = -1;
96 static int hf_ipaccess_attr_tag = -1;
97 static int hf_ipaccess_attr_string = -1;
98
99 /* Initialize the subtree pointers */
100 static gint ett_ipa = -1;
101 static gint ett_ipaccess = -1;
102
103 enum {
104         SUB_OML,
105         SUB_RSL,
106         SUB_SCCP,
107         SUB_MGCP,
108 /*      SUB_IPACCESS, */
109         SUB_DATA,
110
111         SUB_MAX
112 };
113
114 static dissector_handle_t sub_handles[SUB_MAX];
115 static dissector_table_t osmo_dissector_table;
116
117
118 #define ABISIP_RSL_MAX  0x20
119 #define HSL_DEBUG       0xdd
120 #define OSMO_EXT        0xee
121 #define IPA_MGCP        0xfc
122 #define AIP_SCCP        0xfd
123 #define ABISIP_IPACCESS 0xfe
124 #define ABISIP_OML      0xff
125 #define IPAC_PROTO_EXT_CTRL     0x00
126 #define IPAC_PROTO_EXT_MGCP     0x01
127
128 static const value_string ipa_protocol_vals[] = {
129         { 0x00,         "RSL" },
130         { 0xdd,         "HSL Debug" },
131         { 0xee,         "OSMO EXT" },
132         { 0xfc,         "MGCP (old)" },
133         { 0xfd,         "SCCP" },
134         { 0xfe,         "IPA" },
135         { 0xff,         "OML" },
136         { 0,            NULL }
137 };
138
139 static const value_string ipaccess_msgtype_vals[] = {
140         { 0x00,         "PING?" },
141         { 0x01,         "PONG!" },
142         { 0x04,         "IDENTITY REQUEST" },
143         { 0x05,         "IDENTITY RESPONSE" },
144         { 0x06,         "IDENTITY ACK" },
145         { 0x07,         "IDENTITY NACK" },
146         { 0x08,         "PROXY REQUEST" },
147         { 0x09,         "PROXY ACK" },
148         { 0x0a,         "PROXY NACK" },
149         { 0,            NULL }
150 };
151
152 static const value_string ipaccess_idtag_vals[] = {
153         { 0x00,         "Serial Number" },
154         { 0x01,         "Unit Name" },
155         { 0x02,         "Location" },
156         { 0x03,         "Unit Type" },
157         { 0x04,         "Equipment Version" },
158         { 0x05,         "Software Version" },
159         { 0x06,         "IP Address" },
160         { 0x07,         "MAC Address" },
161         { 0x08,         "Unit ID" },
162         { 0,            NULL }
163 };
164
165 static const value_string ipa_osmo_proto_vals[] = {
166         { 0x00,         "CTRL" },
167         { 0x01,         "MGCP" },
168         { 0x02,         "LAC" },
169         { 0x03,         "SMSC" },
170         { 0,            NULL }
171 };
172
173
174 static gint
175 dissect_ipa_attr(tvbuff_t *tvb, int base_offs, proto_tree *tree)
176 {
177         guint8 len, attr_type;
178
179         int offset = base_offs;
180
181         while (tvb_reported_length_remaining(tvb, offset) > 0) {
182                 attr_type = tvb_get_guint8(tvb, offset);
183
184                 switch (attr_type) {
185                 case 0x00:      /* a string prefixed by its length */
186                         len = tvb_get_guint8(tvb, offset+1);
187                         proto_tree_add_item(tree, hf_ipaccess_attr_tag,
188                                             tvb, offset+2, 1, ENC_BIG_ENDIAN);
189                         proto_tree_add_item(tree, hf_ipaccess_attr_string,
190                                             tvb, offset+3, len-1, ENC_ASCII|ENC_NA);
191                         break;
192                 case 0x01:      /* a single-byte reqest for a certain attr */
193                         len = 0;
194                         proto_tree_add_item(tree, hf_ipaccess_attr_tag,
195                                             tvb, offset+1, 1, ENC_BIG_ENDIAN);
196                         break;
197                 default:
198                         len = 0;
199                         proto_tree_add_text(tree, tvb, offset+1, 1,
200                                             "unknown attribute type 0x%02x",
201                                             attr_type);
202                         break;
203                 };
204                 offset += len + 2;
205         };
206         return offset;
207 }
208
209 /* Dissect an ip.access specific message */
210 static gint
211 dissect_ipaccess(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
212 {
213         proto_item *ti;
214         proto_tree *ipaccess_tree;
215         guint8 msg_type;
216
217         msg_type = tvb_get_guint8(tvb, 0);
218
219         col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
220                         val_to_str(msg_type, ipaccess_msgtype_vals,
221                                    "unknown 0x%02x"));
222         if (tree) {
223                 ti = proto_tree_add_item(tree, proto_ipaccess, tvb, 0, -1, ENC_NA);
224                 ipaccess_tree = proto_item_add_subtree(ti, ett_ipaccess);
225                 proto_tree_add_item(ipaccess_tree, hf_ipaccess_msgtype,
226                                     tvb, 0, 1, ENC_BIG_ENDIAN);
227                 switch (msg_type) {
228                 case 4:
229                 case 5:
230                         dissect_ipa_attr(tvb, 1, ipaccess_tree);
231                         break;
232                 }
233         }
234
235         return 1;
236 }
237
238 /* Dissect the osmocom extension header */
239 static gint
240 dissect_osmo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ipatree, proto_tree *tree)
241 {
242         tvbuff_t *next_tvb;
243         guint8 osmo_proto;
244
245         osmo_proto = tvb_get_guint8(tvb, 0);
246
247         col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
248                         val_to_str(osmo_proto, ipa_osmo_proto_vals,
249                                    "unknown 0x%02x"));
250         if (ipatree) {
251                 proto_tree_add_item(ipatree, hf_ipa_osmo_proto,
252                                     tvb, 0, 1, ENC_BIG_ENDIAN);
253         }
254
255         next_tvb = tvb_new_subset_remaining(tvb, 1);
256
257         /* Call any subdissectors that registered for this protocol */
258         if (dissector_try_uint(osmo_dissector_table, osmo_proto, next_tvb, pinfo, tree))
259                 return 1;
260
261         /* Fallback to the standard MGCP dissector */
262         if (osmo_proto == IPAC_PROTO_EXT_MGCP) {
263                 call_dissector(sub_handles[SUB_MGCP], next_tvb, pinfo, tree);
264                 return 1;
265         /* Simply display the CTRL data as text */
266         } else if (osmo_proto == IPAC_PROTO_EXT_CTRL) {
267                 if (tree) {
268                         proto_tree_add_item(tree, hf_ipa_osmo_ctrl_data, next_tvb, 0, -1, ENC_ASCII|ENC_NA);
269                 }
270                 return 1;
271         }
272
273         call_dissector(sub_handles[SUB_DATA], next_tvb, pinfo, tree);
274
275         return 1;
276 }
277
278
279
280 /* Code to actually dissect the packets */
281 static void
282 dissect_ipa(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
283 {
284         gint remaining;
285         gint header_length = 3;
286         int offset = 0;
287
288         col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPA");
289         col_clear(pinfo->cinfo, COL_INFO);
290
291         while ((remaining = tvb_reported_length_remaining(tvb, offset)) > 0) {
292                 proto_item *ti;
293                 proto_tree *ipa_tree = NULL;
294                 guint16 len, msg_type;
295                 tvbuff_t *next_tvb;
296
297                 len = tvb_get_ntohs(tvb, offset);
298                 msg_type = tvb_get_guint8(tvb, offset+2);
299
300                 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
301                                 val_to_str(msg_type, ipa_protocol_vals,
302                                            "unknown 0x%02x"));
303
304                 /*
305                  * The IPA header is different depending on the transport protocol.
306                  * With UDP there seems to be a fourth byte for the IPA header.
307                  * We attempt to detect this by checking if the length from the
308                  * header + four bytes of the IPA header equals the remaining size.
309                  */
310                 if ((pinfo->ipproto == IP_PROTO_UDP) && (len + 4 == remaining)) {
311                         header_length++;
312                 }
313
314                 if (tree) {
315                         ti = proto_tree_add_protocol_format(tree, proto_ipa,
316                                         tvb, offset, len+header_length,
317                                         "IPA protocol ip.access, type: %s",
318                                         val_to_str(msg_type, ipa_protocol_vals,
319                                                    "unknown 0x%02x"));
320                         ipa_tree = proto_item_add_subtree(ti, ett_ipa);
321                         proto_tree_add_item(ipa_tree, hf_ipa_data_len,
322                                             tvb, offset, 2, ENC_BIG_ENDIAN);
323                         proto_tree_add_item(ipa_tree, hf_ipa_protocol,
324                                             tvb, offset+2, 1, ENC_BIG_ENDIAN);
325                 }
326
327                 next_tvb = tvb_new_subset(tvb, offset+header_length, len, len);
328
329                 switch (msg_type) {
330                 case ABISIP_OML:
331                         /* hand this off to the standard A-bis OML dissector */
332                         if (sub_handles[SUB_OML])
333                                 call_dissector(sub_handles[SUB_OML], next_tvb,
334                                                  pinfo, tree);
335                         break;
336                 case ABISIP_IPACCESS:
337                         dissect_ipaccess(next_tvb, pinfo, tree);
338                         break;
339                 case AIP_SCCP:
340                         /* hand this off to the standard SCCP dissector */
341                         call_dissector(sub_handles[SUB_SCCP], next_tvb, pinfo, tree);
342                         break;
343                 case IPA_MGCP:
344                         /* hand this off to the standard MGCP dissector */
345                         call_dissector(sub_handles[SUB_MGCP], next_tvb, pinfo, tree);
346                         break;
347                 case OSMO_EXT:
348                         dissect_osmo(next_tvb, pinfo, ipa_tree, tree);
349                         break;
350                 case HSL_DEBUG:
351                         if (tree) {
352                                 proto_tree_add_item(ipa_tree, hf_ipa_hsl_debug,
353                                                     next_tvb, 0, len, ENC_ASCII|ENC_NA);
354                                 if (global_ipa_in_root == TRUE)
355                                         proto_tree_add_item(tree, hf_ipa_hsl_debug,
356                                                             next_tvb, 0, len, ENC_ASCII|ENC_NA);
357                         }
358                         if (global_ipa_in_info == TRUE)
359                                 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
360                                                 tvb_get_ephemeral_stringz(next_tvb, 0, NULL));
361                         break;
362                 default:
363                         if (msg_type < ABISIP_RSL_MAX) {
364                                 /* hand this off to the standard A-bis RSL dissector */
365                                 call_dissector(sub_handles[SUB_RSL], next_tvb, pinfo, tree);
366                         }
367                         break;
368                 }
369                 offset += len + header_length;
370         }
371 }
372
373 void proto_reg_handoff_gsm_ipa(void);
374
375 void proto_register_ipa(void)
376 {
377         module_t *ipa_module;
378
379         static hf_register_info hf[] = {
380                 {&hf_ipa_data_len,
381                  {"DataLen", "gsm_ipa.data_len",
382                   FT_UINT16, BASE_DEC, NULL, 0x0,
383                   "The length of the data (in bytes)", HFILL}
384                  },
385                 {&hf_ipa_protocol,
386                  {"Protocol", "gsm_ipa.protocol",
387                   FT_UINT8, BASE_HEX, VALS(ipa_protocol_vals), 0x0,
388                   "The IPA Sub-Protocol", HFILL}
389                  },
390                 {&hf_ipa_hsl_debug,
391                  {"Debug Message", "gsm_ipa.hsl_debug",
392                   FT_STRING, BASE_NONE, NULL, 0,
393                   "Hay Systems Limited debug message", HFILL}
394                 },
395                 {&hf_ipa_osmo_proto,
396                  {"Osmo ext protocol", "gsm_ipa.osmo.protocol",
397                   FT_UINT8, BASE_HEX, VALS(ipa_osmo_proto_vals), 0x0,
398                   "The osmo extension protocol", HFILL}
399                 },
400
401                 {&hf_ipa_osmo_ctrl_data,
402                  {"CTRL data", "gsm_ipa.ctrl.data",
403                   FT_STRING, BASE_NONE, NULL, 0x0,
404                   "Control interface data", HFILL}
405                 },
406
407         };
408         static hf_register_info hf_ipa[] = {
409                 {&hf_ipaccess_msgtype,
410                  {"MessageType", "ipaccess.msg_type",
411                   FT_UINT8, BASE_HEX, VALS(ipaccess_msgtype_vals), 0x0,
412                   "Type of ip.access messsage", HFILL}
413                  },
414                 {&hf_ipaccess_attr_tag,
415                  {"Tag", "ipaccess.attr_tag",
416                   FT_UINT8, BASE_HEX, VALS(ipaccess_idtag_vals), 0x0,
417                   "Attribute Tag", HFILL}
418                  },
419                 {&hf_ipaccess_attr_string,
420                  {"String", "ipaccess.attr_string",
421                   FT_STRING, BASE_NONE, NULL, 0x0,
422                   "String attribute", HFILL}
423                  },
424         };
425
426         static gint *ett[] = {
427                 &ett_ipa,
428                 &ett_ipaccess,
429         };
430
431         proto_ipa =
432             proto_register_protocol("GSM over IP protocol as used by ip.access",
433                                     "GSM over IP", "gsm_ipa");
434         proto_ipaccess =
435             proto_register_protocol("GSM over IP ip.access CCM sub-protocol",
436                                     "IPA", "ipaccess");
437
438         proto_register_field_array(proto_ipa, hf, array_length(hf));
439         proto_register_field_array(proto_ipaccess, hf_ipa, array_length(hf_ipa));
440         proto_register_subtree_array(ett, array_length(ett));
441
442         register_dissector("gsm_ipa", dissect_ipa, proto_ipa);
443
444         /* Register table for subdissectors */
445         osmo_dissector_table = register_dissector_table("ipa.osmo.protocol",
446                                         "ip.access Protocol", FT_UINT8, BASE_DEC);
447
448
449         range_convert_str(&global_ipa_tcp_ports, IPA_TCP_PORTS, MAX_TCP_PORT);
450         range_convert_str(&global_ipa_udp_ports, IPA_UDP_PORTS, MAX_UDP_PORT);
451         ipa_module = prefs_register_protocol(proto_ipa,
452                                              proto_reg_handoff_gsm_ipa);
453
454         prefs_register_range_preference(ipa_module, "tcp_ports",
455                                         "GSM IPA TCP Port(s)",
456                                         "Set the port(s) for ip.access IPA"
457                                         " (default: " IPA_TCP_PORTS ")",
458                                         &global_ipa_tcp_ports, MAX_TCP_PORT);
459         prefs_register_range_preference(ipa_module, "udp_ports",
460                                         "GSM IPA UDP Port(s)",
461                                         "Set the port(s) for ip.access IPA"
462                                         " (default: " IPA_UDP_PORTS ")",
463                                         &global_ipa_udp_ports, MAX_UDP_PORT);
464
465         prefs_register_bool_preference(ipa_module, "hsl_debug_in_root_tree",
466                                         "HSL Debug messages in root protocol tree",
467                                         NULL, &global_ipa_in_root);
468         prefs_register_bool_preference(ipa_module, "hsl_debug_in_info",
469                                         "HSL Debug messages in INFO column",
470                                         NULL, &global_ipa_in_info);
471 }
472
473 static void ipa_tcp_delete_callback(guint32 port)
474 {
475         if (port)
476                 dissector_delete_uint("tcp.port", port, ipa_handle);
477 }
478
479 static void ipa_udp_delete_callback(guint32 port)
480 {
481         if (port)
482                 dissector_delete_uint("udp.port", port, ipa_handle);
483 }
484
485 static void ipa_tcp_add_callback(guint32 port)
486 {
487         if (port)
488                 dissector_add_uint("tcp.port", port, ipa_handle);
489 }
490
491 static void ipa_udp_add_callback(guint32 port)
492 {
493         if (port)
494                 dissector_add_uint("udp.port", port, ipa_handle);
495 }
496
497 void proto_reg_handoff_gsm_ipa(void)
498 {
499         static gboolean ipa_initialized = FALSE;
500         static range_t *ipa_tcp_ports, *ipa_udp_ports;
501
502         if (!ipa_initialized) {
503                 sub_handles[SUB_RSL] = find_dissector("gsm_abis_rsl");
504                 sub_handles[SUB_OML] = find_dissector("gsm_abis_oml");
505                 sub_handles[SUB_SCCP] = find_dissector("sccp");
506                 sub_handles[SUB_MGCP] = find_dissector("mgcp");
507                 sub_handles[SUB_DATA] = find_dissector("data");
508
509                 ipa_handle = create_dissector_handle(dissect_ipa, proto_ipa);
510                 ipa_initialized = TRUE;
511         } else {
512                 range_foreach(ipa_tcp_ports, ipa_tcp_delete_callback);
513                 g_free(ipa_tcp_ports);
514                 range_foreach(ipa_udp_ports, ipa_udp_delete_callback);
515                 g_free(ipa_udp_ports);
516         }
517
518         ipa_tcp_ports = range_copy(global_ipa_tcp_ports);
519         ipa_udp_ports = range_copy(global_ipa_udp_ports);
520
521         range_foreach(ipa_tcp_ports, ipa_tcp_add_callback);
522         range_foreach(ipa_udp_ports, ipa_udp_add_callback);
523 }