MMS: Add IEC 61850 decoding to some fields

Based on https://github.com/robidev/iec61850-dissector
and IEC 61850-8-1 found googling
This commit is contained in:
Anders Broman 2024-04-02 23:05:51 +02:00 committed by AndersBroman
parent f98f501b61
commit cd5630e375
4 changed files with 1836 additions and 521 deletions

View File

@ -25,30 +25,47 @@ IMPORTS
FROM ISO-8650-ACSE-1;
-- WS additions for IEC 61850
ReportedOptFlds ::= BIT STRING {
reserved(0),
sequence-number(1),
report-time-stamp(2),
reason-for-inclusion(3),
data-set-name(4),
data-reference(5),
buffer-overflow(6),
entryID(7),
conf-revision(8),
segmentation(9)
}
-- End WS additions for IEC 61850
MMSpdu ::= CHOICE
{
confirmed-RequestPDU [0] IMPLICIT Confirmed-RequestPDU,
confirmed-ResponsePDU [1] IMPLICIT Confirmed-ResponsePDU,
confirmed-RequestPDU [0] IMPLICIT Confirmed-RequestPDU,
confirmed-ResponsePDU [1] IMPLICIT Confirmed-ResponsePDU,
confirmed-ErrorPDU [2] IMPLICIT Confirmed-ErrorPDU,
unconfirmed-PDU [3] IMPLICIT Unconfirmed-PDU,
rejectPDU [4] IMPLICIT RejectPDU,
rejectPDU [4] IMPLICIT RejectPDU,
cancel-RequestPDU [5] IMPLICIT Cancel-RequestPDU,
cancel-ResponsePDU [6] IMPLICIT Cancel-ResponsePDU,
cancel-ErrorPDU [7] IMPLICIT Cancel-ErrorPDU,
initiate-RequestPDU [8] IMPLICIT Initiate-RequestPDU,
initiate-ResponsePDU [9] IMPLICIT Initiate-ResponsePDU,
initiate-ResponsePDU [9] IMPLICIT Initiate-ResponsePDU,
initiate-ErrorPDU [10] IMPLICIT Initiate-ErrorPDU,
conclude-RequestPDU [11] IMPLICIT Conclude-RequestPDU,
conclude-ResponsePDU [12] IMPLICIT Conclude-ResponsePDU,
conclude-ResponsePDU [12] IMPLICIT Conclude-ResponsePDU,
conclude-ErrorPDU [13] IMPLICIT Conclude-ErrorPDU
}
Confirmed-RequestPDU ::= SEQUENCE
{
invokeID Unsigned32,
invokeID Unsigned32,
listOfModifier SEQUENCE OF Modifier OPTIONAL,
confirmedServiceRequest ConfirmedServiceRequest,
confirmedServiceRequest ConfirmedServiceRequest,
cs-request-detail [79] CS-Request-Detail OPTIONAL
}
@ -95,86 +112,86 @@ Modifier ::= CHOICE
ConfirmedServiceRequest ::= CHOICE
{
status [0] IMPLICIT Status-Request,
getNameList [1] IMPLICIT GetNameList-Request,
identify [2] IMPLICIT Identify-Request,
rename [3] IMPLICIT Rename-Request,
read [4] IMPLICIT Read-Request,
write [5] IMPLICIT Write-Request,
getVariableAccessAttributes [6] GetVariableAccessAttributes-Request,
defineNamedVariable [7] IMPLICIT DefineNamedVariable-Request,
defineScatteredAccess [8] IMPLICIT DefineScatteredAccess-Request,
getScatteredAccessAttributes [9] IMPLICIT GetScatteredAccessAttributes-Request,
status [0] IMPLICIT Status-Request,
getNameList [1] IMPLICIT GetNameList-Request,
identify [2] IMPLICIT Identify-Request,
rename [3] IMPLICIT Rename-Request,
read [4] IMPLICIT Read-Request,
write [5] IMPLICIT Write-Request,
getVariableAccessAttributes [6] GetVariableAccessAttributes-Request,
defineNamedVariable [7] IMPLICIT DefineNamedVariable-Request,
defineScatteredAccess [8] IMPLICIT DefineScatteredAccess-Request,
getScatteredAccessAttributes [9] IMPLICIT GetScatteredAccessAttributes-Request,
deleteVariableAccess [10] IMPLICIT DeleteVariableAccess-Request,
defineNamedVariableList [11] IMPLICIT DefineNamedVariableList-Request,
getNamedVariableListAttributes [12] IMPLICIT GetNamedVariableListAttributes-Request,
getNamedVariableListAttributes [12] IMPLICIT GetNamedVariableListAttributes-Request,
deleteNamedVariableList [13] IMPLICIT DeleteNamedVariableList-Request,
defineNamedType [14] IMPLICIT DefineNamedType-Request,
defineNamedType [14] IMPLICIT DefineNamedType-Request,
getNamedTypeAttributes [15] IMPLICIT GetNamedTypeAttributes-Request,
deleteNamedType [16] IMPLICIT DeleteNamedType-Request,
input [17] IMPLICIT Input-Request,
output [18] IMPLICIT Output-Request,
takeControl [19] IMPLICIT TakeControl-Request,
relinquishControl [20] IMPLICIT RelinquishControl-Request,
defineSemaphore [21] IMPLICIT DefineSemaphore-Request,
deleteSemaphore [22] IMPLICIT DeleteSemaphore-Request,
deleteNamedType [16] IMPLICIT DeleteNamedType-Request,
input [17] IMPLICIT Input-Request,
output [18] IMPLICIT Output-Request,
takeControl [19] IMPLICIT TakeControl-Request,
relinquishControl [20] IMPLICIT RelinquishControl-Request,
defineSemaphore [21] IMPLICIT DefineSemaphore-Request,
deleteSemaphore [22] IMPLICIT DeleteSemaphore-Request,
reportSemaphoreStatus [23] IMPLICIT ReportSemaphoreStatus-Request,
reportPoolSemaphoreStatus [24] IMPLICIT ReportPoolSemaphoreStatus-Request,
reportSemaphoreEntryStatus [25] IMPLICIT ReportSemaphoreEntryStatus-Request,
initiateDownloadSequence [26] IMPLICIT InitiateDownloadSequence-Request,
downloadSegment [27] IMPLICIT DownloadSegment-Request,
downloadSegment [27] IMPLICIT DownloadSegment-Request,
terminateDownloadSequence [28] IMPLICIT TerminateDownloadSequence-Request,
initiateUploadSequence [29] IMPLICIT InitiateUploadSequence-Request,
uploadSegment [30] IMPLICIT UploadSegment-Request,
uploadSegment [30] IMPLICIT UploadSegment-Request,
terminateUploadSequence [31] IMPLICIT TerminateUploadSequence-Request,
requestDomainDownload [32] IMPLICIT RequestDomainDownload-Request,
requestDomainUpload [33] IMPLICIT RequestDomainUpload-Request,
loadDomainContent [34] IMPLICIT LoadDomainContent-Request,
storeDomainContent [35] IMPLICIT StoreDomainContent-Request,
deleteDomain [36] IMPLICIT DeleteDomain-Request,
getDomainAttributes [37] IMPLICIT GetDomainAttributes-Request,
requestDomainUpload [33] IMPLICIT RequestDomainUpload-Request,
loadDomainContent [34] IMPLICIT LoadDomainContent-Request,
storeDomainContent [35] IMPLICIT StoreDomainContent-Request,
deleteDomain [36] IMPLICIT DeleteDomain-Request,
getDomainAttributes [37] IMPLICIT GetDomainAttributes-Request,
createProgramInvocation [38] IMPLICIT CreateProgramInvocation-Request,
deleteProgramInvocation [39] IMPLICIT DeleteProgramInvocation-Request,
start [40] IMPLICIT Start-Request,
stop [41] IMPLICIT Stop-Request,
resume [42] IMPLICIT Resume-Request,
reset [43] IMPLICIT Reset-Request,
kill [44] IMPLICIT Kill-Request,
getProgramInvocationAttributes [45] IMPLICIT GetProgramInvocationAttributes-Request,
obtainFile [46] IMPLICIT ObtainFile-Request,
start [40] IMPLICIT Start-Request,
stop [41] IMPLICIT Stop-Request,
resume [42] IMPLICIT Resume-Request,
reset [43] IMPLICIT Reset-Request,
kill [44] IMPLICIT Kill-Request,
getProgramInvocationAttributes [45] IMPLICIT GetProgramInvocationAttributes-Request,
obtainFile [46] IMPLICIT ObtainFile-Request,
defineEventCondition [47] IMPLICIT DefineEventCondition-Request,
deleteEventCondition [48] DeleteEventCondition-Request,
getEventConditionAttributes [49] GetEventConditionAttributes-Request,
reportEventConditionStatus [50] ReportEventConditionStatus-Request,
alterEventConditionMonitoring [51] IMPLICIT AlterEventConditionMonitoring-Request,
triggerEvent [52] IMPLICIT TriggerEvent-Request,
defineEventAction [53] IMPLICIT DefineEventAction-Request,
deleteEventAction [54] DeleteEventAction-Request,
alterEventConditionMonitoring [51] IMPLICIT AlterEventConditionMonitoring-Request,
triggerEvent [52] IMPLICIT TriggerEvent-Request,
defineEventAction [53] IMPLICIT DefineEventAction-Request,
deleteEventAction [54] DeleteEventAction-Request,
getEventActionAttributes [55] GetEventActionAttributes-Request,
reportEventActionStatus [56] ReportEventActionStatus-Request,
defineEventEnrollment [57] IMPLICIT DefineEventEnrollment-Request,
deleteEventEnrollment [58] DeleteEventEnrollment-Request,
alterEventEnrollment [59] IMPLICIT AlterEventEnrollment-Request,
reportEventEnrollmentStatus [60] ReportEventEnrollmentStatus-Request,
getEventEnrollmentAttributes [61] IMPLICIT GetEventEnrollmentAttributes-Request,
acknowledgeEventNotification [62] IMPLICIT AcknowledgeEventNotification-Request,
getAlarmSummary [63] IMPLICIT GetAlarmSummary-Request,
getEventEnrollmentAttributes [61] IMPLICIT GetEventEnrollmentAttributes-Request,
acknowledgeEventNotification [62] IMPLICIT AcknowledgeEventNotification-Request,
getAlarmSummary [63] IMPLICIT GetAlarmSummary-Request,
getAlarmEnrollmentSummary [64] IMPLICIT GetAlarmEnrollmentSummary-Request,
readJournal [65] IMPLICIT ReadJournal-Request,
writeJournal [66] IMPLICIT WriteJournal-Request,
initializeJournal [67] IMPLICIT InitializeJournal-Request,
reportJournalStatus [68] IMPLICIT ReportJournalStatus-Request,
createJournal [69] IMPLICIT CreateJournal-Request,
deleteJournal [70] IMPLICIT DeleteJournal-Request,
getCapabilityList [71] IMPLICIT GetCapabilityList-Request,
fileOpen [72] IMPLICIT FileOpen-Request,
fileRead [73] IMPLICIT FileRead-Request,
fileClose [74] IMPLICIT FileClose-Request,
fileRename [75] IMPLICIT FileRename-Request,
fileDelete [76] IMPLICIT FileDelete-Request,
fileDirectory [77] IMPLICIT FileDirectory-Request
readJournal [65] IMPLICIT ReadJournal-Request,
writeJournal [66] IMPLICIT WriteJournal-Request,
initializeJournal [67] IMPLICIT InitializeJournal-Request,
reportJournalStatus [68] IMPLICIT ReportJournalStatus-Request,
createJournal [69] IMPLICIT CreateJournal-Request,
deleteJournal [70] IMPLICIT DeleteJournal-Request,
getCapabilityList [71] IMPLICIT GetCapabilityList-Request,
fileOpen [72] IMPLICIT FileOpen-Request,
fileRead [73] IMPLICIT FileRead-Request,
fileClose [74] IMPLICIT FileClose-Request,
fileRename [75] IMPLICIT FileRename-Request,
fileDelete [76] IMPLICIT FileDelete-Request,
fileDirectory [77] IMPLICIT FileDirectory-Request
-- XXX this one is neither in this ASN nor in the IMPORTS
-- additionalService [78] AdditionalService-Request
-- additionalService [78] AdditionalService-Request
}
CS-Request-Detail ::= CHOICE {
@ -291,7 +308,7 @@ Unsigned32 ::= INTEGER
ObjectName ::= CHOICE
{
vmd-specific [0] IMPLICIT Identifier,
domain-specific [1] IMPLICIT SEQUENCE
domain-specific [1] IMPLICIT SEQUENCE
{
domainId Identifier,
itemId Identifier
@ -302,7 +319,7 @@ ObjectName ::= CHOICE
ApplicationReference ::= SEQUENCE
{
ap-title [0] AP-title OPTIONAL,
ap-title [0] AP-title OPTIONAL,
ap-invocation-id [1] AP-invocation-identifier OPTIONAL,
ae-qualifier [2] AE-qualifier OPTIONAL,
ae-invocation-id [3] AE-invocation-identifier OPTIONAL
@ -2295,7 +2312,5 @@ FileAttributes ::= SEQUENCE {
lastModified [1] IMPLICIT GeneralizedTime OPTIONAL
}
END

View File

@ -14,6 +14,7 @@ MMSpdu
#.NO_EMIT
#.TYPE_RENAME
ObjectName/domain-specific/itemId ObjectName_domain_specific_itemid
#.TYPE_ATTR
TimeOfDay TYPE = FT_STRING DISPLAY = BASE_NONE
@ -43,12 +44,13 @@ GetDomainAttributes-Response/state getDomainAttributes-Response
GetProgramInvocationAttributes-Response/state getProgramInvocationAttributes-Response_state
ReportSemaphoreEntryStatus-Request/state reportSemaphoreEntryStatus-Request_state
AlterEventEnrollment-Response/currentState/state alterEventEnrollment-Response_currentState_state
ObjectName/domain-specific/itemId objectName-domain-specific-itemId
#.FIELD_ATTR
ConfirmedServiceRequest/deleteEventCondition ABBREV=confirmedServiceRequest.deleteEventCondition
ConfirmedServiceResponse/deleteEventCondition ABBREV=confirmedServiceResponse.deleteEventCondition
ConfirmedServiceRequest/deleteEventAction ABBREV=confirmedServiceRequest.deleteEventAction
ConfirmedServiceResponse/deleteEventAction ABBREV=confirmedServiceRequest.deleteEventAction
ConfirmedServiceResponse/deleteEventAction ABBREV=confirmedServiceRequest.deleteEventAction
ConfirmedServiceRequest/deleteEventEnrollment ABBREV=confirmedServiceRequest.deleteEventEnrollment
ConfirmedServiceResponse/deleteEventEnrollment ABBREV=confirmedServiceResponse.deleteEventEnrollment
TypeSpecification/bit-string ABBREV=typeSpecification_bit-string
@ -71,131 +73,453 @@ AlterEventEnrollment-Response/currentState/state ABBREV=alterEventEnrollment-
#.FN_BODY ApplicationReference/ap-title
offset=dissect_acse_AP_title(FALSE, tvb, offset, actx, tree, hf_mms_ap_title);
offset=dissect_acse_AP_title(FALSE, tvb, offset, actx, tree, hf_mms_ap_title);
#.FN_BODY ApplicationReference/ap-invocation-id
offset=dissect_acse_AP_invocation_identifier(FALSE, tvb, offset, actx, tree, hf_mms_ap_invocation_id);
offset=dissect_acse_AP_invocation_identifier(FALSE, tvb, offset, actx, tree, hf_mms_ap_invocation_id);
#.FN_BODY ApplicationReference/ae-qualifier
offset=dissect_acse_AE_qualifier(FALSE, tvb, offset, actx, tree, hf_mms_ae_qualifier);
offset=dissect_acse_AE_qualifier(FALSE, tvb, offset, actx, tree, hf_mms_ae_qualifier);
#.FN_BODY ApplicationReference/ae-invocation-id
offset=dissect_acse_AE_invocation_identifier(FALSE, tvb, offset, actx, tree, hf_mms_ae_invocation_id);
offset=dissect_acse_AE_invocation_identifier(FALSE, tvb, offset, actx, tree, hf_mms_ae_invocation_id);
#.FN_BODY MMSpdu VAL_PTR=&branch_taken
gint branch_taken;
int branch_taken;
gint8 ber_class;
bool pc;
gint32 tag;
get_ber_identifier(tvb, offset, &ber_class, &pc, &tag);
mms_actx_private_data_t *mms_priv = (mms_actx_private_data_t *)actx->private_data;
mms_priv->mms_pdu_type = tag;
%(DEFAULT_BODY)s
if( (branch_taken!=-1) && mms_MMSpdu_vals[branch_taken].strptr ){
if (mms_has_private_data(actx))
col_append_fstr(actx->pinfo->cinfo, COL_INFO, "%%s%%s%%s",
private_data_get_preCinfo(actx), mms_MMSpdu_vals[branch_taken].strptr, private_data_get_moreCinfo(actx));
else
col_append_fstr(actx->pinfo->cinfo, COL_INFO, "%%s",
mms_MMSpdu_vals[branch_taken].strptr);
}
if( (branch_taken!=-1) && mms_MMSpdu_vals[branch_taken].strptr ){
if (mms_has_private_data(actx)){
col_append_fstr(actx->pinfo->cinfo, COL_INFO, "%%s%%s%%s",
private_data_get_preCinfo(actx), mms_MMSpdu_vals[branch_taken].strptr, private_data_get_moreCinfo(actx));
}else{
col_append_fstr(actx->pinfo->cinfo, COL_INFO, "%%s",
mms_MMSpdu_vals[branch_taken].strptr);
}
}
#.FN_BODY TimeOfDay
guint32 len;
guint32 milliseconds;
guint16 days;
gchar * ptime;
nstime_t ts;
uint32_t len;
uint32_t milliseconds;
uint16_t days;
gchar * ptime;
nstime_t ts;
len = tvb_reported_length_remaining(tvb, offset);
len = tvb_reported_length_remaining(tvb, offset);
if(len == 4)
{
milliseconds = tvb_get_ntohl(tvb, offset);
ptime = signed_time_msecs_to_str(actx->pinfo->pool, milliseconds);
if(len == 4)
{
milliseconds = tvb_get_ntohl(tvb, offset);
ptime = signed_time_msecs_to_str(actx->pinfo->pool, milliseconds);
if(hf_index > 0)
{
proto_tree_add_string(tree, hf_index, tvb, offset, len, ptime);
}
return offset;
}
if(hf_index > 0)
{
proto_tree_add_string(tree, hf_index, tvb, offset, len, ptime);
}
return offset;
}
if(len == 6)
{
milliseconds = tvb_get_ntohl(tvb, offset);
days = tvb_get_ntohs(tvb, offset+4);
if(len == 6)
{
milliseconds = tvb_get_ntohl(tvb, offset);
days = tvb_get_ntohs(tvb, offset+4);
/* 5113 days between 01-01-1970 and 01-01-1984 */
/* 86400 seconds in one day */
/* 5113 days between 01-01-1970 and 01-01-1984 */
/* 86400 seconds in one day */
ts.secs = (days + 5113) * 86400 + milliseconds / 1000;
ts.nsecs = (milliseconds %% 1000) * 1000000U;
ts.secs = (days + 5113) * 86400 + milliseconds / 1000;
ts.nsecs = (milliseconds %% 1000) * 1000000U;
ptime = abs_time_to_str(actx->pinfo->pool, &ts, ABSOLUTE_TIME_UTC, TRUE);
if(hf_index > 0)
{
proto_tree_add_string(tree, hf_index, tvb, offset, len, ptime);
}
ptime = abs_time_to_str(actx->pinfo->pool, &ts, ABSOLUTE_TIME_UTC, TRUE);
if(hf_index > 0)
{
proto_tree_add_string(tree, hf_index, tvb, offset, len, ptime);
}
return offset;
}
return offset;
}
proto_tree_add_expert_format(tree, actx->pinfo, &ei_mms_mal_timeofday_encoding,
tvb, offset, len, "BER Error: malformed TimeOfDay encoding, length must be 4 or 6 bytes");
if(hf_index > 0)
{
proto_tree_add_string(tree, hf_index, tvb, offset, len, "????");
}
proto_tree_add_expert_format(tree, actx->pinfo, &ei_mms_mal_timeofday_encoding,
tvb, offset, len, "BER Error: malformed TimeOfDay encoding, length must be 4 or 6 bytes");
if(hf_index > 0)
{
proto_tree_add_string(tree, hf_index, tvb, offset, len, "????");
}
#.FN_BODY UtcTime
guint32 len;
guint32 seconds;
guint32 fraction;
guint32 nanoseconds;
nstime_t ts;
gchar * ptime;
uint32_t len;
uint32_t seconds;
uint32_t fraction;
uint32_t nanoseconds;
nstime_t ts;
gchar * ptime;
len = tvb_reported_length_remaining(tvb, offset);
static int * const TimeQuality_bits[] = {
&hf_mms_iec61850_timequality80,
&hf_mms_iec61850_timequality40,
&hf_mms_iec61850_timequality20,
&hf_mms_iec61850_timequality1F,
NULL
};
len = tvb_reported_length_remaining(tvb, offset);
if(len != 8)
{
proto_tree_add_expert_format(tree, actx->pinfo, &ei_mms_mal_utctime_encoding,
tvb, offset, len, "BER Error: malformed IEC61850 UTCTime encoding, length must be 8 bytes");
if(hf_index > 0)
{
proto_tree_add_string(tree, hf_index, tvb, offset, len, "????");
}
return offset;
}
if(len != 8)
{
/* The octet format shall be (using ASN.1 bstring notation):
* ssssssssssssssssssssssssssssssssffffffffffffffffffffffffqqqqqqqqB
* q stands for TimeQuality, i.e. reserved to represent TimeQuality based upon the referencing standard.
*/
proto_tree_add_expert_format(tree, actx->pinfo, &ei_mms_mal_utctime_encoding,
tvb, offset, len, "BER Error: malformed IEC61850 UTCTime encoding, length must be 8 bytes");
if(hf_index > 0)
{
proto_tree_add_string(tree, hf_index, tvb, offset, len, "????");
}
return offset;
}
seconds = tvb_get_ntohl(tvb, offset);
fraction = tvb_get_ntoh24(tvb, offset+4) * 0x100; /* Only 3 bytes are recommended */
nanoseconds = (guint32)( ((guint64)fraction * G_GUINT64_CONSTANT(1000000000)) / G_GUINT64_CONSTANT(0x100000000) ) ;
seconds = tvb_get_ntohl(tvb, offset);
fraction = tvb_get_ntoh24(tvb, offset+4) * 0x100; /* Only 3 bytes are recommended */
nanoseconds = (uint32_t )( ((guint64)fraction * G_GUINT64_CONSTANT(1000000000)) / G_GUINT64_CONSTANT(0x100000000) ) ;
ts.secs = seconds;
ts.nsecs = nanoseconds;
ts.secs = seconds;
ts.nsecs = nanoseconds;
ptime = abs_time_to_str(actx->pinfo->pool, &ts, ABSOLUTE_TIME_UTC, TRUE);
ptime = abs_time_to_str(actx->pinfo->pool, &ts, ABSOLUTE_TIME_UTC, TRUE);
if(hf_index > 0)
{
proto_tree_add_string(tree, hf_index, tvb, offset, len, ptime);
}
if(hf_index > 0)
{
proto_tree_add_string(tree, hf_index, tvb, offset, len, ptime);
proto_tree_add_bitmask_list(tree, tvb, offset+7, 1, TimeQuality_bits, ENC_BIG_ENDIAN);
}
#.FN_BODY Unsigned32 VAL_PTR=&val
guint32 val;
uint32_t val;
conversation_t *conversation;
mms_conv_info_t *mms_info;
mms_transaction_t *mms_trans;
%(DEFAULT_BODY)s
if (hf_index == hf_mms_invokeID)
private_data_add_preCinfo(actx, val);
if (hf_index == hf_mms_invokeID){
mms_actx_private_data_t* mms_priv = (mms_actx_private_data_t*)actx->private_data;
mms_priv->invokeid=val;
private_data_add_preCinfo(actx, val);
conversation = find_or_create_conversation(actx->pinfo);
mms_info = (mms_conv_info_t *)conversation_get_proto_data(conversation, proto_mms);
if (!mms_info) {
/*
* No. Attach that information to the conversation, and add
* it to the list of information structures.
*/
mms_info = wmem_new(wmem_file_scope(), mms_conv_info_t);
mms_info->pdus=wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
conversation_add_proto_data(conversation, proto_mms, mms_info);
}
/* Request or response? */
bool is_request;
switch(mms_priv->mms_pdu_type){
case 0:
/* Confirmed-RequestPDU */
is_request = true;
break;
case 1:
/* confirmed-ResponsePDU */
is_request = false;
break;
case 2:
/* Confirmed-ErrorPDU */
is_request = false;
break;
default:
is_request = false;
break;
}
if (!PINFO_FD_VISITED(actx->pinfo)) {
if (is_request==true) {
/* This is a request */
mms_trans=wmem_new(wmem_file_scope(), mms_transaction_t);
mms_trans->req_frame = actx->pinfo->num;
mms_trans->rep_frame = 0;
mms_trans->req_time = actx->pinfo->fd->abs_ts;
wmem_map_insert(mms_info->pdus, GUINT_TO_POINTER(mms_priv->invokeid), (void *)mms_trans);
} else {
mms_trans=(mms_transaction_t *)wmem_map_lookup(mms_info->pdus, GUINT_TO_POINTER(mms_priv->invokeid));
if (mms_trans) {
mms_trans->rep_frame = actx->pinfo->num;
}
}
} else {
mms_trans=(mms_transaction_t *)wmem_map_lookup(mms_info->pdus, GUINT_TO_POINTER(mms_priv->invokeid));
}
if (!mms_trans) {
/* create a "fake" mms_trans structure */
mms_trans=wmem_new(actx->pinfo->pool, mms_transaction_t);
mms_trans->req_frame = 0;
mms_trans->rep_frame = 0;
mms_trans->req_time = actx->pinfo->fd->abs_ts;
}
mms_priv->mms_trans = mms_trans;
/* print state tracking in the tree */
if (is_request) {
/* This is a request */
if (mms_trans->rep_frame) {
proto_item *it;
it = proto_tree_add_uint(actx->subtree.top_tree, hf_mms_response_in, tvb, 0, 0, mms_trans->rep_frame);
proto_item_set_generated(it);
}
} else {
/* This is a reply */
if (mms_trans->req_frame) {
proto_item *it;
nstime_t ns;
it = proto_tree_add_uint(actx->subtree.top_tree, hf_mms_response_to, tvb, 0, 0, mms_trans->req_frame);
proto_item_set_generated(it);
nstime_delta(&ns, &actx->pinfo->fd->abs_ts, &mms_trans->req_time);
it = proto_tree_add_time(actx->subtree.top_tree, hf_mms_response_time, tvb, 0, 0, &ns);
proto_item_set_generated(it);
}
}
}
#.FN_BODY FloatingPoint
%(DEFAULT_BODY)s
private_data_add_moreCinfo_float(actx, tvb);
private_data_add_moreCinfo_float(actx, tvb);
#.FN_BODY Identifier VAL_PTR= &parameter_tvb
tvbuff_t *parameter_tvb;
mms_actx_private_data_t *mms_priv = (mms_actx_private_data_t *)actx->private_data;
#.FN_BODY Identifier
int offset_id = offset;
%(DEFAULT_BODY)s
if ((hf_index == hf_mms_domainId) || (hf_index == hf_mms_itemId)) {
if (tvb_get_guint8(tvb, offset_id) == 0x1a)
private_data_add_moreCinfo_id(actx,tvb);
}
if (hf_index == hf_mms_domainId) {
private_data_add_moreCinfo_id(actx,tvb);
}
if (hf_index == hf_mms_objectName_domain_specific_itemId) {
private_data_add_moreCinfo_id(actx,tvb);
const char *itemid_str = tvb_get_string_enc(actx->pinfo->pool, tvb, 0, tvb_reported_length(tvb), ENC_ASCII|ENC_NA);
if(g_str_has_suffix(itemid_str,"$ctlModel")){
mms_priv->mms_trans->itemid = IEC61850_ITEM_ID_CTLMODEL;
}else if(g_str_has_suffix(itemid_str,"$q")){
mms_priv->mms_trans->itemid = IEC61850_ITEM_ID_Q;
}
}
if (hf_index == hf_mms_vmd_specific){
const char *vmd_specific_str = tvb_get_string_enc(actx->pinfo->pool, tvb, 0, tvb_reported_length(tvb), ENC_ASCII|ENC_NA);
if (strcmp(vmd_specific_str, "RPT") == 0) {
mms_priv->vmd_specific = IEC61850_8_1_RPT;
}
}
#.FN_BODY InformationReport/listOfAccessResult
mms_actx_private_data_t *mms_priv = (mms_actx_private_data_t *)actx->private_data;
mms_priv->listOfAccessResult_cnt = 0;
%(DEFAULT_BODY)s
#.FN_BODY AccessResult
mms_actx_private_data_t *mms_priv = (mms_actx_private_data_t *)actx->private_data;
/* If listOfAccessResult_cnt > 2 we are into the optional data.
* if data is not present increase count.
*/
bool present;
do {
mms_priv->listOfAccessResult_cnt+=1;
present = TRUE;
switch(mms_priv->listOfAccessResult_cnt){
case 1: /*RptID*/
break;
case 2: /* Reported OptFlds */
break;
case 3: /* SeqNum Shall be present if OptFlds.sequence-number is TRUE */
if((mms_priv->reported_optflds & 0x4000) != 0x4000){
present = false;
}
break;
case 4: /*TimeOfEntry Shall be present if OptFlds.report-time-stamp is TRUE */
if((mms_priv->reported_optflds & 0x2000) != 0x2000){
present = false;
}
break;
case 5: /*DatSet Shall be present if OptFlds.data-set-name is TRUE */
if((mms_priv->reported_optflds & 0x0800) !=0x0800){
present = false;
}
break;
case 6: /*BufOvfl Shall be present if OptFlds.buffer-overflow is TRUE */
if((mms_priv->reported_optflds & 0x0200) !=0x0200){
present = false;
}
break;
case 7: /*EntryID Shall be present if OptFlds.entryID is TRUE */
if((mms_priv->reported_optflds & 0x0100) !=0x0100){
present = false;
}
break;
case 8: /*ConfRev Shall be present if OptFlds.conf-rev is TRUE */
if((mms_priv->reported_optflds & 0x0080) !=0x0080){
present = false;
}
break;
case 9: /*SubSeqNum Shall be present if OptFlds.segmentation is TRUE */
if((mms_priv->reported_optflds & 0x0040) !=0x0040){
present = false;
}
break;
case 10: /*MoreSegmentsFollow Shall be present if OptFlds.segmentation is TRUE */
if((mms_priv->reported_optflds & 0x0040) !=0x0040){
present = false;
}
break;
case 11: /*Inclusion-bitstring Shall be present */
break;
case 12: /*data-reference(s) Shall be present if OptFlds.data-reference is TRUE */
if((mms_priv->reported_optflds & 0x0400) !=0x0400){
present = false;
}
break;
case 13: /*value(s) See AccessResult for value(s) */
break;
case 14: /*ReasonCode(s) Shall be present if OptFlds OptFlds.reason-for-inclusion is TRUE */
if((mms_priv->reported_optflds & 0x1000) !=0x1000){
present = false;
}
break;
default:
break;
}
} while(!present);
%(DEFAULT_BODY)s
#.FN_BODY Data/visible-string
mms_actx_private_data_t *mms_priv = (mms_actx_private_data_t *)actx->private_data;
if(mms_priv->vmd_specific == IEC61850_8_1_RPT ){
if(mms_priv->listOfAccessResult_cnt == 1){
/* IEC 61850-8-1 RptID */
hf_index = hf_mms_iec61850_rptid;
}else if(mms_priv->listOfAccessResult_cnt == 5){
/* IEC 61850-8-1 DatSet */
hf_index = hf_mms_iec61850_datset;
}
}
%(DEFAULT_BODY)s
#.FN_BODY Data/bit-string VAL_PTR= &parameter_tvb
static int* const quality_field_bits_oct1[] = {
&hf_mms_iec61850_QualityC0,
&hf_mms_iec61850_Quality20,
&hf_mms_iec61850_Quality10,
&hf_mms_iec61850_Quality8,
&hf_mms_iec61850_Quality4,
&hf_mms_iec61850_Quality2,
&hf_mms_iec61850_Quality1,
NULL
};
static int* const quality_field_bits_oct2[] = {
&hf_mms_iec61850_Quality0080,
&hf_mms_iec61850_Quality0040,
&hf_mms_iec61850_Quality0020,
&hf_mms_iec61850_Quality0010,
&hf_mms_iec61850_Quality0008,
NULL
};
tvbuff_t *parameter_tvb;
mms_actx_private_data_t *mms_priv = (mms_actx_private_data_t *)actx->private_data;
if(mms_priv->vmd_specific == IEC61850_8_1_RPT ){
if(mms_priv->listOfAccessResult_cnt == 2){
/* IEC 61850-8-1 Reported OptFlds */
return dissect_mms_ReportedOptFlds(implicit_tag, tvb, offset, actx, tree, hf_mms_iec61850_reported_optflds);
}else{
if(mms_priv->listOfAccessResult_cnt == 11){
hf_index = hf_mms_iec61850_inclusion_bitstring;
}
}
}else if((mms_priv->mms_trans)&&(mms_priv->mms_trans->itemid == IEC61850_ITEM_ID_Q)){
hf_index = hf_mms_iec61850_quality_bitstring;
}
%(DEFAULT_BODY)s
if((parameter_tvb)&&(mms_priv->mms_trans)&&(mms_priv->mms_trans->itemid == IEC61850_ITEM_ID_Q)){
proto_tree *sub_tree;
sub_tree = proto_item_add_subtree(actx->created_item, ett_mms_iec61850_quality_bitstring);
proto_tree_add_bitmask_list(sub_tree, parameter_tvb, 0, 1, quality_field_bits_oct1, ENC_NA);
proto_tree_add_bitmask_list(sub_tree, parameter_tvb, 1, 1, quality_field_bits_oct2, ENC_NA);
}
#.FN_BODY ReportedOptFlds VAL_PTR= &parameter_tvb
tvbuff_t *parameter_tvb;
mms_actx_private_data_t *mms_priv = (mms_actx_private_data_t *)actx->private_data;
%(DEFAULT_BODY)s
mms_priv->reported_optflds = tvb_get_ntohs(parameter_tvb,0);
#.FN_BODY Data/unsigned
mms_actx_private_data_t *mms_priv = (mms_actx_private_data_t *)actx->private_data;
if(mms_priv->vmd_specific == IEC61850_8_1_RPT ){
if(mms_priv->listOfAccessResult_cnt == 3){
/* IEC 61850-8-1 SeqNum */
hf_index = hf_mms_iec61850_seqnum;
}else if(mms_priv->listOfAccessResult_cnt == 8){
/* IEC 61850-8-1 ConfRev */
hf_index = hf_mms_iec61850_confrev;
}
}
%(DEFAULT_BODY)s
#.FN_BODY Data/boolean
mms_actx_private_data_t *mms_priv = (mms_actx_private_data_t *)actx->private_data;
if(mms_priv->vmd_specific == IEC61850_8_1_RPT ){
if(mms_priv->listOfAccessResult_cnt == 6){
/* IEC 61850-8-1 BufOvfl */
hf_index = hf_mms_iec61850_bufovfl;
}
}
%(DEFAULT_BODY)s
#.FN_BODY Data/binary-time
mms_actx_private_data_t *mms_priv = (mms_actx_private_data_t *)actx->private_data;
if(mms_priv->vmd_specific == IEC61850_8_1_RPT ){
if(mms_priv->listOfAccessResult_cnt == 4){
/* IEC 61850-8-1 TimeOfEntry */
hf_index = hf_mms_iec61850_timeofentry;
}
}
%(DEFAULT_BODY)s
#.FN_BODY Data/integer
mms_actx_private_data_t *mms_priv = (mms_actx_private_data_t *)actx->private_data;
if((mms_priv->mms_trans)&&(mms_priv->mms_trans->itemid == IEC61850_ITEM_ID_CTLMODEL)){
hf_index = hf_mms_iec61850_ctlModel;
}
%(DEFAULT_BODY)s

View File

@ -16,6 +16,7 @@
#include <epan/asn1.h>
#include <epan/expert.h>
#include <epan/proto_data.h>
#include <epan/conversation.h>
#include "packet-ber.h"
#include "packet-acse.h"
@ -31,10 +32,44 @@ void proto_reg_handoff_mms(void);
/* Initialize the protocol and registered fields */
static int proto_mms;
/* Converstaion */
static int hf_mms_response_in;
static int hf_mms_response_to;
static int hf_mms_response_time;
/* IEC 61850-8-1 filters */
static int hf_mms_iec61850_rptid;
static int hf_mms_iec61850_reported_optflds;
static int hf_mms_iec61850_seqnum;
static int hf_mms_iec61850_timeofentry;
static int hf_mms_iec61850_datset;
static int hf_mms_iec61850_bufovfl;
static int hf_mms_iec61850_confrev;
static int hf_mms_iec61850_inclusion_bitstring;
static int hf_mms_iec61850_ctlModel;
static int hf_mms_iec61850_QualityC0;
static int hf_mms_iec61850_Quality20;
static int hf_mms_iec61850_Quality10;
static int hf_mms_iec61850_Quality8;
static int hf_mms_iec61850_Quality4;
static int hf_mms_iec61850_Quality2;
static int hf_mms_iec61850_Quality1;
static int hf_mms_iec61850_Quality0080;
static int hf_mms_iec61850_Quality0040;
static int hf_mms_iec61850_Quality0020;
static int hf_mms_iec61850_Quality0010;
static int hf_mms_iec61850_Quality0008;
static int hf_mms_iec61850_quality_bitstring;
static int hf_mms_iec61850_timequality80;
static int hf_mms_iec61850_timequality40;
static int hf_mms_iec61850_timequality20;
static int hf_mms_iec61850_timequality1F;
#include "packet-mms-hf.c"
/* Initialize the subtree pointers */
static gint ett_mms;
static int ett_mms;
static int ett_mms_iec61850_quality_bitstring;
#include "packet-mms-ett.c"
static expert_field ei_mms_mal_timeofday_encoding;
@ -50,72 +85,164 @@ static expert_field ei_mms_zero_pdu;
#define BUFFER_SIZE_PRE 10
#define BUFFER_SIZE_MORE 1024
typedef enum _iec61850_8_1_vmd_specific {
IEC61850_8_1_NOT_SET = 0,
IEC61850_8_1_RPT
} iec61850_8_1_vmd_specific;
typedef enum _itemid_type {
IEC61850_ITEM_ID_NOT_SET = 0,
IEC61850_ITEM_ID_CTLMODEL,
IEC61850_ITEM_ID_Q
} itemid_type;
typedef struct _mms_transaction_t {
uint32_t req_frame;
uint32_t rep_frame;
nstime_t req_time;
/* Rquest info*/
itemid_type itemid; /* Numeric representation of ItemId substring */
} mms_transaction_t;
typedef struct _mms_conv_info_t {
wmem_map_t* pdus;
} mms_conv_info_t;
typedef struct mms_private_data_t
{
char preCinfo[BUFFER_SIZE_PRE];
char moreCinfo[BUFFER_SIZE_MORE];
char preCinfo[BUFFER_SIZE_PRE];
char moreCinfo[BUFFER_SIZE_MORE];
} mms_private_data_t;
typedef struct mms_actx_private_data_t
{
int mms_pdu_type; /* MMSpdu type taken from MMSpdu CHOISE branch_taken */
int invokeid;
iec61850_8_1_vmd_specific vmd_specific; /* Numeric representation of decode vmd_specific strings */
int listOfAccessResult_cnt; /* Posision in the list, 1 count*/
guint16 reported_optflds; /* Bitmap over included fields*/
mms_transaction_t* mms_trans;
} mms_actx_private_data_t;
static const value_string mms_iec6150_cntmodel_vals[] = {
{0, "status-only"},
{1, "direct-with-normal-security"},
{2, "sbo-with-normal-security"},
{3, "direct-with-enhanced-security"},
{4, "sbo-with-enhanced-security"},
{0, NULL}
};
static const value_string mms_iec6150_validity_vals[] = {
{0, "Good"},
{1, "Invalid"},
{2, "Reserved"},
{3, "Questionable"},
{0, NULL}
};
static const value_string mms_iec6150_source_vals[] = {
{0, "Process"},
{1, "Substituted"},
{0, NULL}
};
static const value_string mms_iec6150_timeaccuracy_vals[] = {
{0, "0 bits accuracy"},
{1, "1 bits accuracy"},
{2, "2 bits accuracy"},
{3, "3 bits accuracy"},
{4, "4 bits accuracy"},
{5, "5 bits accuracy"},
{6, "6 bits accuracy"},
{7, "7 bits accuracy"},
{8, "8 bits accuracy"},
{9, "9 bits accuracy"},
{10, "10 bits accuracy"},
{11, "11 bits accuracy"},
{12, "12 bits accuracy"},
{13, "13 bits accuracy"},
{14, "14 bits accuracy"},
{15, "15 bits accuracy"},
{16, "16 bits accuracy"},
{17, "17 bits accuracy"},
{18, "18 bits accuracy"},
{19, "19 bits accuracy"},
{20, "20 bits accuracy"},
{21, "21 bits accuracy"},
{22, "22 bits accuracy"},
{23, "23 bits accuracy"},
{24, "24 bits accuracy"},
{25, "25 bits accuracy"},
{26, "26 bits accuracy"},
{27, "27 bits accuracy"},
{28, "28 bits accuracy"},
{29, "29 bits accuracy"},
{30, "Invalid"},
{31, "Unspecified"},
{0, NULL}
};
/* Helper function to get or create the private data struct */
static
mms_private_data_t* mms_get_private_data(asn1_ctx_t *actx)
mms_private_data_t* mms_get_private_data(asn1_ctx_t* actx)
{
packet_info *pinfo = actx->pinfo;
mms_private_data_t *private_data = (mms_private_data_t *)p_get_proto_data(pinfo->pool, pinfo, proto_mms, pinfo->curr_layer_num);
if(private_data != NULL )
return private_data;
else {
private_data = wmem_new0(pinfo->pool, mms_private_data_t);
p_add_proto_data(pinfo->pool, pinfo, proto_mms, pinfo->curr_layer_num, private_data);
return private_data;
}
packet_info* pinfo = actx->pinfo;
mms_private_data_t* private_data = (mms_private_data_t*)p_get_proto_data(pinfo->pool, pinfo, proto_mms, pinfo->curr_layer_num);
if (private_data != NULL) {
return private_data;
} else {
private_data = wmem_new0(pinfo->pool, mms_private_data_t);
p_add_proto_data(pinfo->pool, pinfo, proto_mms, pinfo->curr_layer_num, private_data);
return private_data;
}
}
/* Helper function to test presence of private data struct */
static gboolean
mms_has_private_data(asn1_ctx_t *actx)
mms_has_private_data(asn1_ctx_t* actx)
{
packet_info *pinfo = actx->pinfo;
return (p_get_proto_data(pinfo->pool, pinfo, proto_mms, pinfo->curr_layer_num) != NULL);
packet_info* pinfo = actx->pinfo;
return (p_get_proto_data(pinfo->pool, pinfo, proto_mms, pinfo->curr_layer_num) != NULL);
}
static void
private_data_add_preCinfo(asn1_ctx_t *actx, guint32 val)
private_data_add_preCinfo(asn1_ctx_t* actx, guint32 val)
{
mms_private_data_t *private_data = (mms_private_data_t*)mms_get_private_data(actx);
snprintf(private_data->preCinfo, BUFFER_SIZE_PRE, "%02d ", val);
mms_private_data_t* private_data = (mms_private_data_t*)mms_get_private_data(actx);
snprintf(private_data->preCinfo, BUFFER_SIZE_PRE, "%02d ", val);
}
static char*
private_data_get_preCinfo(asn1_ctx_t *actx)
private_data_get_preCinfo(asn1_ctx_t* actx)
{
mms_private_data_t *private_data = (mms_private_data_t*)mms_get_private_data(actx);
return private_data->preCinfo;
mms_private_data_t* private_data = (mms_private_data_t*)mms_get_private_data(actx);
return private_data->preCinfo;
}
static void
private_data_add_moreCinfo_id(asn1_ctx_t *actx, tvbuff_t *tvb)
private_data_add_moreCinfo_id(asn1_ctx_t* actx, tvbuff_t* tvb)
{
mms_private_data_t *private_data = (mms_private_data_t*)mms_get_private_data(actx);
(void) g_strlcat(private_data->moreCinfo, " ", BUFFER_SIZE_MORE);
(void) g_strlcat(private_data->moreCinfo, tvb_get_string_enc(actx->pinfo->pool,
tvb, 2, tvb_get_guint8(tvb, 1), ENC_STRING), BUFFER_SIZE_MORE);
mms_private_data_t* private_data = (mms_private_data_t*)mms_get_private_data(actx);
(void)g_strlcat(private_data->moreCinfo, " ", BUFFER_SIZE_MORE);
(void)g_strlcat(private_data->moreCinfo, tvb_get_string_enc(actx->pinfo->pool,
tvb, 2, tvb_get_guint8(tvb, 1), ENC_STRING), BUFFER_SIZE_MORE);
}
static void
private_data_add_moreCinfo_float(asn1_ctx_t *actx, tvbuff_t *tvb)
private_data_add_moreCinfo_float(asn1_ctx_t* actx, tvbuff_t* tvb)
{
mms_private_data_t *private_data = (mms_private_data_t*)mms_get_private_data(actx);
snprintf(private_data->moreCinfo, BUFFER_SIZE_MORE,
" %f", tvb_get_ieee_float(tvb, 1, ENC_BIG_ENDIAN));
mms_private_data_t* private_data = (mms_private_data_t*)mms_get_private_data(actx);
snprintf(private_data->moreCinfo, BUFFER_SIZE_MORE,
" %f", tvb_get_ieee_float(tvb, 1, ENC_BIG_ENDIAN));
}
static char*
private_data_get_moreCinfo(asn1_ctx_t *actx)
private_data_get_moreCinfo(asn1_ctx_t* actx)
{
mms_private_data_t *private_data = (mms_private_data_t*)mms_get_private_data(actx);
return private_data->moreCinfo;
mms_private_data_t* private_data = (mms_private_data_t*)mms_get_private_data(actx);
return private_data->moreCinfo;
}
/*****************************************************************************/
@ -127,122 +254,244 @@ private_data_get_moreCinfo(asn1_ctx_t *actx)
* Dissect MMS PDUs inside a PPDU.
*/
static int
dissect_mms(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
dissect_mms(tvbuff_t* tvb, packet_info* pinfo, proto_tree* parent_tree, void* data _U_)
{
int offset = 0;
int old_offset;
proto_item *item=NULL;
proto_tree *tree=NULL;
asn1_ctx_t asn1_ctx;
asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
int offset = 0;
int old_offset;
proto_item* item = NULL;
proto_tree* tree = NULL;
asn1_ctx_t asn1_ctx;
asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
if(parent_tree){
item = proto_tree_add_item(parent_tree, proto_mms, tvb, 0, -1, ENC_NA);
tree = proto_item_add_subtree(item, ett_mms);
}
col_set_str(pinfo->cinfo, COL_PROTOCOL, "MMS");
col_clear(pinfo->cinfo, COL_INFO);
if (parent_tree) {
item = proto_tree_add_item(parent_tree, proto_mms, tvb, 0, -1, ENC_NA);
tree = proto_item_add_subtree(item, ett_mms);
asn1_ctx.subtree.top_tree = parent_tree;
}
col_set_str(pinfo->cinfo, COL_PROTOCOL, "MMS");
col_clear(pinfo->cinfo, COL_INFO);
while (tvb_reported_length_remaining(tvb, offset) > 0){
old_offset=offset;
offset=dissect_mms_MMSpdu(FALSE, tvb, offset, &asn1_ctx , tree, -1);
if(offset == old_offset){
proto_tree_add_expert(tree, pinfo, &ei_mms_zero_pdu, tvb, offset, -1);
break;
}
}
return tvb_captured_length(tvb);
while (tvb_reported_length_remaining(tvb, offset) > 0) {
old_offset = offset;
asn1_ctx.private_data = (void*)wmem_new0(pinfo->pool, mms_actx_private_data_t);
offset = dissect_mms_MMSpdu(FALSE, tvb, offset, &asn1_ctx, tree, -1);
wmem_free(pinfo->pool, asn1_ctx.private_data);
if (offset == old_offset) {
proto_tree_add_expert(tree, pinfo, &ei_mms_zero_pdu, tvb, offset, -1);
break;
}
}
return tvb_captured_length(tvb);
}
/*--- proto_register_mms -------------------------------------------*/
void proto_register_mms(void) {
/* List of fields */
static hf_register_info hf[] =
{
/* List of fields */
static hf_register_info hf[] =
{
{ &hf_mms_response_in,
{ "Response In", "mms.response_in",
FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
"The response to this mms request is in this frame", HFILL }
},
{ &hf_mms_response_to,
{ "Request In", "mms.response_to",
FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
"This is a response to the mms request in this frame", HFILL }
},
{ &hf_mms_response_time,
{ "Response Time", "mms.response_time",
FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
"The time between the Call and the Reply", HFILL }
},
{ &hf_mms_iec61850_rptid,
{ "RptID", "mms.iec61850.rptid",
FT_STRING, BASE_NONE, NULL, 0,
NULL, HFILL }},
{ &hf_mms_iec61850_reported_optflds,
{ "Reported OptFlds", "mms.iec61850.reported_optfld",
FT_BYTES, BASE_NONE, NULL, 0,
NULL, HFILL }},
{ &hf_mms_iec61850_seqnum,
{ "SeqNum", "mms.iec61850.seqnum",
FT_INT32, BASE_DEC, NULL, 0,
NULL, HFILL }},
{ &hf_mms_iec61850_timeofentry,
{ "TimeOfEntry", "mms.iec61850.timeofentry",
FT_STRING, BASE_NONE, NULL, 0,
NULL, HFILL }},
{ &hf_mms_iec61850_datset,
{ "DatSet", "mms.iec61850.datset",
FT_STRING, BASE_NONE, NULL, 0,
NULL, HFILL }},
{ &hf_mms_iec61850_bufovfl,
{ "BufOvfl", "mms.iec61850.bufovfl",
FT_BOOLEAN, BASE_NONE, NULL, 0,
NULL, HFILL }},
{ &hf_mms_iec61850_confrev,
{ "ConfRev", "mms.iec61850.confrev",
FT_INT32, BASE_DEC, NULL, 0,
NULL, HFILL }},
{ &hf_mms_iec61850_inclusion_bitstring,
{ "Inclusion-bitstring", "mms.iec61850.inclusion_bitstring",
FT_BYTES, BASE_NONE, NULL, 0,
NULL, HFILL }},
{ &hf_mms_iec61850_ctlModel,
{ "ctlModel", "mms.iec61850.ctlmodel",
FT_UINT8, BASE_DEC, VALS(mms_iec6150_cntmodel_vals), 0,
NULL, HFILL }},
{ &hf_mms_iec61850_QualityC0,
{ "Validity", "mms.iec61850.validity",
FT_UINT8, BASE_HEX, VALS(mms_iec6150_validity_vals), 0xC0,
NULL, HFILL }},
{ &hf_mms_iec61850_Quality20,
{ "Overflow", "mms.iec61850.overflow",
FT_BOOLEAN, 8, NULL, 0x20,
NULL, HFILL }},
{ &hf_mms_iec61850_Quality10,
{ "OutofRange", "mms.iec61850.outofrange",
FT_BOOLEAN, 8, NULL, 0x10,
NULL, HFILL }},
{ &hf_mms_iec61850_Quality8,
{ "BadReference", "mms.iec61850.badreference",
FT_BOOLEAN, 8, NULL, 0x08,
NULL, HFILL }},
{ &hf_mms_iec61850_Quality4,
{ "Oscillatory", "mms.iec61850.oscillatory",
FT_BOOLEAN, 8, NULL, 0x04,
NULL, HFILL }},
{ &hf_mms_iec61850_Quality2,
{ "Failure", "mms.iec61850.failure",
FT_BOOLEAN, 8, NULL, 0x02,
NULL, HFILL }},
{ &hf_mms_iec61850_Quality1,
{ "OldData", "mms.iec61850.oldData",
FT_BOOLEAN, 8, NULL, 0x01,
NULL, HFILL }},
{ &hf_mms_iec61850_Quality0080,
{ "Inconsistent", "mms.iec61850.inconsistent",
FT_BOOLEAN, 8, NULL, 0x80,
NULL, HFILL }},
{ &hf_mms_iec61850_Quality0040,
{ "Inaccurate", "mms.iec61850.inaccurate",
FT_BOOLEAN, 8, NULL, 0x40,
NULL, HFILL }},
{ &hf_mms_iec61850_Quality0020,
{ "Source", "mms.iec61850.source",
FT_UINT8, BASE_HEX, VALS(mms_iec6150_source_vals), 0x20,
NULL, HFILL }},
{ &hf_mms_iec61850_Quality0010,
{ "Test", "mms.iec61850.test",
FT_BOOLEAN, 8, NULL, 0x10,
NULL, HFILL }},
{ &hf_mms_iec61850_Quality0008,
{ "OperatorBlocked", "mms.iec61850.operatorblocked",
FT_BOOLEAN, 8, NULL, 0x08,
NULL, HFILL }},
{ &hf_mms_iec61850_quality_bitstring,
{ "Quality", "mms.iec61850.quality_bitstring",
FT_BYTES, BASE_NONE, NULL, 0,
NULL, HFILL } },
{ &hf_mms_iec61850_timequality80,
{ "Leap Second Known", "mms.iec61850.leapsecondknown",
FT_BOOLEAN, 8, NULL, 0x80,
NULL, HFILL } },
{ &hf_mms_iec61850_timequality40,
{ "ClockFailure", "mms.iec61850.clockfailure",
FT_BOOLEAN, 8, NULL, 0x40,
NULL, HFILL } },
{ &hf_mms_iec61850_timequality20,
{ "Clock not synchronized", "mms.iec61850.clocknotsynchronized",
FT_BOOLEAN, 8, NULL, 0x20,
NULL, HFILL } },
{ &hf_mms_iec61850_timequality1F,
{ "Time Accuracy", "mms.iec61850.timeaccuracy",
FT_UINT8, BASE_HEX, VALS(mms_iec6150_timeaccuracy_vals), 0x1F,
NULL, HFILL } },
#include "packet-mms-hfarr.c"
};
};
/* List of subtrees */
static gint *ett[] = {
&ett_mms,
/* List of subtrees */
static gint* ett[] = {
&ett_mms,
#include "packet-mms-ettarr.c"
};
};
static ei_register_info ei[] = {
{ &ei_mms_mal_timeofday_encoding, { "mms.malformed.timeofday_encoding", PI_MALFORMED, PI_WARN, "BER Error: malformed TimeOfDay encoding", EXPFILL }},
{ &ei_mms_mal_utctime_encoding, { "mms.malformed.utctime", PI_MALFORMED, PI_WARN, "BER Error: malformed IEC61850 UTCTime encoding", EXPFILL }},
{ &ei_mms_zero_pdu, { "mms.zero_pdu", PI_PROTOCOL, PI_ERROR, "Internal error, zero-byte MMS PDU", EXPFILL }},
};
static ei_register_info ei[] = {
{ &ei_mms_mal_timeofday_encoding, { "mms.malformed.timeofday_encoding", PI_MALFORMED, PI_WARN, "BER Error: malformed TimeOfDay encoding", EXPFILL }},
{ &ei_mms_mal_utctime_encoding, { "mms.malformed.utctime", PI_MALFORMED, PI_WARN, "BER Error: malformed IEC61850 UTCTime encoding", EXPFILL }},
{ &ei_mms_zero_pdu, { "mms.zero_pdu", PI_PROTOCOL, PI_ERROR, "Internal error, zero-byte MMS PDU", EXPFILL }},
};
expert_module_t* expert_mms;
expert_module_t* expert_mms;
/* Register protocol */
proto_mms = proto_register_protocol(PNAME, PSNAME, PFNAME);
register_dissector("mms", dissect_mms, proto_mms);
/* Register fields and subtrees */
proto_register_field_array(proto_mms, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
expert_mms = expert_register_protocol(proto_mms);
expert_register_field_array(expert_mms, ei, array_length(ei));
/* Register protocol */
proto_mms = proto_register_protocol(PNAME, PSNAME, PFNAME);
register_dissector("mms", dissect_mms, proto_mms);
/* Register fields and subtrees */
proto_register_field_array(proto_mms, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
expert_mms = expert_register_protocol(proto_mms);
expert_register_field_array(expert_mms, ei, array_length(ei));
}
static gboolean
dissect_mms_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void *data _U_)
dissect_mms_heur(tvbuff_t* tvb, packet_info* pinfo, proto_tree* parent_tree, void* data _U_)
{
/* must check that this really is an mms packet */
int offset = 0;
guint32 length = 0 ;
guint32 oct;
gint idx = 0 ;
/* must check that this really is an mms packet */
int offset = 0;
guint32 length = 0;
guint32 oct;
gint idx = 0;
gint8 tmp_class;
bool tmp_pc;
gint32 tmp_tag;
gint8 tmp_class;
bool tmp_pc;
gint32 tmp_tag;
/* first, check do we have at least 2 bytes (pdu) */
if (!tvb_bytes_exist(tvb, 0, 2))
return FALSE; /* no */
/* first, check do we have at least 2 bytes (pdu) */
if (!tvb_bytes_exist(tvb, 0, 2))
return FALSE; /* no */
/* can we recognize MMS PDU ? Return FALSE if not */
/* get MMS PDU type */
offset = get_ber_identifier(tvb, offset, &tmp_class, &tmp_pc, &tmp_tag);
/* can we recognize MMS PDU ? Return FALSE if not */
/* get MMS PDU type */
offset = get_ber_identifier(tvb, offset, &tmp_class, &tmp_pc, &tmp_tag);
/* check MMS type */
/* check MMS type */
/* Class should be constructed */
if (tmp_class!=BER_CLASS_CON)
return FALSE;
/* Class should be constructed */
if (tmp_class != BER_CLASS_CON)
return FALSE;
/* see if the tag is a valid MMS PDU */
try_val_to_str_idx(tmp_tag, mms_MMSpdu_vals, &idx);
if (idx == -1) {
return FALSE; /* no, it isn't an MMS PDU */
}
/* see if the tag is a valid MMS PDU */
try_val_to_str_idx(tmp_tag, mms_MMSpdu_vals, &idx);
if (idx == -1) {
return FALSE; /* no, it isn't an MMS PDU */
}
/* check MMS length */
oct = tvb_get_guint8(tvb, offset)& 0x7F;
if (oct==0)
/* MMS requires length after tag so not MMS if indefinite length*/
return FALSE;
/* check MMS length */
oct = tvb_get_guint8(tvb, offset) & 0x7F;
if (oct == 0)
/* MMS requires length after tag so not MMS if indefinite length*/
return FALSE;
offset = get_ber_length(tvb, offset, &length, NULL);
/* do we have enough bytes? */
if (!tvb_bytes_exist(tvb, offset, length))
return FALSE;
offset = get_ber_length(tvb, offset, &length, NULL);
/* do we have enough bytes? */
if (!tvb_bytes_exist(tvb, offset, length))
return FALSE;
dissect_mms(tvb, pinfo, parent_tree, data);
return TRUE;
dissect_mms(tvb, pinfo, parent_tree, data);
return TRUE;
}
/*--- proto_reg_handoff_mms --- */
void proto_reg_handoff_mms(void) {
register_ber_oid_dissector("1.0.9506.2.3", dissect_mms, proto_mms,"MMS");
register_ber_oid_dissector("1.0.9506.2.1", dissect_mms, proto_mms,"mms-abstract-syntax-version1(1)");
heur_dissector_add("cotp", dissect_mms_heur, "MMS over COTP", "mms_cotp", proto_mms, HEURISTIC_ENABLE);
heur_dissector_add("cotp_is", dissect_mms_heur, "MMS over COTP (inactive subset)", "mms_cotp_is", proto_mms, HEURISTIC_ENABLE);
register_ber_oid_dissector("1.0.9506.2.3", dissect_mms, proto_mms, "MMS");
register_ber_oid_dissector("1.0.9506.2.1", dissect_mms, proto_mms, "mms-abstract-syntax-version1(1)");
heur_dissector_add("cotp", dissect_mms_heur, "MMS over COTP", "mms_cotp", proto_mms, HEURISTIC_ENABLE);
heur_dissector_add("cotp_is", dissect_mms_heur, "MMS over COTP (inactive subset)", "mms_cotp_is", proto_mms, HEURISTIC_ENABLE);
}

File diff suppressed because it is too large Load Diff