Include <string.h> to get "strcmp()" declared.
[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.21 2003/09/02 19:18:52 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <string.h>
32
33 #include <glib.h>
34 #include <epan/packet.h>
35 #include "xdlc.h"
36
37 /*
38  * N(S) and N(R) fields, in basic and extended operation.
39  */
40 #define XDLC_N_R_MASK           0xE0    /* basic */
41 #define XDLC_N_R_SHIFT          5
42 #define XDLC_N_R_EXT_MASK       0xFE00  /* extended */
43 #define XDLC_N_R_EXT_SHIFT      9
44 #define XDLC_N_S_MASK           0x0E    /* basic */
45 #define XDLC_N_S_SHIFT          1
46 #define XDLC_N_S_EXT_MASK       0x00FE  /* extended */
47 #define XDLC_N_S_EXT_SHIFT      1
48
49 /*
50  * Poll/Final bit, in basic and extended operation.
51  */
52 #define XDLC_P_F        0x10    /* basic */
53 #define XDLC_P_F_EXT    0x0100  /* extended */
54
55 /*
56  * S-format frame types.
57  */
58 #define XDLC_S_FTYPE_MASK       0x0C
59 #define XDLC_RR                 0x00    /* Receiver ready */
60 #define XDLC_RNR                0x04    /* Receiver not ready */
61 #define XDLC_REJ                0x08    /* Reject */
62 #define XDLC_SREJ               0x0C    /* Selective reject */
63
64 static const value_string stype_vals[] = {
65     { XDLC_RR,   "Receiver ready" },
66     { XDLC_RNR,  "Receiver not ready" },
67     { XDLC_REJ,  "Reject" },
68     { XDLC_SREJ, "Selective reject" },
69     { 0,         NULL }
70 };
71
72 static const value_string modifier_short_vals_cmd[] = {
73     { XDLC_UI,    "UI" },
74     { XDLC_UP,    "UP" },
75     { XDLC_DISC,  "DISC" },
76     { XDLC_UA,    "UA" },
77     { XDLC_SNRM,  "SNRM" },
78     { XDLC_SNRME, "SNRME" },
79     { XDLC_TEST,  "TEST" },
80     { XDLC_SIM,   "SIM" },
81     { XDLC_FRMR,  "FRMR" },
82     { XDLC_CFGR,  "CFGR" },
83     { XDLC_SARM,  "SARM" },
84     { XDLC_SABM,  "SABM" },
85     { XDLC_SARME, "SARME" },
86     { XDLC_SABME, "SABME" },
87     { XDLC_RESET, "RESET" },
88     { XDLC_XID,   "XID" },
89     { XDLC_SNRME, "SNRME" },
90     { XDLC_BCN,   "BCN" },
91     { 0,          NULL }
92 };
93
94 static const value_string modifier_vals_cmd[] = {
95     { XDLC_UI,    "Unnumbered Information" },
96     { XDLC_UP,    "Unnumbered Poll" },
97     { XDLC_DISC,  "Disconnect" },
98     { XDLC_UA,    "Unnumbered Acknowledge" },
99     { XDLC_SNRM,  "Set Normal Response Mode" },
100     { XDLC_TEST,  "Test" },
101     { XDLC_SIM,   "Set Initialization Mode" },
102     { XDLC_FRMR,  "Frame reject" },
103     { XDLC_CFGR,  "Configure" },
104     { XDLC_SARM,  "Set Asynchronous Response Mode" },
105     { XDLC_SABM,  "Set Asynchronous Balanced Mode" },
106     { XDLC_SARME, "Set Asynchronous Response Mode Extended" },
107     { XDLC_SABME, "Set Asynchronous Balanced Mode Extended" },
108     { XDLC_RESET, "Reset" },
109     { XDLC_XID,   "Exchange identification" },
110     { XDLC_SNRME, "Set Normal Response Mode Extended" },
111     { XDLC_BCN,   "Beacon" },
112     { 0,          NULL }
113 };
114
115 static const value_string modifier_short_vals_resp[] = {
116     { XDLC_UI,    "UI" },
117     { XDLC_UP,    "UP" },
118     { XDLC_RD,    "RD" },
119     { XDLC_UA,    "UA" },
120     { XDLC_SNRM,  "SNRM" },
121     { XDLC_TEST,  "TEST" },
122     { XDLC_RIM,   "RIM" },
123     { XDLC_FRMR,  "FRMR" },
124     { XDLC_CFGR,  "CFGR" },
125     { XDLC_DM,    "DM" },
126     { XDLC_SABM,  "SABM" },
127     { XDLC_SARME, "SARME" },
128     { XDLC_SABME, "SABME" },
129     { XDLC_RESET, "RESET" },
130     { XDLC_XID,   "XID" },
131     { XDLC_SNRME, "SNRME" },
132     { XDLC_BCN,   "BCN" },
133     { 0,          NULL }
134 };
135
136 static const value_string modifier_vals_resp[] = {
137     { XDLC_UI,    "Unnumbered Information" },
138     { XDLC_UP,    "Unnumbered Poll" },
139     { XDLC_RD,    "Request Disconnect" },
140     { XDLC_UA,    "Unnumbered Acknowledge" },
141     { XDLC_SNRM,  "Set Normal Response Mode" },
142     { XDLC_TEST,  "Test" },
143     { XDLC_RIM,   "Request Initialization Mode" },
144     { XDLC_FRMR,  "Frame reject" },
145     { XDLC_CFGR,  "Configure" },
146     { XDLC_DM,    "Disconnected mode" },
147     { XDLC_SABM,  "Set Asynchronous Balanced Mode" },
148     { XDLC_SARME, "Set Asynchronous Response Mode Extended" },
149     { XDLC_SABME, "Set Asynchronous Balanced Mode Extended" },
150     { XDLC_RESET, "Reset" },
151     { XDLC_XID,   "Exchange identification" },
152     { XDLC_SNRME, "Set Normal Response Mode Extended" },
153     { XDLC_BCN,   "Beacon" },
154     { 0,          NULL }
155 };
156
157 int
158 get_xdlc_control(const guchar *pd, int offset, int is_extended)
159 {
160     guint16 control;
161
162     switch (pd[offset] & 0x03) {
163
164     case XDLC_S:
165     default:
166         /*
167          * Supervisory or Information frame.
168          */
169         if (is_extended)
170                 control = pletohs(&pd[offset]);
171         else
172                 control = pd[offset];
173         break;
174
175     case XDLC_U:
176         /*
177          * Unnumbered frame.
178          *
179          * XXX - is this two octets, with a P/F bit, in HDLC extended
180          * operation?  It's one octet in LLC, even though the control
181          * field of I and S frames is a 2-byte extended-operation field
182          * in LLC.  Given that there are no sequence numbers in the
183          * control field of a U frame, there doesn't appear to be any
184          * need for it to be 2 bytes in extended operation.
185          */
186         control = pd[offset];
187         break;
188     }
189     return control;
190 }
191
192 int
193 dissect_xdlc_control(tvbuff_t *tvb, int offset, packet_info *pinfo,
194   proto_tree *xdlc_tree, int hf_xdlc_control, gint ett_xdlc_control,
195   int is_response, int is_extended, int append_info)
196 {
197     guint16 control;
198     char info[80];
199     proto_tree *tc, *control_tree;
200     gchar *frame_type = NULL;
201     gchar *modifier;
202
203     switch (tvb_get_guint8(tvb, offset) & 0x03) {
204
205     case XDLC_S:
206         /*
207          * Supervisory frame.
208          */
209         if (is_extended)
210                 control = tvb_get_letohs(tvb, offset);
211         else
212                 control = tvb_get_guint8(tvb, offset);
213         switch (control & XDLC_S_FTYPE_MASK) {
214         case XDLC_RR:
215             frame_type = "RR";
216             break;
217
218         case XDLC_RNR:
219             frame_type = "RNR";
220             break;
221
222         case XDLC_REJ:
223             frame_type = "REJ";
224             break;
225
226         case XDLC_SREJ:
227             frame_type = "SREJ";
228             break;
229         }
230         if (is_extended) {
231             sprintf(info, "S%s, %sN(R) = %u", frame_type,
232                         ((control & XDLC_P_F_EXT) ?
233                             (is_response ? "func = F, " : "func = P, ") :
234                             ""),
235                         (control & XDLC_N_R_EXT_MASK) >> XDLC_N_R_EXT_SHIFT);
236         } else {
237             sprintf(info, "S%s, %sN(R) = %u", frame_type,
238                         ((control & XDLC_P_F) ?
239                             (is_response ? "func = F, " : "func = P, ") :
240                             ""),
241                         (control & XDLC_N_R_MASK) >> XDLC_N_R_SHIFT);
242         }
243         if (check_col(pinfo->cinfo, COL_INFO)) {
244             if (append_info) {
245                 col_append_str(pinfo->cinfo, COL_INFO, ", ");
246                 col_append_str(pinfo->cinfo, COL_INFO, info);
247             } else
248                 col_add_str(pinfo->cinfo, COL_INFO, info);
249         }
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->cinfo, COL_INFO)) {
324             if (append_info) {
325                 col_append_str(pinfo->cinfo, COL_INFO, ", ");
326                 col_append_str(pinfo->cinfo, COL_INFO, info);
327             } else
328                 col_add_str(pinfo->cinfo, COL_INFO, info);
329         }
330         if (xdlc_tree) {
331             tc = proto_tree_add_uint_format(xdlc_tree, hf_xdlc_control, tvb,
332                         offset, 1,
333                         control,
334                         "Control field: %s (0x%02X)", info, control);
335             control_tree = proto_item_add_subtree(tc, ett_xdlc_control);
336             if (control & XDLC_P_F) {
337                 proto_tree_add_text(control_tree, tvb, offset, 2,
338                     decode_boolean_bitfield(control, XDLC_P_F, 1*8,
339                         (is_response ? "Final" : "Poll"), NULL));
340             }
341             proto_tree_add_text(control_tree, tvb, offset, 1,
342                 decode_enumerated_bitfield(control, XDLC_U_MODIFIER_MASK, 1*8,
343                     (is_response ? modifier_vals_resp : modifier_vals_cmd),
344                     "%s"));
345             /* This will always say it's an unnumbered frame */
346             proto_tree_add_text(control_tree, tvb, offset, 1,
347                 decode_boolean_bitfield(control, 0x03, 1*8,
348                     "Unnumbered frame", NULL));
349         }
350         break;
351
352     default:
353         /*
354          * Information frame.
355          */
356         if (is_extended)
357                 control = tvb_get_letohs(tvb, offset);
358         else
359                 control = tvb_get_guint8(tvb, offset);
360         if (is_extended) {
361             sprintf(info, "I%s, N(R) = %u, N(S) = %u",
362                         ((control & XDLC_P_F_EXT) ? " P" : ""),
363                         (control & XDLC_N_R_EXT_MASK) >> XDLC_N_R_EXT_SHIFT,
364                         (control & XDLC_N_S_EXT_MASK) >> XDLC_N_S_EXT_SHIFT);
365         } else {
366             sprintf(info, "I%s, N(R) = %u, N(S) = %u",
367                         ((control & XDLC_P_F) ? " P" : ""),
368                         (control & XDLC_N_R_MASK) >> XDLC_N_R_SHIFT,
369                         (control & XDLC_N_S_MASK) >> XDLC_N_S_SHIFT);
370         }
371         if (check_col(pinfo->cinfo, COL_INFO)) {
372             if (append_info) {
373                 col_append_str(pinfo->cinfo, COL_INFO, ", ");
374                 col_append_str(pinfo->cinfo, COL_INFO, info);
375             } else
376                 col_add_str(pinfo->cinfo, COL_INFO, info);
377         }
378         if (xdlc_tree) {
379             tc = proto_tree_add_uint_format(xdlc_tree, hf_xdlc_control, tvb,
380                         offset, (is_extended) ? 2 : 1,
381                         control,
382                         (is_extended) ? "Control field: %s (0x%04X)"
383                                       : "Control field: %s (0x%02X)",
384                         info, control);
385             control_tree = proto_item_add_subtree(tc, ett_xdlc_control);
386             if (is_extended) {
387                 proto_tree_add_text(control_tree, tvb, offset, 2,
388                     decode_numeric_bitfield(control, XDLC_N_R_EXT_MASK, 2*8,
389                                 "N(R) = %u"));
390                 proto_tree_add_text(control_tree, tvb, offset, 2,
391                     decode_numeric_bitfield(control, XDLC_N_S_EXT_MASK, 2*8,
392                                 "N(S) = %u"));
393                 if (control & XDLC_P_F_EXT) {
394                     proto_tree_add_text(control_tree, tvb, offset, 2,
395                         decode_boolean_bitfield(control, XDLC_P_F_EXT, 2*8,
396                                 "Poll", NULL));
397                 }
398                 /* This will always say it's an information frame */
399                 proto_tree_add_text(control_tree, tvb, offset, 2,
400                     decode_boolean_bitfield(control, 0x01, 2*8,
401                         NULL, "Information frame"));
402             } else {
403                 proto_tree_add_text(control_tree, tvb, offset, 1,
404                     decode_numeric_bitfield(control, XDLC_N_R_MASK, 1*8,
405                                 "N(R) = %u"));
406                 proto_tree_add_text(control_tree, tvb, offset, 1,
407                     decode_numeric_bitfield(control, XDLC_N_S_MASK, 1*8,
408                                 "N(S) = %u"));
409                 if (control & XDLC_P_F) {
410                     proto_tree_add_text(control_tree, tvb, offset, 1,
411                         decode_boolean_bitfield(control, XDLC_P_F, 1*8,
412                                 "Poll", NULL));
413                 }
414                 /* This will always say it's an information frame */
415                 proto_tree_add_text(control_tree, tvb, offset, 1,
416                     decode_boolean_bitfield(control, 0x01, 1*8,
417                         NULL, "Information frame"));
418             }
419         }
420     }
421     return control;
422 }