Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
/** 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);
}
Пример #4
0
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;
}
Пример #5
0
/** 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);
}
Пример #6
0
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;
}
Пример #7
0
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);
}
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
/**
*   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;
}
Пример #11
0
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;
}
Пример #12
0
/* 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 */
}
Пример #13
0
/*
 * 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;
}
Пример #14
0
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);
        }
    }
}
Пример #15
0
/* 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) */
Пример #16
0
/* 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);
    }
Пример #17
0
/* 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);
}
Пример #18
0
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));
	}
}
Пример #19
0
/*
 * 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;
}
Пример #20
0
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);
		}
	}
}
Пример #21
0
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;
}
Пример #22
0
/* 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;
}