From Chris Waters: export "find_dissector_table()" and add
[metze/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.20 2002/08/28 21:00:41 jmayer 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)
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             col_add_str(pinfo->cinfo, COL_INFO, info);
245         if (xdlc_tree) {
246             if (is_extended) {
247                 tc = proto_tree_add_uint_format(xdlc_tree, hf_xdlc_control, tvb,
248                         offset, 2,
249                         control,
250                         "Control field: %s (0x%04X)", info, control);
251                 control_tree = proto_item_add_subtree(tc, ett_xdlc_control);
252                 proto_tree_add_text(control_tree, tvb, offset, 2,
253                     decode_numeric_bitfield(control, XDLC_N_R_EXT_MASK, 2*8,
254                         "N(R) = %u"));
255                 if (control & XDLC_P_F_EXT) {
256                     proto_tree_add_text(control_tree, tvb, offset, 2,
257                         decode_boolean_bitfield(control, XDLC_P_F_EXT, 2*8,
258                             (is_response ? "Final" : "Poll"), NULL));
259                 }
260                 proto_tree_add_text(control_tree, tvb, offset, 2,
261                     decode_enumerated_bitfield(control, XDLC_S_FTYPE_MASK, 2*8,
262                         stype_vals, "Supervisory frame - %s"));
263                 /* This will always say it's a supervisory frame */
264                 proto_tree_add_text(control_tree, tvb, offset, 2,
265                     decode_boolean_bitfield(control, 0x03, 2*8,
266                         "Supervisory frame", NULL));
267             } else {
268                 tc = proto_tree_add_uint_format(xdlc_tree, hf_xdlc_control, tvb,
269                         offset, 1,
270                         control,
271                         "Control field: %s (0x%02X)", info, control);
272                 control_tree = proto_item_add_subtree(tc, ett_xdlc_control);
273                 proto_tree_add_text(control_tree, tvb, offset, 1,
274                     decode_numeric_bitfield(control, XDLC_N_R_MASK, 1*8,
275                         "N(R) = %u"));
276                 if (control & XDLC_P_F) {
277                     proto_tree_add_text(control_tree, tvb, offset, 1,
278                         decode_boolean_bitfield(control, XDLC_P_F, 1*8,
279                             (is_response ? "Final" : "Poll"), NULL));
280                 }
281                 proto_tree_add_text(control_tree, tvb, offset, 1,
282                     decode_enumerated_bitfield(control, XDLC_S_FTYPE_MASK, 1*8,
283                         stype_vals, "%s"));
284                 /* This will always say it's a supervisory frame */
285                 proto_tree_add_text(control_tree, tvb, offset, 1,
286                     decode_boolean_bitfield(control, 0x03, 1*8,
287                         "Supervisory frame", NULL));
288             }
289         }
290         break;
291
292     case XDLC_U:
293         /*
294          * Unnumbered frame.
295          *
296          * XXX - is this two octets, with a P/F bit, in HDLC extended
297          * operation?  It's one octet in LLC, even though the control
298          * field of I and S frames is a 2-byte extended-operation field
299          * in LLC.  Given that there are no sequence numbers in the
300          * control field of a U frame, there doesn't appear to be any
301          * need for it to be 2 bytes in extended operation.
302          */
303         control = tvb_get_guint8(tvb, offset);
304         if (is_response) {
305                 modifier = match_strval(control & XDLC_U_MODIFIER_MASK,
306                         modifier_short_vals_resp);
307         } else {
308                 modifier = match_strval(control & XDLC_U_MODIFIER_MASK,
309                         modifier_short_vals_cmd);
310         }
311         if (modifier == NULL)
312                 modifier = "Unknown";
313         sprintf(info, "U%s, func = %s",
314                 ((control & XDLC_P_F) ?
315                     (is_response ? " F" : " P") :
316                     ""),
317                 modifier);
318         if (check_col(pinfo->cinfo, COL_INFO))
319             col_add_str(pinfo->cinfo, COL_INFO, info);
320         if (xdlc_tree) {
321             tc = proto_tree_add_uint_format(xdlc_tree, hf_xdlc_control, tvb,
322                         offset, 1,
323                         control,
324                         "Control field: %s (0x%02X)", info, control);
325             control_tree = proto_item_add_subtree(tc, ett_xdlc_control);
326             if (control & XDLC_P_F) {
327                 proto_tree_add_text(control_tree, tvb, offset, 2,
328                     decode_boolean_bitfield(control, XDLC_P_F, 1*8,
329                         (is_response ? "Final" : "Poll"), NULL));
330             }
331             proto_tree_add_text(control_tree, tvb, offset, 1,
332                 decode_enumerated_bitfield(control, XDLC_U_MODIFIER_MASK, 1*8,
333                     (is_response ? modifier_vals_resp : modifier_vals_cmd),
334                     "%s"));
335             /* This will always say it's an unnumbered frame */
336             proto_tree_add_text(control_tree, tvb, offset, 1,
337                 decode_boolean_bitfield(control, 0x03, 1*8,
338                     "Unnumbered frame", NULL));
339         }
340         break;
341
342     default:
343         /*
344          * Information frame.
345          */
346         if (is_extended)
347                 control = tvb_get_letohs(tvb, offset);
348         else
349                 control = tvb_get_guint8(tvb, offset);
350         if (is_extended) {
351             sprintf(info, "I%s, N(R) = %u, N(S) = %u",
352                         ((control & XDLC_P_F_EXT) ? " P" : ""),
353                         (control & XDLC_N_R_EXT_MASK) >> XDLC_N_R_EXT_SHIFT,
354                         (control & XDLC_N_S_EXT_MASK) >> XDLC_N_S_EXT_SHIFT);
355         } else {
356             sprintf(info, "I%s, N(R) = %u, N(S) = %u",
357                         ((control & XDLC_P_F) ? " P" : ""),
358                         (control & XDLC_N_R_MASK) >> XDLC_N_R_SHIFT,
359                         (control & XDLC_N_S_MASK) >> XDLC_N_S_SHIFT);
360         }
361         if (check_col(pinfo->cinfo, COL_INFO))
362             col_add_str(pinfo->cinfo, COL_INFO, info);
363         if (xdlc_tree) {
364             tc = proto_tree_add_uint_format(xdlc_tree, hf_xdlc_control, tvb,
365                         offset, (is_extended) ? 2 : 1,
366                         control,
367                         (is_extended) ? "Control field: %s (0x%04X)"
368                                       : "Control field: %s (0x%02X)",
369                         info, control);
370             control_tree = proto_item_add_subtree(tc, ett_xdlc_control);
371             if (is_extended) {
372                 proto_tree_add_text(control_tree, tvb, offset, 2,
373                     decode_numeric_bitfield(control, XDLC_N_R_EXT_MASK, 2*8,
374                                 "N(R) = %u"));
375                 proto_tree_add_text(control_tree, tvb, offset, 2,
376                     decode_numeric_bitfield(control, XDLC_N_S_EXT_MASK, 2*8,
377                                 "N(S) = %u"));
378                 if (control & XDLC_P_F_EXT) {
379                     proto_tree_add_text(control_tree, tvb, offset, 2,
380                         decode_boolean_bitfield(control, XDLC_P_F_EXT, 2*8,
381                                 "Poll", NULL));
382                 }
383                 /* This will always say it's an information frame */
384                 proto_tree_add_text(control_tree, tvb, offset, 2,
385                     decode_boolean_bitfield(control, 0x01, 2*8,
386                         NULL, "Information frame"));
387             } else {
388                 proto_tree_add_text(control_tree, tvb, offset, 1,
389                     decode_numeric_bitfield(control, XDLC_N_R_MASK, 1*8,
390                                 "N(R) = %u"));
391                 proto_tree_add_text(control_tree, tvb, offset, 1,
392                     decode_numeric_bitfield(control, XDLC_N_S_MASK, 1*8,
393                                 "N(S) = %u"));
394                 if (control & XDLC_P_F) {
395                     proto_tree_add_text(control_tree, tvb, offset, 1,
396                         decode_boolean_bitfield(control, XDLC_P_F, 1*8,
397                                 "Poll", NULL));
398                 }
399                 /* This will always say it's an information frame */
400                 proto_tree_add_text(control_tree, tvb, offset, 1,
401                     decode_boolean_bitfield(control, 0x01, 1*8,
402                         NULL, "Information frame"));
403             }
404         }
405     }
406     return control;
407 }