/* * packet-gcsna.c * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later * * Ref GCSNA: 3GPP2 C.S0097 v2.0 */ # include "config.h" #include #include void proto_reg_handoff_gcsna(void); void proto_register_gcsna(void); /* gcsna Handle for the dissection */ static dissector_handle_t gcsna_handle; static dissector_handle_t cdma2k_handle; /* Function handlers for each message/information fields */ static void gcsna_message_decode(proto_item *item, tvbuff_t *tvb, proto_tree *tree, unsigned *offset, proto_tree *mainTree, uint16_t *noerror, packet_info *pinfo); static void gcsna_message_GCSNA1xCircuitService(proto_item *item, tvbuff_t *tvb, packet_info *pinfo, proto_tree *mainTree, proto_tree *tree, unsigned *offset); static void gcsna_message_GCSNAL2Ack(proto_item *item, tvbuff_t *tvb, proto_tree *tree, unsigned *offset); static void gcsna_message_GCSNAServiceReject(proto_item *item, tvbuff_t *tvb, proto_tree *tree, unsigned *offset); /*Initialize all the header parameters that are to be displayed*/ static int proto_gcsna; static int hf_gcsna_msghdr; static int hf_gcsna_msgid; static int hf_gcsna_rejSequence; static int hf_gcsna_cause; static int hf_gcsna_ackSequence; static int hf_gcsna_recordType; static int hf_gcsna_1xProtocolRevision; static int hf_gcsna_invalidMessageId; static int hf_gcsna_l2ack; static int hf_gcsna_servicereject; static int hf_gcsna_gcsna_option; static int hf_gcsna_gcsnaClass; static int hf_gcsna_gcsnaClassRev; static int hf_gcsna_altGCSNAOption; static int hf_gcsna_altGCSNAOptionIncluded; static int hf_gcsna_NumaltGCSNAOption; static int hf_gcsna_ackRequired; static int hf_gcsna_stopDupDetect; static int hf_gcsna_msgSequence; static int hf_gcsna_tlacEncapsulated; static int hf_gcsna_NumTLACEncapsulated1xL3PDU; static int hf_gcsna_tlacReserved; static int hf_gcsna_iwsidIncluded; static int hf_gcsna_iwsidValue; static int hf_gcsna_unsupported_reject_seq; /* Toggle sub-tree items */ static int ett_gcsna_msghdr; static int ett_gcsna_subtree; static int ett_gcsna_option; static expert_field ei_gcsna_error; #define GCSNA1XCIRCUITSERVICE 0x01 #define GCSNAL2ACK 0x02 #define GCSNASERVICEREJECT 0x03 /* Msg Types */ static const value_string gcsna_message_types[] = { { 0x01, "GCSNA 1X Circuitservice" }, { 0x02, "GCSNA L2 Ack"}, { 0x03, "GCSNA Servicereject"}, { 0, NULL }, }; /* Cause Types */ static const value_string gcsna_cause_types[] = { { 0, "Invalid GCSNAOption" }, { 1, "Invalid 1xProtocolRevision" }, { 2, "Invalid GCSNAOption and 1xProtocolRevision"}, { 3, "Invalid Message Id"}, { 4, "GCSNA 1xParameters provisioning is not supported" }, { 5, "Unsupported RecordType in GCSNA 1xParameters message"}, { 0, NULL }, }; /* GCSNA Class GCSNA ClassRevision 1x Service +----------+-------------------+--------------------------------+ | | 0 | Release 8 1xCSFB from E-UTRAN | | +-------------------+--------------------------------+ | 0 | 1 | Release 9 e1xCSFB from E-UTRAN | | +-------------------+--------------------------------+ | | 2 | C.S0097-A supported eCSFB | +----------+-------------------+--------------------------------+ | 1 | 0 | SRVCC from E-UTRAN | +----------+-------------------+--------------------------------+ */ static const value_string gcsna_option_values[] = { { 0, "Release 8 1xCSFB from E-UTRAN" }, { 1, "Release 9 e1xCSFB from E-UTRAN" }, { 2, "C.S0097-A supported eCSFB"}, { 8, "SRVCC from E-UTRAN"}, { 0, NULL }, }; static const value_string gcsna_tru_false_values[] = { { 0, "False" }, { 1, "True" }, { 0, NULL }, }; /* Decoder for all the information elements of A21 Message Type */ static void gcsna_message_decode(proto_item *item, tvbuff_t *tvb, proto_tree *tree, unsigned *offset, proto_tree *mainTree, uint16_t *noerror, packet_info *pinfo) { uint16_t msgId = -1; msgId = tvb_get_uint8(tvb, *offset); *offset += 1; switch (msgId) { case GCSNA1XCIRCUITSERVICE: { gcsna_message_GCSNA1xCircuitService(item, tvb, pinfo, mainTree, tree, offset); break; } case GCSNAL2ACK: { gcsna_message_GCSNAL2Ack(item, tvb, tree, offset); break; } case GCSNASERVICEREJECT: { gcsna_message_GCSNAServiceReject(item, tvb, tree, offset); break; } default: { *noerror = 0; break; } } } static void gcsna_message_GCSNA1xCircuitService(proto_item *item, tvbuff_t *tvb, packet_info *pinfo, proto_tree *mainTree, proto_tree *tree, unsigned *offset) { uint16_t alt_gcsna_incl = 0, num_alt_gcsna_opt = -1, iws_incl = 0; uint8_t num_res; unsigned bit_offset = *offset * 8; proto_tree *subtree = NULL; tvbuff_t *new_tvb; /* GCSNAOption 8 bits */ item = proto_tree_add_item(tree, hf_gcsna_gcsna_option, tvb, *offset, 1, ENC_BIG_ENDIAN); subtree = proto_item_add_subtree(item, ett_gcsna_option); proto_tree_add_bits_item(subtree, hf_gcsna_gcsnaClass, tvb, bit_offset, 5, ENC_BIG_ENDIAN); bit_offset += 5; proto_tree_add_bits_item(subtree, hf_gcsna_gcsnaClassRev, tvb, bit_offset, 3, ENC_BIG_ENDIAN); bit_offset += 3; alt_gcsna_incl = tvb_get_bits8(tvb, bit_offset, 1); proto_tree_add_bits_item(tree, hf_gcsna_altGCSNAOptionIncluded, tvb, bit_offset, 1, ENC_BIG_ENDIAN); bit_offset += 1; if (alt_gcsna_incl) { num_alt_gcsna_opt = tvb_get_bits8(tvb, bit_offset, 8); proto_tree_add_bits_item(tree, hf_gcsna_NumaltGCSNAOption, tvb, bit_offset, 8, ENC_BIG_ENDIAN); bit_offset += 8; while (num_alt_gcsna_opt != 0) { proto_tree_add_bits_item(tree, hf_gcsna_altGCSNAOption, tvb, bit_offset, 8, ENC_BIG_ENDIAN); bit_offset += 8; num_alt_gcsna_opt--; } } iws_incl = tvb_get_bits8(tvb, bit_offset, 1); proto_tree_add_bits_item(tree, hf_gcsna_iwsidIncluded, tvb, bit_offset, 1, ENC_BIG_ENDIAN); bit_offset++; if (iws_incl) { proto_tree_add_bits_item(tree, hf_gcsna_iwsidValue, tvb, bit_offset, 16, ENC_BIG_ENDIAN); bit_offset += 16; } proto_tree_add_bits_item(tree, hf_gcsna_ackRequired, tvb, bit_offset, 1, ENC_BIG_ENDIAN); bit_offset++; proto_tree_add_bits_item(tree, hf_gcsna_stopDupDetect, tvb, bit_offset, 1, ENC_BIG_ENDIAN); bit_offset++; proto_tree_add_bits_item(tree, hf_gcsna_msgSequence, tvb, bit_offset, 6, ENC_BIG_ENDIAN); bit_offset += 6; proto_tree_add_bits_item(tree, hf_gcsna_NumTLACEncapsulated1xL3PDU, tvb, bit_offset, 2, ENC_BIG_ENDIAN); bit_offset += 2; /* The sender shall include reserved bits to make this message integral number of octets up to TLACEncapsulated1xL3PDU field. * The sender shall set all bits in this field to '0'. The receiver shall ignore this field. */ /* calculate number of reserved bits */ num_res = 8 - (bit_offset & 0x3); proto_tree_add_bits_item(tree, hf_gcsna_tlacReserved, tvb, bit_offset, num_res, ENC_BIG_ENDIAN); bit_offset = bit_offset + num_res; *offset = bit_offset >> 3; proto_tree_add_item(tree, hf_gcsna_tlacEncapsulated, tvb, *offset, -1, ENC_NA); if (cdma2k_handle) { new_tvb = tvb_new_subset_length(tvb, *offset, -1); call_dissector(cdma2k_handle, new_tvb, pinfo, mainTree); } /* set the offset to the end of the message */ *offset += tvb_reported_length_remaining(tvb, *offset); } static void gcsna_message_GCSNAL2Ack(proto_item *item, tvbuff_t *tvb, proto_tree *tree, unsigned *offset) { proto_tree *subtree = NULL; item = proto_tree_add_item(tree, hf_gcsna_l2ack, tvb, *offset, 1, ENC_NA); subtree = proto_item_add_subtree(item, ett_gcsna_subtree); proto_tree_add_bits_item(subtree, hf_gcsna_ackSequence, tvb, *offset * 8, 6, ENC_BIG_ENDIAN); *offset += 1; } static void gcsna_message_GCSNAServiceReject(proto_item *item, tvbuff_t *tvb, proto_tree *tree, unsigned *offset) { uint16_t cause_val = -1, num_fields = -1, l_offset = -1; proto_tree *subtree = NULL; item = proto_tree_add_item(tree, hf_gcsna_servicereject, tvb, *offset, 1, ENC_NA); subtree = proto_item_add_subtree(item, ett_gcsna_subtree); l_offset = *offset * 8; proto_tree_add_bits_item(subtree, hf_gcsna_rejSequence, tvb, l_offset, 6, ENC_BIG_ENDIAN); l_offset += 6; proto_tree_add_bits_item(subtree, hf_gcsna_cause, tvb, l_offset, 8, ENC_BIG_ENDIAN); cause_val = tvb_get_bits8(tvb, *offset * 8 + 6, 8); l_offset += 8; switch (cause_val) { case 0: case 2: { num_fields = tvb_get_bits8(tvb, l_offset, 8); l_offset += 8; while (num_fields > 0) { proto_tree_add_bits_item(subtree, hf_gcsna_gcsnaClass, tvb, l_offset, 5, ENC_BIG_ENDIAN); l_offset += 5; proto_tree_add_bits_item(subtree, hf_gcsna_gcsnaClassRev, tvb, l_offset, 3, ENC_BIG_ENDIAN); l_offset += 3; num_fields--; } if (cause_val == 2) { proto_tree_add_bits_item(subtree, hf_gcsna_1xProtocolRevision, tvb, l_offset, 8, ENC_BIG_ENDIAN); l_offset += 8; } break; } case 1: { proto_tree_add_bits_item(subtree, hf_gcsna_1xProtocolRevision, tvb, l_offset, 8, ENC_BIG_ENDIAN); l_offset += 8; break; } case 3: { proto_tree_add_bits_item(subtree, hf_gcsna_invalidMessageId, tvb, l_offset, 8, ENC_BIG_ENDIAN); l_offset += 8; break; } /*This Cause Value is not supported in IWS Stack*/ case 5: { num_fields = tvb_get_bits8(tvb, l_offset, 8); l_offset += 8; while (num_fields > 0) { proto_tree_add_bits_item(subtree, hf_gcsna_recordType, tvb, l_offset, 8, ENC_BIG_ENDIAN); l_offset += 8; num_fields--; } break; } default: { proto_tree_add_item(subtree, hf_gcsna_unsupported_reject_seq, tvb, l_offset, -1, ENC_NA); break; } } if (l_offset % 8 == 0) { *offset = (l_offset / 8); } else { *offset = (l_offset / 8) + 1; } } /*Method called when the dissection starts.....Starting point*/ static int dissect_gcsna(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_) { /* Initialization*/ proto_tree *gcsna_msghdr_tree_start = NULL; proto_item *item = NULL; uint32_t offset = 0; uint16_t noerror = 1; /*Add the protocol name to display*/ col_set_str(pinfo->cinfo, COL_PROTOCOL, "gcsna"); col_set_str(pinfo->cinfo, COL_INFO, "[gcsna]"); item = proto_tree_add_item(tree, hf_gcsna_msghdr, tvb, 0, -1, ENC_NA); gcsna_msghdr_tree_start = proto_item_add_subtree(item, ett_gcsna_msghdr); if (tree) { proto_tree_add_item(gcsna_msghdr_tree_start, hf_gcsna_msgid, tvb, offset, 1, ENC_BIG_ENDIAN); while (tvb_captured_length_remaining(tvb, offset) != 0 && noerror == 1) gcsna_message_decode(item, tvb, gcsna_msghdr_tree_start, &offset, tree, &noerror, pinfo); if (noerror == 0) { expert_add_info(pinfo, item, &ei_gcsna_error); } } return tvb_reported_length(tvb); } /*Register gcsna to be accessed by other dissectors/plugins*/ void proto_register_gcsna(void) { static hf_register_info hf[] = { { &hf_gcsna_servicereject, { "GCSNA SERVICEREJECT", "gcsna.servicereject", FT_NONE, BASE_NONE,NULL, 0x0, NULL, HFILL } }, /*{ & hf_gcsna_msgid, { "GCSNA Message Type", "gcsna.MsgType", FT_UINT8, BASE_HEX_DEC, VALS(A21_Message_Types), 0x0, NULL, HFILL } },*/ { &hf_gcsna_l2ack, { "L2ACK", "gcsna.l2ack", FT_NONE, BASE_NONE,NULL, 0x0, NULL, HFILL } }, { &hf_gcsna_msghdr, { "General Circuit Services Notification Application Protocol", "gcsna.msghdr", FT_NONE, BASE_NONE,NULL, 0x0, NULL, HFILL } }, { &hf_gcsna_NumTLACEncapsulated1xL3PDU, { "NumTLACEncapsulated1xL3PDU", "gcsna.NumTLACEncapsulated1xL3PDU", FT_UINT8, BASE_HEX_DEC,NULL, 0x0, NULL, HFILL } }, { &hf_gcsna_tlacReserved, { "Reserved", "gcsna.tlacReserved", FT_UINT8, BASE_HEX_DEC,NULL, 0x0, NULL, HFILL } }, { &hf_gcsna_tlacEncapsulated, { "TLAC Encapsulated", "gcsna.tlacEncapsulated", FT_BYTES, BASE_NONE,NULL, 0x0, NULL, HFILL } }, { &hf_gcsna_msgSequence, { "Msg Sequence", "gcsna.msgSequence", FT_UINT8, BASE_HEX_DEC,NULL, 0x0, NULL, HFILL } }, { &hf_gcsna_stopDupDetect, { "Stop Dup Detect", "gcsna.stopDupDetect", FT_UINT8, BASE_HEX_DEC,NULL, 0x0, NULL, HFILL } }, { &hf_gcsna_ackRequired, { "Ack Required", "gcsna.ackRequired", FT_UINT8, BASE_DEC,VALS(gcsna_tru_false_values), 0x0, NULL, HFILL } }, { &hf_gcsna_altGCSNAOptionIncluded, { "AlternativeGCSNAOption_INCL", "gcsna.altGCSNAOptionIncluded", FT_UINT8, BASE_DEC,VALS(gcsna_tru_false_values), 0x0, NULL, HFILL } }, { &hf_gcsna_altGCSNAOption, { "Alternate GCSNA Option", "gcsna.altGCSNAOption", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_gcsna_gcsna_option, { "GCSNA Option", "gcsna.Option", FT_UINT8, BASE_HEX, VALS(gcsna_option_values), 0x0, NULL, HFILL } }, { &hf_gcsna_NumaltGCSNAOption, { "NumAlternativeGCSNAOptions", "gcsna.NumaltGCSNAOption", FT_UINT8, BASE_HEX_DEC,NULL, 0x0, NULL, HFILL } }, { &hf_gcsna_iwsidValue, { "IWS_ID", "gcsna.iwsidValue", FT_UINT16, BASE_HEX_DEC,NULL, 0x0, NULL, HFILL } }, { &hf_gcsna_iwsidIncluded, { "IWSIDIncl", "gcsna.iwsidIncluded", FT_UINT8, BASE_DEC,VALS(gcsna_tru_false_values), 0x0, NULL, HFILL } }, { &hf_gcsna_gcsnaClassRev, { "GCSNA Class revision", "gcsna.ClassRev", FT_UINT8, BASE_HEX_DEC,NULL, 0x0, NULL, HFILL } }, { &hf_gcsna_gcsnaClass, { "GCSNA Class", "gcsna.Class", FT_UINT8, BASE_HEX_DEC,NULL, 0x0, NULL, HFILL } }, { &hf_gcsna_invalidMessageId, { "InvalidMessageId", "gcsna.invalidMessageId", FT_UINT8, BASE_HEX_DEC,NULL, 0x0, NULL, HFILL } }, { &hf_gcsna_1xProtocolRevision, { "1xProtocolRevision", "gcsna.1xProtocolRevision", FT_UINT8, BASE_HEX_DEC,NULL, 0x0, NULL, HFILL } }, { &hf_gcsna_recordType, { "Record Type", "gcsna.recordType", FT_UINT8, BASE_HEX_DEC,NULL, 0x0, NULL, HFILL } }, { &hf_gcsna_ackSequence, { "Ack Sequence", "gcsna.ackSequence", FT_UINT8, BASE_HEX_DEC,NULL, 0x0, NULL, HFILL } }, { &hf_gcsna_cause, { "Cause", "gcsna.cause", FT_UINT8, BASE_HEX_DEC,VALS(gcsna_cause_types), 0x0, NULL, HFILL } }, { &hf_gcsna_rejSequence, { "Reject Sequence", "gcsna.rejSequence", FT_UINT8, BASE_HEX_DEC,NULL, 0x0, NULL, HFILL } }, { &hf_gcsna_msgid, { "GCSNA Message Type", "gcsna.msgId", FT_UINT8, BASE_HEX_DEC,VALS(gcsna_message_types), 0x0, NULL, HFILL } }, { &hf_gcsna_unsupported_reject_seq, { "Invalid / Unsupported GCSNA Message Reject Sequence", "gcsna.unsupportedrejectseq", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } } }; static int *ett[] = { &ett_gcsna_msghdr, &ett_gcsna_subtree, &ett_gcsna_option }; static ei_register_info ei[] = { { &ei_gcsna_error, { "gcsna.error", PI_PROTOCOL, PI_ERROR, "Violation of protocol specs (e.g. invalid information element)", EXPFILL }}, }; expert_module_t* expert_gcsna; proto_gcsna = proto_register_protocol("GCSNA", "GCSNA", "gcsna"); gcsna_handle = register_dissector("gcsna", dissect_gcsna, proto_gcsna); proto_register_field_array(proto_gcsna, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); expert_gcsna = expert_register_protocol(proto_gcsna); expert_register_field_array(expert_gcsna, ei, array_length(ei)); } void proto_reg_handoff_gcsna(void) { cdma2k_handle = find_dissector("cdma2k"); }