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