Put "WTP" into the Info column for segmented invoke/result PDUs on which
[obnox/wireshark/wip.git] / packet-sscop.c
1 /* packet-sscop.c
2  * Routines for SSCOP (Q.2110, Q.SAAL) frame disassembly
3  * Guy Harris <guy@alum.mit.edu>
4  *
5  * $Id: packet-sscop.c,v 1.20 2002/08/28 21:00:35 jmayer Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998
10  *
11  *
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.
16  *
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.
21  *
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <stdio.h>
32 #include <glib.h>
33 #include <string.h>
34 #include <epan/packet.h>
35
36 static int proto_sscop = -1;
37
38 static gint ett_sscop = -1;
39
40 static dissector_handle_t q2931_handle;
41 static dissector_handle_t data_handle;
42
43 /*
44  * See
45  *
46  *      http://www.protocols.com/pbook/atmsig.htm
47  *
48  * for some information on SSCOP, although, alas, not the actual PDU
49  * type values - those I got from the FreeBSD 3.2 ATM code.
50  */
51
52 /*
53  * SSCOP PDU types.
54  */
55 #define SSCOP_TYPE_MASK 0x0f
56
57 #define SSCOP_BGN       0x01    /* Begin */
58 #define SSCOP_BGAK      0x02    /* Begin Acknowledge */
59 #define SSCOP_BGREJ     0x07    /* Begin Reject */
60 #define SSCOP_END       0x03    /* End */
61 #define SSCOP_ENDAK     0x04    /* End Acknowledge */
62 #define SSCOP_RS        0x05    /* Resynchronization */
63 #define SSCOP_RSAK      0x06    /* Resynchronization Acknowledge */
64 #define SSCOP_SD        0x08    /* Sequenced Data */
65 #define SSCOP_SDP       0x09    /* Sequenced Data with Poll */
66 #define SSCOP_POLL      0x0a    /* Status Request */
67 #define SSCOP_STAT      0x0b    /* Solicited Status Response */
68 #define SSCOP_USTAT     0x0c    /* Unsolicited Status Response */
69 #define SSCOP_UD        0x0d    /* Unnumbered Data */
70 #define SSCOP_MD        0x0e    /* Management Data */
71 #define SSCOP_ER        0x09    /* Error Recovery */
72 #define SSCOP_ERAK      0x0f    /* Error Acknowledge */
73
74 #define SSCOP_S         0x10    /* Source bit in End PDU */
75
76 /*
77  * XXX - how to distinguish SDP from ER?
78  */
79 static const value_string sscop_type_vals[] = {
80         { SSCOP_BGN,   "Begin" },
81         { SSCOP_BGAK,  "Begin Acknowledge" },
82         { SSCOP_BGREJ, "Begin Reject" },
83         { SSCOP_END,   "End" },
84         { SSCOP_ENDAK, "End Acknowledge" },
85         { SSCOP_RS,    "Resynchronization" },
86         { SSCOP_RSAK,  "Resynchronization Acknowledge" },
87         { SSCOP_SD,    "Sequenced Data" },
88 #if 0
89         { SSCOP_SDP,   "Sequenced Data with Poll" },
90 #endif
91         { SSCOP_POLL,  "Status Request" },
92         { SSCOP_STAT,  "Solicited Status Response" },
93         { SSCOP_USTAT, "Unsolicited Status Response" },
94         { SSCOP_UD,    "Unnumbered Data" },
95         { SSCOP_MD,    "Management Data" },
96         { SSCOP_ER,    "Error Recovery" },
97         { SSCOP_ERAK,  "Error Acknowledge" },
98         { 0,            NULL }
99 };
100
101 /*
102  * The SSCOP "header" is a trailer, so the "offsets" are computed based
103  * on the length of the packet.
104  */
105
106 /*
107  * PDU type.
108  */
109 #define SSCOP_PDU_TYPE  (reported_length - 4)   /* single byte */
110
111 /*
112  * Begin PDU, Begin Acknowledge PDU (no N(SQ) in it), Resynchronization
113  * PDU, Resynchronization Acknowledge PDU (no N(SQ) in it in Q.SAAL),
114  * Error Recovery PDU, Error Recovery Acknoledge PDU (no N(SQ) in it).
115  */
116 #define SSCOP_N_SQ      (reported_length - 5)   /* One byte */
117 #define SSCOP_N_MR      (reported_length - 4)   /* lower 3 bytes thereof */
118
119 /*
120  * Sequenced Data PDU (no N(PS) in it), Sequenced Data with Poll PDU,
121  * Poll PDU.
122  */
123 #define SSCOP_N_PS      (reported_length - 8)   /* lower 3 bytes thereof */
124 #define SSCOP_N_S       (reported_length - 4)   /* lower 3 bytes thereof */
125
126 /*
127  * Solicited Status PDU, Unsolicited Status PDU (no N(PS) in it).
128  */
129 #define SSCOP_SS_N_PS   (reported_length - 12)  /* lower 3 bytes thereof */
130 #define SSCOP_SS_N_MR   (reported_length - 8)   /* lower 3 bytes thereof */
131 #define SSCOP_SS_N_R    (reported_length - 4)   /* lower 3 bytes thereof */
132
133 static void
134 dissect_sscop(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
135 {
136   guint reported_length;
137   proto_item *ti;
138   proto_tree *sscop_tree = NULL;
139   guint8 sscop_pdu_type;
140   guint8 pdu_type;
141   int pdu_len;
142   int pad_len;
143   tvbuff_t *next_tvb;
144
145   reported_length = tvb_reported_length(tvb);   /* frame length */
146   sscop_pdu_type = tvb_get_guint8(tvb, SSCOP_PDU_TYPE);
147   pdu_type = sscop_pdu_type & SSCOP_TYPE_MASK;
148   if (check_col(pinfo->cinfo, COL_PROTOCOL))
149     col_set_str(pinfo->cinfo, COL_PROTOCOL, "SSCOP");
150   if (check_col(pinfo->cinfo, COL_INFO))
151     col_add_str(pinfo->cinfo, COL_INFO, val_to_str(pdu_type, sscop_type_vals,
152                                         "Unknown PDU type (0x%02x)"));
153
154   /*
155    * Find the length of the PDU and, if there's any payload and
156    * padding, the length of the padding.
157    */
158   switch (pdu_type) {
159
160   case SSCOP_SD:
161     pad_len = (sscop_pdu_type >> 6) & 0x03;
162     pdu_len = 4;
163     break;
164
165   case SSCOP_BGN:
166   case SSCOP_BGAK:
167   case SSCOP_BGREJ:
168   case SSCOP_END:
169   case SSCOP_RS:
170 #if 0
171   case SSCOP_SDP:
172 #endif
173     pad_len = (sscop_pdu_type >> 6) & 0x03;
174     pdu_len = 8;
175     break;
176
177   case SSCOP_UD:
178     pad_len = (sscop_pdu_type >> 6) & 0x03;
179     pdu_len = 4;
180     break;
181
182   default:
183     pad_len = 0;
184     pdu_len = reported_length;  /* No payload, just SSCOP */
185     break;
186   }
187   if (tree) {
188     ti = proto_tree_add_protocol_format(tree, proto_sscop, tvb,
189                                         reported_length - pdu_len,
190                                         pdu_len, "SSCOP");
191     sscop_tree = proto_item_add_subtree(ti, ett_sscop);
192
193     proto_tree_add_text(sscop_tree, tvb, SSCOP_PDU_TYPE, 1,
194                         "PDU Type: %s",
195                         val_to_str(pdu_type, sscop_type_vals,
196                                 "Unknown (0x%02x)"));
197
198     switch (pdu_type) {
199
200     case SSCOP_BGN:
201     case SSCOP_RS:
202     case SSCOP_ER:
203       proto_tree_add_text(sscop_tree, tvb, SSCOP_N_SQ, 1,
204           "N(SQ): %u", tvb_get_guint8(tvb, SSCOP_N_SQ));
205       proto_tree_add_text(sscop_tree, tvb, SSCOP_N_MR + 1, 3,
206           "N(MR): %u", tvb_get_ntohl(tvb, SSCOP_N_MR) & 0xFFFFFF);
207       break;
208
209     case SSCOP_END:
210       proto_tree_add_text(sscop_tree, tvb, SSCOP_PDU_TYPE, 1,
211           "Source: %s", (sscop_pdu_type & SSCOP_S) ? "SSCOP" : "User");
212       break;
213
214     case SSCOP_BGAK:
215     case SSCOP_RSAK:
216       proto_tree_add_text(sscop_tree, tvb, SSCOP_N_MR + 1, 3,
217           "N(MR): %u", tvb_get_ntohl(tvb, SSCOP_N_MR) & 0xFFFFFF);
218       break;
219
220     case SSCOP_ERAK:
221       proto_tree_add_text(sscop_tree, tvb, SSCOP_N_MR + 3, 3,
222           "N(MR): %u", tvb_get_ntohl(tvb, SSCOP_N_MR) & 0xFFFFFF);
223       break;
224
225     case SSCOP_SD:
226       proto_tree_add_text(sscop_tree, tvb, SSCOP_N_S + 1, 3,
227           "N(S): %u", tvb_get_ntohl(tvb, SSCOP_N_S) & 0xFFFFFF);
228       break;
229
230 #if 0
231     case SSCOP_SDP:
232 #endif
233     case SSCOP_POLL:
234       proto_tree_add_text(sscop_tree, tvb, SSCOP_N_PS + 1, 3,
235           "N(PS): %u", tvb_get_ntohl(tvb, SSCOP_N_PS) & 0xFFFFFF);
236       proto_tree_add_text(sscop_tree, tvb, SSCOP_N_S + 1, 3,
237           "N(S): %u", tvb_get_ntohl(tvb, SSCOP_N_S) & 0xFFFFFF);
238       break;
239
240     case SSCOP_STAT:
241       /*
242        * XXX - dissect the list elements....
243        */
244       proto_tree_add_text(sscop_tree, tvb, SSCOP_SS_N_PS + 1, 3,
245           "N(PS): %u", tvb_get_ntohl(tvb, SSCOP_SS_N_PS) & 0xFFFFFF);
246       proto_tree_add_text(sscop_tree, tvb, SSCOP_SS_N_MR + 1, 3,
247           "N(MR): %u", tvb_get_ntohl(tvb, SSCOP_SS_N_MR) & 0xFFFFFF);
248       proto_tree_add_text(sscop_tree, tvb, SSCOP_SS_N_R + 1, 3,
249           "N(R): %u", tvb_get_ntohl(tvb, SSCOP_SS_N_R) & 0xFFFFFF);
250       break;
251
252     case SSCOP_USTAT:
253       /*
254        * XXX - dissect the list elements....
255        */
256       proto_tree_add_text(sscop_tree, tvb, SSCOP_SS_N_MR + 1, 3,
257           "N(MR): %u", tvb_get_ntohl(tvb, SSCOP_SS_N_MR) & 0xFFFFFF);
258       proto_tree_add_text(sscop_tree, tvb, SSCOP_SS_N_R + 1, 3,
259           "N(R): %u", tvb_get_ntohl(tvb, SSCOP_SS_N_R) & 0xFFFFFF);
260       break;
261     }
262   }
263
264   /*
265    * Dissect the payload, if any.
266    *
267    * XXX - what about a Management Data PDU?
268    */
269   switch (pdu_type) {
270
271   case SSCOP_SD:
272   case SSCOP_UD:
273   case SSCOP_BGN:
274   case SSCOP_BGAK:
275   case SSCOP_BGREJ:
276   case SSCOP_END:
277   case SSCOP_RS:
278 #if 0
279   case SSCOP_SDP:
280 #endif
281     if (tree) {
282       proto_tree_add_text(sscop_tree, tvb, SSCOP_PDU_TYPE, 1,
283                         "Pad length: %u", pad_len);
284     }
285
286     /*
287      * Compute length of data in PDU - subtract the trailer length
288      * and the pad length from the reported length.
289      */
290     reported_length -= (pdu_len + pad_len);
291
292     /*
293      * XXX - if more than just Q.2931 uses SSCOP, we need to tell
294      * SSCOP what dissector to use here.
295      */
296     if (reported_length != 0) {
297       /*
298        * We know that we have all of the payload, because we know we have
299        * at least 4 bytes of data after the payload, i.e. the SSCOP trailer.
300        * Therefore, we know that the captured length of the payload is
301        * equal to the length of the payload.
302        */
303       next_tvb = tvb_new_subset(tvb, 0, reported_length, reported_length);
304       if (pdu_type == SSCOP_SD)
305         call_dissector(q2931_handle, next_tvb, pinfo, tree);
306       else
307         call_dissector(data_handle,next_tvb, pinfo, tree);
308     }
309     break;
310   }
311 }
312
313 void
314 proto_register_sscop(void)
315 {
316   static gint *ett[] = {
317     &ett_sscop,
318   };
319   proto_sscop = proto_register_protocol("SSCOP", "SSCOP", "sscop");
320   proto_register_subtree_array(ett, array_length(ett));
321   register_dissector("sscop", dissect_sscop, proto_sscop);
322 }
323
324 void
325 proto_reg_handoff_sscop(void)
326 {
327   /*
328    * Get handle for the Q.2931 dissector.
329    */
330   q2931_handle = find_dissector("q2931");
331   data_handle = find_dissector("data");
332 }