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>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include <epan/packet.h>
16 #include <epan/prefs.h>
18 void proto_register_ipa(void);
19 void proto_reg_handoff_gsm_ipa(void);
22 * Protocol used by ip.access's nanoBTS/nanoGSM GSM picocells:
24 * http://www.ipaccess.com/en/nanoGSM-picocell
26 * to transport the GSM A-bis interface over TCP and UDP.
30 * http://openbsc.osmocom.org/trac/wiki/nanoBTS
32 * for some information about this protocol determined by reverse-
37 * These ports are also registered for other protocols, as per
39 * http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml
44 * vrml-multi-use 4200-4299
47 * But, as that document says:
49 ************************************************************************
50 * PLEASE NOTE THE FOLLOWING: *
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 ************************************************************************
62 #define IPA_TCP_PORTS "3002,3003,3006,4222,4249,4250,5000"
64 static dissector_handle_t ipa_tcp_handle
;
65 static dissector_handle_t ipa_udp_handle
;
66 static bool global_ipa_in_root
;
67 static bool global_ipa_in_info
;
69 /* Initialize the protocol and registered fields */
71 static int proto_ipaccess
;
73 static int hf_ipa_data_len
;
74 static int hf_ipa_protocol
;
75 static int hf_ipa_hsl_debug
;
76 static int hf_ipa_osmo_proto
;
77 static int hf_ipa_osmo_ctrl_data
;
79 static int hf_ipaccess_msgtype
;
80 static int hf_ipaccess_attr_tag
;
81 static int hf_ipaccess_attr_string
;
82 static int hf_ipaccess_attribute_unk
;
84 /* Initialize the subtree pointers */
86 static int ett_ipaccess
;
99 static dissector_handle_t sub_handles
[SUB_MAX
];
100 static dissector_table_t osmo_dissector_table
;
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 #define IPAC_PROTO_EXT_LAC 0x02
113 #define IPAC_PROTO_EXT_SMSC 0x03
114 #define IPAC_PROTO_EXT_ORC 0x04
115 #define IPAC_PROTO_EXT_GSUP 0x05
116 #define IPAC_PROTO_EXT_OAP 0x06
118 static const value_string ipa_protocol_vals
[] = {
120 { HSL_DEBUG
, "HSL Debug" },
121 { OSMO_EXT
, "OSMO EXT" },
122 { IPA_MGCP
, "MGCP (old)" },
123 { AIP_SCCP
, "SCCP" },
124 { ABISIP_IPACCESS
, "IPA" },
125 { ABISIP_OML
, "OML" },
129 static const value_string ipaccess_msgtype_vals
[] = {
132 { 0x04, "IDENTITY REQUEST" },
133 { 0x05, "IDENTITY RESPONSE" },
134 { 0x06, "IDENTITY ACK" },
135 { 0x07, "IDENTITY NACK" },
136 { 0x08, "PROXY REQUEST" },
137 { 0x09, "PROXY ACK" },
138 { 0x0a, "PROXY NACK" },
139 { 0x0b, "SSL INFO" },
143 static const value_string ipaccess_idtag_vals
[] = {
144 { 0x00, "Serial Number" },
145 { 0x01, "Unit Name" },
146 { 0x02, "Location" },
147 { 0x03, "Unit Type" },
148 { 0x04, "Equipment Version" },
149 { 0x05, "Software Version" },
150 { 0x06, "IP Address" },
151 { 0x07, "MAC Address" },
153 { 0x09, "User Name" },
154 { 0x0a, "Password" },
155 { 0x0b, "Access Class" },
156 { 0x0c, "Application Protocol Version" },
160 static const value_string ipa_osmo_proto_vals
[] = {
173 dissect_ipa_attr(tvbuff_t
*tvb
, int base_offs
, proto_tree
*tree
)
175 uint8_t len
, attr_type
;
177 int offset
= base_offs
;
179 while (tvb_reported_length_remaining(tvb
, offset
) > 0) {
180 attr_type
= tvb_get_uint8(tvb
, offset
);
183 case 0x00: /* a string prefixed by its length */
184 len
= tvb_get_uint8(tvb
, offset
+1);
185 proto_tree_add_item(tree
, hf_ipaccess_attr_tag
,
186 tvb
, offset
+2, 1, ENC_BIG_ENDIAN
);
187 proto_tree_add_item(tree
, hf_ipaccess_attr_string
,
188 tvb
, offset
+3, len
-1, ENC_ASCII
);
190 case 0x01: /* a single-byte request for a certain attr */
192 proto_tree_add_item(tree
, hf_ipaccess_attr_tag
,
193 tvb
, offset
+1, 1, ENC_BIG_ENDIAN
);
197 proto_tree_add_uint(tree
, hf_ipaccess_attribute_unk
, tvb
, offset
+1, 1,
206 /* Dissect an ip.access specific message */
208 dissect_ipaccess(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
211 proto_tree
*ipaccess_tree
;
214 msg_type
= tvb_get_uint8(tvb
, 0);
216 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s ",
217 val_to_str(msg_type
, ipaccess_msgtype_vals
,
219 ti
= proto_tree_add_item(tree
, proto_ipaccess
, tvb
, 0, -1, ENC_NA
);
220 ipaccess_tree
= proto_item_add_subtree(ti
, ett_ipaccess
);
221 proto_tree_add_item(ipaccess_tree
, hf_ipaccess_msgtype
,
222 tvb
, 0, 1, ENC_BIG_ENDIAN
);
226 dissect_ipa_attr(tvb
, 1, ipaccess_tree
);
233 /* Dissect the osmocom extension header */
235 dissect_osmo(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*ipatree
, proto_tree
*tree
, proto_item
*ipa_ti
)
241 osmo_proto
= tvb_get_uint8(tvb
, 0);
242 name
= val_to_str(osmo_proto
, ipa_osmo_proto_vals
, "unknown 0x%02x");
243 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s ", name
);
245 proto_item_append_text(ipa_ti
, " %s", name
);
246 proto_tree_add_item(ipatree
, hf_ipa_osmo_proto
,
247 tvb
, 0, 1, ENC_BIG_ENDIAN
);
250 next_tvb
= tvb_new_subset_remaining(tvb
, 1);
252 /* Call any subdissectors that registered for this protocol */
253 if (dissector_try_uint(osmo_dissector_table
, osmo_proto
, next_tvb
, pinfo
, tree
))
256 /* Fallback to the standard MGCP dissector */
257 if (osmo_proto
== IPAC_PROTO_EXT_MGCP
) {
258 call_dissector(sub_handles
[SUB_MGCP
], next_tvb
, pinfo
, tree
);
260 /* Simply display the CTRL data as text */
261 } else if (osmo_proto
== IPAC_PROTO_EXT_CTRL
) {
262 proto_tree_add_item(tree
, hf_ipa_osmo_ctrl_data
, next_tvb
, 0, -1, ENC_ASCII
);
266 call_dissector(sub_handles
[SUB_DATA
], next_tvb
, pinfo
, tree
);
273 /* Code to actually dissect the packets */
275 dissect_ipa(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, bool is_udp
)
278 int header_length
= 3;
280 uint16_t len
, msg_type
;
282 if (tvb_reported_length(tvb
) < 4)
285 //sanity check the message type
286 msg_type
= tvb_get_uint8(tvb
, 2);
287 if ((try_val_to_str(msg_type
, ipa_protocol_vals
) == NULL
) &&
288 (msg_type
>= ABISIP_RSL_MAX
))
291 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "IPA");
292 col_clear(pinfo
->cinfo
, COL_INFO
);
294 while ((remaining
= tvb_reported_length_remaining(tvb
, offset
)) > 0) {
296 proto_tree
*ipa_tree
= NULL
;
299 len
= tvb_get_ntohs(tvb
, offset
);
300 msg_type
= tvb_get_uint8(tvb
, offset
+2);
302 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s ",
303 val_to_str(msg_type
, ipa_protocol_vals
,
307 * The IPA header is different depending on the transport protocol.
308 * With UDP there seems to be a fourth byte for the IPA header.
309 * We attempt to detect this by checking if the length from the
310 * header + four bytes of the IPA header equals the remaining size.
312 if (is_udp
&& (len
+ 4 == remaining
)) {
316 ti
= proto_tree_add_protocol_format(tree
, proto_ipa
,
317 tvb
, offset
, len
+header_length
,
318 "IPA protocol ip.access, type: %s",
319 val_to_str(msg_type
, ipa_protocol_vals
,
321 ipa_tree
= proto_item_add_subtree(ti
, ett_ipa
);
322 proto_tree_add_item(ipa_tree
, hf_ipa_data_len
,
323 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
324 proto_tree_add_item(ipa_tree
, hf_ipa_protocol
,
325 tvb
, offset
+2, 1, ENC_BIG_ENDIAN
);
327 next_tvb
= tvb_new_subset_length(tvb
, offset
+header_length
, len
);
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
,
336 case ABISIP_IPACCESS
:
337 dissect_ipaccess(next_tvb
, pinfo
, tree
);
340 /* hand this off to the standard SCCP dissector */
341 call_dissector(sub_handles
[SUB_SCCP
], next_tvb
, pinfo
, tree
);
344 /* hand this off to the standard MGCP dissector */
345 call_dissector(sub_handles
[SUB_MGCP
], next_tvb
, pinfo
, tree
);
348 dissect_osmo(next_tvb
, pinfo
, ipa_tree
, tree
, ti
);
351 proto_tree_add_item(ipa_tree
, hf_ipa_hsl_debug
,
352 next_tvb
, 0, len
, ENC_ASCII
);
353 if (global_ipa_in_root
== true)
354 proto_tree_add_item(tree
, hf_ipa_hsl_debug
,
355 next_tvb
, 0, len
, ENC_ASCII
);
356 if (global_ipa_in_info
== true)
357 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s ",
358 tvb_get_stringz_enc(pinfo
->pool
, next_tvb
, 0, NULL
, ENC_ASCII
));
361 if (msg_type
< ABISIP_RSL_MAX
) {
362 /* hand this off to the standard A-bis RSL dissector */
363 call_dissector(sub_handles
[SUB_RSL
], next_tvb
, pinfo
, tree
);
367 offset
+= len
+ header_length
;
374 dissect_ipa_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
376 if (!dissect_ipa(tvb
, pinfo
, tree
, false))
378 return tvb_captured_length(tvb
);
382 dissect_ipa_udp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
384 if (!dissect_ipa(tvb
, pinfo
, tree
, true))
387 return tvb_captured_length(tvb
);
390 void proto_register_ipa(void)
392 module_t
*ipa_module
;
394 static hf_register_info hf
[] = {
396 {"DataLen", "gsm_ipa.data_len",
397 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
398 "The length of the data (in bytes)", HFILL
}
401 {"Protocol", "gsm_ipa.protocol",
402 FT_UINT8
, BASE_HEX
, VALS(ipa_protocol_vals
), 0x0,
403 "The IPA Sub-Protocol", HFILL
}
406 {"Debug Message", "gsm_ipa.hsl_debug",
407 FT_STRING
, BASE_NONE
, NULL
, 0,
408 "Hay Systems Limited debug message", HFILL
}
411 {"Osmo ext protocol", "gsm_ipa.osmo.protocol",
412 FT_UINT8
, BASE_HEX
, VALS(ipa_osmo_proto_vals
), 0x0,
413 "The osmo extension protocol", HFILL
}
416 {&hf_ipa_osmo_ctrl_data
,
417 {"CTRL data", "gsm_ipa.ctrl.data",
418 FT_STRING
, BASE_NONE
, NULL
, 0x0,
419 "Control interface data", HFILL
}
423 static hf_register_info hf_ipa
[] = {
424 {&hf_ipaccess_msgtype
,
425 {"MessageType", "ipaccess.msg_type",
426 FT_UINT8
, BASE_HEX
, VALS(ipaccess_msgtype_vals
), 0x0,
427 "Type of ip.access message", HFILL
}
429 {&hf_ipaccess_attr_tag
,
430 {"Tag", "ipaccess.attr_tag",
431 FT_UINT8
, BASE_HEX
, VALS(ipaccess_idtag_vals
), 0x0,
432 "Attribute Tag", HFILL
}
434 {&hf_ipaccess_attr_string
,
435 {"String", "ipaccess.attr_string",
436 FT_STRING
, BASE_NONE
, NULL
, 0x0,
437 "String attribute", HFILL
}
439 {&hf_ipaccess_attribute_unk
,
440 {"Unknown attribute type", "ipaccess.attr_unk",
441 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
446 static int *ett
[] = {
451 proto_ipa
= proto_register_protocol("GSM over IP protocol as used by ip.access", "GSM over IP", "gsm_ipa");
452 proto_ipaccess
= proto_register_protocol("GSM over IP ip.access CCM sub-protocol", "IPA", "ipaccess");
454 proto_register_field_array(proto_ipa
, hf
, array_length(hf
));
455 proto_register_field_array(proto_ipaccess
, hf_ipa
, array_length(hf_ipa
));
456 proto_register_subtree_array(ett
, array_length(ett
));
458 /* Register table for subdissectors */
459 osmo_dissector_table
= register_dissector_table("ipa.osmo.protocol",
460 "GSM over IP ip.access Protocol", proto_ipa
,
463 ipa_module
= prefs_register_protocol(proto_ipa
, NULL
);
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
);
472 ipa_tcp_handle
= register_dissector("gsm_ipa.tcp", dissect_ipa_tcp
, proto_ipa
);
473 ipa_udp_handle
= register_dissector("gsm_ipa.udp", dissect_ipa_udp
, proto_ipa
);
476 void proto_reg_handoff_gsm_ipa(void)
478 sub_handles
[SUB_RSL
] = find_dissector_add_dependency("gsm_abis_rsl", proto_ipa
);
479 sub_handles
[SUB_OML
] = find_dissector_add_dependency("gsm_abis_oml", proto_ipa
);
480 sub_handles
[SUB_SCCP
] = find_dissector_add_dependency("sccp", proto_ipa
);
481 sub_handles
[SUB_MGCP
] = find_dissector_add_dependency("mgcp", proto_ipa
);
482 sub_handles
[SUB_DATA
] = find_dissector("data");
484 dissector_add_uint_range_with_preference("tcp.port", IPA_TCP_PORTS
, ipa_tcp_handle
);
485 dissector_add_uint_range_with_preference("udp.port", "", ipa_udp_handle
);
489 * Editor modelines - https://www.wireshark.org/tools/modelines.html
494 * indent-tabs-mode: t
497 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
498 * :indentSize=8:tabSize=8:noTabs=false: