wireshark/epan/dissectors/packet-sndcp.c
Guy Harris e1d9a226a2 Fix the type of arrays of pointers to hf_ values for bitfield routines.
The static arrays are supposed to be arrays of const pointers to int,
not arrays of non-const pointers to const int.

Fixing that means some bugs (scribbling on what's *supposed* to be a
const array) will be caught (see packet-ieee80211-radiotap.c for
examples, the first of which inspired this change and the second of
which was discovered while testing compiles with this change), and
removes the need for some annoying casts.

Also make some of those arrays static while we're at it.

Update documentation and dissector-generator tools.

Change-Id: I789da5fc60aadc15797cefecfd9a9fbe9a130ccc
Reviewed-on: https://code.wireshark.org/review/37517
Petri-Dish: Guy Harris <gharris@sonic.net>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
2020-06-19 11:32:26 +00:00

575 lines
17 KiB
C

/* packet-sndcp.c
* Routines for Subnetwork Dependent Convergence Protocol (SNDCP) dissection
* Copyright 2000, Christian Falckenberg <christian.falckenberg@nortelnetworks.com>
*
* 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 <epan/packet.h>
#include <epan/reassemble.h>
/* Bitmasks for the bits in the address field
*/
#define MASK_X 0x80
#define MASK_F 0x40
#define MASK_T 0x20
#define MASK_M 0x10
void proto_register_sndcp(void);
void proto_reg_handoff_sndcp(void);
/* Initialize the protocol and registered fields
*/
static int proto_sndcp = -1;
static int hf_sndcp_x = -1;
static int hf_sndcp_f = -1;
static int hf_sndcp_t = -1;
static int hf_sndcp_m = -1;
static int hf_sndcp_nsapi = -1;
static int hf_sndcp_nsapib = -1;
static int hf_sndcp_dcomp = -1;
static int hf_sndcp_pcomp = -1;
static int hf_sndcp_segment = -1;
static int hf_sndcp_npdu1 = -1;
static int hf_sndcp_npdu2 = -1;
static int hf_sndcp_payload = -1;
/* These fields are used when reassembling N-PDU fragments
*/
static int hf_npdu_fragments = -1;
static int hf_npdu_fragment = -1;
static int hf_npdu_fragment_overlap = -1;
static int hf_npdu_fragment_overlap_conflict = -1;
static int hf_npdu_fragment_multiple_tails = -1;
static int hf_npdu_fragment_too_long_fragment = -1;
static int hf_npdu_fragment_error = -1;
static int hf_npdu_fragment_count = -1;
static int hf_npdu_reassembled_in = -1;
static int hf_npdu_reassembled_length = -1;
/* Initialize the subtree pointers
*/
static gint ett_sndcp = -1;
static gint ett_sndcp_address_field = -1;
static gint ett_sndcp_compression_field = -1;
static gint ett_sndcp_npdu_field = -1;
static gint ett_npdu_fragment = -1;
static gint ett_npdu_fragments = -1;
/* Structure needed for the fragmentation routines in reassemble.c
*/
static const fragment_items npdu_frag_items = {
&ett_npdu_fragment,
&ett_npdu_fragments,
&hf_npdu_fragments,
&hf_npdu_fragment,
&hf_npdu_fragment_overlap,
&hf_npdu_fragment_overlap_conflict,
&hf_npdu_fragment_multiple_tails,
&hf_npdu_fragment_too_long_fragment,
&hf_npdu_fragment_error,
&hf_npdu_fragment_count,
&hf_npdu_reassembled_in,
&hf_npdu_reassembled_length,
/* Reassembled data field */
NULL,
"fragments"
};
/* dissectors for the data portion of this protocol
*/
static dissector_handle_t ip_handle;
static dissector_handle_t sndcp_handle;
/* reassembly of N-PDU
*/
static reassembly_table npdu_reassembly_table;
/* value strings
*/
static const value_string nsapi_t[] = {
{ 0, "Escape mechanism for future extensions"},
{ 1, "Point-to-Multipoint (PTM-M) Information" },
{ 2, "Reserved for future use" },
{ 3, "Reserved for future use" },
{ 4, "Reserved for future use" },
{ 5, "Dynamically allocated"},
{ 6, "Dynamically allocated"},
{ 7, "Dynamically allocated"},
{ 8, "Dynamically allocated"},
{ 9, "Dynamically allocated"},
{ 10, "Dynamically allocated"},
{ 11, "Dynamically allocated"},
{ 12, "Dynamically allocated"},
{ 13, "Dynamically allocated"},
{ 14, "Dynamically allocated"},
{ 15, "Dynamically allocated"},
{ 0, NULL },
};
static const value_string nsapi_abrv[] = {
{ 0, "0"},
{ 1, "PTM-M" },
{ 2, "2" },
{ 3, "3"},
{ 4, "4" },
{ 5, "DYN5" },
{ 6, "DYN6" },
{ 7, "DYN7" },
{ 8, "DYN8" },
{ 9, "DYN9" },
{ 10, "DYN10" },
{ 11, "DYN11" },
{ 12, "DYN12" },
{ 13, "DYN13" },
{ 14, "DYN14" },
{ 15, "DYN15" },
{ 0, NULL },
};
static const value_string compression_vals[] = {
{ 0, "No compression"},
{ 1, "Pointer to selected protocol/data compression mechanism" },
{ 2, "Pointer to selected protocol/data compression mechanism" },
{ 3, "Pointer to selected protocol/data compression mechanism" },
{ 4, "Pointer to selected protocol/data compression mechanism" },
{ 5, "Pointer to selected protocol/data compression mechanism" },
{ 6, "Pointer to selected protocol/data compression mechanism" },
{ 7, "Pointer to selected protocol/data compression mechanism" },
{ 8, "Pointer to selected protocol/data compression mechanism" },
{ 9, "Pointer to selected protocol/data compression mechanism" },
{ 10, "Pointer to selected protocol/data compression mechanism" },
{ 11, "Pointer to selected protocol/data compression mechanism" },
{ 12, "Pointer to selected protocol/data compression mechanism" },
{ 13, "Pointer to selected protocol/data compression mechanism" },
{ 14, "Pointer to selected protocol/data compression mechanism" },
{ 15, "Pointer to selected protocol/data compression mechanism" },
{ 0, NULL },
};
static const true_false_string x_bit = {
"Invalid",
"Set to 0 by transmitting SNDCP entity (ignored by receiver)"
};
static const true_false_string f_bit = {
"This SN-PDU is the first segment of an N-PDU",
"This SN-PDU is not the first segment of an N-PDU"
};
static const true_false_string t_bit = {
"SN-UNITDATA PDU",
"SN-DATA PDU"
};
static const true_false_string m_bit = {
"Not the last segment of N-PDU, more segments to follow",
"Last segment of N-PDU"
};
/* Code to actually dissect the packets
*/
static int
dissect_sndcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
guint8 addr_field, comp_field, npdu_field1, dcomp=0, pcomp=0;
guint16 offset=0, npdu=0, segment=0, npdu_field2;
tvbuff_t *next_tvb, *npdu_tvb;
gint len;
gboolean first, more_frags, unack;
static int * const addr_fields[] = {
&hf_sndcp_x,
&hf_sndcp_f,
&hf_sndcp_t,
&hf_sndcp_m,
&hf_sndcp_nsapib,
NULL
};
/* Set up structures needed to add the protocol subtree and manage it
*/
proto_item *ti;
proto_tree *sndcp_tree, *compression_field_tree, *npdu_field_tree;
/* Make entries in Protocol column and clear Info column on summary display
*/
col_set_str(pinfo->cinfo, COL_PROTOCOL, "SNDCP");
col_clear(pinfo->cinfo, COL_INFO);
/* create display subtree for the protocol
*/
ti = proto_tree_add_item(tree, proto_sndcp, tvb, 0, -1, ENC_NA);
sndcp_tree = proto_item_add_subtree(ti, ett_sndcp);
/* get address field from next byte
*/
addr_field = tvb_get_guint8(tvb,offset);
first = addr_field & MASK_F;
more_frags = addr_field & MASK_M;
unack = addr_field & MASK_T;
/* add subtree for the address field
*/
proto_tree_add_bitmask_with_flags(sndcp_tree, tvb, offset, hf_sndcp_nsapi,
ett_sndcp_address_field, addr_fields, ENC_NA, BMT_NO_APPEND);
offset++;
/* get compression pointers from next byte if this is the first segment
*/
if (first) {
comp_field = tvb_get_guint8(tvb,offset);
dcomp = comp_field & 0xF0;
pcomp = comp_field & 0x0F;
/* add subtree for the compression field
*/
if (tree) {
if (!pcomp) {
if (!dcomp) {
compression_field_tree = proto_tree_add_subtree(sndcp_tree, tvb, offset, 1, ett_sndcp_compression_field, NULL, "No compression");
}
else {
compression_field_tree = proto_tree_add_subtree(sndcp_tree, tvb, offset, 1, ett_sndcp_compression_field, NULL, "Data compression");
}
}
else {
if (!dcomp) {
compression_field_tree = proto_tree_add_subtree(sndcp_tree, tvb, offset, 1, ett_sndcp_compression_field, NULL, "Protocol compression");
}
else {
compression_field_tree = proto_tree_add_subtree(sndcp_tree, tvb, offset, 1, ett_sndcp_compression_field, NULL, "Data and Protocol compression");
}
}
proto_tree_add_uint(compression_field_tree, hf_sndcp_dcomp, tvb, offset, 1, comp_field );
proto_tree_add_uint(compression_field_tree, hf_sndcp_pcomp, tvb, offset, 1, comp_field );
}
offset++;
/* get N-PDU number from next byte for acknowledged mode (only for first segment)
*/
if (!unack) {
npdu = npdu_field1 = tvb_get_guint8(tvb,offset);
col_add_fstr(pinfo->cinfo, COL_INFO, "SN-DATA N-PDU %d", npdu_field1);
if (tree) {
npdu_field_tree = proto_tree_add_subtree_format(sndcp_tree, tvb, offset, 1, ett_sndcp_npdu_field, NULL, "Acknowledged mode, N-PDU %d", npdu_field1 );
proto_tree_add_uint(npdu_field_tree, hf_sndcp_npdu1, tvb, offset, 1, npdu_field1 );
}
offset++;
}
}
/* get segment and N-PDU number from next two bytes for unacknowledged mode
*/
if (unack) {
npdu_field2 = tvb_get_ntohs(tvb, offset);
segment = (npdu_field2 & 0xF000) >> 12;
npdu = (npdu_field2 & 0x0FFF);
col_add_fstr(pinfo->cinfo, COL_INFO, "SN-UNITDATA N-PDU %d (segment %d)", npdu, segment);
if (tree) {
npdu_field_tree = proto_tree_add_subtree_format(sndcp_tree, tvb, offset, 2, ett_sndcp_npdu_field, NULL,
"Unacknowledged mode, N-PDU %d (segment %d)", npdu, segment );
proto_tree_add_uint(npdu_field_tree, hf_sndcp_segment, tvb, offset, 2, npdu_field2 );
proto_tree_add_uint(npdu_field_tree, hf_sndcp_npdu2, tvb, offset, 2, npdu_field2 );
}
offset += 2;
}
/* handle N-PDU data, reassemble if necessary
*/
if (first && !more_frags) {
next_tvb = tvb_new_subset_remaining (tvb, offset);
if (!dcomp && !pcomp) {
call_dissector(ip_handle, next_tvb, pinfo, tree);
}
else {
call_data_dissector(next_tvb, pinfo, tree);
}
}
else {
/* Try reassembling fragments
*/
fragment_head *fd_npdu = NULL;
guint32 reassembled_in = 0;
gboolean save_fragmented = pinfo->fragmented;
len = tvb_captured_length_remaining(tvb, offset);
if(len<=0){
return offset;
}
pinfo->fragmented = TRUE;
if (unack)
fd_npdu = fragment_add_seq_check(&npdu_reassembly_table, tvb, offset,
pinfo, npdu, NULL, segment, len, more_frags);
else
fd_npdu = fragment_add(&npdu_reassembly_table, tvb, offset, pinfo, npdu, NULL,
offset, len, more_frags);
npdu_tvb = process_reassembled_data(tvb, offset, pinfo,
"Reassembled N-PDU", fd_npdu, &npdu_frag_items,
NULL, sndcp_tree);
if (fd_npdu) {
/* Reassembled
*/
reassembled_in = fd_npdu->reassembled_in;
if (pinfo->num == reassembled_in) {
/* Reassembled in this very packet:
* We can safely hand the tvb to the IP dissector
*/
call_dissector(ip_handle, npdu_tvb, pinfo, tree);
}
else {
/* Not reassembled in this packet
*/
col_append_fstr(pinfo->cinfo, COL_INFO,
" (N-PDU payload reassembled in packet %u)",
fd_npdu->reassembled_in);
proto_tree_add_item(sndcp_tree, hf_sndcp_payload, tvb, offset, -1, ENC_NA);
}
} else {
/* Not reassembled yet, or not reassembled at all
*/
if (unack)
col_append_fstr(pinfo->cinfo, COL_INFO, " (Unreassembled fragment %u)", segment);
else
col_append_str(pinfo->cinfo, COL_INFO, " (Unreassembled fragment)");
proto_tree_add_item(sndcp_tree, hf_sndcp_payload, tvb, offset, -1, ENC_NA);
}
/* Now reset fragmentation information in pinfo
*/
pinfo->fragmented = save_fragmented;
}
return tvb_captured_length(tvb);
}
/* Register the protocol with Wireshark
this format is required because a script is used to build the C function
that calls all the protocol registration.
*/
void
proto_register_sndcp(void)
{
/* Setup list of header fields
*/
static hf_register_info hf[] = {
{ &hf_sndcp_nsapi,
{ "Address field NSAPI",
"sndcp.nsapi",
FT_UINT8, BASE_DEC, VALS(nsapi_abrv), 0x0,
"Network Layer Service Access Point Identifier", HFILL
}
},
{ &hf_sndcp_x,
{ "Spare bit",
"sndcp.x",
FT_BOOLEAN,8, TFS(&x_bit), MASK_X,
"Spare bit (should be 0)", HFILL
}
},
{ &hf_sndcp_f,
{ "First segment indicator bit",
"sndcp.f",
FT_BOOLEAN,8, TFS(&f_bit), MASK_F,
NULL, HFILL
}
},
{ &hf_sndcp_t,
{ "Type",
"sndcp.t",
FT_BOOLEAN,8, TFS(&t_bit), MASK_T,
"SN-PDU Type", HFILL
}
},
{ &hf_sndcp_m,
{ "More bit",
"sndcp.m",
FT_BOOLEAN,8, TFS(&m_bit), MASK_M,
NULL, HFILL
}
},
{ &hf_sndcp_dcomp,
{ "DCOMP",
"sndcp.dcomp",
FT_UINT8, BASE_DEC, VALS(compression_vals), 0xF0,
"Data compression coding", HFILL
}
},
{ &hf_sndcp_pcomp,
{ "PCOMP",
"sndcp.pcomp",
FT_UINT8, BASE_DEC, VALS(compression_vals), 0x0F,
"Protocol compression coding", HFILL
}
},
{ &hf_sndcp_nsapib,
{ "NSAPI",
"sndcp.nsapib",
FT_UINT8, BASE_DEC , VALS(nsapi_t), 0xf,
"Network Layer Service Access Point Identifier",HFILL
}
},
{ &hf_sndcp_segment,
{ "Segment",
"sndcp.segment",
FT_UINT16, BASE_DEC, NULL, 0xF000,
"Segment number", HFILL
}
},
{ &hf_sndcp_npdu1,
{ "N-PDU",
"sndcp.npdu",
FT_UINT8, BASE_DEC, NULL, 0,
NULL, HFILL
}
},
{ &hf_sndcp_npdu2,
{ "N-PDU",
"sndcp.npdu",
FT_UINT16, BASE_DEC, NULL, 0x0FFF,
NULL, HFILL
}
},
{ &hf_sndcp_payload,
{ "Payload",
"sndcp.payload",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL
}
},
/* Fragment fields
*/
{ &hf_npdu_fragment_overlap,
{ "Fragment overlap",
"sndcp.npdu.fragment.overlap",
FT_BOOLEAN, BASE_NONE, NULL, 0x0,
"Fragment overlaps with other fragments", HFILL
}
},
{ &hf_npdu_fragment_overlap_conflict,
{ "Conflicting data in fragment overlap",
"sndcp.npdu.fragment.overlap.conflict",
FT_BOOLEAN, BASE_NONE, NULL, 0x0,
"Overlapping fragments contained conflicting data", HFILL
}
},
{ &hf_npdu_fragment_multiple_tails,
{ "Multiple tail fragments found",
"sndcp.npdu.fragment.multipletails",
FT_BOOLEAN, BASE_NONE, NULL, 0x0,
"Several tails were found when defragmenting the packet", HFILL
}
},
{ &hf_npdu_fragment_too_long_fragment,
{ "Fragment too long",
"sndcp.npdu.fragment.toolongfragment",
FT_BOOLEAN, BASE_NONE, NULL, 0x0,
"Fragment contained data past end of packet", HFILL
}
},
{ &hf_npdu_fragment_error,
{ "Defragmentation error",
"sndcp.npdu.fragment.error",
FT_FRAMENUM, BASE_NONE, NULL, 0x0,
"Defragmentation error due to illegal fragments", HFILL
}
},
{ &hf_npdu_fragment_count,
{ "Fragment count",
"sndcp.npdu.fragment.count",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_npdu_reassembled_in,
{ "Reassembled in",
"sndcp.npdu.reassembled.in",
FT_FRAMENUM, BASE_NONE, NULL, 0x0,
"N-PDU fragments are reassembled in the given packet", HFILL
}
},
{ &hf_npdu_reassembled_length,
{ "Reassembled N-PDU length",
"sndcp.npdu.reassembled.length",
FT_UINT32, BASE_DEC, NULL, 0x0,
"The total length of the reassembled payload", HFILL
}
},
{ &hf_npdu_fragment,
{ "N-PDU Fragment",
"sndcp.npdu.fragment",
FT_FRAMENUM, BASE_NONE, NULL, 0x0,
NULL, HFILL
}
},
{ &hf_npdu_fragments,
{ "N-PDU Fragments",
"sndcp.npdu.fragments",
FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL
}
},
};
/* Setup protocol subtree array */
static gint *ett[] = {
&ett_sndcp ,
&ett_sndcp_address_field,
&ett_sndcp_compression_field,
&ett_sndcp_npdu_field,
&ett_npdu_fragment,
&ett_npdu_fragments,
};
/* Register the protocol name and description */
proto_sndcp = proto_register_protocol("Subnetwork Dependent Convergence Protocol",
"SNDCP", "sndcp");
/* Required function calls to register the header fields and subtrees used */
proto_register_field_array(proto_sndcp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
sndcp_handle = register_dissector("sndcp", dissect_sndcp, proto_sndcp);
reassembly_table_register(&npdu_reassembly_table, &addresses_reassembly_table_functions);
}
/* If this dissector uses sub-dissector registration add a registration routine.
This format is required because a script is used to find these routines and
create the code that calls these routines.
*/
void
proto_reg_handoff_sndcp(void)
{
/* Register SNDCP dissector with LLC layer for SAPI 3,5,9 and 11
*/
dissector_add_uint("llcgprs.sapi", 3, sndcp_handle);
dissector_add_uint("llcgprs.sapi", 5, sndcp_handle);
dissector_add_uint("llcgprs.sapi", 9, sndcp_handle);
dissector_add_uint("llcgprs.sapi", 11, sndcp_handle);
/* Find IP and data handle for upper layer dissectors
*/
ip_handle = find_dissector_add_dependency("ip", proto_sndcp);
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local Variables:
* c-basic-offset: 2
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=2 tabstop=8 expandtab:
* :indentSize=2:tabSize=8:noTabs=true:
*/