Ensure that all value_string arrays end in {0, NULL}. Dissectors got away
[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.13 2001/01/03 06:55:33 guy 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  (reported_length - 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      (reported_length - 5)   /* One byte */
119 #define SSCOP_N_MR      (reported_length - 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      (reported_length - 8)   /* lower 3 bytes thereof */
126 #define SSCOP_N_S       (reported_length - 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   (reported_length - 12)  /* lower 3 bytes thereof */
132 #define SSCOP_SS_N_MR   (reported_length - 8)   /* lower 3 bytes thereof */
133 #define SSCOP_SS_N_R    (reported_length - 4)   /* lower 3 bytes thereof */
134
135 void
136 dissect_sscop(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
137 {
138   guint reported_length;
139   proto_item *ti;
140   proto_tree *sscop_tree = NULL;
141   guint8 sscop_pdu_type;
142   guint8 pdu_type;
143   int pdu_len;
144   int pad_len;
145   tvbuff_t *next_tvb;
146
147   CHECK_DISPLAY_AS_DATA(proto_sscop, tvb, pinfo, tree);
148
149   pinfo->current_proto = "SSCOP";
150
151   reported_length = tvb_reported_length(tvb);   /* frame length */
152   sscop_pdu_type = tvb_get_guint8(tvb, SSCOP_PDU_TYPE);
153   pdu_type = sscop_pdu_type & SSCOP_TYPE_MASK;
154   if (check_col(pinfo->fd, COL_PROTOCOL))
155     col_set_str(pinfo->fd, COL_PROTOCOL, "SSCOP");
156   if (check_col(pinfo->fd, COL_INFO))
157     col_add_str(pinfo->fd, COL_INFO, val_to_str(pdu_type, sscop_type_vals,
158                                         "Unknown PDU type (0x%02x)"));
159
160   /*
161    * Find the length of the PDU and, if there's any payload and
162    * padding, the length of the padding.
163    */
164   switch (pdu_type) {
165
166   case SSCOP_SD:
167     pad_len = (sscop_pdu_type >> 6) & 0x03;
168     pdu_len = 4;
169     break;
170
171   case SSCOP_BGN:
172   case SSCOP_BGAK:
173   case SSCOP_BGREJ:
174   case SSCOP_END:
175   case SSCOP_RS:
176 #if 0
177   case SSCOP_SDP:
178 #endif
179     pad_len = (sscop_pdu_type >> 6) & 0x03;
180     pdu_len = 8;
181     break;
182
183   case SSCOP_UD:
184     pad_len = (sscop_pdu_type >> 6) & 0x03;
185     pdu_len = 4;
186     break;
187
188   default:
189     pad_len = 0;
190     pdu_len = reported_length;  /* No payload, just SSCOP */
191     break;
192   }
193   if (tree) {
194     ti = proto_tree_add_protocol_format(tree, proto_sscop, tvb,
195                                         reported_length - pdu_len,
196                                         pdu_len, "SSCOP");
197     sscop_tree = proto_item_add_subtree(ti, ett_sscop);
198
199     proto_tree_add_text(sscop_tree, tvb, 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, tvb, SSCOP_N_SQ, 1,
210           "N(SQ): %u", tvb_get_guint8(tvb, SSCOP_N_SQ));
211       proto_tree_add_text(sscop_tree, tvb, SSCOP_N_MR + 1, 3,
212           "N(MR): %u", tvb_get_ntohl(tvb, SSCOP_N_MR) & 0xFFFFFF);
213       break;
214
215     case SSCOP_END:
216       proto_tree_add_text(sscop_tree, tvb, SSCOP_PDU_TYPE, 1,
217           "Source: %s", (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, tvb, SSCOP_N_MR + 1, 3,
223           "N(MR): %u", tvb_get_ntohl(tvb, SSCOP_N_MR) & 0xFFFFFF);
224       break;
225
226     case SSCOP_ERAK:
227       proto_tree_add_text(sscop_tree, tvb, SSCOP_N_MR + 3, 3,
228           "N(MR): %u", tvb_get_ntohl(tvb, SSCOP_N_MR) & 0xFFFFFF);
229       break;
230
231     case SSCOP_SD:
232       proto_tree_add_text(sscop_tree, tvb, SSCOP_N_S + 1, 3,
233           "N(S): %u", tvb_get_ntohl(tvb, 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, tvb, SSCOP_N_PS + 1, 3,
241           "N(PS): %u", tvb_get_ntohl(tvb, SSCOP_N_PS) & 0xFFFFFF);
242       proto_tree_add_text(sscop_tree, tvb, SSCOP_N_S + 1, 3,
243           "N(S): %u", tvb_get_ntohl(tvb, 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, tvb, SSCOP_SS_N_PS + 1, 3,
251           "N(PS): %u", tvb_get_ntohl(tvb, SSCOP_SS_N_PS) & 0xFFFFFF);
252       proto_tree_add_text(sscop_tree, tvb, SSCOP_SS_N_MR + 1, 3,
253           "N(MR): %u", tvb_get_ntohl(tvb, SSCOP_SS_N_MR) & 0xFFFFFF);
254       proto_tree_add_text(sscop_tree, tvb, SSCOP_SS_N_R + 1, 3,
255           "N(R): %u", tvb_get_ntohl(tvb, 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, tvb, SSCOP_SS_N_MR + 1, 3,
263           "N(MR): %u", tvb_get_ntohl(tvb, SSCOP_SS_N_MR) & 0xFFFFFF);
264       proto_tree_add_text(sscop_tree, tvb, SSCOP_SS_N_R + 1, 3,
265           "N(R): %u", tvb_get_ntohl(tvb, 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, tvb, 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 from the reported length.
295      */
296     reported_length -= (pdu_len + pad_len);
297
298     /*
299      * XXX - if more than just Q.2931 uses SSCOP, we need to tell
300      * SSCOP what dissector to use here.
301      */
302     if (reported_length != 0) {
303       /*
304        * We know that we have all of the payload, because we know we have
305        * at least 4 bytes of data after the payload, i.e. the SSCOP trailer.
306        * Therefore, we know that the captured length of the payload is
307        * equal to the length of the payload.
308        */
309       next_tvb = tvb_new_subset(tvb, 0, reported_length, reported_length);
310       if (pdu_type == SSCOP_SD)
311         dissect_q2931(next_tvb, pinfo, tree);
312       else
313         dissect_data(next_tvb, 0, pinfo, tree);
314     }
315     break;
316   }
317 }
318
319 void
320 proto_register_sscop(void)
321 {
322         static gint *ett[] = {
323                 &ett_sscop,
324         };
325         proto_sscop = proto_register_protocol("SSCOP", "SSCOP", "sscop");
326         proto_register_subtree_array(ett, array_length(ett));
327 }