void parseByteString(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, int hfIndex) { char *szValue; int iOffset = *pOffset; gint32 iLen = tvb_get_letohl(tvb, iOffset); iOffset += 4; if (iLen == -1) { proto_item *item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 0, ENC_NA); proto_item_append_text(item, "[OpcUa Null ByteString]"); proto_item_set_end(item, tvb, *pOffset + 4); } else if (iLen == 0) { proto_item *item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 0, ENC_NA); proto_item_append_text(item, "[OpcUa Empty ByteString]"); proto_item_set_end(item, tvb, *pOffset + 4); } else if (iLen > 0) { proto_tree_add_item(tree, hfIndex, tvb, iOffset, iLen, ENC_NA); iOffset += iLen; /* eat the whole bytestring */ } else { proto_item *item = proto_tree_add_item(tree, hfIndex, tvb, *pOffset, 0, ENC_NA); szValue = ep_strdup_printf("[Invalid ByteString] Invalid length: %d", iLen); proto_item_append_text(item, "%s", szValue); proto_item_set_end(item, tvb, *pOffset + 4); } *pOffset = iOffset; }
void parseLocalizedText(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, const char *szFieldName) { gint iOffset = *pOffset; guint8 EncodingMask; proto_tree *mask_tree; proto_tree *subtree; proto_item *ti; proto_item *ti_inner; ti = proto_tree_add_text(tree, tvb, *pOffset, -1, "%s: LocalizedText", szFieldName); subtree = proto_item_add_subtree(ti, ett_opcua_localizedtext); /* parse encoding mask */ EncodingMask = tvb_get_guint8(tvb, iOffset); ti_inner = proto_tree_add_text(subtree, tvb, iOffset, 1, "EncodingMask"); mask_tree = proto_item_add_subtree(ti_inner, ett_opcua_localizedtext); proto_tree_add_item(mask_tree, hf_opcua_loctext_mask_localeflag, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(mask_tree, hf_opcua_loctext_mask_textflag, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); iOffset++; if (EncodingMask & LOCALIZEDTEXT_ENCODINGBYTE_LOCALE) { parseString(subtree, tvb, &iOffset, hf_opcua_localizedtext_locale); } if (EncodingMask & LOCALIZEDTEXT_ENCODINGBYTE_TEXT) { parseString(subtree, tvb, &iOffset, hf_opcua_localizedtext_text); } proto_item_set_end(ti, tvb, iOffset); *pOffset = iOffset; }
/** General parsing function for arrays of complex types. * All arrays have one 4 byte signed integer length information, * followed by n data elements. */ void parseArrayComplex(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, const char *szFieldName, fctComplexTypeParser pParserFunction) { proto_item *ti = proto_tree_add_text(tree, tvb, *pOffset, -1, "Array of %s", szFieldName); proto_tree *subtree = proto_item_add_subtree(ti, ett_opcua_array); int i; gint32 iLen; /* read array length */ iLen = tvb_get_letohl(tvb, *pOffset); proto_tree_add_item(subtree, hf_opcua_ArraySize, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); if (iLen > MAX_ARRAY_LEN) { proto_item *pi; pi = proto_tree_add_text(tree, tvb, *pOffset, 4, "Array length %d too large to process", iLen); PROTO_ITEM_SET_GENERATED(pi); return; } *pOffset += 4; for (i=0; i<iLen; i++) { char szNum[20]; g_snprintf(szNum, 20, "[%i]", i); (*pParserFunction)(subtree, tvb, pOffset, szNum); } proto_item_set_end(ti, tvb, *pOffset); }
void parseExtensionObject(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, const char *szFieldName) { gint iOffset = *pOffset; guint8 EncodingMask; guint32 TypeId; proto_tree *extobj_tree; proto_tree *mask_tree; proto_item *ti; proto_item *ti_inner; /* add extension object subtree */ ti = proto_tree_add_text(tree, tvb, *pOffset, -1, "%s : ExtensionObject", szFieldName); extobj_tree = proto_item_add_subtree(ti, ett_opcua_extensionobject); /* add nodeid subtree */ TypeId = getExtensionObjectType(tvb, &iOffset); parseExpandedNodeId(extobj_tree, tvb, &iOffset, "TypeId"); /* parse encoding mask */ EncodingMask = tvb_get_guint8(tvb, iOffset); ti_inner = proto_tree_add_text(extobj_tree, tvb, iOffset, 1, "EncodingMask"); mask_tree = proto_item_add_subtree(ti_inner, ett_opcua_extobj_encodingmask); proto_tree_add_item(mask_tree, hf_opcua_extobj_mask_binbodyflag, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(mask_tree, hf_opcua_extobj_mask_xmlbodyflag, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); iOffset++; if (EncodingMask & EXTOBJ_ENCODINGMASK_BINBODY_FLAG) /* has binary body ? */ { dispatchExtensionObjectType(extobj_tree, tvb, &iOffset, TypeId); } proto_item_set_end(ti, tvb, iOffset); *pOffset = iOffset; }
/** General parsing function for arrays of enums. * All arrays have one 4 byte signed integer length information, * followed by n data elements. */ void parseArrayEnum(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, fctEnumParser pParserFunction) { static const char szFieldName[] = "Array of Enum Type"; proto_item *ti = proto_tree_add_text(tree, tvb, *pOffset, -1, "%s", szFieldName); proto_tree *subtree = proto_item_add_subtree(ti, ett_opcua_array); int i; gint32 iLen; /* read array length */ iLen = tvb_get_letohl(tvb, *pOffset); proto_tree_add_item(subtree, hf_opcua_ArraySize, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); if (iLen > MAX_ARRAY_LEN) { proto_item *pi; pi = proto_tree_add_text(tree, tvb, *pOffset, 4, "Array length %d too large to process", iLen); PROTO_ITEM_SET_GENERATED(pi); return; } *pOffset += 4; for (i=0; i<iLen; i++) { (*pParserFunction)(subtree, tvb, pOffset); } proto_item_set_end(ti, tvb, *pOffset); }
void parseExpandedNodeId(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, const char *szFieldName) { proto_item *ti = proto_tree_add_text(tree, tvb, *pOffset, -1, "%s: ExpandedNodeId", szFieldName); proto_tree *subtree = proto_item_add_subtree(ti, ett_opcua_nodeid); gint iOffset = *pOffset; guint8 EncodingMask; EncodingMask = tvb_get_guint8(tvb, iOffset); proto_tree_add_item(subtree, hf_opcua_nodeid_encodingmask, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); iOffset++; switch(EncodingMask) { case 0x00: /* two byte node id */ proto_tree_add_item(subtree, hf_opcua_nodeid_numeric, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); iOffset+=1; break; case 0x01: /* four byte node id */ proto_tree_add_item(subtree, hf_opcua_nodeid_nsid, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); iOffset+=1; proto_tree_add_item(subtree, hf_opcua_nodeid_numeric, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); iOffset+=2; break; case 0x02: /* numeric, that does not fit into four bytes */ proto_tree_add_item(subtree, hf_opcua_nodeid_nsid, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); iOffset+=2; proto_tree_add_item(subtree, hf_opcua_nodeid_numeric, tvb, iOffset, 4, ENC_LITTLE_ENDIAN); iOffset+=4; break; case 0x03: /* string */ proto_tree_add_item(subtree, hf_opcua_nodeid_nsid, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); iOffset+=2; parseString(subtree, tvb, &iOffset, hf_opcua_String); break; case 0x04: /* guid */ proto_tree_add_item(subtree, hf_opcua_nodeid_nsid, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); iOffset+=2; parseGuid(subtree, tvb, &iOffset, hf_opcua_Guid); break; case 0x05: /* byte string */ proto_tree_add_item(subtree, hf_opcua_nodeid_nsid, tvb, iOffset, 2, ENC_LITTLE_ENDIAN); iOffset+=2; parseByteString(subtree, tvb, &iOffset, hf_opcua_ByteString); break; }; if (EncodingMask & NODEID_URIMASK) { parseString(subtree, tvb, &iOffset, hf_opcua_Uri); } if (EncodingMask & NODEID_SERVERINDEXFLAG) { parseUInt32(subtree, tvb, &iOffset, hf_opcua_ServerIndex); } proto_item_set_end(ti, tvb, iOffset); *pOffset = iOffset; }
void parseQualifiedName(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, const char *szFieldName) { proto_item *ti = proto_tree_add_text(tree, tvb, *pOffset, -1, "%s: QualifiedName", szFieldName); proto_tree *subtree = proto_item_add_subtree(ti, ett_opcua_qualifiedname); parseUInt16(subtree, tvb, pOffset, hf_opcua_qualifiedname_id); parseString(subtree, tvb, pOffset, hf_opcua_qualifiedname_name); proto_item_set_end(ti, tvb, *pOffset); }
void parseDiagnosticInfo(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, const char *szFieldName) { gint iOffset = *pOffset; guint8 EncodingMask; proto_tree *mask_tree; proto_tree *subtree; proto_item *ti; proto_item *ti_inner; ti = proto_tree_add_text(tree, tvb, *pOffset, -1, "%s: DiagnosticInfo", szFieldName); subtree = proto_item_add_subtree(ti, ett_opcua_diagnosticinfo); /* parse encoding mask */ EncodingMask = tvb_get_guint8(tvb, iOffset); ti_inner = proto_tree_add_text(subtree, tvb, iOffset, 1, "EncodingMask"); mask_tree = proto_item_add_subtree(ti_inner, ett_opcua_diagnosticinfo); proto_tree_add_item(mask_tree, hf_opcua_diag_mask_symbolicflag, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(mask_tree, hf_opcua_diag_mask_namespaceflag, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(mask_tree, hf_opcua_diag_mask_localizedtextflag, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(mask_tree, hf_opcua_diag_mask_additionalinfoflag, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(mask_tree, hf_opcua_diag_mask_innerstatuscodeflag, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(mask_tree, hf_opcua_diag_mask_innerdiaginfoflag, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); iOffset++; if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_SYMBOLICID_FLAG) { parseInt32(subtree, tvb, &iOffset, hf_opcua_diag_symbolicid); } if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_NAMESPACE_FLAG) { parseInt32(subtree, tvb, &iOffset, hf_opcua_diag_namespace); } if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_LOCALIZEDTEXT_FLAG) { parseInt32(subtree, tvb, &iOffset, hf_opcua_diag_localizedtext); } if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_ADDITIONALINFO_FLAG) { parseString(subtree, tvb, &iOffset, hf_opcua_diag_additionalinfo); } if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_INNERSTATUSCODE_FLAG) { parseStatusCode(subtree, tvb, &iOffset, hf_opcua_diag_innerstatuscode); } if (EncodingMask & DIAGNOSTICINFO_ENCODINGMASK_INNERDIAGNOSTICINFO_FLAG) { parseDiagnosticInfo(subtree, tvb, &iOffset, "Inner DiagnosticInfo"); } proto_item_set_end(ti, tvb, iOffset); *pOffset = iOffset; }
void parseDataValue(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, const char *szFieldName) { proto_item *ti = proto_tree_add_text(tree, tvb, *pOffset, -1, "%s: DataValue", szFieldName); proto_tree *subtree = proto_item_add_subtree(ti, ett_opcua_datavalue); proto_tree *mask_tree; gint iOffset = *pOffset; guint8 EncodingMask; proto_item *ti_inner; EncodingMask = tvb_get_guint8(tvb, iOffset); ti_inner = proto_tree_add_text(subtree, tvb, iOffset, 1, "EncodingMask"); mask_tree = proto_item_add_subtree(ti_inner, ett_opcua_datavalue); proto_tree_add_item(mask_tree, hf_opcua_datavalue_mask_valueflag, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(mask_tree, hf_opcua_datavalue_mask_statuscodeflag, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(mask_tree, hf_opcua_datavalue_mask_sourcetimestampflag, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(mask_tree, hf_opcua_datavalue_mask_servertimestampflag, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(mask_tree, hf_opcua_datavalue_mask_sourcepicoseconds, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(mask_tree, hf_opcua_datavalue_mask_serverpicoseconds, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); iOffset++; if (EncodingMask & DATAVALUE_ENCODINGBYTE_VALUE) { parseVariant(subtree, tvb, &iOffset, "Value"); } if (EncodingMask & DATAVALUE_ENCODINGBYTE_STATUSCODE) { parseStatusCode(subtree, tvb, &iOffset, hf_opcua_StatusCode); } if (EncodingMask & DATAVALUE_ENCODINGBYTE_SOURCETIMESTAMP) { parseDateTime(subtree, tvb, &iOffset, hf_opcua_SourceTimestamp); } if (EncodingMask & DATAVALUE_ENCODINGBYTE_SOURCEPICOSECONDS) { parseUInt16(subtree, tvb, &iOffset, hf_opcua_SourcePicoseconds); } if (EncodingMask & DATAVALUE_ENCODINGBYTE_SERVERTIMESTAMP) { parseDateTime(subtree, tvb, &iOffset, hf_opcua_ServerTimestamp); } if (EncodingMask & DATAVALUE_ENCODINGBYTE_SERVERPICOSECONDS) { parseUInt16(subtree, tvb, &iOffset, hf_opcua_ServerPicoseconds); } proto_item_set_end(ti, tvb, iOffset); *pOffset = iOffset; }
/** * Decode a "Source Route" object. * @return the new offset or -1 on error. **/ static gint decode_sourceroute(tvbuff_t *tvb, proto_tree *parent_tree, gint offset, gchar *attribute_name) { proto_item *ti = NULL; proto_tree *sourceroute_tree = NULL; guint32 i; guint32 sourceroute_size = tvb_get_ntohl(tvb, offset); ti = proto_tree_add_text(parent_tree, tvb, offset, 1, attribute_name); sourceroute_tree = proto_item_add_subtree(ti, ett_freepastry_core_v0_sr); proto_tree_add_uint(sourceroute_tree, hf_freepastry_direct_sourceroute_numhops, tvb, offset, 4, sourceroute_size); offset += 4; /*for each hop (do not parse the last hop)*/ for (i=0; i < (sourceroute_size - 1); ++i){ offset = decode_epoch_inet_socket_address(tvb, sourceroute_tree, offset, "Hop"); if (offset == -1){ return -1; } } /*Parse the last node in the sourceroute*/ if (sourceroute_size > 0) { gchar *ip_str; guint16 port_number; gint former_offset = offset; offset = decode_epoch_inet_socket_address(tvb, sourceroute_tree, offset, "Hop"); if (offset == -1){ return -1; } /*Print final destination on the subtree root*/ ip_str = ip_to_str(tvb_get_ptr(tvb, former_offset + 1, 4)); former_offset += 5; port_number = tvb_get_ntohs(tvb, former_offset); proto_item_append_text(ti, " -> %s:%d", ip_str, port_number); } proto_item_set_end(ti, tvb, offset); return offset; }
void parseVariant(proto_tree *tree, tvbuff_t *tvb, gint *pOffset, const char *szFieldName) { proto_item *ti = proto_tree_add_text(tree, tvb, *pOffset, -1, "%s: Variant", szFieldName); proto_tree *subtree = proto_item_add_subtree(ti, ett_opcua_variant); gint iOffset = *pOffset; guint8 EncodingMask; gint32 ArrayDimensions = 0; EncodingMask = tvb_get_guint8(tvb, iOffset); proto_tree_add_item(subtree, hf_opcua_variant_encodingmask, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); iOffset++; if (EncodingMask & VARIANT_ARRAYMASK) { /* type is encoded in bits 0-5 */ switch(EncodingMask & 0x3f) { case OpcUaType_Null: break; case OpcUaType_Boolean: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_Boolean, parseBoolean); break; case OpcUaType_SByte: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_SByte, parseSByte); break; case OpcUaType_Byte: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_Byte, parseByte); break; case OpcUaType_Int16: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_Int16, parseInt16); break; case OpcUaType_UInt16: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_UInt16, parseUInt16); break; case OpcUaType_Int32: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_Int32, parseInt32); break; case OpcUaType_UInt32: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_UInt32, parseUInt32); break; case OpcUaType_Int64: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_Int64, parseInt64); break; case OpcUaType_UInt64: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_UInt64, parseUInt64); break; case OpcUaType_Float: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_Float, parseFloat); break; case OpcUaType_Double: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_Double, parseDouble); break; case OpcUaType_String: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_String, parseString); break; case OpcUaType_DateTime: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_DateTime, parseDateTime); break; case OpcUaType_Guid: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_Guid, parseGuid); break; case OpcUaType_ByteString: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_ByteString, parseByteString); break; case OpcUaType_XmlElement: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_XmlElement, parseXmlElement); break; case OpcUaType_NodeId: parseArrayComplex(subtree, tvb, &iOffset, "NodeId", parseNodeId); break; case OpcUaType_ExpandedNodeId: parseArrayComplex(subtree, tvb, &iOffset, "ExpandedNodeId", parseExpandedNodeId); break; case OpcUaType_StatusCode: parseArraySimple(subtree, tvb, &iOffset, hf_opcua_StatusCode, parseStatusCode); break; case OpcUaType_DiagnosticInfo: parseArrayComplex(subtree, tvb, &iOffset, "DiagnosticInfo", parseDiagnosticInfo); break; case OpcUaType_QualifiedName: parseArrayComplex(subtree, tvb, &iOffset, "QualifiedName", parseQualifiedName); break; case OpcUaType_LocalizedText: parseArrayComplex(subtree, tvb, &iOffset, "LocalizedText", parseLocalizedText); break; case OpcUaType_ExtensionObject: parseArrayComplex(subtree, tvb, &iOffset, "ExtensionObject", parseExtensionObject); break; case OpcUaType_DataValue: parseArrayComplex(subtree, tvb, &iOffset, "DataValue", parseDataValue); break; case OpcUaType_Variant: parseArrayComplex(subtree, tvb, &iOffset, "Variant", parseVariant); break; } if (EncodingMask & VARIANT_ARRAYDIMENSIONS) { proto_item *ti_2 = proto_tree_add_text(subtree, tvb, iOffset, -1, "ArrayDimensions"); proto_tree *subtree_2 = proto_item_add_subtree(ti_2, ett_opcua_array); int i; /* read array length */ ArrayDimensions = tvb_get_letohl(tvb, iOffset); proto_tree_add_item(subtree_2, hf_opcua_ArraySize, tvb, iOffset, 4, ENC_LITTLE_ENDIAN); if (ArrayDimensions > MAX_ARRAY_LEN) { proto_item *pi; pi = proto_tree_add_text(subtree_2, tvb, iOffset, 4, "ArrayDimensions length %d too large to process", ArrayDimensions); PROTO_ITEM_SET_GENERATED(pi); return; } iOffset += 4; for (i=0; i<ArrayDimensions; i++) { parseInt32(subtree_2, tvb, &iOffset, hf_opcua_Int32); } proto_item_set_end(ti_2, tvb, iOffset); } } else { /* type is encoded in bits 0-5 */ switch(EncodingMask & 0x3f) { case OpcUaType_Null: break; case OpcUaType_Boolean: parseBoolean(subtree, tvb, &iOffset, hf_opcua_Boolean); break; case OpcUaType_SByte: parseSByte(subtree, tvb, &iOffset, hf_opcua_SByte); break; case OpcUaType_Byte: parseByte(subtree, tvb, &iOffset, hf_opcua_Byte); break; case OpcUaType_Int16: parseInt16(subtree, tvb, &iOffset, hf_opcua_Int16); break; case OpcUaType_UInt16: parseUInt16(subtree, tvb, &iOffset, hf_opcua_UInt16); break; case OpcUaType_Int32: parseInt32(subtree, tvb, &iOffset, hf_opcua_Int32); break; case OpcUaType_UInt32: parseUInt32(subtree, tvb, &iOffset, hf_opcua_UInt32); break; case OpcUaType_Int64: parseInt64(subtree, tvb, &iOffset, hf_opcua_Int64); break; case OpcUaType_UInt64: parseUInt64(subtree, tvb, &iOffset, hf_opcua_UInt64); break; case OpcUaType_Float: parseFloat(subtree, tvb, &iOffset, hf_opcua_Float); break; case OpcUaType_Double: parseDouble(subtree, tvb, &iOffset, hf_opcua_Double); break; case OpcUaType_String: parseString(subtree, tvb, &iOffset, hf_opcua_String); break; case OpcUaType_DateTime: parseDateTime(subtree, tvb, &iOffset, hf_opcua_DateTime); break; case OpcUaType_Guid: parseGuid(subtree, tvb, &iOffset, hf_opcua_Guid); break; case OpcUaType_ByteString: parseByteString(subtree, tvb, &iOffset, hf_opcua_ByteString); break; case OpcUaType_XmlElement: parseXmlElement(subtree, tvb, &iOffset, hf_opcua_XmlElement); break; case OpcUaType_NodeId: parseNodeId(subtree, tvb, &iOffset, "Value"); break; case OpcUaType_ExpandedNodeId: parseExpandedNodeId(subtree, tvb, &iOffset, "Value"); break; case OpcUaType_StatusCode: parseStatusCode(subtree, tvb, &iOffset, hf_opcua_StatusCode); break; case OpcUaType_DiagnosticInfo: parseDiagnosticInfo(subtree, tvb, &iOffset, "Value"); break; case OpcUaType_QualifiedName: parseQualifiedName(subtree, tvb, &iOffset, "Value"); break; case OpcUaType_LocalizedText: parseLocalizedText(subtree, tvb, &iOffset, "Value"); break; case OpcUaType_ExtensionObject: parseExtensionObject(subtree, tvb, &iOffset, "Value"); break; case OpcUaType_DataValue: parseDataValue(subtree, tvb, &iOffset, "Value"); break; case OpcUaType_Variant: parseVariant(subtree, tvb, &iOffset, "Value"); break; } } proto_item_set_end(ti, tvb, iOffset); *pOffset = iOffset; }
/* Code to actually dissect the packets */ static int dissect_msrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gint offset = 0; gint next_offset = 0; proto_item *ti, *th, *msrp_headers_item, *msrp_element_item; proto_tree *msrp_tree, *reqresp_tree, *raw_tree, *msrp_hdr_tree, *msrp_end_tree; proto_tree *msrp_element_tree, *msrp_data_tree; gint linelen; gint space_offset; gint token_2_start; guint token_2_len; gint token_3_start; guint token_3_len; gint token_4_start = 0; guint token_4_len = 0; gboolean is_msrp_response; gint end_line_offset; gint end_line_len; gint line_end_offset; gint message_end_offset; gint colon_offset; char *transaction_id_str = NULL; gint header_len; gint hf_index; gint value_offset; guchar c; gint value_len; char *value; gboolean have_body = FALSE; gboolean found_match = FALSE; gint content_type_len, content_type_parameter_str_len; gchar *media_type_str_lower_case = NULL; char *content_type_parameter_str = NULL; tvbuff_t *next_tvb; gint parameter_offset; gint semi_colon_offset; if ( !check_msrp_header(tvb)){ return 0; } /* We have a MSRP header with at least three tokens * * Note that "tvb_find_line_end()" will return a value that * is not longer than what's in the buffer, so the * "tvb_get_ptr()" calls below won't throw exceptions. * */ offset = 0; linelen = tvb_find_line_end(tvb, 0, -1, &next_offset, FALSE); /* Find the first SP and skip the first token */ token_2_start = tvb_find_guint8(tvb, 0, linelen, ' ') + 1; /* Work out 2nd token's length by finding next space */ space_offset = tvb_find_guint8(tvb, token_2_start, linelen-token_2_start, ' '); token_2_len = space_offset - token_2_start; /* Transaction ID found store it for later use */ transaction_id_str = tvb_get_ephemeral_string(tvb, token_2_start, token_2_len); /* Look for another space in this line to indicate a 4th token */ token_3_start = space_offset + 1; space_offset = tvb_find_guint8(tvb, token_3_start,linelen-token_3_start, ' '); if ( space_offset == -1){ /* 3rd token runs to the end of the line */ token_3_len = linelen - token_3_start; }else{ /* We have a fourth token */ token_3_len = space_offset - token_3_start; token_4_start = space_offset + 1; token_4_len = linelen - token_4_start; } /* * Yes, so this is either a msrp-request or msrp-response. * To be a msrp-response, the second token must be * a 3-digit number. */ is_msrp_response = FALSE; if (token_3_len == 3) { if (isdigit(tvb_get_guint8(tvb, token_3_start)) && isdigit(tvb_get_guint8(tvb, token_3_start + 1)) && isdigit(tvb_get_guint8(tvb, token_3_start + 2))) { is_msrp_response = TRUE; } } /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "MSRP"); if (is_msrp_response){ if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "Response: %s ", tvb_format_text(tvb, token_3_start, token_3_len)); if (token_4_len ) col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", tvb_format_text(tvb, token_4_start, token_4_len)); col_append_fstr(pinfo->cinfo, COL_INFO, "Transaction ID: %s", tvb_format_text(tvb, token_2_start, token_2_len)); } }else{ if (check_col(pinfo->cinfo, COL_INFO)) { proto_tree_add_text(tree, tvb, token_3_start, token_3_len, "Col %s L=%u", tvb_format_text(tvb, token_3_start, token_3_len),token_3_len); col_add_fstr(pinfo->cinfo, COL_INFO, "Request: %s ", tvb_format_text(tvb, token_3_start, token_3_len)); col_append_fstr(pinfo->cinfo, COL_INFO, "Transaction ID: %s", tvb_format_text(tvb, token_2_start, token_2_len)); } } /* Find the end line to be able to process the headers * Note that in case of [content-stuff] headers and [content-stuff] is separated by CRLF */ offset = next_offset; end_line_offset = find_end_line(tvb,offset); /* TODO if -1 (No end line found, is returned do something) */ end_line_len = tvb_find_line_end(tvb, end_line_offset, -1, &next_offset, FALSE); message_end_offset = end_line_offset + end_line_len + 2; if (tree) { ti = proto_tree_add_item(tree, proto_msrp, tvb, 0, message_end_offset, FALSE); msrp_tree = proto_item_add_subtree(ti, ett_msrp); if (is_msrp_response){ th = proto_tree_add_item(msrp_tree,hf_msrp_response_line,tvb,0,linelen,FALSE); reqresp_tree = proto_item_add_subtree(th, ett_msrp_reqresp); proto_tree_add_item(reqresp_tree,hf_msrp_transactionID,tvb,token_2_start,token_2_len,FALSE); proto_tree_add_uint(reqresp_tree,hf_msrp_status_code,tvb,token_3_start,token_3_len, atoi(tvb_get_ephemeral_string(tvb, token_3_start, token_3_len))); }else{ th = proto_tree_add_item(msrp_tree,hf_msrp_request_line,tvb,0,linelen,FALSE); reqresp_tree = proto_item_add_subtree(th, ett_msrp_reqresp); proto_tree_add_item(reqresp_tree,hf_msrp_transactionID,tvb,token_2_start,token_2_len,FALSE); proto_tree_add_item(reqresp_tree,hf_msrp_method,tvb,token_3_start,token_3_len,FALSE); } /* Conversation setup info */ if (global_msrp_show_setup_info) { show_setup_info(tvb, pinfo, msrp_tree); } /* Headers */ msrp_headers_item = proto_tree_add_item(msrp_tree, hf_msrp_msg_hdr, tvb, offset,(end_line_offset - offset), FALSE); msrp_hdr_tree = proto_item_add_subtree(msrp_headers_item, ett_msrp_hdr); /* * Process the headers */ while (tvb_reported_length_remaining(tvb, offset) > 0 && offset < end_line_offset ) { /* 'desegment' is FALSE so will set next_offset to beyond the end of the buffer if no line ending is found */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); if (linelen == 0) { /* * This is a blank line separating the * message header from the message body. */ have_body = TRUE; break; } line_end_offset = offset + linelen; colon_offset = tvb_find_guint8(tvb, offset, linelen, ':'); if (colon_offset == -1) { /* * Malformed header - no colon after the name. */ proto_tree_add_text(msrp_hdr_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, linelen)); } else { header_len = colon_offset - offset; hf_index = msrp_is_known_msrp_header(tvb, offset, header_len); if (hf_index == -1) { proto_tree_add_text(msrp_hdr_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, linelen)); } else { /* * Skip whitespace after the colon. */ value_offset = colon_offset + 1; while (value_offset < line_end_offset && ((c = tvb_get_guint8(tvb, value_offset)) == ' ' || c == '\t')) value_offset++; /* * Fetch the value. */ value_len = line_end_offset - value_offset; value = tvb_get_ephemeral_string(tvb, value_offset, value_len); /* * Add it to the protocol tree, * but display the line as is. */ msrp_element_item = proto_tree_add_string_format(msrp_hdr_tree, hf_header_array[hf_index], tvb, offset, next_offset - offset, value, "%s", tvb_format_text(tvb, offset, linelen)); msrp_element_tree = proto_item_add_subtree( msrp_element_item, ett_msrp_element); switch ( hf_index ) { case MSRP_CONTENT_TYPE : content_type_len = value_len; semi_colon_offset = tvb_find_guint8(tvb, value_offset,linelen, ';'); if ( semi_colon_offset != -1) { parameter_offset = semi_colon_offset +1; /* * Skip whitespace after the semicolon. */ while (parameter_offset < line_end_offset && ((c = tvb_get_guint8(tvb, parameter_offset)) == ' ' || c == '\t')) parameter_offset++; content_type_len = semi_colon_offset - value_offset; content_type_parameter_str_len = line_end_offset - parameter_offset; content_type_parameter_str = tvb_get_ephemeral_string(tvb, parameter_offset, content_type_parameter_str_len); } media_type_str_lower_case = ascii_strdown_inplace( (gchar *)tvb_get_ephemeral_string(tvb, value_offset, content_type_len)); break; default: break; } } } offset = next_offset; }/* End while */ if ( have_body ){ /* * There's a message body starting at "next_offset". * Set the length of the header item. */ proto_item_set_end(msrp_headers_item, tvb, next_offset); /* Create new tree & tvb for data */ next_tvb = tvb_new_subset_remaining(tvb, next_offset); ti = proto_tree_add_item(msrp_tree, hf_msrp_data, tvb, next_offset, -1, FALSE); msrp_data_tree = proto_item_add_subtree(ti, ett_msrp_data); /* give the content type parameters to sub dissectors */ if ( media_type_str_lower_case != NULL ) { void *save_private_data = pinfo->private_data; pinfo->private_data = content_type_parameter_str; found_match = dissector_try_string(media_type_dissector_table, media_type_str_lower_case, next_tvb, pinfo, msrp_data_tree); pinfo->private_data = save_private_data; /* If no match dump as text */ } if ( found_match != TRUE ) { offset = 0; while (tvb_offset_exists(next_tvb, offset)) { tvb_find_line_end(next_tvb, offset, -1, &next_offset, FALSE); linelen = next_offset - offset; proto_tree_add_text(msrp_data_tree, next_tvb, offset, linelen, "%s", tvb_format_text(next_tvb, offset, linelen)); offset = next_offset; }/* end while */ } } /* End line */ ti = proto_tree_add_item(msrp_tree,hf_msrp_end_line,tvb,end_line_offset,end_line_len,FALSE); msrp_end_tree = proto_item_add_subtree(ti, ett_msrp_end_line); proto_tree_add_item(msrp_end_tree,hf_msrp_transactionID,tvb,end_line_offset + 7,token_2_len,FALSE); /* continuation-flag */ proto_tree_add_item(msrp_end_tree,hf_msrp_cnt_flg,tvb,end_line_offset+end_line_len-1,1,FALSE); if (global_msrp_raw_text){ ti = proto_tree_add_text(tree, tvb, 0, -1,"Message Session Relay Protocol(as raw text)"); raw_tree = proto_item_add_subtree(ti, ett_msrp); tvb_raw_text_add(tvb,raw_tree); } }/* if tree */ return message_end_offset; /* return tvb_length(tvb); */ /* If this protocol has a sub-dissector call it here, see section 1.8 */ }
/* * Dissect an SPDU. */ static int dissect_spdu(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, gboolean tokens, gboolean connectionless) { gboolean has_user_information = FALSE; guint8 type; proto_item *ti = NULL; proto_tree *ses_tree = NULL; int len_len; guint16 parameters_len; tvbuff_t *next_tvb = NULL; guint32 *pres_ctx_id = NULL; guint8 enclosure_item_flags = BEGINNING_SPDU|END_SPDU; struct SESSION_DATA_STRUCTURE session; /* * Get SPDU type. */ type = tvb_get_guint8(tvb, offset); session.spdu_type = type; session.abort_type = SESSION_NO_ABORT; session.pres_ctx_id = 0; session.ros_op = 0; session.rtse_reassemble = FALSE; if(connectionless) { col_add_str(pinfo->cinfo, COL_INFO, val_to_str(type, ses_vals, "Unknown SPDU type (0x%02x)")); if (tree) { ti = proto_tree_add_item(tree, proto_clses, tvb, offset, -1, ENC_NA); ses_tree = proto_item_add_subtree(ti, ett_ses); proto_tree_add_uint(ses_tree, hf_ses_type, tvb, offset, 1, type); } has_user_information = TRUE; } else if (tokens) { col_add_str(pinfo->cinfo, COL_INFO, val_to_str(type, ses_category0_vals, "Unknown SPDU type (0x%02x)")); if (tree) { ti = proto_tree_add_item(tree, proto_ses, tvb, offset, -1, ENC_NA); ses_tree = proto_item_add_subtree(ti, ett_ses); proto_tree_add_uint(ses_tree, hf_ses_type_0, tvb, offset, 1, type); } } else { col_add_str(pinfo->cinfo, COL_INFO, val_to_str(type, ses_vals, "Unknown SPDU type (0x%02x)")); if (tree) { ti = proto_tree_add_item(tree, proto_ses, tvb, offset, -1, ENC_NA); ses_tree = proto_item_add_subtree(ti, ett_ses); proto_tree_add_uint(ses_tree, hf_ses_type, tvb, offset, 1, type); } /* * Might this SPDU have a User Information field? */ switch (type) { case SES_DATA_TRANSFER: case SES_EXPEDITED: case SES_TYPED_DATA: has_user_information = TRUE; break; case SES_MAJOR_SYNC_POINT: pres_ctx_id = (guint32 *)p_get_proto_data(wmem_file_scope(), pinfo, proto_ses, 0); if (ses_rtse_reassemble != 0 && !pres_ctx_id) { /* First time visited - save pres_ctx_id */ pres_ctx_id = wmem_new(wmem_file_scope(), guint32); *pres_ctx_id = ses_pres_ctx_id; p_add_proto_data(wmem_file_scope(), pinfo, proto_ses, 0, pres_ctx_id); } if (pres_ctx_id) { session.pres_ctx_id = *pres_ctx_id; session.rtse_reassemble = TRUE; has_user_information = TRUE; } ses_rtse_reassemble = FALSE; break; } } offset++; /* get length of SPDU parameter field */ parameters_len = get_item_len(tvb, offset, &len_len); if (tree) proto_tree_add_uint(ses_tree, hf_ses_length, tvb, offset, len_len, parameters_len); offset += len_len; /* Dissect parameters. */ if (!dissect_parameters(tvb, offset, parameters_len, tree, ses_tree, pinfo, &enclosure_item_flags, &session)) has_user_information = FALSE; offset += parameters_len; proto_item_set_end(ti, tvb, offset); /* Dissect user information, if present */ if (!ses_desegment || enclosure_item_flags == (BEGINNING_SPDU|END_SPDU)) { if (has_user_information) { /* Not desegment or only one segment */ if (tvb_reported_length_remaining(tvb, offset) > 0 || type == SES_MAJOR_SYNC_POINT) { next_tvb = tvb_new_subset_remaining(tvb, offset); } } } else { conversation_t *conversation = NULL; fragment_head *frag_msg = NULL; gint fragment_len; guint32 ses_id = 0; /* Use conversation index as segment id */ conversation = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (conversation != NULL) { ses_id = conversation->index; } fragment_len = tvb_reported_length_remaining (tvb, offset); ti = proto_tree_add_item (ses_tree, hf_ses_segment_data, tvb, offset, fragment_len, ENC_NA); proto_item_append_text (ti, " (%d byte%s)", fragment_len, plurality (fragment_len, "", "s")); frag_msg = fragment_add_seq_next (&ses_reassembly_table, tvb, offset, pinfo, ses_id, NULL, fragment_len, (enclosure_item_flags & END_SPDU) ? FALSE : TRUE); next_tvb = process_reassembled_data (tvb, offset, pinfo, "Reassembled SES", frag_msg, &ses_frag_items, NULL, (enclosure_item_flags & END_SPDU) ? tree : ses_tree); has_user_information = TRUE; offset += fragment_len; } if (has_user_information && next_tvb) { if (!pres_handle) { call_dissector(data_handle, next_tvb, pinfo, tree); } else { /* Pass the session pdu to the presentation dissector */ call_dissector_with_data(pres_handle, next_tvb, pinfo, tree, &session); } /* * No more SPDUs to dissect. Set the offset to the * end of the tvbuff. */ offset = tvb_captured_length(tvb); if (session.rtse_reassemble && type == SES_DATA_TRANSFER) { ses_pres_ctx_id = session.pres_ctx_id; ses_rtse_reassemble = TRUE; } } return offset; }
static void dissect_tzsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *tzsp_tree = NULL; proto_item *ti = NULL; int pos = 0; tvbuff_t *next_tvb; guint16 encapsulation = 0; int wtap_encap; dissector_handle_t encap_dissector; const char *encap_name; const char *info; guint8 type; col_set_str(pinfo->cinfo, COL_PROTOCOL, "TZSP"); col_clear(pinfo->cinfo, COL_INFO); type = tvb_get_guint8(tvb, 1); /* Find the dissector. */ encapsulation = tvb_get_ntohs(tvb, 2); if (encapsulation != 0) { wtap_encap = tzsp_encap_to_wtap_encap(encapsulation); if ((wtap_encap != -1) && (encap_dissector = dissector_get_uint_handle(encap_dissector_table, wtap_encap))) { encap_name = dissector_handle_get_short_name(encap_dissector); } else { encap_name = "Unknown"; } info = encap_name; } else { wtap_encap = -1; encap_name = "Nothing"; info = val_to_str(type, tzsp_type, "Unknown (%u)"); } col_add_str(pinfo->cinfo, COL_INFO, info); if (tree) { /* Adding TZSP item and subtree */ ti = proto_tree_add_protocol_format(tree, proto_tzsp, tvb, 0, -1, "TZSP: %s: ", info); tzsp_tree = proto_item_add_subtree(ti, ett_tzsp); proto_tree_add_item (tzsp_tree, hf_tzsp_version, tvb, 0, 1, ENC_BIG_ENDIAN); proto_tree_add_uint (tzsp_tree, hf_tzsp_type, tvb, 1, 1, type); proto_tree_add_uint_format (tzsp_tree, hf_tzsp_encap, tvb, 2, 2, encapsulation, "Encapsulates: %s (%d)", encap_name, encapsulation); } /* * XXX - what about TZSP_CONFIG frames? * * The MIB at * * http://web.archive.org/web/20021221195733/http://www.networkchemistry.com/support/appnotes/SENSOR-MIB * * seems to indicate that you can configure the probe using SNMP; * does TZSP_CONFIG also support that? An old version of Kismet * included code to control a Network Chemistry WSP100 sensor: * * https://www.kismetwireless.net/code-old/svn/tags/kismet-2004-02-R1/wsp100source.cc * * and it used SNMP to configure the probe. */ if ((type != TZSP_NULL) && (type != TZSP_PORT)) { pos = add_option_info(tvb, 4, tzsp_tree, ti); if (tree) proto_item_set_end(ti, tvb, pos); next_tvb = tvb_new_subset_remaining(tvb, pos); if ((encapsulation != 0) && ((wtap_encap == -1) || !dissector_try_uint(encap_dissector_table, wtap_encap, next_tvb, pinfo, tree))) { col_set_str(pinfo->cinfo, COL_PROTOCOL, "UNKNOWN"); col_add_fstr(pinfo->cinfo, COL_INFO, "TZSP_ENCAP = %u", encapsulation); call_dissector(data_handle, next_tvb, pinfo, tree); } } }
/* Code to actually dissect the packets */ static void dissect_ccsds(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset = 0; proto_item *ccsds_packet; proto_tree *ccsds_tree = NULL; proto_item *primary_header = NULL; proto_tree *primary_header_tree; guint16 first_word; guint32 coarse_time; guint8 fine_time; proto_item *secondary_header; proto_tree *secondary_header_tree; const char* time_string; gint ccsds_length; gint length = 0; gint reported_length; guint8 checkword_flag = 0; gint counter = 0; proto_item *item = NULL; proto_tree *checkword_tree; guint16 checkword_field = 0; guint16 checkword_sum = 0; col_set_str(pinfo->cinfo, COL_PROTOCOL, "CCSDS"); col_set_str(pinfo->cinfo, COL_INFO, "CCSDS Packet"); first_word=tvb_get_ntohs(tvb, 0); col_add_fstr(pinfo->cinfo, COL_INFO, "APID %1$4d (0x%1$03X)", first_word&HDR_APID); reported_length = tvb_reported_length_remaining(tvb, 0); ccsds_length = tvb_get_ntohs(tvb, 4) + CCSDS_PRIMARY_HEADER_LENGTH + 1; if (tree) { /* Min length is size of headers, whereas max length is reported length. * If the length field in the CCSDS header is outside of these bounds, * use the value it violates. Otherwise, use the length field value. */ if (ccsds_length > reported_length) length = reported_length; else if (ccsds_length < CCSDS_PRIMARY_HEADER_LENGTH + CCSDS_SECONDARY_HEADER_LENGTH) length = CCSDS_PRIMARY_HEADER_LENGTH + CCSDS_SECONDARY_HEADER_LENGTH; else length = ccsds_length; ccsds_packet = proto_tree_add_item(tree, proto_ccsds, tvb, 0, length, ENC_NA); ccsds_tree = proto_item_add_subtree(ccsds_packet, ett_ccsds); /* build the ccsds primary header tree */ primary_header=proto_tree_add_text(ccsds_tree, tvb, offset, CCSDS_PRIMARY_HEADER_LENGTH, "Primary CCSDS Header"); primary_header_tree=proto_item_add_subtree(primary_header, ett_ccsds_primary_header); proto_tree_add_uint(primary_header_tree, hf_ccsds_version, tvb, offset, 2, first_word); proto_tree_add_uint(primary_header_tree, hf_ccsds_type, tvb, offset, 2, first_word); proto_tree_add_boolean(primary_header_tree, hf_ccsds_secheader, tvb, offset, 2, first_word); proto_tree_add_uint(primary_header_tree, hf_ccsds_apid, tvb, offset, 2, first_word); offset += 2; proto_tree_add_item(primary_header_tree, hf_ccsds_seqflag, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(primary_header_tree, hf_ccsds_seqnum, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; item = proto_tree_add_item(primary_header_tree, hf_ccsds_length, tvb, offset, 2, ENC_BIG_ENDIAN); } if (ccsds_length > reported_length) { expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "Length field value is greater than the packet seen on the wire"); } if (tree) { offset += 2; proto_item_set_end(primary_header, tvb, offset); /* build the ccsds secondary header tree */ if ( first_word & HDR_SECHDR ) { secondary_header=proto_tree_add_text(ccsds_tree, tvb, offset, CCSDS_SECONDARY_HEADER_LENGTH, "Secondary CCSDS Header"); secondary_header_tree=proto_item_add_subtree(secondary_header, ett_ccsds_secondary_header); /* command ccsds secondary header flags */ coarse_time=tvb_get_ntohl(tvb, offset); proto_tree_add_item(secondary_header_tree, hf_ccsds_coarse_time, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; fine_time=tvb_get_guint8(tvb, offset); proto_tree_add_item(secondary_header_tree, hf_ccsds_fine_time, tvb, offset, 1, ENC_BIG_ENDIAN); ++offset; time_string = embedded_time_to_string ( coarse_time, fine_time ); proto_tree_add_text(secondary_header_tree, tvb, offset-5, 5, "%s = Embedded Time", time_string); proto_tree_add_item(secondary_header_tree, hf_ccsds_timeid, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_checkword_flag, tvb, offset, 1, ENC_BIG_ENDIAN); /* Global Preference: how to handle checkword flag */ switch (global_dissect_checkword) { case 0: /* force checkword presence flag to be false */ checkword_flag = 0; break; case 1: /* force checkword presence flag to be true */ checkword_flag = 1; break; default: /* use value of checkword presence flag from header */ checkword_flag = (tvb_get_guint8(tvb, offset)&0x20) >> 5; break; } /* payload specific ccsds secondary header flags */ if ( first_word & HDR_TYPE ) { proto_tree_add_item(secondary_header_tree, hf_ccsds_zoe, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_packet_type_unused, tvb, offset, 1, ENC_BIG_ENDIAN); ++offset; proto_tree_add_item(secondary_header_tree, hf_ccsds_vid, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(secondary_header_tree, hf_ccsds_dcc, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; } /* core specific ccsds secondary header flags */ else { /* proto_tree_add_item(secondary_header_tree, hf_ccsds_spare1, tvb, offset, 1, ENC_BIG_ENDIAN); */ proto_tree_add_item(secondary_header_tree, hf_ccsds_packet_type, tvb, offset, 1, ENC_BIG_ENDIAN); ++offset; /* proto_tree_add_item(secondary_header_tree, hf_ccsds_spare2, tvb, offset, 2, ENC_BIG_ENDIAN); */ proto_tree_add_item(secondary_header_tree, hf_ccsds_element_id, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_cmd_data_packet, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_format_version_id, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_extended_format_id, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* proto_tree_add_item(secondary_header_tree, hf_ccsds_spare3, tvb, offset, 1, ENC_BIG_ENDIAN); */ ++offset; proto_tree_add_item(secondary_header_tree, hf_ccsds_frame_id, tvb, offset, 1, ENC_BIG_ENDIAN); ++offset; } /* finish the ccsds secondary header */ proto_item_set_end(secondary_header, tvb, offset); } /* If there wasn't a full packet, then don't allow a tree item for checkword. */ if (reported_length < ccsds_length || ccsds_length < CCSDS_PRIMARY_HEADER_LENGTH + CCSDS_SECONDARY_HEADER_LENGTH) { /* Label CCSDS payload 'User Data' */ if (length > offset) proto_tree_add_text(ccsds_tree, tvb, offset, length-offset, "User Data"); offset += length-offset; if (checkword_flag == 1) proto_tree_add_text(ccsds_tree, tvb, offset, 0, "Packet does not contain a Checkword"); } /* Handle checkword according to CCSDS preference setting. */ else { /* Label CCSDS payload 'User Data' */ proto_tree_add_text(ccsds_tree, tvb, offset, length-offset-2*checkword_flag, "User Data"); offset += length-offset-2*checkword_flag; /* If checkword is present, calculate packet checksum (16-bit running sum) for comparison */ if (checkword_flag == 1) { /* don't count the checkword as part of the checksum */ while (counter < ccsds_length-2) { checkword_sum += tvb_get_ntohs(tvb, counter); counter += 2; } checkword_field = tvb_get_ntohs(tvb, offset); /* Report checkword status */ if (checkword_sum == checkword_field) { item = proto_tree_add_uint_format(ccsds_tree, hf_ccsds_checkword, tvb, offset, 2, checkword_field, "CCSDS checkword: 0x%04x [correct]", checkword_field); checkword_tree = proto_item_add_subtree(item, ett_ccsds_checkword); item = proto_tree_add_boolean(checkword_tree, hf_ccsds_checkword_good, tvb, offset, 2, TRUE); PROTO_ITEM_SET_GENERATED(item); item = proto_tree_add_boolean(checkword_tree, hf_ccsds_checkword_bad, tvb, offset, 2, FALSE); PROTO_ITEM_SET_GENERATED(item); } else { item = proto_tree_add_uint_format(ccsds_tree, hf_ccsds_checkword, tvb, offset, 2, checkword_field, "CCSDS checkword: 0x%04x [incorrect, should be 0x%04x]", checkword_field, checkword_sum); checkword_tree = proto_item_add_subtree(item, ett_ccsds_checkword); item = proto_tree_add_boolean(checkword_tree, hf_ccsds_checkword_good, tvb, offset, 2, FALSE); PROTO_ITEM_SET_GENERATED(item); item = proto_tree_add_boolean(checkword_tree, hf_ccsds_checkword_bad, tvb, offset, 2, TRUE); PROTO_ITEM_SET_GENERATED(item); } offset += 2; } } /* Give the data dissector any bytes past the CCSDS packet length */ /* (XXX: Not really OK under 'if (tree)' but will work; see packet-data.c */ call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree); } /* if(tree) */
/* Code to actually dissect the packets */ static void dissect_ccsds(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset = 0; proto_item *ccsds_packet; proto_tree *ccsds_tree; proto_item *primary_header; proto_tree *primary_header_tree; guint16 first_word; guint32 coarse_time; guint8 fine_time; proto_item *secondary_header; proto_tree *secondary_header_tree; const char *time_string; gint ccsds_length; gint length = 0; gint reported_length; guint8 checkword_flag = 0; gint counter = 0; proto_item *item, *checkword_item = NULL; proto_tree *checkword_tree; guint16 checkword_field = 0; guint16 checkword_sum = 0; tvbuff_t *next_tvb; static const int * header_flags[] = { &hf_ccsds_version, &hf_ccsds_type, &hf_ccsds_secheader, &hf_ccsds_apid, NULL }; col_set_str(pinfo->cinfo, COL_PROTOCOL, "CCSDS"); col_set_str(pinfo->cinfo, COL_INFO, "CCSDS Packet"); first_word = tvb_get_ntohs(tvb, 0); col_add_fstr(pinfo->cinfo, COL_INFO, "APID %4d (0x%03X)", first_word&HDR_APID, first_word&HDR_APID); reported_length = tvb_reported_length_remaining(tvb, 0); ccsds_length = tvb_get_ntohs(tvb, 4) + CCSDS_PRIMARY_HEADER_LENGTH + 1; /* Min length is size of headers, whereas max length is reported length. * If the length field in the CCSDS header is outside of these bounds, * use the value it violates. Otherwise, use the length field value. */ if (ccsds_length > reported_length) length = reported_length; else if (ccsds_length < CCSDS_PRIMARY_HEADER_LENGTH + CCSDS_SECONDARY_HEADER_LENGTH) length = CCSDS_PRIMARY_HEADER_LENGTH + CCSDS_SECONDARY_HEADER_LENGTH; else length = ccsds_length; ccsds_packet = proto_tree_add_item(tree, proto_ccsds, tvb, 0, length, ENC_NA); ccsds_tree = proto_item_add_subtree(ccsds_packet, ett_ccsds); /* build the ccsds primary header tree */ primary_header_tree = proto_tree_add_subtree(ccsds_tree, tvb, offset, CCSDS_PRIMARY_HEADER_LENGTH, ett_ccsds_primary_header, &primary_header, "Primary CCSDS Header"); proto_tree_add_bitmask(primary_header_tree, tvb, offset, hf_ccsds_header_flags, ett_ccsds_primary_header_flags, header_flags, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(primary_header_tree, hf_ccsds_seqflag, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(primary_header_tree, hf_ccsds_seqnum, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; item = proto_tree_add_item(primary_header_tree, hf_ccsds_length, tvb, offset, 2, ENC_BIG_ENDIAN); if (ccsds_length > reported_length) { expert_add_info(pinfo, item, &ei_ccsds_length_error); } offset += 2; proto_item_set_end(primary_header, tvb, offset); /* build the ccsds secondary header tree */ if ( first_word & HDR_SECHDR ) { secondary_header_tree = proto_tree_add_subtree(ccsds_tree, tvb, offset, CCSDS_SECONDARY_HEADER_LENGTH, ett_ccsds_secondary_header, &secondary_header, "Secondary CCSDS Header"); /* command ccsds secondary header flags */ coarse_time = tvb_get_ntohl(tvb, offset); proto_tree_add_item(secondary_header_tree, hf_ccsds_coarse_time, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; fine_time = tvb_get_guint8(tvb, offset); proto_tree_add_item(secondary_header_tree, hf_ccsds_fine_time, tvb, offset, 1, ENC_BIG_ENDIAN); ++offset; time_string = embedded_time_to_string ( coarse_time, fine_time ); proto_tree_add_string(secondary_header_tree, hf_ccsds_embedded_time, tvb, offset-5, 5, time_string); proto_tree_add_item(secondary_header_tree, hf_ccsds_timeid, tvb, offset, 1, ENC_BIG_ENDIAN); checkword_item = proto_tree_add_item(secondary_header_tree, hf_ccsds_checkword_flag, tvb, offset, 1, ENC_BIG_ENDIAN); /* Global Preference: how to handle checkword flag */ switch (global_dissect_checkword) { case 0: /* force checkword presence flag to be false */ checkword_flag = 0; break; case 1: /* force checkword presence flag to be true */ checkword_flag = 1; break; default: /* use value of checkword presence flag from header */ checkword_flag = (tvb_get_guint8(tvb, offset)&0x20) >> 5; break; } /* payload specific ccsds secondary header flags */ if ( first_word & HDR_TYPE ) { proto_tree_add_item(secondary_header_tree, hf_ccsds_zoe, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_packet_type_unused, tvb, offset, 1, ENC_BIG_ENDIAN); ++offset; proto_tree_add_item(secondary_header_tree, hf_ccsds_vid, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(secondary_header_tree, hf_ccsds_dcc, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; } /* core specific ccsds secondary header flags */ else { /* proto_tree_add_item(secondary_header_tree, hf_ccsds_spare1, tvb, offset, 1, ENC_BIG_ENDIAN); */ proto_tree_add_item(secondary_header_tree, hf_ccsds_packet_type, tvb, offset, 1, ENC_BIG_ENDIAN); ++offset; /* proto_tree_add_item(secondary_header_tree, hf_ccsds_spare2, tvb, offset, 2, ENC_BIG_ENDIAN); */ proto_tree_add_item(secondary_header_tree, hf_ccsds_element_id, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_cmd_data_packet, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_format_version_id, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_extended_format_id, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* proto_tree_add_item(secondary_header_tree, hf_ccsds_spare3, tvb, offset, 1, ENC_BIG_ENDIAN); */ ++offset; proto_tree_add_item(secondary_header_tree, hf_ccsds_frame_id, tvb, offset, 1, ENC_BIG_ENDIAN); ++offset; } /* finish the ccsds secondary header */ proto_item_set_end(secondary_header, tvb, offset); }
/* Main dissector routine to be invoked for a DIS PDU. */ static gint dissect_dis(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *dis_tree = 0; proto_item *dis_node = 0; proto_item *dis_header_tree = 0; proto_item *dis_header_node = 0; proto_item *dis_payload_tree = 0; proto_item *dis_payload_node = 0; gint offset = 0; const gchar *pduString = 0; DIS_ParserNode *pduParser = 0; /* DIS packets must be at least 12 bytes long. DIS uses port 3000, by * default, but the Cisco Redundant Link Management protocol can also use * that port; RLM packets are 8 bytes long, so we use this to distinguish * between them. */ if (tvb_reported_length(tvb) < 12) { return 0; } /* Reset the global PDU type variable -- this will be parsed as part of * the DIS header. */ pduType = DIS_PDUTYPE_OTHER; protocolFamily = DIS_PROTOCOLFAMILY_OTHER; persistentObjectPduType = DIS_PERSISTENT_OBJECT_TYPE_OTHER; /* set the protocol column */ col_set_str(pinfo->cinfo, COL_PROTOCOL, dis_proto_name_short); /* Add the top-level DIS node under which the rest of the fields will be * displayed. */ dis_node = proto_tree_add_protocol_format(tree, proto_dis, tvb, offset, -1, "Distributed Interactive Simulation"); dis_tree = proto_item_add_subtree(dis_node, ett_dis); /* Add a node to contain the DIS header fields. */ dis_header_node = proto_tree_add_text(dis_tree, tvb, offset, -1, "Header"); dis_header_tree = proto_item_add_subtree(dis_header_node, ett_dis_header); offset = parseFields(tvb, dis_header_tree, offset, DIS_FIELDS_PDU_HEADER); proto_item_set_end(dis_header_node, tvb, offset); /* Locate the string name for the PDU type enumeration, * or default to "Unknown". */ pduString = val_to_str(pduType, DIS_PDU_Type_Strings, "Unknown"); /* Locate the appropriate PDU parser, if type is known. */ switch (protocolFamily) { case DIS_PROTOCOLFAMILY_PERSISTENT_OBJECT: { proto_item *dis_po_header_tree = 0; proto_item *dis_po_header_node = 0; dis_po_header_node = proto_tree_add_text (dis_header_tree, tvb, offset, -1, "PO Header"); dis_po_header_tree = proto_item_add_subtree (dis_po_header_node, ett_dis_po_header); offset = parseFields (tvb, dis_po_header_tree, offset, DIS_FIELDS_PERSISTENT_OBJECT_HEADER); proto_item_set_end(dis_po_header_node, tvb, offset); /* Locate the appropriate PO PDU parser, if type is known. */ switch (persistentObjectPduType) { case DIS_PERSISTENT_OBJECT_TYPE_SIMULATOR_PRESENT: pduParser = DIS_PARSER_SIMULATOR_PRESENT_PO_PDU; break; case DIS_PERSISTENT_OBJECT_TYPE_DESCRIBE_OBJECT: pduParser = DIS_PARSER_DESCRIBE_OBJECT_PO_PDU; break; case DIS_PERSISTENT_OBJECT_TYPE_OBJECTS_PRESENT: pduParser = DIS_PARSER_OBJECTS_PRESENT_PO_PDU; break; case DIS_PERSISTENT_OBJECT_TYPE_OBJECT_REQUEST: pduParser = DIS_PARSER_OBJECT_REQUEST_PO_PDU; break; case DIS_PERSISTENT_OBJECT_TYPE_DELETE_OBJECTS: pduParser = DIS_PARSER_DELETE_OBJECTS_PO_PDU; break; case DIS_PERSISTENT_OBJECT_TYPE_SET_WORLD_STATE: pduParser = DIS_PARSER_SET_WORLD_STATE_PO_PDU; break; case DIS_PERSISTENT_OBJECT_TYPE_NOMINATION: pduParser = DIS_PARSER_NOMINATION_PO_PDU; break; default: pduParser = 0; break; } /* Locate the string name for the PO PDU type enumeration, * or default to "Unknown". */ pduString = val_to_str (persistentObjectPduType, DIS_PDU_PersistentObjectType_Strings, "Unknown"); /* Add a node to contain the DIS PDU fields. */ dis_payload_node = proto_tree_add_text(dis_tree, tvb, offset, -1, "%s PO PDU", pduString); } break; default: /* Add a node to contain the DIS PDU fields. */ dis_payload_node = proto_tree_add_text(dis_tree, tvb, offset, -1, "%s PDU", pduString); switch (pduType) { /* DIS Entity Information / Interaction PDUs */ case DIS_PDUTYPE_ENTITY_STATE: pduParser = DIS_PARSER_ENTITY_STATE_PDU; break; /* DIS Distributed Emission Regeneration PDUs */ case DIS_PDUTYPE_ELECTROMAGNETIC_EMISSION: pduParser = DIS_PARSER_ELECTROMAGNETIC_EMISSION_PDU; break; /* DIS Radio Communications protocol (RCP) family PDUs */ case DIS_PDUTYPE_TRANSMITTER: pduParser = DIS_PARSER_TRANSMITTER_PDU; break; case DIS_PDUTYPE_SIGNAL: pduParser = DIS_PARSER_SIGNAL_PDU; break; /* DIS Warfare PDUs */ case DIS_PDUTYPE_FIRE: pduParser = DIS_PARSER_FIRE_PDU; break; case DIS_PDUTYPE_DETONATION: if ( disProtocolVersion < DIS_VERSION_IEEE_1278_1_200X ) { pduParser = DIS_PARSER_DETONATION_PDU; } else { /* TODO: Version 7 changed the Detonation PDU format * Need a different parser */ pduParser = DIS_PARSER_DETONATION_PDU; } break; /* DIS Simulation Management PDUs */ case DIS_PDUTYPE_START_RESUME: pduParser = DIS_PARSER_START_RESUME_PDU; break; case DIS_PDUTYPE_STOP_FREEZE: pduParser = DIS_PARSER_STOP_FREEZE_PDU; break; case DIS_PDUTYPE_ACKNOWLEDGE: pduParser = DIS_PARSER_ACKNOWLEDGE_PDU; break; case DIS_PDUTYPE_ACTION_REQUEST: pduParser = DIS_PARSER_ACTION_REQUEST_PDU; break; case DIS_PDUTYPE_ACTION_RESPONSE: pduParser = DIS_PARSER_ACTION_RESPONSE_PDU; break; case DIS_PDUTYPE_DATA: case DIS_PDUTYPE_SET_DATA: pduParser = DIS_PARSER_DATA_PDU; break; case DIS_PDUTYPE_DATA_QUERY: pduParser = DIS_PARSER_DATA_QUERY_PDU; break; case DIS_PDUTYPE_COMMENT: pduParser = DIS_PARSER_COMMENT_PDU; break; case DIS_PDUTYPE_CREATE_ENTITY: case DIS_PDUTYPE_REMOVE_ENTITY: pduParser = DIS_PARSER_SIMAN_ENTITY_PDU; break; /* DIS Simulation Management with Reliability PDUs */ case DIS_PDUTYPE_START_RESUME_R: pduParser = DIS_PARSER_START_RESUME_R_PDU; break; case DIS_PDUTYPE_STOP_FREEZE_R: pduParser = DIS_PARSER_STOP_FREEZE_R_PDU; break; case DIS_PDUTYPE_ACKNOWLEDGE_R: pduParser = DIS_PARSER_ACKNOWLEDGE_PDU; break; case DIS_PDUTYPE_ACTION_REQUEST_R: pduParser = DIS_PARSER_ACTION_REQUEST_R_PDU; break; case DIS_PDUTYPE_ACTION_RESPONSE_R: pduParser = DIS_PARSER_ACTION_RESPONSE_PDU; break; case DIS_PDUTYPE_DATA_R: case DIS_PDUTYPE_SET_DATA_R: pduParser = DIS_PARSER_DATA_R_PDU; break; case DIS_PDUTYPE_DATA_QUERY_R: pduParser = DIS_PARSER_DATA_QUERY_R_PDU; break; case DIS_PDUTYPE_COMMENT_R: pduParser = DIS_PARSER_COMMENT_PDU; break; case DIS_PDUTYPE_CREATE_ENTITY_R: case DIS_PDUTYPE_REMOVE_ENTITY_R: pduParser = DIS_PARSER_SIMAN_ENTITY_R_PDU; break; /* DIS Experimental V-DIS PDUs */ case DIS_PDUTYPE_APPLICATION_CONTROL: pduParser = DIS_PARSER_APPLICATION_CONTROL_PDU; break; default: pduParser = 0; break; } break; } /* If a parser was located, invoke it on the data packet. */ if (pduParser != 0) { dis_payload_tree = proto_item_add_subtree(dis_payload_node, ett_dis_payload); offset = parseFields(tvb, dis_payload_tree, offset, pduParser); proto_item_set_end(dis_payload_node, tvb, offset); } /* Add detail to the INFO column */ switch (pduType) { /* DIS Entity Information / Interaction PDUs */ case DIS_PDUTYPE_ENTITY_STATE: col_add_fstr( pinfo->cinfo, COL_INFO, "PDUType: %s, %s, %s", pduString, val_to_str(entityKind, DIS_PDU_EntityKind_Strings, "Unknown Entity Kind"), val_to_str(entityDomain, DIS_PDU_Domain_Strings, "Unknown Entity Domain") ); break; case DIS_PDUTYPE_SIGNAL: col_add_fstr( pinfo->cinfo, COL_INFO, "PDUType: %s, RadioID=%u, Encoding Type=%s, Number of Samples=%u", pduString, radioID, val_to_str(DIS_ENCODING_TYPE(encodingScheme), DIS_PDU_Encoding_Type_Strings, "Unknown Encoding Type"), numSamples ); break; case DIS_PDUTYPE_TRANSMITTER: col_add_fstr( pinfo->cinfo, COL_INFO, "PDUType: %s, RadioID=%u, Transmit State=%s", pduString, radioID, val_to_str(disRadioTransmitState, DIS_PDU_RadioTransmitState_Strings, "Unknown Transmit State") ); break; default: /* set the basic info column (pdu type) */ col_add_fstr( pinfo->cinfo, COL_INFO, "PDUType: %s", pduString); break; } return tvb_length(tvb); }
static void display_socks_v5(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, socks_hash_entry_t *hash_info) { /* Display the protocol tree for the version. This routine uses the */ /* stored conversation information to decide what to do with the row. */ /* Per packet information would have been better to do this, but we */ /* didn't have that when I wrote this. And I didn't expect this to get */ /* so messy. */ unsigned int i, command; guint temp; const char *AuthMethodStr; guint8 auth_status; proto_tree_add_item( tree, hf_socks_ver, tvb, offset, 1, FALSE); ++offset; if (compare_packet( hash_info->connect_row)){ proto_tree *AuthTree; proto_item *ti; temp = tvb_get_guint8(tvb, offset); /* Get Auth method count */ /* build auth tree */ ti = proto_tree_add_text( tree, tvb, offset, -1, "Client Authentication Methods"); AuthTree = proto_item_add_subtree(ti, ett_socks_auth); proto_tree_add_text( AuthTree, tvb, offset, 1, "Count: %u", temp); ++offset; for( i = 0; i < temp; ++i) { AuthMethodStr = get_auth_method_name( tvb_get_guint8( tvb, offset)); proto_tree_add_text( AuthTree, tvb, offset, 1, "Method[%u]: %u (%s)", i, tvb_get_guint8( tvb, offset), AuthMethodStr); ++offset; } proto_item_set_end( ti, tvb, offset); return; } /* Get accepted auth method */ else if (compare_packet( hash_info->auth_method_row)) { proto_tree_add_text( tree, tvb, offset, 1, "Accepted Auth Method: 0x%0x (%s)", tvb_get_guint8( tvb, offset), get_auth_method_name( tvb_get_guint8( tvb, offset))); return; } /* handle user/password auth */ else if (compare_packet( hash_info->user_name_auth_row)) { /* process user name */ offset += display_string( tvb, offset, tree, "User name"); /* process password */ offset += display_string( tvb, offset, tree, "Password"); } /* command to the server */ /* command response from server */ else if (compare_packet( hash_info->auth_version)) { auth_status = tvb_get_guint8(tvb, offset); if(auth_status != 0) proto_tree_add_text( tree, tvb, offset, 1, "Status: %u (failure)", auth_status); else proto_tree_add_text( tree, tvb, offset, 1, "Status: success"); offset ++; } else if (compare_packet( hash_info->gssapi_auth_row)) { guint16 len; proto_tree_add_item( tree, hf_gssapi_command, tvb, offset, 1, FALSE); proto_tree_add_item( tree, hf_gssapi_length, tvb, offset+1, 2, FALSE); len = tvb_get_ntohs(tvb, offset+1); if (len > 0) proto_tree_add_item( tree, hf_gssapi_payload, tvb, offset+3, len, FALSE); } else if (compare_packet( hash_info->gssapi_auth_failure_row)) { proto_tree_add_item( tree, hf_gssapi_command, tvb, offset, 1, FALSE); } else if (compare_packet( hash_info->gssapi_auth_reply_row)) { guint16 len; proto_tree_add_item( tree, hf_gssapi_command, tvb, offset, 1, FALSE); proto_tree_add_item( tree, hf_gssapi_length, tvb, offset+1, 2, FALSE); len = tvb_get_ntohs(tvb, offset+1); if (len > 0) proto_tree_add_item( tree, hf_gssapi_payload, tvb, offset+3, len, FALSE); } else if ((compare_packet( hash_info->command_row)) || (compare_packet( hash_info->cmd_reply_row)) || (compare_packet( hash_info->bind_reply_row))){ command = tvb_get_guint8(tvb, offset); if (compare_packet( hash_info->command_row)) proto_tree_add_uint( tree, hf_socks_cmd, tvb, offset, 1, command); else { proto_item *hidden_item; proto_tree_add_item( tree, hf_socks_results_5, tvb, offset, 1, FALSE); hidden_item = proto_tree_add_item(tree, hf_socks_results, tvb, offset, 1, FALSE); PROTO_ITEM_SET_HIDDEN(hidden_item); } ++offset; proto_tree_add_text( tree, tvb, offset, 1, "Reserved: 0x%0x (should = 0x00)", tvb_get_guint8(tvb, offset)); ++offset; offset = display_address(tvb, offset, tree); /*XXX Add remote port for search somehow */ /* Do remote port */ proto_tree_add_text( tree, tvb, offset, 2, "%sPort: %u", (compare_packet( hash_info->bind_reply_row) ? "Remote Host " : ""), tvb_get_ntohs(tvb, offset)); } }
/* * Dissect an SPDU. */ static int dissect_spdu(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, gboolean tokens, gboolean connectionless) { gboolean has_user_information = FALSE; guint8 type; proto_item *ti = NULL; proto_tree *ses_tree = NULL; int len_len; guint16 parameters_len; tvbuff_t *next_tvb; void *save_private_data; guint32 *pres_ctx_id = NULL; struct SESSION_DATA_STRUCTURE session; /* * Get SPDU type. */ type = tvb_get_guint8(tvb, offset); session.spdu_type = type; session.abort_type = SESSION_NO_ABORT; session.ros_op = 0; session.rtse_reassemble = FALSE; if(connectionless) { if (check_col(pinfo->cinfo, COL_INFO)) col_add_str(pinfo->cinfo, COL_INFO, val_to_str(type, ses_vals, "Unknown SPDU type (0x%02x)")); if (tree) { ti = proto_tree_add_item(tree, proto_clses, tvb, offset, -1, FALSE); ses_tree = proto_item_add_subtree(ti, ett_ses); proto_tree_add_uint(ses_tree, hf_ses_type, tvb, offset, 1, type); } has_user_information = TRUE; } else if (tokens) { if (check_col(pinfo->cinfo, COL_INFO)) col_add_str(pinfo->cinfo, COL_INFO, val_to_str(type, ses_category0_vals, "Unknown SPDU type (0x%02x)")); if (tree) { ti = proto_tree_add_item(tree, proto_ses, tvb, offset, -1, FALSE); ses_tree = proto_item_add_subtree(ti, ett_ses); proto_tree_add_uint(ses_tree, hf_ses_type_0, tvb, offset, 1, type); } } else { if (check_col(pinfo->cinfo, COL_INFO)) col_add_str(pinfo->cinfo, COL_INFO, val_to_str(type, ses_vals, "Unknown SPDU type (0x%02x)")); if (tree) { ti = proto_tree_add_item(tree, proto_ses, tvb, offset, -1, FALSE); ses_tree = proto_item_add_subtree(ti, ett_ses); proto_tree_add_uint(ses_tree, hf_ses_type, tvb, offset, 1, type); } /* * Might this SPDU have a User Information field? */ switch (type) { case SES_DATA_TRANSFER: case SES_EXPEDITED: case SES_TYPED_DATA: has_user_information = TRUE; break; case SES_MAJOR_SYNC_POINT: pres_ctx_id = p_get_proto_data (pinfo->fd, proto_ses); if (ses_rtse_reassemble != 0 && !pres_ctx_id) { /* First time visited - save pres_ctx_id */ pres_ctx_id = se_alloc (sizeof (guint32)); *pres_ctx_id = ses_pres_ctx_id; p_add_proto_data (pinfo->fd, proto_ses, pres_ctx_id); } if (pres_ctx_id) { session.pres_ctx_id = *pres_ctx_id; session.rtse_reassemble = TRUE; has_user_information = TRUE; } ses_rtse_reassemble = FALSE; break; } } offset++; /* get length of SPDU parameter field */ parameters_len = get_item_len(tvb, offset, &len_len); if (tree) proto_tree_add_uint(ses_tree, hf_ses_length, tvb, offset, len_len, parameters_len); offset += len_len; /* Dissect parameters. */ if (!dissect_parameters(tvb, offset, parameters_len, tree, ses_tree, pinfo, &session)) has_user_information = FALSE; offset += parameters_len; proto_item_set_end(ti, tvb, offset); /* Dissect user information, if present */ if (has_user_information) { if (tvb_reported_length_remaining(tvb, offset) > 0 || type == SES_MAJOR_SYNC_POINT) { next_tvb = tvb_new_subset_remaining(tvb, offset); if(!pres_handle) { call_dissector(data_handle, next_tvb, pinfo, tree); } else { /* save type of session pdu. We'll need it in the presentation dissector */ save_private_data = pinfo->private_data; pinfo->private_data = &session; call_dissector(pres_handle, next_tvb, pinfo, tree); pinfo->private_data = save_private_data; } /* * No more SPDUs to dissect. Set the offset to the * end of the tvbuff. */ offset = tvb_length(tvb); if (session.rtse_reassemble && type == SES_DATA_TRANSFER) { ses_pres_ctx_id = session.pres_ctx_id; ses_rtse_reassemble = TRUE; } } } return offset; }
static void dissect_tzsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *tzsp_tree = NULL; proto_item *ti = NULL; int pos = 0; tvbuff_t *next_tvb; guint16 encapsulation = 0; int wtap_encap; dissector_handle_t encap_dissector; const char *encap_name; const char *info; guint8 type; col_set_str(pinfo->cinfo, COL_PROTOCOL, "TZSP"); col_clear(pinfo->cinfo, COL_INFO); type = tvb_get_guint8(tvb, 1); /* Find the dissector. */ encapsulation = tvb_get_ntohs(tvb, 2); if (encapsulation != 0) { wtap_encap = tzsp_encap_to_wtap_encap(encapsulation); if (wtap_encap != -1 && (encap_dissector = dissector_get_port_handle(encap_dissector_table, wtap_encap))) { encap_name = dissector_handle_get_short_name(encap_dissector); } else { encap_name = "Unknown"; } info = encap_name; } else { wtap_encap = -1; encap_name = "Nothing"; info = val_to_str(type, tzsp_type, "Unknown (%u)"); } col_add_str(pinfo->cinfo, COL_INFO, info); if (tree) { /* Adding TZSP item and subtree */ ti = proto_tree_add_protocol_format(tree, proto_tzsp, tvb, 0, -1, "TZSP: %s: ", info); tzsp_tree = proto_item_add_subtree(ti, ett_tzsp); proto_tree_add_item (tzsp_tree, hf_tzsp_version, tvb, 0, 1, FALSE); proto_tree_add_uint (tzsp_tree, hf_tzsp_type, tvb, 1, 1, type); proto_tree_add_uint_format (tzsp_tree, hf_tzsp_encap, tvb, 2, 2, encapsulation, "Encapsulates: %s (%d)", encap_name, encapsulation); } if (type != 4 && type != 5) { pos = add_option_info(tvb, 4, tzsp_tree, ti); if (tree) proto_item_set_end(ti, tvb, pos); next_tvb = tvb_new_subset_remaining(tvb, pos); if (encapsulation != 0 && (wtap_encap == -1 || !dissector_try_port(encap_dissector_table, wtap_encap, next_tvb, pinfo, tree))) { col_set_str(pinfo->cinfo, COL_PROTOCOL, "UNKNOWN"); if (check_col(pinfo->cinfo, COL_INFO)) col_add_fstr(pinfo->cinfo, COL_INFO, "TZSP_ENCAP = %u", encapsulation); call_dissector(data_handle, next_tvb, pinfo, tree); } } }
static int dissect_report_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ltp_tree, int frame_offset) { guint64 rpt_sno; guint64 chkp_sno; guint64 upper_bound; guint64 lower_bound; int rcpt_clm_cnt; guint64 offset; guint64 length; int rpt_sno_size; int chkp_sno_size; int upper_bound_size; int lower_bound_size; int rcpt_clm_cnt_size; int offset_size; int length_size; int segment_offset = 0; int i; proto_item *ltp_rpt_item; proto_item *ltp_rpt_clm_item; proto_tree *ltp_rpt_tree; proto_tree *ltp_rpt_clm_tree; /* Create the subtree for report segment under the main LTP tree and all the report segment fields under it */ ltp_rpt_item = proto_tree_add_text(ltp_tree, tvb, frame_offset, -1, "Report Segment"); ltp_rpt_tree = proto_item_add_subtree(ltp_rpt_item, ett_rpt_segm); /* Extract the report segment info */ rpt_sno = evaluate_sdnv_64(tvb, frame_offset, &rpt_sno_size); proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_sno, tvb, frame_offset + segment_offset, rpt_sno_size, rpt_sno); segment_offset += rpt_sno_size; chkp_sno = evaluate_sdnv_64(tvb, frame_offset + segment_offset, &chkp_sno_size); proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_chkp, tvb, frame_offset + segment_offset, chkp_sno_size, chkp_sno); segment_offset += chkp_sno_size; upper_bound = evaluate_sdnv(tvb, frame_offset + segment_offset, &upper_bound_size); proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_ub, tvb, frame_offset + segment_offset, upper_bound_size, upper_bound); segment_offset += upper_bound_size; lower_bound = evaluate_sdnv(tvb, frame_offset + segment_offset, &lower_bound_size); proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_lb, tvb, frame_offset + segment_offset, lower_bound_size, lower_bound); segment_offset += lower_bound_size; rcpt_clm_cnt = evaluate_sdnv(tvb, frame_offset + segment_offset, &rcpt_clm_cnt_size); if (rcpt_clm_cnt < 0){ proto_item_set_end(ltp_rpt_item, tvb, frame_offset + segment_offset); expert_add_info_format(pinfo, ltp_tree, PI_UNDECODED, PI_ERROR, "Negative reception claim count: %d", rcpt_clm_cnt); return 0; } /* Each reception claim is at least 2 bytes, so if the count is larger than the * max number of claims we can possibly squeeze into the remaining tvbuff, then * the packet is malformed. */ if (rcpt_clm_cnt > tvb_length_remaining(tvb, frame_offset + segment_offset) / 2) { proto_item_set_end(ltp_rpt_item, tvb, frame_offset + segment_offset); expert_add_info_format(pinfo, ltp_tree, PI_MALFORMED, PI_ERROR, "Reception claim count impossibly large: %d > %d", rcpt_clm_cnt, tvb_length_remaining(tvb, frame_offset + segment_offset) / 2); return 0; } proto_tree_add_uint(ltp_rpt_tree, hf_ltp_rpt_clm_cnt, tvb, frame_offset + segment_offset, rcpt_clm_cnt_size, rcpt_clm_cnt); segment_offset += rcpt_clm_cnt_size; ltp_rpt_clm_item = proto_tree_add_text(ltp_rpt_tree, tvb, frame_offset + segment_offset, -1, "Reception claims"); ltp_rpt_clm_tree = proto_item_add_subtree(ltp_rpt_clm_item, ett_rpt_clm); /* There can be multiple reception claims in the same report segment */ for(i = 0; i<rcpt_clm_cnt; i++){ offset = evaluate_sdnv(tvb,frame_offset + segment_offset, &offset_size); proto_tree_add_uint64_format(ltp_rpt_clm_tree, hf_ltp_rpt_clm_off, tvb, frame_offset + segment_offset, offset_size, offset, "Offset[%d] : %"G_GINT64_MODIFIER"d", i, offset); segment_offset += offset_size; length = evaluate_sdnv(tvb,frame_offset + segment_offset, &length_size); proto_tree_add_uint64_format(ltp_rpt_clm_tree, hf_ltp_rpt_clm_len, tvb, frame_offset + segment_offset, length_size, length, "Length[%d] : %"G_GINT64_MODIFIER"d",i, length); segment_offset += length_size; } proto_item_set_end(ltp_rpt_clm_item, tvb, frame_offset + segment_offset); proto_item_set_end(ltp_rpt_item, tvb, frame_offset + segment_offset); return segment_offset; }
/* G.7041 6.1.2 GFP payload area */ static void dissect_gfp_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree *gfp_tree, guint *offset, guint payload_len) { tvbuff_t *payload_tvb; proto_item *type_ti = NULL; proto_item *fcs_ti; proto_tree *fcs_tree = NULL; guint pti, pfi, exi, upi; guint fcs, fcs_calc; guint fcs_len = 0; /* G.7041 6.1.2.3 Payload area scrambling * Note that payload when sent on the wire is scrambled as per ATM * with a 1 + x^43 multiplicative scrambler. Likely already removed by * the time we get a capture file (as with ATM). Could have a pref, * but if it's present we have to save state over subsequent frames, * always would fail to decode the first 43 payload bytes of a capture. */ /* G.7041 6.1.2.1 Payload Header - at least 4 bytes */ tvb_ensure_bytes_exist(tvb, *offset, 4); payload_len -= 4; /* G.7041 6.1.2.1.1 GFP type field - mandatory 2 bytes */ pti = tvb_get_bits8(tvb, 8*(*offset), 3); pfi = tvb_get_bits8(tvb, 8*(*offset)+3, 1); exi = tvb_get_bits8(tvb, 8*(*offset)+4, 4); upi = tvb_get_guint8(tvb, *offset+1); p_add_proto_data(pinfo->pool, pinfo, proto_gfp, 0, GUINT_TO_POINTER(upi)); col_add_str(pinfo->cinfo, COL_INFO, val_to_str(pti, gfp_pti_vals, "Reserved PTI (%d)")); if (pti == GFP_USER_DATA || pti == GFP_MANAGEMENT_COMMUNICATIONS) { /* G.7041 Table 6-3 - GFP_MANAGEMENT_COMMUNICATIONS * uses the same UPI table as USER_DATA, though * "not all of these UPI types are applicable" in that case. */ type_ti = proto_tree_add_bitmask_with_flags(gfp_tree, tvb, *offset, hf_gfp_type, ett_gfp_type, gfp_type_data_fields, ENC_BIG_ENDIAN, BMT_NO_FLAGS); col_append_sep_str(pinfo->cinfo, COL_INFO, ": ", rval_to_str(upi, gfp_upi_data_rvals, "Unknown 0x%02x")); } else if (pti == GFP_CLIENT_MANAGEMENT) { /* G.7041 Table 6-4 */ type_ti = proto_tree_add_bitmask_with_flags(gfp_tree, tvb, *offset, hf_gfp_type, ett_gfp_type, gfp_type_management_fields, ENC_BIG_ENDIAN, BMT_NO_FLAGS); col_append_sep_str(pinfo->cinfo, COL_INFO, ": ", rval_to_str(upi, gfp_upi_management_rvals, "Unknown 0x%02x")); } /* G.7041 6.1.2.1.2 Type HEC (tHEC) - mandatory 2 bytes */ gfp_add_hec_tree(tvb, pinfo, gfp_tree, offset, 2, hf_gfp_thec, hf_gfp_thec_status, &ei_gfp_thec_bad); switch (exi) { case GFP_EXT_NULL: /* G.7041 6.1.2.1.3.1 Null extension header */ break; case GFP_EXT_LINEAR: /* G.7041 6.1.2.1.3.2 Extension header for a linear frame */ if (payload_len < 4) { expert_add_info(pinfo, type_ti, &ei_gfp_exi_short); payload_len = 0; } else { payload_len -= 4; } proto_tree_add_item(gfp_tree, hf_gfp_cid, tvb, *offset, 1, ENC_BIG_ENDIAN); /* Next byte spare field, reserved */ /* 6.1.2.1.4 Extension HEC field */ gfp_add_hec_tree(tvb, pinfo, gfp_tree, offset, 2, hf_gfp_ehec, hf_gfp_ehec_status, &ei_gfp_ehec_bad); break; case GFP_EXT_RING: /* 6.1.2.1.3.3 Extension header for a ring frame */ /* "For further study." Undefined so fall through */ default: /* Reserved */ /* TODO: Mark as error / unhandled? */ break; } proto_item_set_end(gfp_tree, tvb, *offset); if (pfi == 1) { /* 6.1.2.2.1 Payload FCS field present */ if (payload_len < 4) { expert_add_info(pinfo, type_ti, &ei_gfp_pfi_short); fcs_len = payload_len; payload_len = 0; } else { fcs_len = 4; payload_len -= 4; } proto_tree_set_appendix(gfp_tree, tvb, *offset + payload_len, fcs_len); fcs = tvb_get_ntohl(tvb, *offset + payload_len); /* Same CRC32 as ATM */ /* As with ATM, we can either compute the CRC as it would be * calculated and compare (last step involves taking the complement), * or we can include the passed CRC in the input and check to see * if the remainder is a known value. I like the first method * only because it lets us display what we should have received. */ /* Method 1: */ fcs_calc = crc32_mpeg2_tvb_offset(tvb, *offset, payload_len); if (fcs == ~fcs_calc) { fcs_ti = proto_tree_add_uint_format_value(gfp_tree, hf_gfp_fcs, tvb, *offset+payload_len, 4, fcs, "0x%08x [correct]", fcs); fcs_tree = proto_item_add_subtree(fcs_ti, ett_gfp_fcs); fcs_ti = proto_tree_add_boolean(fcs_tree, hf_gfp_fcs_good, tvb, *offset+payload_len, 4, TRUE); PROTO_ITEM_SET_GENERATED(fcs_ti); fcs_ti = proto_tree_add_boolean(fcs_tree, hf_gfp_fcs_bad, tvb, *offset+payload_len, 4, FALSE); PROTO_ITEM_SET_GENERATED(fcs_ti); } else { fcs_ti = proto_tree_add_uint_format_value(gfp_tree, hf_gfp_fcs, tvb, *offset+payload_len, 4, fcs, "0x%08x [incorrect, should be 0x%08x]", fcs, fcs_calc); fcs_tree = proto_item_add_subtree(fcs_ti, ett_gfp_fcs); fcs_ti = proto_tree_add_boolean(fcs_tree, hf_gfp_fcs_good, tvb, *offset+payload_len, 4, FALSE); PROTO_ITEM_SET_GENERATED(fcs_ti); fcs_ti = proto_tree_add_boolean(fcs_tree, hf_gfp_fcs_bad, tvb, *offset+payload_len, 4, TRUE); PROTO_ITEM_SET_GENERATED(fcs_ti); expert_add_info(pinfo, fcs_ti, &ei_gfp_fcs_bad); } /* Method 2: */ /* fcs_calc = crc32_mpeg2_tvb_offset(tvb, *offset, payload_len+4); fcs_ti = proto_tree_add_uint(gfp_tree, hf_gfp_fcs, tvb, *offset+payload_len, 4, fcs); proto_item_append_text(fcs_ti, (fcs_calc == 0xC704DD7B) ? " [correct]" : " [incorrect]"); */ } /* Some client frames we can do. Others are not implemented yet. * Transparent mode types are much trickier than frame-mapped, * since they requires reassembling streams across multiple GFP packets. */ payload_tvb = tvb_new_subset_length(tvb, *offset, payload_len); switch (pti) { case GFP_USER_DATA: case GFP_MANAGEMENT_COMMUNICATIONS: if (!dissector_try_uint(gfp_dissector_table, upi, payload_tvb, pinfo, tree)) { expert_add_info_format(pinfo, type_ti, &ei_gfp_payload_undecoded, "Payload type 0x%02x (%s) unsupported", upi, rval_to_str_const(upi, gfp_upi_data_rvals, "UNKNOWN")); call_data_dissector(payload_tvb, pinfo, tree); } break; case GFP_CLIENT_MANAGEMENT: call_data_dissector(payload_tvb, pinfo, tree); break; default: break; } *offset += payload_len; *offset += fcs_len; }