Squelch an MSVC++ complaint.
[obnox/wireshark/wip.git] / xdlc.c
1 /* xdlc.c
2  * Routines for use by various SDLC-derived protocols, such as HDLC
3  * and its derivatives LAPB, IEEE 802.2 LLC, etc..
4  *
5  * $Id: xdlc.c,v 1.15 2000/05/31 03:58:55 gram Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
9  * Copyright 1998 Gerald Combs
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 <string.h>
37
38 #include <glib.h>
39 #include "packet.h"
40 #include "xdlc.h"
41         
42 /*
43  * N(S) and N(R) fields, in basic and extended operation.
44  */
45 #define XDLC_N_R_MASK           0xE0    /* basic */
46 #define XDLC_N_R_SHIFT          5
47 #define XDLC_N_R_EXT_MASK       0xFE00  /* extended */
48 #define XDLC_N_R_EXT_SHIFT      9
49 #define XDLC_N_S_MASK           0x0E    /* basic */
50 #define XDLC_N_S_SHIFT          1
51 #define XDLC_N_S_EXT_MASK       0x00FE  /* extended */
52 #define XDLC_N_S_EXT_SHIFT      1
53
54 /*
55  * Poll/Final bit, in basic and extended operation.
56  */
57 #define XDLC_P_F        0x10    /* basic */
58 #define XDLC_P_F_EXT    0x0100  /* extended */
59
60 /*
61  * S-format frame types.
62  */
63 #define XDLC_S_FTYPE_MASK       0x0C
64 #define XDLC_RR                 0x00    /* Receiver ready */
65 #define XDLC_RNR                0x04    /* Receiver not ready */
66 #define XDLC_REJ                0x08    /* Reject */
67 #define XDLC_SREJ               0x0C    /* Selective reject */
68
69 static const value_string stype_vals[] = {
70     { XDLC_RR,   "Receiver ready" },
71     { XDLC_RNR,  "Receiver not ready" },
72     { XDLC_REJ,  "Reject" },
73     { XDLC_SREJ, "Selective reject" },
74     { 0,         NULL }
75 };
76
77 static const value_string modifier_short_vals_cmd[] = {
78     { XDLC_UI,    "UI" },
79     { XDLC_UP,    "UP" },
80     { XDLC_DISC,  "DISC" },
81     { XDLC_UA,    "UA" },
82     { XDLC_SNRM,  "SNRM" },
83     { XDLC_SNRME, "SNRME" },
84     { XDLC_TEST,  "TEST" },
85     { XDLC_SIM,   "SIM" },
86     { XDLC_FRMR,  "FRMR" },
87     { XDLC_CFGR,  "CFGR" },
88     { XDLC_SARM,  "SARM" },
89     { XDLC_SABM,  "SABM" },
90     { XDLC_SARME, "SARME" },
91     { XDLC_SABME, "SABME" },
92     { XDLC_RESET, "RESET" },
93     { XDLC_XID,   "XID" },
94     { XDLC_SNRME, "SNRME" },
95     { XDLC_BCN,   "BCN" },
96     { 0,          NULL }
97 };
98
99 static const value_string modifier_vals_cmd[] = {
100     { XDLC_UI,    "Unnumbered Information" },
101     { XDLC_UP,    "Unnumbered Poll" },
102     { XDLC_DISC,  "Disconnect" },
103     { XDLC_UA,    "Unnumbered Acknowledge" },
104     { XDLC_SNRM,  "Set Normal Response Mode" },
105     { XDLC_TEST,  "Test" },
106     { XDLC_SIM,   "Set Initialization Mode" },
107     { XDLC_FRMR,  "Frame reject" },
108     { XDLC_CFGR,  "Configure" },
109     { XDLC_SARM,  "Set Asynchronous Response Mode" },
110     { XDLC_SABM,  "Set Asynchronous Balanced Mode" },
111     { XDLC_SARME, "Set Asynchronous Response Mode Extended" },
112     { XDLC_SABME, "Set Asynchronous Balanced Mode Extended" },
113     { XDLC_RESET, "Reset" },
114     { XDLC_XID,   "Exchange identification" },
115     { XDLC_SNRME, "Set Normal Response Mode Extended" },
116     { XDLC_BCN,   "Beacon" },
117     { 0,          NULL }
118 };
119
120 static const value_string modifier_short_vals_resp[] = {
121     { XDLC_UI,    "UI" },
122     { XDLC_UP,    "UP" },
123     { XDLC_RD,    "RD" },
124     { XDLC_UA,    "UA" },
125     { XDLC_SNRM,  "SNRM" },
126     { XDLC_TEST,  "TEST" },
127     { XDLC_RIM,   "RIM" },
128     { XDLC_FRMR,  "FRMR" },
129     { XDLC_CFGR,  "CFGR" },
130     { XDLC_DM,    "DM" },
131     { XDLC_SABM,  "SABM" },
132     { XDLC_SARME, "SARME" },
133     { XDLC_SABME, "SABME" },
134     { XDLC_RESET, "RESET" },
135     { XDLC_XID,   "XID" },
136     { XDLC_SNRME, "SNRME" },
137     { XDLC_BCN,   "BCN" },
138     { 0,          NULL }
139 };
140
141 static const value_string modifier_vals_resp[] = {
142     { XDLC_UI,    "Unnumbered Information" },
143     { XDLC_UP,    "Unnumbered Poll" },
144     { XDLC_RD,    "Request Disconnect" },
145     { XDLC_UA,    "Unnumbered Acknowledge" },
146     { XDLC_SNRM,  "Set Normal Response Mode" },
147     { XDLC_TEST,  "Test" },
148     { XDLC_RIM,   "Request Initialization Mode" },
149     { XDLC_FRMR,  "Frame reject" },
150     { XDLC_CFGR,  "Configure" },
151     { XDLC_DM,    "Disconnected mode" },
152     { XDLC_SABM,  "Set Asynchronous Balanced Mode" },
153     { XDLC_SARME, "Set Asynchronous Response Mode Extended" },
154     { XDLC_SABME, "Set Asynchronous Balanced Mode Extended" },
155     { XDLC_RESET, "Reset" },
156     { XDLC_XID,   "Exchange identification" },
157     { XDLC_SNRME, "Set Normal Response Mode Extended" },
158     { XDLC_BCN,   "Beacon" },
159     { 0,          NULL }
160 };
161
162 int
163 get_xdlc_control(const u_char *pd, int offset, int is_response, int is_extended)
164 {
165     guint16 control;
166
167     switch (pd[offset] & 0x03) {
168
169     case XDLC_S:
170     default:
171         /*
172          * Supervisory or Information frame.
173          */
174         if (is_extended)
175                 control = pletohs(&pd[offset]);
176         else
177                 control = pd[offset];
178         break;
179
180     case XDLC_U:
181         /*
182          * Unnumbered frame.
183          *
184          * XXX - is this two octets, with a P/F bit, in HDLC extended
185          * operation?  It's one octet in LLC, even though the control
186          * field of I and S frames is a 2-byte extended-operation field
187          * in LLC.  Given that there are no sequence numbers in the
188          * control field of a U frame, there doesn't appear to be any
189          * need for it to be 2 bytes in extended operation.
190          */
191         control = pd[offset];
192         break;
193     }
194     return control;
195 }
196
197 int
198 dissect_xdlc_control(tvbuff_t *tvb, int offset, packet_info *pinfo,
199   proto_tree *xdlc_tree, int hf_xdlc_control, gint ett_xdlc_control,
200   int is_response, int is_extended)
201 {
202     guint16 control;
203     char info[80];
204     proto_tree *tc, *control_tree;
205     gchar *frame_type = NULL;
206     gchar *modifier;
207
208     switch (tvb_get_guint8(tvb, offset) & 0x03) {
209
210     case XDLC_S:
211         /*
212          * Supervisory frame.
213          */
214         if (is_extended)
215                 control = tvb_get_letohs(tvb, offset);
216         else
217                 control = tvb_get_guint8(tvb, offset);
218         switch (control & XDLC_S_FTYPE_MASK) {
219         case XDLC_RR:
220             frame_type = "RR";
221             break;
222
223         case XDLC_RNR:
224             frame_type = "RNR";
225             break;
226
227         case XDLC_REJ:
228             frame_type = "REJ";
229             break;
230
231         case XDLC_SREJ:
232             frame_type = "SREJ";
233             break;
234         }
235         if (is_extended) {
236             sprintf(info, "S%s, %sN(R) = %u", frame_type,
237                         ((control & XDLC_P_F_EXT) ?
238                             (is_response ? "func = F, " : "func = P, ") :
239                             ""),
240                         (control & XDLC_N_R_EXT_MASK) >> XDLC_N_R_EXT_SHIFT);
241         } else {
242             sprintf(info, "S%s, %sN(R) = %u", frame_type,
243                         ((control & XDLC_P_F) ?
244                             (is_response ? "func = F, " : "func = P, ") :
245                             ""),
246                         (control & XDLC_N_R_MASK) >> XDLC_N_R_SHIFT);
247         }
248         if (check_col(pinfo->fd, COL_INFO))
249             col_add_str(pinfo->fd, COL_INFO, info);
250         if (xdlc_tree) {
251             if (is_extended) {
252                 tc = proto_tree_add_uint_format(xdlc_tree, hf_xdlc_control, tvb,
253                         offset, 2,
254                         control,
255                         "Control field: %s (0x%04X)", info, control);
256                 control_tree = proto_item_add_subtree(tc, ett_xdlc_control);
257                 proto_tree_add_text(control_tree, tvb, offset, 2,
258                     decode_numeric_bitfield(control, XDLC_N_R_EXT_MASK, 2*8,
259                         "N(R) = %u"));
260                 if (control & XDLC_P_F_EXT) {
261                     proto_tree_add_text(control_tree, tvb, offset, 2,
262                         decode_boolean_bitfield(control, XDLC_P_F_EXT, 2*8,
263                             (is_response ? "Final" : "Poll"), NULL));
264                 }
265                 proto_tree_add_text(control_tree, tvb, offset, 2,
266                     decode_enumerated_bitfield(control, XDLC_S_FTYPE_MASK, 2*8,
267                         stype_vals, "Supervisory frame - %s"));
268                 /* This will always say it's a supervisory frame */
269                 proto_tree_add_text(control_tree, tvb, offset, 2,
270                     decode_boolean_bitfield(control, 0x03, 2*8,
271                         "Supervisory frame", NULL));
272             } else {
273                 tc = proto_tree_add_uint_format(xdlc_tree, hf_xdlc_control, tvb,
274                         offset, 1,
275                         control,
276                         "Control field: %s (0x%02X)", info, control);
277                 control_tree = proto_item_add_subtree(tc, ett_xdlc_control);
278                 proto_tree_add_text(control_tree, tvb, offset, 1,
279                     decode_numeric_bitfield(control, XDLC_N_R_MASK, 1*8,
280                         "N(R) = %u"));
281                 if (control & XDLC_P_F) {
282                     proto_tree_add_text(control_tree, tvb, offset, 1,
283                         decode_boolean_bitfield(control, XDLC_P_F, 1*8,
284                             (is_response ? "Final" : "Poll"), NULL));
285                 }
286                 proto_tree_add_text(control_tree, tvb, offset, 1,
287                     decode_enumerated_bitfield(control, XDLC_S_FTYPE_MASK, 1*8,
288                         stype_vals, "%s"));
289                 /* This will always say it's a supervisory frame */
290                 proto_tree_add_text(control_tree, tvb, offset, 1,
291                     decode_boolean_bitfield(control, 0x03, 1*8,
292                         "Supervisory frame", NULL));
293             }
294         }
295         break;
296
297     case XDLC_U:
298         /*
299          * Unnumbered frame.
300          *
301          * XXX - is this two octets, with a P/F bit, in HDLC extended
302          * operation?  It's one octet in LLC, even though the control
303          * field of I and S frames is a 2-byte extended-operation field
304          * in LLC.  Given that there are no sequence numbers in the
305          * control field of a U frame, there doesn't appear to be any
306          * need for it to be 2 bytes in extended operation.
307          */
308         control = tvb_get_guint8(tvb, offset);
309         if (is_response) {
310                 modifier = match_strval(control & XDLC_U_MODIFIER_MASK,
311                         modifier_short_vals_resp);
312         } else {
313                 modifier = match_strval(control & XDLC_U_MODIFIER_MASK,
314                         modifier_short_vals_cmd);
315         }
316         if (modifier == NULL)
317                 modifier = "Unknown";
318         sprintf(info, "U%s, func = %s",
319                 ((control & XDLC_P_F) ?
320                     (is_response ? " F" : " P") :
321                     ""),
322                 modifier);
323         if (check_col(pinfo->fd, COL_INFO))
324             col_add_str(pinfo->fd, COL_INFO, info);
325         if (xdlc_tree) {
326             tc = proto_tree_add_uint_format(xdlc_tree, hf_xdlc_control, tvb,
327                         offset, 1,
328                         control,
329                         "Control field: %s (0x%02X)", info, control);
330             control_tree = proto_item_add_subtree(tc, ett_xdlc_control);
331             if (control & XDLC_P_F) {
332                 proto_tree_add_text(control_tree, tvb, offset, 2,
333                     decode_boolean_bitfield(control, XDLC_P_F, 1*8,
334                         (is_response ? "Final" : "Poll"), NULL));
335             }
336             proto_tree_add_text(control_tree, tvb, offset, 1,
337                 decode_enumerated_bitfield(control, XDLC_U_MODIFIER_MASK, 1*8,
338                     (is_response ? modifier_vals_resp : modifier_vals_cmd),
339                     "%s"));
340             /* This will always say it's an unnumbered frame */
341             proto_tree_add_text(control_tree, tvb, offset, 1,
342                 decode_boolean_bitfield(control, 0x03, 1*8,
343                     "Unnumbered frame", NULL));
344         }
345         break;
346
347     default:
348         /*
349          * Information frame.
350          */
351         if (is_extended)
352                 control = tvb_get_letohs(tvb, offset);
353         else
354                 control = tvb_get_guint8(tvb, offset);
355         if (is_extended) {
356             sprintf(info, "I%s, N(R) = %u, N(S) = %u",
357                         ((control & XDLC_P_F_EXT) ? " P" : ""),
358                         (control & XDLC_N_R_EXT_MASK) >> XDLC_N_R_EXT_SHIFT,
359                         (control & XDLC_N_S_EXT_MASK) >> XDLC_N_S_EXT_SHIFT);
360         } else {
361             sprintf(info, "I%s, N(R) = %u, N(S) = %u",
362                         ((control & XDLC_P_F) ? " P" : ""),
363                         (control & XDLC_N_R_MASK) >> XDLC_N_R_SHIFT,
364                         (control & XDLC_N_S_MASK) >> XDLC_N_S_SHIFT);
365         }
366         if (check_col(pinfo->fd, COL_INFO))
367             col_add_str(pinfo->fd, COL_INFO, info);
368         if (xdlc_tree) {
369             tc = proto_tree_add_uint_format(xdlc_tree, hf_xdlc_control, tvb,
370                         offset, (is_extended) ? 2 : 1,
371                         control,
372                         (is_extended) ? "Control field: %s (0x%04X)"
373                                       : "Control field: %s (0x%02X)",
374                         info, control);
375             control_tree = proto_item_add_subtree(tc, ett_xdlc_control);
376             if (is_extended) {
377                 proto_tree_add_text(control_tree, tvb, offset, 2,
378                     decode_numeric_bitfield(control, XDLC_N_R_EXT_MASK, 2*8,
379                                 "N(R) = %u"));
380                 proto_tree_add_text(control_tree, tvb, offset, 2,
381                     decode_numeric_bitfield(control, XDLC_N_S_EXT_MASK, 2*8,
382                                 "N(S) = %u"));
383                 if (control & XDLC_P_F_EXT) {
384                     proto_tree_add_text(control_tree, tvb, offset, 2,
385                         decode_boolean_bitfield(control, XDLC_P_F_EXT, 2*8,
386                                 "Poll", NULL));
387                 }
388                 /* This will always say it's an information frame */
389                 proto_tree_add_text(control_tree, tvb, offset, 2,
390                     decode_boolean_bitfield(control, 0x01, 2*8,
391                         NULL, "Information frame"));
392             } else {
393                 proto_tree_add_text(control_tree, tvb, offset, 1,
394                     decode_numeric_bitfield(control, XDLC_N_R_MASK, 1*8,
395                                 "N(R) = %u"));
396                 proto_tree_add_text(control_tree, tvb, offset, 1,
397                     decode_numeric_bitfield(control, XDLC_N_S_MASK, 1*8,
398                                 "N(S) = %u"));
399                 if (control & XDLC_P_F) {
400                     proto_tree_add_text(control_tree, tvb, offset, 1,
401                         decode_boolean_bitfield(control, XDLC_P_F, 1*8,
402                                 "Poll", NULL));
403                 }
404                 /* This will always say it's an information frame */
405                 proto_tree_add_text(control_tree, tvb, offset, 1,
406                     decode_boolean_bitfield(control, 0x01, 1*8,
407                         NULL, "Information frame"));
408             }
409         }
410     }
411     return control;
412 }