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