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>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
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.
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.
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.
31 #include <epan/packet.h>
32 #include <epan/ipproto.h>
33 #include <epan/prefs.h>
36 * Protocol used by ip.access's nanoBTS/nanoGSM GSM picocells:
38 * http://www.ipaccess.com/en/nanoGSM-picocell
40 * to transport the GSM A-bis interface over TCP and UDP.
44 * http://openbsc.osmocom.org/trac/wiki/nanoBTS
46 * for some information about this protocol determined by reverse-
51 * These ports are also registered for other protocols, as per
53 * http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml
58 * vrml-multi-use 4200-4299
61 * But, as that document says:
63 ************************************************************************
64 * PLEASE NOTE THE FOLLOWING: *
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 ************************************************************************
76 #define IPA_TCP_PORTS "3002,3003,3006,4249,4250,5000"
77 #define IPA_UDP_PORTS "3006"
78 #define IPA_UDP_PORTS_DEFAULT "0"
80 static dissector_handle_t ipa_handle
;
81 static range_t
*global_ipa_tcp_ports
= NULL
;
82 static range_t
*global_ipa_udp_ports
= NULL
;
83 static gboolean global_ipa_in_root
= FALSE
;
84 static gboolean global_ipa_in_info
= FALSE
;
86 /* Initialize the protocol and registered fields */
87 static int proto_ipa
= -1;
88 static int proto_ipaccess
= -1;
90 static int hf_ipa_data_len
= -1;
91 static int hf_ipa_protocol
= -1;
92 static int hf_ipa_hsl_debug
= -1;
93 static int hf_ipa_osmo_proto
= -1;
94 static int hf_ipa_osmo_ctrl_data
= -1;
96 static int hf_ipaccess_msgtype
= -1;
97 static int hf_ipaccess_attr_tag
= -1;
98 static int hf_ipaccess_attr_string
= -1;
100 /* Initialize the subtree pointers */
101 static gint ett_ipa
= -1;
102 static gint ett_ipaccess
= -1;
115 static dissector_handle_t sub_handles
[SUB_MAX
];
116 static dissector_table_t osmo_dissector_table
;
119 #define ABISIP_RSL_MAX 0x20
120 #define HSL_DEBUG 0xdd
121 #define OSMO_EXT 0xee
122 #define IPA_MGCP 0xfc
123 #define AIP_SCCP 0xfd
124 #define ABISIP_IPACCESS 0xfe
125 #define ABISIP_OML 0xff
126 #define IPAC_PROTO_EXT_CTRL 0x00
127 #define IPAC_PROTO_EXT_MGCP 0x01
129 static const value_string ipa_protocol_vals
[] = {
131 { 0xdd, "HSL Debug" },
132 { 0xee, "OSMO EXT" },
133 { 0xfc, "MGCP (old)" },
140 static const value_string ipaccess_msgtype_vals
[] = {
143 { 0x04, "IDENTITY REQUEST" },
144 { 0x05, "IDENTITY RESPONSE" },
145 { 0x06, "IDENTITY ACK" },
146 { 0x07, "IDENTITY NACK" },
147 { 0x08, "PROXY REQUEST" },
148 { 0x09, "PROXY ACK" },
149 { 0x0a, "PROXY NACK" },
153 static const value_string ipaccess_idtag_vals
[] = {
154 { 0x00, "Serial Number" },
155 { 0x01, "Unit Name" },
156 { 0x02, "Location" },
157 { 0x03, "Unit Type" },
158 { 0x04, "Equipment Version" },
159 { 0x05, "Software Version" },
160 { 0x06, "IP Address" },
161 { 0x07, "MAC Address" },
166 static const value_string ipa_osmo_proto_vals
[] = {
176 dissect_ipa_attr(tvbuff_t
*tvb
, int base_offs
, proto_tree
*tree
)
178 guint8 len
, attr_type
;
180 int offset
= base_offs
;
182 while (tvb_reported_length_remaining(tvb
, offset
) > 0) {
183 attr_type
= tvb_get_guint8(tvb
, offset
);
186 case 0x00: /* a string prefixed by its length */
187 len
= tvb_get_guint8(tvb
, offset
+1);
188 proto_tree_add_item(tree
, hf_ipaccess_attr_tag
,
189 tvb
, offset
+2, 1, ENC_BIG_ENDIAN
);
190 proto_tree_add_item(tree
, hf_ipaccess_attr_string
,
191 tvb
, offset
+3, len
-1, ENC_ASCII
|ENC_NA
);
193 case 0x01: /* a single-byte reqest for a certain attr */
195 proto_tree_add_item(tree
, hf_ipaccess_attr_tag
,
196 tvb
, offset
+1, 1, ENC_BIG_ENDIAN
);
200 proto_tree_add_text(tree
, tvb
, offset
+1, 1,
201 "unknown attribute type 0x%02x",
210 /* Dissect an ip.access specific message */
212 dissect_ipaccess(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
215 proto_tree
*ipaccess_tree
;
218 msg_type
= tvb_get_guint8(tvb
, 0);
220 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s ",
221 val_to_str(msg_type
, ipaccess_msgtype_vals
,
224 ti
= proto_tree_add_item(tree
, proto_ipaccess
, tvb
, 0, -1, ENC_NA
);
225 ipaccess_tree
= proto_item_add_subtree(ti
, ett_ipaccess
);
226 proto_tree_add_item(ipaccess_tree
, hf_ipaccess_msgtype
,
227 tvb
, 0, 1, ENC_BIG_ENDIAN
);
231 dissect_ipa_attr(tvb
, 1, ipaccess_tree
);
239 /* Dissect the osmocom extension header */
241 dissect_osmo(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*ipatree
, proto_tree
*tree
)
246 osmo_proto
= tvb_get_guint8(tvb
, 0);
248 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s ",
249 val_to_str(osmo_proto
, ipa_osmo_proto_vals
,
252 proto_tree_add_item(ipatree
, hf_ipa_osmo_proto
,
253 tvb
, 0, 1, ENC_BIG_ENDIAN
);
256 next_tvb
= tvb_new_subset_remaining(tvb
, 1);
258 /* Call any subdissectors that registered for this protocol */
259 if (dissector_try_uint(osmo_dissector_table
, osmo_proto
, next_tvb
, pinfo
, tree
))
262 /* Fallback to the standard MGCP dissector */
263 if (osmo_proto
== IPAC_PROTO_EXT_MGCP
) {
264 call_dissector(sub_handles
[SUB_MGCP
], next_tvb
, pinfo
, tree
);
266 /* Simply display the CTRL data as text */
267 } else if (osmo_proto
== IPAC_PROTO_EXT_CTRL
) {
269 proto_tree_add_item(tree
, hf_ipa_osmo_ctrl_data
, next_tvb
, 0, -1, ENC_ASCII
|ENC_NA
);
274 call_dissector(sub_handles
[SUB_DATA
], next_tvb
, pinfo
, tree
);
281 /* Code to actually dissect the packets */
283 dissect_ipa(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
286 gint header_length
= 3;
289 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "IPA");
290 col_clear(pinfo
->cinfo
, COL_INFO
);
292 while ((remaining
= tvb_reported_length_remaining(tvb
, offset
)) > 0) {
294 proto_tree
*ipa_tree
= NULL
;
295 guint16 len
, msg_type
;
298 len
= tvb_get_ntohs(tvb
, offset
);
299 msg_type
= tvb_get_guint8(tvb
, offset
+2);
301 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s ",
302 val_to_str(msg_type
, ipa_protocol_vals
,
306 * The IPA header is different depending on the transport protocol.
307 * With UDP there seems to be a fourth byte for the IPA header.
308 * We attempt to detect this by checking if the length from the
309 * header + four bytes of the IPA header equals the remaining size.
311 if ((pinfo
->ipproto
== IP_PROTO_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
);
328 next_tvb
= tvb_new_subset(tvb
, offset
+header_length
, len
, len
);
332 /* hand this off to the standard A-bis OML dissector */
333 if (sub_handles
[SUB_OML
])
334 call_dissector(sub_handles
[SUB_OML
], next_tvb
,
337 case ABISIP_IPACCESS
:
338 dissect_ipaccess(next_tvb
, pinfo
, tree
);
341 /* hand this off to the standard SCCP dissector */
342 call_dissector(sub_handles
[SUB_SCCP
], next_tvb
, pinfo
, tree
);
345 /* hand this off to the standard MGCP dissector */
346 call_dissector(sub_handles
[SUB_MGCP
], next_tvb
, pinfo
, tree
);
349 dissect_osmo(next_tvb
, pinfo
, ipa_tree
, tree
);
353 proto_tree_add_item(ipa_tree
, hf_ipa_hsl_debug
,
354 next_tvb
, 0, len
, ENC_ASCII
|ENC_NA
);
355 if (global_ipa_in_root
== TRUE
)
356 proto_tree_add_item(tree
, hf_ipa_hsl_debug
,
357 next_tvb
, 0, len
, ENC_ASCII
|ENC_NA
);
359 if (global_ipa_in_info
== TRUE
)
360 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s ",
361 tvb_get_stringz(wmem_packet_scope(), next_tvb
, 0, NULL
));
364 if (msg_type
< ABISIP_RSL_MAX
) {
365 /* hand this off to the standard A-bis RSL dissector */
366 call_dissector(sub_handles
[SUB_RSL
], next_tvb
, pinfo
, tree
);
370 offset
+= len
+ header_length
;
374 void proto_reg_handoff_gsm_ipa(void);
376 void proto_register_ipa(void)
378 module_t
*ipa_module
;
380 static hf_register_info hf
[] = {
382 {"DataLen", "gsm_ipa.data_len",
383 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
384 "The length of the data (in bytes)", HFILL
}
387 {"Protocol", "gsm_ipa.protocol",
388 FT_UINT8
, BASE_HEX
, VALS(ipa_protocol_vals
), 0x0,
389 "The IPA Sub-Protocol", HFILL
}
392 {"Debug Message", "gsm_ipa.hsl_debug",
393 FT_STRING
, BASE_NONE
, NULL
, 0,
394 "Hay Systems Limited debug message", HFILL
}
397 {"Osmo ext protocol", "gsm_ipa.osmo.protocol",
398 FT_UINT8
, BASE_HEX
, VALS(ipa_osmo_proto_vals
), 0x0,
399 "The osmo extension protocol", HFILL
}
402 {&hf_ipa_osmo_ctrl_data
,
403 {"CTRL data", "gsm_ipa.ctrl.data",
404 FT_STRING
, BASE_NONE
, NULL
, 0x0,
405 "Control interface data", HFILL
}
409 static hf_register_info hf_ipa
[] = {
410 {&hf_ipaccess_msgtype
,
411 {"MessageType", "ipaccess.msg_type",
412 FT_UINT8
, BASE_HEX
, VALS(ipaccess_msgtype_vals
), 0x0,
413 "Type of ip.access messsage", HFILL
}
415 {&hf_ipaccess_attr_tag
,
416 {"Tag", "ipaccess.attr_tag",
417 FT_UINT8
, BASE_HEX
, VALS(ipaccess_idtag_vals
), 0x0,
418 "Attribute Tag", HFILL
}
420 {&hf_ipaccess_attr_string
,
421 {"String", "ipaccess.attr_string",
422 FT_STRING
, BASE_NONE
, NULL
, 0x0,
423 "String attribute", HFILL
}
427 static gint
*ett
[] = {
433 proto_register_protocol("GSM over IP protocol as used by ip.access",
434 "GSM over IP", "gsm_ipa");
436 proto_register_protocol("GSM over IP ip.access CCM sub-protocol",
439 proto_register_field_array(proto_ipa
, hf
, array_length(hf
));
440 proto_register_field_array(proto_ipaccess
, hf_ipa
, array_length(hf_ipa
));
441 proto_register_subtree_array(ett
, array_length(ett
));
443 register_dissector("gsm_ipa", dissect_ipa
, proto_ipa
);
445 /* Register table for subdissectors */
446 osmo_dissector_table
= register_dissector_table("ipa.osmo.protocol",
447 "GSM over IP ip.access Protocol",
451 range_convert_str(&global_ipa_tcp_ports
, IPA_TCP_PORTS
, MAX_TCP_PORT
);
452 range_convert_str(&global_ipa_udp_ports
, IPA_UDP_PORTS_DEFAULT
, MAX_UDP_PORT
);
453 ipa_module
= prefs_register_protocol(proto_ipa
,
454 proto_reg_handoff_gsm_ipa
);
456 prefs_register_range_preference(ipa_module
, "tcp_ports",
457 "GSM IPA TCP Port(s)",
458 "Set the port(s) for ip.access IPA"
459 " (default: " IPA_TCP_PORTS
")",
460 &global_ipa_tcp_ports
, MAX_TCP_PORT
);
461 prefs_register_range_preference(ipa_module
, "udp_ports",
462 "GSM IPA UDP Port(s)",
463 "Set the port(s) for ip.access IPA"
464 " (usually: " IPA_UDP_PORTS
")",
465 &global_ipa_udp_ports
, MAX_UDP_PORT
);
467 prefs_register_bool_preference(ipa_module
, "hsl_debug_in_root_tree",
468 "HSL Debug messages in root protocol tree",
469 NULL
, &global_ipa_in_root
);
470 prefs_register_bool_preference(ipa_module
, "hsl_debug_in_info",
471 "HSL Debug messages in INFO column",
472 NULL
, &global_ipa_in_info
);
475 void proto_reg_handoff_gsm_ipa(void)
477 static gboolean ipa_initialized
= FALSE
;
478 static range_t
*ipa_tcp_ports
, *ipa_udp_ports
;
480 if (!ipa_initialized
) {
481 sub_handles
[SUB_RSL
] = find_dissector("gsm_abis_rsl");
482 sub_handles
[SUB_OML
] = find_dissector("gsm_abis_oml");
483 sub_handles
[SUB_SCCP
] = find_dissector("sccp");
484 sub_handles
[SUB_MGCP
] = find_dissector("mgcp");
485 sub_handles
[SUB_DATA
] = find_dissector("data");
487 ipa_handle
= create_dissector_handle(dissect_ipa
, proto_ipa
);
488 ipa_initialized
= TRUE
;
490 dissector_delete_uint_range("tcp.port", ipa_tcp_ports
, ipa_handle
);
491 g_free(ipa_tcp_ports
);
492 dissector_delete_uint_range("udp.port", ipa_udp_ports
, ipa_handle
);
493 g_free(ipa_udp_ports
);
496 ipa_tcp_ports
= range_copy(global_ipa_tcp_ports
);
497 ipa_udp_ports
= range_copy(global_ipa_udp_ports
);
499 dissector_add_uint_range("udp.port", ipa_udp_ports
, ipa_handle
);
500 dissector_add_uint_range("tcp.port", ipa_tcp_ports
, ipa_handle
);