diff options
Diffstat (limited to 'epan/xdlc.c')
-rw-r--r-- | epan/xdlc.c | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/epan/xdlc.c b/epan/xdlc.c new file mode 100644 index 0000000..df87065 --- /dev/null +++ b/epan/xdlc.c @@ -0,0 +1,374 @@ +/* xdlc.c + * Routines for use by various SDLC-derived protocols, such as HDLC + * and its derivatives LAPB, IEEE 802.2 LLC, etc.. + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <stdio.h> +#include <string.h> + +#include <glib.h> +#include <epan/packet.h> +#include <epan/xdlc.h> +#include <wsutil/pint.h> + +const value_string ftype_vals[] = { + { XDLC_I, "Information frame" }, + { XDLC_S, "Supervisory frame" }, + { XDLC_U, "Unnumbered frame" }, + { 0, NULL } +}; + +const value_string stype_vals[] = { + { XDLC_RR>>2, "Receiver ready" }, + { XDLC_RNR>>2, "Receiver not ready" }, + { XDLC_REJ>>2, "Reject" }, + { XDLC_SREJ>>2, "Selective reject" }, + { 0, NULL } +}; + +static const value_string modifier_short_vals_cmd[] = { + { XDLC_UI, "UI" }, + { XDLC_UP, "UP" }, + { XDLC_DISC, "DISC" }, + { XDLC_UA, "UA" }, + { XDLC_SNRM, "SNRM" }, + { XDLC_SNRME, "SNRME" }, + { XDLC_TEST, "TEST" }, + { XDLC_SIM, "SIM" }, + { XDLC_FRMR, "FRMR" }, + { XDLC_CFGR, "CFGR" }, + { XDLC_SARM, "SARM" }, + { XDLC_SABM, "SABM" }, + { XDLC_SARME, "SARME" }, + { XDLC_SABME, "SABME" }, + { XDLC_RESET, "RESET" }, + { XDLC_XID, "XID" }, + { XDLC_SNRME, "SNRME" }, + { XDLC_BCN, "BCN" }, + { 0, NULL } +}; + +const value_string modifier_vals_cmd[] = { + { XDLC_UI>>2, "Unnumbered Information" }, + { XDLC_UP>>2, "Unnumbered Poll" }, + { XDLC_DISC>>2, "Disconnect" }, + { XDLC_UA>>2, "Unnumbered Acknowledge" }, + { XDLC_SNRM>>2, "Set Normal Response Mode" }, + { XDLC_TEST>>2, "Test" }, + { XDLC_SIM>>2, "Set Initialization Mode" }, + { XDLC_FRMR>>2, "Frame reject" }, + { XDLC_CFGR>>2, "Configure" }, + { XDLC_SARM>>2, "Set Asynchronous Response Mode" }, + { XDLC_SABM>>2, "Set Asynchronous Balanced Mode" }, + { XDLC_SARME>>2, "Set Asynchronous Response Mode Extended" }, + { XDLC_SABME>>2, "Set Asynchronous Balanced Mode Extended" }, + { XDLC_RESET>>2, "Reset" }, + { XDLC_XID>>2, "Exchange identification" }, + { XDLC_SNRME>>2, "Set Normal Response Mode Extended" }, + { XDLC_BCN>>2, "Beacon" }, + { 0, NULL } +}; + +static const value_string modifier_short_vals_resp[] = { + { XDLC_UI, "UI" }, + { XDLC_UP, "UP" }, + { XDLC_RD, "RD" }, + { XDLC_UA, "UA" }, + { XDLC_SNRM, "SNRM" }, + { XDLC_TEST, "TEST" }, + { XDLC_RIM, "RIM" }, + { XDLC_FRMR, "FRMR" }, + { XDLC_CFGR, "CFGR" }, + { XDLC_DM, "DM" }, + { XDLC_SABM, "SABM" }, + { XDLC_SARME, "SARME" }, + { XDLC_SABME, "SABME" }, + { XDLC_RESET, "RESET" }, + { XDLC_XID, "XID" }, + { XDLC_SNRME, "SNRME" }, + { XDLC_BCN, "BCN" }, + { 0, NULL } +}; + +const value_string modifier_vals_resp[] = { + { XDLC_UI>>2, "Unnumbered Information" }, + { XDLC_UP>>2, "Unnumbered Poll" }, + { XDLC_RD>>2, "Request Disconnect" }, + { XDLC_UA>>2, "Unnumbered Acknowledge" }, + { XDLC_SNRM>>2, "Set Normal Response Mode" }, + { XDLC_TEST>>2, "Test" }, + { XDLC_RIM>>2, "Request Initialization Mode" }, + { XDLC_FRMR>>2, "Frame reject" }, + { XDLC_CFGR>>2, "Configure" }, + { XDLC_DM>>2, "Disconnected mode" }, + { XDLC_SABM>>2, "Set Asynchronous Balanced Mode" }, + { XDLC_SARME>>2, "Set Asynchronous Response Mode Extended" }, + { XDLC_SABME>>2, "Set Asynchronous Balanced Mode Extended" }, + { XDLC_RESET>>2, "Reset" }, + { XDLC_XID>>2, "Exchange identification" }, + { XDLC_SNRME>>2, "Set Normal Response Mode Extended" }, + { XDLC_BCN>>2, "Beacon" }, + { 0, NULL } +}; + +int +get_xdlc_control(const guint8 *pd, int offset, gboolean is_extended) +{ + guint16 control; + + switch (pd[offset] & 0x03) { + + case XDLC_S: + default: + /* + * Supervisory or Information frame. + */ + if (is_extended) + control = pletoh16(&pd[offset]); + else + control = pd[offset]; + break; + + case XDLC_U: + /* + * Unnumbered frame. + * + * XXX - is this two octets, with a P/F bit, in HDLC extended + * operation? It's one octet in LLC, even though the control + * field of I and S frames is a 2-byte extended-operation field + * in LLC. Given that there are no sequence numbers in the + * control field of a U frame, there doesn't appear to be any + * need for it to be 2 bytes in extended operation. + */ + control = pd[offset]; + break; + } + return control; +} + +int +dissect_xdlc_control(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *xdlc_tree, int hf_xdlc_control, gint ett_xdlc_control, + const xdlc_cf_items *cf_items_nonext, const xdlc_cf_items *cf_items_ext, + const value_string *u_modifier_short_vals_cmd, + const value_string *u_modifier_short_vals_resp, gboolean is_response, + gboolean is_extended, gboolean append_info) +{ + guint16 control; + int control_len; + const xdlc_cf_items *cf_items; + const char *control_format; + guint16 poll_final; + char *info; + proto_tree *tc, *control_tree; + const gchar *frame_type = NULL; + const gchar *modifier; + + info=(char *)wmem_alloc(pinfo->pool, 80); + switch (tvb_get_guint8(tvb, offset) & 0x03) { + + case XDLC_S: + /* + * Supervisory frame. + */ + if (is_extended) { + control = tvb_get_letohs(tvb, offset); + control_len = 2; + cf_items = cf_items_ext; + control_format = "Control field: %s (0x%04X)"; + } else { + control = tvb_get_guint8(tvb, offset); + control_len = 1; + cf_items = cf_items_nonext; + control_format = "Control field: %s (0x%02X)"; + } + switch (control & XDLC_S_FTYPE_MASK) { + case XDLC_RR: + frame_type = "RR"; + break; + + case XDLC_RNR: + frame_type = "RNR"; + break; + + case XDLC_REJ: + frame_type = "REJ"; + break; + + case XDLC_SREJ: + frame_type = "SREJ"; + break; + } + if (is_extended) { + poll_final = (control & XDLC_P_F_EXT); + snprintf(info, 80, "S%s, func=%s, N(R)=%u", + (poll_final ? + (is_response ? " F" : " P") : + ""), + frame_type, + (control & XDLC_N_R_EXT_MASK) >> XDLC_N_R_EXT_SHIFT); + } else { + poll_final = (control & XDLC_P_F); + snprintf(info, 80, "S%s, func=%s, N(R)=%u", + (poll_final ? + (is_response ? " F" : " P") : + ""), + frame_type, + (control & XDLC_N_R_MASK) >> XDLC_N_R_SHIFT); + } + if (append_info) { + col_append_str(pinfo->cinfo, COL_INFO, ", "); + col_append_str(pinfo->cinfo, COL_INFO, info); + } else { + col_add_str(pinfo->cinfo, COL_INFO, info); + } + if (xdlc_tree) { + tc = proto_tree_add_uint_format(xdlc_tree, hf_xdlc_control, tvb, + offset, control_len, control, control_format, info, control); + control_tree = proto_item_add_subtree(tc, ett_xdlc_control); + proto_tree_add_uint(control_tree, *cf_items->hf_xdlc_n_r, + tvb, offset, control_len, control); + if (poll_final) { + proto_tree_add_boolean(control_tree, + (is_response ? *cf_items->hf_xdlc_f : + *cf_items->hf_xdlc_p), + tvb, offset, control_len, control); + } + proto_tree_add_uint(control_tree, *cf_items->hf_xdlc_s_ftype, + tvb, offset, control_len, control); + /* This will always say it's a supervisory frame */ + proto_tree_add_uint(control_tree, *cf_items->hf_xdlc_ftype_s_u, + tvb, offset, control_len, control); + } + break; + + case XDLC_U: + /* + * Unnumbered frame. + * + * XXX - is this two octets, with a P/F bit, in HDLC extended + * operation? It's one octet in LLC, even though the control + * field of I and S frames is a 2-byte extended-operation field + * in LLC. Given that there are no sequence numbers in the + * control field of a U frame, there doesn't appear to be any + * need for it to be 2 bytes in extended operation. + */ + if (u_modifier_short_vals_cmd == NULL) + u_modifier_short_vals_cmd = modifier_short_vals_cmd; + if (u_modifier_short_vals_resp == NULL) + u_modifier_short_vals_resp = modifier_short_vals_resp; + control = tvb_get_guint8(tvb, offset); + control_len = 1; + cf_items = cf_items_nonext; + control_format = "Control field: %s (0x%02X)"; + if (is_response) { + modifier = val_to_str(control & XDLC_U_MODIFIER_MASK, + u_modifier_short_vals_resp, "Unknown"); + } else { + modifier = val_to_str(control & XDLC_U_MODIFIER_MASK, + u_modifier_short_vals_cmd, "Unknown"); + } + poll_final = (control & XDLC_P_F); + snprintf(info, 80, "U%s, func=%s", + (poll_final ? + (is_response ? " F" : " P") : + ""), + modifier); + if (append_info) { + col_append_str(pinfo->cinfo, COL_INFO, ", "); + col_append_str(pinfo->cinfo, COL_INFO, info); + } else { + col_add_str(pinfo->cinfo, COL_INFO, info); + } + if (xdlc_tree) { + tc = proto_tree_add_uint_format(xdlc_tree, hf_xdlc_control, tvb, + offset, control_len, control, control_format, info, control); + control_tree = proto_item_add_subtree(tc, ett_xdlc_control); + if (poll_final) { + proto_tree_add_boolean(control_tree, + (is_response ? *cf_items->hf_xdlc_f: + *cf_items->hf_xdlc_p), + tvb, offset, control_len, control); + } + proto_tree_add_uint(control_tree, + (is_response ? *cf_items->hf_xdlc_u_modifier_resp : + *cf_items->hf_xdlc_u_modifier_cmd), + tvb, offset, control_len, control); + /* This will always say it's an unnumbered frame */ + proto_tree_add_uint(control_tree, *cf_items->hf_xdlc_ftype_s_u, + tvb, offset, control_len, control); + } + break; + + default: + /* + * Information frame. + */ + if (is_extended) { + control = tvb_get_letohs(tvb, offset); + control_len = 2; + cf_items = cf_items_ext; + control_format = "Control field: %s (0x%04X)"; + poll_final = (control & XDLC_P_F_EXT); + snprintf(info, 80, "I%s, N(R)=%u, N(S)=%u", + ((control & XDLC_P_F_EXT) ? " P" : ""), + (control & XDLC_N_R_EXT_MASK) >> XDLC_N_R_EXT_SHIFT, + (control & XDLC_N_S_EXT_MASK) >> XDLC_N_S_EXT_SHIFT); + } else { + control = tvb_get_guint8(tvb, offset); + control_len = 1; + cf_items = cf_items_nonext; + control_format = "Control field: %s (0x%02X)"; + poll_final = (control & XDLC_P_F); + snprintf(info, 80, "I%s, N(R)=%u, N(S)=%u", + ((control & XDLC_P_F) ? " P" : ""), + (control & XDLC_N_R_MASK) >> XDLC_N_R_SHIFT, + (control & XDLC_N_S_MASK) >> XDLC_N_S_SHIFT); + } + if (append_info) { + col_append_str(pinfo->cinfo, COL_INFO, ", "); + col_append_str(pinfo->cinfo, COL_INFO, info); + } else { + col_add_str(pinfo->cinfo, COL_INFO, info); + } + if (xdlc_tree) { + tc = proto_tree_add_uint_format(xdlc_tree, hf_xdlc_control, tvb, + offset, control_len, control, control_format, info, control); + control_tree = proto_item_add_subtree(tc, ett_xdlc_control); + proto_tree_add_uint(control_tree, *cf_items->hf_xdlc_n_r, + tvb, offset, control_len, control); + proto_tree_add_uint(control_tree, *cf_items->hf_xdlc_n_s, + tvb, offset, control_len, control); + if (poll_final) { + proto_tree_add_boolean(control_tree, *cf_items->hf_xdlc_p, + tvb, offset, control_len, control); + } + /* This will always say it's an information frame */ + proto_tree_add_uint(control_tree, *cf_items->hf_xdlc_ftype_i, + tvb, offset, control_len, control); + } + break; + } + return control; +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ |