2 * Routines for SSCOP (Q.2110, Q.SAAL) frame disassembly
3 * Guy Harris <guy@alum.mit.edu>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
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.
30 #include <epan/packet.h>
32 #include "packet-sscop.h"
36 static int hf_sscop_type
= -1;
37 static int hf_sscop_sq
= -1;
38 static int hf_sscop_mr
= -1;
39 static int hf_sscop_s
= -1;
40 static int hf_sscop_ps
= -1;
41 static int hf_sscop_r
= -1;
42 static int hf_sscop_stat_s
= -1;
43 /* static int hf_sscop_stat_count = -1; */
45 static gint ett_sscop
= -1;
46 static gint ett_stat
= -1;
48 static dissector_handle_t q2931_handle
;
49 static dissector_handle_t data_handle
;
50 static dissector_handle_t sscf_nni_handle
;
51 static dissector_handle_t alcap_handle
;
52 static dissector_handle_t nbap_handle
;
54 static module_t
*sscop_module
;
56 static range_t
*global_udp_port_range
;
58 static dissector_handle_t sscop_handle
;
61 static const enum_val_t sscop_payload_dissector_options
[] = {
62 { "data", "Data (no further dissection)", DATA_DISSECTOR
},
63 { "Q.2931", "Q.2931", Q2931_DISSECTOR
},
64 { "SSCF-NNI", "SSCF-NNI (MTP3-b)", SSCF_NNI_DISSECTOR
},
65 { "ALCAP", "ALCAP", ALCAP_DISSECTOR
},
66 { "NBAP", "NBAP", NBAP_DISSECTOR
},
70 static guint sscop_payload_dissector
= Q2931_DISSECTOR
;
71 static dissector_handle_t default_handle
;
73 static sscop_info_t sscop_info
;
77 * http://www.protocols.com/pbook/atmsig.htm
79 * for some information on SSCOP, although, alas, not the actual PDU
80 * type values - those I got from the FreeBSD 3.2 ATM code.
86 #define SSCOP_TYPE_MASK 0x0f
88 #define SSCOP_BGN 0x01 /* Begin */
89 #define SSCOP_BGAK 0x02 /* Begin Acknowledge */
90 #define SSCOP_BGREJ 0x07 /* Begin Reject */
91 #define SSCOP_END 0x03 /* End */
92 #define SSCOP_ENDAK 0x04 /* End Acknowledge */
93 #define SSCOP_RS 0x05 /* Resynchronization */
94 #define SSCOP_RSAK 0x06 /* Resynchronization Acknowledge */
95 #define SSCOP_SD 0x08 /* Sequenced Data */
96 #define SSCOP_SDP 0x09 /* Sequenced Data with Poll */
97 #define SSCOP_POLL 0x0a /* Status Request */
98 #define SSCOP_STAT 0x0b /* Solicited Status Response */
99 #define SSCOP_USTAT 0x0c /* Unsolicited Status Response */
100 #define SSCOP_UD 0x0d /* Unnumbered Data */
101 #define SSCOP_MD 0x0e /* Management Data */
102 #define SSCOP_ER 0x09 /* Error Recovery */
103 #define SSCOP_ERAK 0x0f /* Error Acknowledge */
105 #define SSCOP_S 0x10 /* Source bit in End PDU */
108 * XXX - how to distinguish SDP from ER?
110 static const value_string sscop_type_vals
[] = {
111 { SSCOP_BGN
, "Begin" },
112 { SSCOP_BGAK
, "Begin Acknowledge" },
113 { SSCOP_BGREJ
, "Begin Reject" },
114 { SSCOP_END
, "End" },
115 { SSCOP_ENDAK
, "End Acknowledge" },
116 { SSCOP_RS
, "Resynchronization" },
117 { SSCOP_RSAK
, "Resynchronization Acknowledge" },
118 { SSCOP_SD
, "Sequenced Data" },
120 { SSCOP_SDP
, "Sequenced Data with Poll" },
122 { SSCOP_POLL
, "Status Request" },
123 { SSCOP_STAT
, "Solicited Status Response" },
124 { SSCOP_USTAT
, "Unsolicited Status Response" },
125 { SSCOP_UD
, "Unnumbered Data" },
126 { SSCOP_MD
, "Management Data" },
127 { SSCOP_ER
, "Error Recovery" },
128 { SSCOP_ERAK
, "Error Acknowledge" },
133 * The SSCOP "header" is a trailer, so the "offsets" are computed based
134 * on the length of the packet.
140 #define SSCOP_PDU_TYPE (reported_length - 4) /* single byte */
143 * Begin PDU, Begin Acknowledge PDU (no N(SQ) in it), Resynchronization
144 * PDU, Resynchronization Acknowledge PDU (no N(SQ) in it in Q.SAAL),
145 * Error Recovery PDU, Error Recovery Acknoledge PDU (no N(SQ) in it).
147 #define SSCOP_N_SQ (reported_length - 5) /* One byte */
148 #define SSCOP_N_MR (reported_length - 4) /* lower 3 bytes thereof */
151 * Sequenced Data PDU (no N(PS) in it), Sequenced Data with Poll PDU,
154 #define SSCOP_N_PS (reported_length - 8) /* lower 3 bytes thereof */
155 #define SSCOP_N_S (reported_length - 4) /* lower 3 bytes thereof */
158 * Solicited Status PDU, Unsolicited Status PDU (no N(PS) in it).
160 #define SSCOP_SS_N_PS (reported_length - 12) /* lower 3 bytes thereof */
161 #define SSCOP_SS_N_MR (reported_length - 8) /* lower 3 bytes thereof */
162 #define SSCOP_SS_N_R (reported_length - 4) /* lower 3 bytes thereof */
164 static void dissect_stat_list(proto_tree
*tree
, tvbuff_t
*tvb
,guint h
) {
168 if ((n
= (tvb_reported_length(tvb
))/4 - h
)) {
169 pi
= proto_tree_add_text(tree
,tvb
,0,n
*4,"SD List");
170 tree
= proto_item_add_subtree(pi
,ett_stat
);
172 for (i
= 0; i
< n
; i
++) {
173 proto_tree_add_item(tree
, hf_sscop_stat_s
, tvb
, i
*4 + 1,3,ENC_BIG_ENDIAN
);
179 dissect_sscop_and_payload(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, dissector_handle_t payload_handle
)
181 guint reported_length
;
183 proto_tree
*sscop_tree
= NULL
;
184 guint8 sscop_pdu_type
;
189 reported_length
= tvb_reported_length(tvb
); /* frame length */
190 sscop_pdu_type
= tvb_get_guint8(tvb
, SSCOP_PDU_TYPE
);
191 sscop_info
.type
= sscop_pdu_type
& SSCOP_TYPE_MASK
;
193 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "SSCOP");
194 col_add_str(pinfo
->cinfo
, COL_INFO
, val_to_str(sscop_info
.type
, sscop_type_vals
,
195 "Unknown PDU type (0x%02x)"));
198 * Find the length of the PDU and, if there's any payload and
199 * padding, the length of the padding.
201 switch (sscop_info
.type
) {
204 pad_len
= (sscop_pdu_type
>> 6) & 0x03;
216 pad_len
= (sscop_pdu_type
>> 6) & 0x03;
217 sscop_info
.payload_len
= pdu_len
= 8;
221 pad_len
= (sscop_pdu_type
>> 6) & 0x03;
222 sscop_info
.payload_len
= pdu_len
= 4;
227 pdu_len
= reported_length
; /* No payload, just SSCOP */
228 sscop_info
.payload_len
= 0;
233 ti
= proto_tree_add_protocol_format(tree
, proto_sscop
, tvb
,
234 reported_length
- pdu_len
,
236 sscop_tree
= proto_item_add_subtree(ti
, ett_sscop
);
238 proto_tree_add_item(sscop_tree
, hf_sscop_type
, tvb
, SSCOP_PDU_TYPE
, 1,ENC_BIG_ENDIAN
);
240 switch (sscop_info
.type
) {
245 proto_tree_add_item(sscop_tree
, hf_sscop_sq
, tvb
, SSCOP_N_SQ
, 1,ENC_BIG_ENDIAN
);
246 proto_tree_add_item(sscop_tree
, hf_sscop_mr
, tvb
, SSCOP_N_MR
+ 1, 3, ENC_BIG_ENDIAN
);
250 proto_tree_add_text(sscop_tree
, tvb
, SSCOP_PDU_TYPE
, 1,
251 "Source: %s", (sscop_pdu_type
& SSCOP_S
) ? "SSCOP" : "User");
256 proto_tree_add_item(sscop_tree
, hf_sscop_mr
, tvb
, SSCOP_N_MR
+ 1, 3, ENC_BIG_ENDIAN
);
260 proto_tree_add_item(sscop_tree
, hf_sscop_mr
, tvb
, SSCOP_N_MR
+ 1, 3, ENC_BIG_ENDIAN
);
264 proto_tree_add_item(sscop_tree
, hf_sscop_s
, tvb
, SSCOP_N_S
+ 1, 3, ENC_BIG_ENDIAN
);
271 proto_tree_add_item(sscop_tree
, hf_sscop_ps
, tvb
, SSCOP_N_PS
+ 1, 3,ENC_BIG_ENDIAN
);
272 proto_tree_add_item(sscop_tree
, hf_sscop_s
, tvb
, SSCOP_N_S
+ 1, 3,ENC_BIG_ENDIAN
);
276 proto_tree_add_item(sscop_tree
, hf_sscop_ps
, tvb
, SSCOP_SS_N_PS
+ 1, 3,ENC_BIG_ENDIAN
);
277 proto_tree_add_item(sscop_tree
, hf_sscop_mr
, tvb
, SSCOP_SS_N_MR
+ 1, 3, ENC_BIG_ENDIAN
);
278 proto_tree_add_item(sscop_tree
, hf_sscop_r
, tvb
, SSCOP_SS_N_R
+ 1, 3,ENC_BIG_ENDIAN
);
279 dissect_stat_list(sscop_tree
,tvb
,3);
283 proto_tree_add_item(sscop_tree
, hf_sscop_mr
, tvb
, SSCOP_SS_N_MR
+ 1, 3, ENC_BIG_ENDIAN
);
284 proto_tree_add_item(sscop_tree
, hf_sscop_r
, tvb
, SSCOP_SS_N_R
+ 1, 3,ENC_BIG_ENDIAN
);
285 dissect_stat_list(sscop_tree
,tvb
,2);
291 * Dissect the payload, if any.
293 * XXX - what about a Management Data PDU?
295 switch (sscop_info
.type
) {
308 proto_tree_add_text(sscop_tree
, tvb
, SSCOP_PDU_TYPE
, 1,
309 "Pad length: %u", pad_len
);
313 * Compute length of data in PDU - subtract the trailer length
314 * and the pad length from the reported length.
316 reported_length
-= (pdu_len
+ pad_len
);
318 if (reported_length
!= 0) {
320 * We know that we have all of the payload, because we know we have
321 * at least 4 bytes of data after the payload, i.e. the SSCOP trailer.
322 * Therefore, we know that the captured length of the payload is
323 * equal to the length of the payload.
325 next_tvb
= tvb_new_subset(tvb
, 0, reported_length
, reported_length
);
326 if (sscop_info
.type
== SSCOP_SD
)
328 call_dissector(payload_handle
, next_tvb
, pinfo
, tree
);
335 static void dissect_sscop(tvbuff_t
* tvb
, packet_info
* pinfo
,proto_tree
* tree
)
337 struct _sscop_payload_info
*p_sscop_info
;
338 dissector_handle_t subdissector
;
340 /* Look for packet info for subdissector information */
341 p_sscop_info
= (struct _sscop_payload_info
*)p_get_proto_data(pinfo
->fd
, proto_sscop
, 0);
344 && ( subdissector
= p_sscop_info
->subdissector
)
345 && ( subdissector
== data_handle
346 || subdissector
== q2931_handle
347 || subdissector
== sscf_nni_handle
348 || subdissector
== alcap_handle
349 || subdissector
== nbap_handle
) )
350 dissect_sscop_and_payload(tvb
,pinfo
,tree
,subdissector
);
352 dissect_sscop_and_payload(tvb
,pinfo
,tree
,default_handle
);
355 /* Make sure handles for various protocols are initialized */
356 static void initialize_handles_once(void) {
357 static gboolean initialized
= FALSE
;
359 q2931_handle
= find_dissector("q2931");
360 data_handle
= find_dissector("data");
361 sscf_nni_handle
= find_dissector("sscf-nni");
362 alcap_handle
= find_dissector("alcap");
363 nbap_handle
= find_dissector("nbap");
369 gboolean
sscop_allowed_subdissector(dissector_handle_t handle
)
371 initialize_handles_once();
372 if (handle
== q2931_handle
|| handle
== data_handle
373 || handle
== sscf_nni_handle
|| handle
== alcap_handle
374 || handle
== nbap_handle
)
380 proto_reg_handoff_sscop(void)
382 static gboolean prefs_initialized
= FALSE
;
383 static range_t
*udp_port_range
;
385 if (!prefs_initialized
) {
386 initialize_handles_once();
387 prefs_initialized
= TRUE
;
391 dissector_delete_uint_range("udp.port", udp_port_range
, sscop_handle
);
392 g_free(udp_port_range
);
396 udp_port_range
= range_copy(global_udp_port_range
);
397 dissector_add_uint_range("udp.port", udp_port_range
, sscop_handle
);
399 switch(sscop_payload_dissector
) {
400 case DATA_DISSECTOR
: default_handle
= data_handle
; break;
401 case Q2931_DISSECTOR
: default_handle
= q2931_handle
; break;
402 case SSCF_NNI_DISSECTOR
: default_handle
= sscf_nni_handle
; break;
403 case ALCAP_DISSECTOR
: default_handle
= alcap_handle
; break;
404 case NBAP_DISSECTOR
: default_handle
= nbap_handle
; break;
410 proto_register_sscop(void)
412 static hf_register_info hf
[] = {
413 { &hf_sscop_type
, { "PDU Type", "sscop.type", FT_UINT8
, BASE_HEX
, VALS(sscop_type_vals
), SSCOP_TYPE_MASK
, NULL
, HFILL
}},
414 { &hf_sscop_sq
, { "N(SQ)", "sscop.sq", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
415 { &hf_sscop_mr
, { "N(MR)", "sscop.mr", FT_UINT24
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
416 { &hf_sscop_s
, { "N(S)", "sscop.s", FT_UINT24
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
417 { &hf_sscop_ps
, { "N(PS)", "sscop.ps", FT_UINT24
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
418 { &hf_sscop_r
, { "N(R)", "sscop.r", FT_UINT24
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
419 { &hf_sscop_stat_s
, { "N(S)", "sscop.stat.s", FT_UINT24
, BASE_DEC
, NULL
, 0x0,NULL
, HFILL
}},
421 { &hf_sscop_stat_count
, { "Number of NACKed pdus", "sscop.stat.count", FT_UINT32
, BASE_DEC
, NULL
, 0x0,NULL
, HFILL
}}
425 static gint
*ett
[] = {
430 proto_sscop
= proto_register_protocol("SSCOP", "SSCOP", "sscop");
431 proto_register_field_array(proto_sscop
, hf
, array_length(hf
));
432 proto_register_subtree_array(ett
, array_length(ett
));
434 sscop_handle
= register_dissector("sscop", dissect_sscop
, proto_sscop
);
436 sscop_module
= prefs_register_protocol(proto_sscop
, proto_reg_handoff_sscop
);
438 global_udp_port_range
= range_empty();
440 prefs_register_range_preference(sscop_module
, "udp.ports",
441 "SSCOP UDP port range",
442 "Set the UDP port for SSCOP messages encapsulated in UDP (0 to disable)",
443 &global_udp_port_range
, MAX_UDP_PORT
);
445 prefs_register_enum_preference(sscop_module
, "payload",
446 "SSCOP payload protocol",
447 "SSCOP payload (dissector to call on SSCOP payload)",
448 (gint
*)&sscop_payload_dissector
,
449 sscop_payload_dissector_options
, FALSE
);