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