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