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