HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / dissectors / packet-sscop.c
blob0d8b7b2a1270f8c9eb1aaf7464c18191cd1e6717
1 /* packet-sscop.c
2 * Routines for SSCOP (Q.2110, Q.SAAL) frame disassembly
3 * Guy Harris <guy@alum.mit.edu>
5 * $Id$
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998
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.
27 #include "config.h"
29 #include <glib.h>
30 #include <epan/packet.h>
31 #include <prefs.h>
32 #include "packet-sscop.h"
34 int proto_sscop = -1;
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 },
67 { NULL, NULL, 0 }
70 static guint sscop_payload_dissector = Q2931_DISSECTOR;
71 static dissector_handle_t default_handle;
73 static sscop_info_t sscop_info;
75 * See
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.
84 * SSCOP PDU types.
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" },
119 #if 0
120 { SSCOP_SDP, "Sequenced Data with Poll" },
121 #endif
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" },
129 { 0, NULL }
133 * The SSCOP "header" is a trailer, so the "offsets" are computed based
134 * on the length of the packet.
138 * PDU type.
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,
152 * 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) {
165 gint n,i;
166 proto_item* pi;
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);
178 extern void
179 dissect_sscop_and_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, dissector_handle_t payload_handle)
181 guint reported_length;
182 proto_item *ti;
183 proto_tree *sscop_tree = NULL;
184 guint8 sscop_pdu_type;
185 int pdu_len;
186 int pad_len;
187 tvbuff_t *next_tvb;
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) {
203 case SSCOP_SD:
204 pad_len = (sscop_pdu_type >> 6) & 0x03;
205 pdu_len = 4;
206 break;
208 case SSCOP_BGN:
209 case SSCOP_BGAK:
210 case SSCOP_BGREJ:
211 case SSCOP_END:
212 case SSCOP_RS:
213 #if 0
214 case SSCOP_SDP:
215 #endif
216 pad_len = (sscop_pdu_type >> 6) & 0x03;
217 sscop_info.payload_len = pdu_len = 8;
218 break;
220 case SSCOP_UD:
221 pad_len = (sscop_pdu_type >> 6) & 0x03;
222 sscop_info.payload_len = pdu_len = 4;
223 break;
225 default:
226 pad_len = 0;
227 pdu_len = reported_length; /* No payload, just SSCOP */
228 sscop_info.payload_len = 0;
229 break;
232 if (tree) {
233 ti = proto_tree_add_protocol_format(tree, proto_sscop, tvb,
234 reported_length - pdu_len,
235 pdu_len, "SSCOP");
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) {
242 case SSCOP_BGN:
243 case SSCOP_RS:
244 case SSCOP_ER:
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);
247 break;
249 case SSCOP_END:
250 proto_tree_add_text(sscop_tree, tvb, SSCOP_PDU_TYPE, 1,
251 "Source: %s", (sscop_pdu_type & SSCOP_S) ? "SSCOP" : "User");
252 break;
254 case SSCOP_BGAK:
255 case SSCOP_RSAK:
256 proto_tree_add_item(sscop_tree, hf_sscop_mr, tvb, SSCOP_N_MR + 1, 3, ENC_BIG_ENDIAN);
257 break;
259 case SSCOP_ERAK:
260 proto_tree_add_item(sscop_tree, hf_sscop_mr, tvb, SSCOP_N_MR + 1, 3, ENC_BIG_ENDIAN);
261 break;
263 case SSCOP_SD:
264 proto_tree_add_item(sscop_tree, hf_sscop_s, tvb, SSCOP_N_S + 1, 3, ENC_BIG_ENDIAN);
265 break;
267 #if 0
268 case SSCOP_SDP:
269 #endif
270 case SSCOP_POLL:
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);
273 break;
275 case SSCOP_STAT:
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);
280 break;
282 case SSCOP_USTAT:
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);
286 break;
291 * Dissect the payload, if any.
293 * XXX - what about a Management Data PDU?
295 switch (sscop_info.type) {
297 case SSCOP_SD:
298 case SSCOP_UD:
299 case SSCOP_BGN:
300 case SSCOP_BGAK:
301 case SSCOP_BGREJ:
302 case SSCOP_END:
303 case SSCOP_RS:
304 #if 0
305 case SSCOP_SDP:
306 #endif
307 if (tree) {
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);
330 break;
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);
343 if ( p_sscop_info
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);
351 else
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;
358 if (!initialized) {
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");
365 initialized = TRUE;
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)
375 return TRUE;
376 return FALSE;
379 void
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;
389 } else {
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;
409 void
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 }},
420 #if 0
421 { &hf_sscop_stat_count, { "Number of NACKed pdus", "sscop.stat.count", FT_UINT32, BASE_DEC, NULL, 0x0,NULL, HFILL }}
422 #endif
425 static gint *ett[] = {
426 &ett_sscop,
427 &ett_stat
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);