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