Modbus analyser, added support: FC=20,21

This commit is contained in:
dina 2012-08-22 16:47:34 +02:00
parent e8f4c7bc3d
commit c58c6791c5
5 changed files with 611 additions and 21 deletions

View file

@ -688,6 +688,274 @@ event modbus_write_multi_response(c:connection,is_orig:bool,tid:count,pid:count,
#REQUEST FC=20
event modbus_read_reference_request(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,refCount:count,t:int_vec)
{
local k:file;
local m:file;
local ftime:string;
local src:string;
local dst:string;
local src_p:string;
local dst_p:string;
k=open_for_append (string_cat(path,"f20_new.log"));
m=open_for_append (string_cat(path,"fall_new.log"));
ftime=strftime("%F %T",network_time());
src= cat(c$id$orig_h);
dst=cat(c$id$resp_h);
src_p=cat(c$id$orig_p);
dst_p=cat(c$id$resp_p);
#according to the specification, this FC usually has 4xxxx offset in the memory map
#local prefix_ref:count;
#prefix_ref=ref+40000;
local text=string_cat(ftime,"\t",src,"\t",dst,"\t",src_p, "\t REQUEST \t",cat(tid), "\t",cat(pid),"\t", cat(uid),"\t",cat(fc),"\t",cat(refCount),"\t",cat(t),"\n");
write_file(k,text);
write_file(m,text);
close(k);
close(m);
}
#RESPONSE FC=20
event modbus_read_reference_response(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,byteCount:count,t:int_vec)
{
local k:file;
local m:file;
local ftime:string;
local src:string;
local dst:string;
local src_p:string;
local dst_p:string;
k=open_for_append (string_cat(path,"f20_new.log"));
m=open_for_append (string_cat(path,"fall_new.log"));
ftime=strftime("%F %T",network_time());
src= cat(c$id$orig_h);
dst=cat(c$id$resp_h);
src_p=cat(c$id$orig_p);
dst_p=cat(c$id$resp_p);
#according to the specification, this FC usually has 4xxxx offset in the memory map
#local prefix_ref:count;
#prefix_ref=ref+40000;
local text=string_cat(ftime,"\t",src,"\t",dst,"\t",src_p, "\t RESPONSE \t",cat(tid), "\t",cat(pid),"\t", cat(uid),"\t",cat(fc),"\t",cat(byteCount),"\t",cat(t),"\n");
write_file(k,text);
write_file(m,text);
close(k);
close(m);
}
#REQUEST FC=20 (for single reference)
event modbus_read_single_reference_request(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,refType:count,refNumber:count,wordCount:count)
{
local k:file;
local m:file;
local ftime:string;
local src:string;
local dst:string;
local src_p:string;
local dst_p:string;
k=open_for_append (string_cat(path,"f20_singles_new.log"));
m=open_for_append (string_cat(path,"fall_new.log"));
ftime=strftime("%F %T",network_time());
src= cat(c$id$orig_h);
dst=cat(c$id$resp_h);
src_p=cat(c$id$orig_p);
dst_p=cat(c$id$resp_p);
#according to the specification, this FC usually has 4xxxx offset in the memory map
#local prefix_ref:count;
#prefix_ref=ref+40000;
local text=string_cat(ftime,"\t",src,"\t",dst,"\t",src_p, "\t REQUEST \t",cat(tid), "\t",cat(pid),"\t", cat(uid),"\t",cat(fc),"\t",cat(refType),"\t",cat(refNumber),"\t",cat(wordCount),"\n");
write_file(k,text);
write_file(m,text);
close(k);
close(m);
}
#RESPONSE FC=20 (for single reference)
event modbus_read_single_reference_response(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,byteCount:count,refType:count,t:int_vec)
{
local k:file;
local m:file;
local ftime:string;
local src:string;
local dst:string;
local src_p:string;
local dst_p:string;
k=open_for_append (string_cat(path,"f20_singles_new.log"));
m=open_for_append (string_cat(path,"fall_new.log"));
ftime=strftime("%F %T",network_time());
src= cat(c$id$orig_h);
dst=cat(c$id$resp_h);
src_p=cat(c$id$orig_p);
dst_p=cat(c$id$resp_p);
#according to the specification, this FC usually has 4xxxx offset in the memory map
#local prefix_ref:count;
#prefix_ref=ref+40000;
local text=string_cat(ftime,"\t",src,"\t",dst,"\t",src_p, "\t RESPONSE \t",cat(tid), "\t",cat(pid),"\t", cat(uid),"\t",cat(fc),"\t",cat(byteCount),"\t",cat(refType),"\t",cat(t),"\n");
write_file(k,text);
write_file(m,text);
close(k);
close(m);
}
#REQUEST FC=21
event modbus_write_reference_request(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,byteCount:count,t:int_vec)
{
local k:file;
local m:file;
local ftime:string;
local src:string;
local dst:string;
local src_p:string;
local dst_p:string;
k=open_for_append (string_cat(path,"f21_new.log"));
m=open_for_append (string_cat(path,"fall_new.log"));
ftime=strftime("%F %T",network_time());
src= cat(c$id$orig_h);
dst=cat(c$id$resp_h);
src_p=cat(c$id$orig_p);
dst_p=cat(c$id$resp_p);
#according to the specification, this FC usually has 4xxxx offset in the memory map
#local prefix_ref:count;
#prefix_ref=ref+40000;
local text=string_cat(ftime,"\t",src,"\t",dst,"\t",src_p, "\t REQUEST \t",cat(tid), "\t",cat(pid),"\t", cat(uid),"\t",cat(fc),"\t",cat(byteCount),"\t",cat(t),"\n");
write_file(k,text);
write_file(m,text);
close(k);
close(m);
}
#RESPONSE FC=21
event modbus_read_reference_response(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,byteCount:count,t:int_vec)
{
local k:file;
local m:file;
local ftime:string;
local src:string;
local dst:string;
local src_p:string;
local dst_p:string;
k=open_for_append (string_cat(path,"f21_new.log"));
m=open_for_append (string_cat(path,"fall_new.log"));
ftime=strftime("%F %T",network_time());
src= cat(c$id$orig_h);
dst=cat(c$id$resp_h);
src_p=cat(c$id$orig_p);
dst_p=cat(c$id$resp_p);
#according to the specification, this FC usually has 4xxxx offset in the memory map
#local prefix_ref:count;
#prefix_ref=ref+40000;
local text=string_cat(ftime,"\t",src,"\t",dst,"\t",src_p, "\t RESPONSE \t",cat(tid), "\t",cat(pid),"\t", cat(uid),"\t",cat(fc),"\t",cat(byteCount),"\t",cat(t),"\n");
write_file(k,text);
write_file(m,text);
close(k);
close(m);
}
#REQUEST/RESPONSE FC=20 (for single reference)
event modbus_write_single_reference(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,refType:count,refNumber:count,wordCount:count,t:int_vec)
{
local k:file;
local m:file;
local ftime:string;
local src:string;
local dst:string;
local src_p:string;
local dst_p:string;
k=open_for_append (string_cat(path,"f21_singles_new.log"));
m=open_for_append (string_cat(path,"fall_new.log"));
ftime=strftime("%F %T",network_time());
src= cat(c$id$orig_h);
dst=cat(c$id$resp_h);
src_p=cat(c$id$orig_p);
dst_p=cat(c$id$resp_p);
#according to the specification, this FC usually has 4xxxx offset in the memory map
#local prefix_ref:count;
#prefix_ref=ref+40000;
local text=string_cat(ftime,"\t",src,"\t",dst,"\t",src_p, "\t REQUEST/RESPONSE \t",cat(tid), "\t",cat(pid),"\t", cat(uid),"\t",cat(fc),"\t",cat(refType),"\t",cat(refNumber),"\t",cat(wordCount),"\t",cat(t),"\n");
write_file(k,text);
write_file(m,text);
close(k);
close(m);
}
#REQUEST FC=22
event modbus_mask_write_request(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,ref:count,andMask:count,orMask:count)
{

View file

@ -46,6 +46,17 @@ public:
|| modbus_force_coils_request
|| modbus_force_coils_response
|| modbus_read_reference_request
|| modbus_read_reference_response
|| modbus_read_single_reference_request
|| modbus_read_single_reference_response
|| modbus_write_reference_request
|| modbus_write_reference_response
|| modbus_write_single_reference
|| modbus_write_multi_request
|| modbus_write_multi_response

View file

@ -6650,10 +6650,26 @@ event modbus_force_coils_request%(c:connection,is_orig:bool,tid:count,pid:count,
event modbus_write_multi_request%(c:connection,is_orig:bool,t:int_vec,tid:count,pid:count,uid:count,fc:count,ref:count,wCount:count,bCount:count,len:count%);
#Event that passes modbus request function code=20
event modbus_read_reference_request%(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,refCount:count,t:int_vec%);
#Event that passes modbus request function code=20 for single reference
event modbus_read_single_reference_request%(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,refType:count,refNumber:count,wordCount:count%);
#Event that passes modbus request function code=21
event modbus_write_reference_request%(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,byteCount:count,t:int_vec%);
#Event that passes modbus request/response function code=21 for single reference
event modbus_write_single_reference%(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,refType:count,refNumber:count,wordCount:count,t:int_vec%);
#Event that passes modbus request function code=22
event modbus_mask_write_request%(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,ref:count,andMask:count,orMask:count%);
#Event that passes modbus request function code=23
event modbus_read_write_request%(c:connection,is_orig:bool,t:int_vec,tid:count,pid:count,uid:count,fc:count,refRead:count,wcRead:count,refWrite:count,wcWrite:count,bCount:count,len:count%);
@ -6693,6 +6709,16 @@ event modbus_force_coils_response%(c:connection,is_orig:bool,tid:count,pid:count
event modbus_write_multi_response%(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,ref:count,wcount:count,len:count%);
#Event that passes modbus response function code=20
event modbus_read_reference_response%(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,byteCount:count,t:int_vec%);
#Event that passes modbus response function code=20 for single reference
event modbus_read_single_reference_response%(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,byteCount:count,refType:count,t:int_vec%);
#Event that passes modbus response function code=21
event modbus_write_reference_response%(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,byteCount:count,t:int_vec%);
#Event that passes modbus response function code=22
event modbus_mask_write_response%(c:connection,is_orig:bool,tid:count,pid:count,uid:count,fc:count,ref:count,andMask:count,orMask:count%);

View file

@ -183,6 +183,161 @@ function deliver_WriteMultiRegReq( writeMulti: WriteMultipleRegistersRequest, ti
%}
#REQUEST FC=20
function deliver_ReadReferenceReq(tid:uint16, pid:uint16, uid: uint8, fc: uint8,refCount:uint8,reference:Reference[]): bool
%{
VectorVal * t=new VectorVal( new VectorType(base_type(TYPE_INT)));
for (unsigned int i=0; i < (${reference}->size()); ++i)
{
Val* r=new Val((${reference[i].refType}),TYPE_INT);
t->Assign(i,r,0,OP_ASSIGN);
Val* k=new Val((${reference[i].refNumber}),TYPE_INT);
t->Assign(i,k,0,OP_ASSIGN);
Val* l=new Val((${reference[i].wordCount}),TYPE_INT);
t->Assign(i,l,0,OP_ASSIGN);
}
if ( ::modbus_read_reference_request )
{
BifEvent::generate_modbus_read_reference_request(
connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(),
is_orig(),tid,pid,uid,fc,refCount,t);
}
return true;
%}
#REQUEST FC=20 (to read single reference)
function deliver_ReadSingleReferenceReq(tid:uint16,pid:uint16,uid:uint8,fc:uint8,refType:uint8,refNumber:uint32,wordCount:uint16): bool
%{
if ( ::modbus_read_single_reference_request)
{
BifEvent::generate_modbus_read_single_reference_request(
connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(),
is_orig(),tid,pid,uid,fc,refType,refNumber,wordCount);
}
return true;
%}
#RESPONSE FC=20 (to read single reference)
function deliver_ReadSingleReferenceRes(tid:uint16, pid:uint16, uid: uint8, fc: uint8,byteCount:uint8,refType:uint8,ref:ReferenceResponse): bool
%{
VectorVal * t=new VectorVal( new VectorType(base_type(TYPE_INT)));
for (unsigned int i=0; i < (${ref.registerValue}->size()); ++i)
{
Val* r=new Val(((*ref->registerValue())[i]),TYPE_INT);
t->Assign(i,r,0,OP_ASSIGN);
}
if ( ::modbus_read_single_reference_response )
{
BifEvent::generate_modbus_read_single_reference_response(
connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(),
is_orig(),tid,pid,uid,fc,byteCount,refType,t);
}
return true;
%}
#REQUEST FC=21
function deliver_WriteReferenceReq(tid:uint16,pid:uint16,uid:uint8,fc:uint8,byteCount:uint8,reference:ReferenceWithData[]): bool
%{
VectorVal * t=new VectorVal( new VectorType(base_type(TYPE_INT)));
for (unsigned int i=0; i < (${reference}->size()); ++i)
{
Val* r=new Val((${reference[i].refType}),TYPE_INT);
t->Assign(i,r,0,OP_ASSIGN);
Val* k=new Val((${reference[i].refNumber}),TYPE_INT);
t->Assign(i,k,0,OP_ASSIGN);
Val* n=new Val((${reference[i].wordCount}),TYPE_INT);
t->Assign(i,n,0,OP_ASSIGN);
for (unsigned int j=0; j<(${reference[i].registerValue}->size());++j)
{
k=new Val((${reference[i].registerValue[j]}),TYPE_INT);
t->Assign(i,k,0,OP_ASSIGN);
}
}
if ( ::modbus_write_reference_request )
{
BifEvent::generate_modbus_write_reference_request(
connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(),
is_orig(),tid,pid,uid,fc,byteCount,t);
}
return true;
%}
#RESPONSE FC=21 (to write single reference)
function deliver_WriteSingleReference(tid:uint16, pid:uint16, uid: uint8, fc: uint8,refType:uint8,refNumber:uint32,wordCount:uint16,ref:ReferenceWithData): bool
%{
VectorVal * t=new VectorVal( new VectorType(base_type(TYPE_INT)));
for (unsigned int i=0; i < (${ref.registerValue}->size()); ++i)
{
Val* r=new Val(((*ref->registerValue())[i]),TYPE_INT);
t->Assign(i,r,0,OP_ASSIGN);
}
if ( ::modbus_write_single_reference)
{
BifEvent::generate_modbus_write_single_reference(
connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(),
is_orig(),tid,pid,uid,fc,refType,refNumber,wordCount,t);
}
return true;
%}
#REQUEST FC=22
function deliver_MaskWriteRegReq(tid:uint16,pid:uint16,uid:uint8,fc:uint8,ref:uint16,andMask:uint16,orMask:uint16): bool
%{
@ -405,6 +560,88 @@ function deliver_WriteMultiRegRes(tid:uint16,pid:uint16,uid:uint8,fc:uint8, ref:
#RESPONSE FC=20
function deliver_ReadReferenceRes(tid:uint16,pid:uint16,uid:uint8,fc:uint8,byteCount:uint8,reference:ReferenceResponse[]): bool
%{
VectorVal * t=new VectorVal( new VectorType(base_type(TYPE_INT)));
for (unsigned int i=0; i < (${reference}->size()); ++i)
{
Val* r=new Val((${reference[i].byteCount}),TYPE_INT);
t->Assign(i,r,0,OP_ASSIGN);
Val* k=new Val((${reference[i].refType}),TYPE_INT);
t->Assign(i,k,0,OP_ASSIGN);
for (unsigned int j=0; j<(${reference[i].registerValue}->size());++j)
{
k=new Val((${reference[i].registerValue[j]}),TYPE_INT);
t->Assign(i,k,0,OP_ASSIGN);
}
}
if ( ::modbus_read_reference_response )
{
BifEvent::generate_modbus_read_reference_response(
connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(),
is_orig(),tid,pid,uid,fc,byteCount,t);
}
return true;
%}
#RESPONSE FC=21
function deliver_WriteReferenceRes(tid:uint16,pid:uint16,uid:uint8,fc:uint8,byteCount:uint8,reference:ReferenceWithData[]): bool
%{
VectorVal * t=new VectorVal( new VectorType(base_type(TYPE_INT)));
for (unsigned int i=0; i < (${reference}->size()); ++i)
{
Val* r=new Val((${reference[i].refType}),TYPE_INT);
t->Assign(i,r,0,OP_ASSIGN);
Val* k=new Val((${reference[i].refNumber}),TYPE_INT);
t->Assign(i,k,0,OP_ASSIGN);
Val* n=new Val((${reference[i].wordCount}),TYPE_INT);
t->Assign(i,n,0,OP_ASSIGN);
for (unsigned int j=0; j<(${reference[i].registerValue}->size());++j)
{
k=new Val((${reference[i].registerValue[j]}),TYPE_INT);
t->Assign(i,k,0,OP_ASSIGN);
}
}
if ( ::modbus_write_reference_response )
{
BifEvent::generate_modbus_write_reference_response(
connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(),
is_orig(),tid,pid,uid,fc,byteCount,t);
}
return true;
%}
#RESPONSE FC=22
function deliver_MaskWriteRegRes(tid:uint16,pid:uint16,uid:uint8,fc:uint8,ref:uint16,andMask:uint16,orMask:uint16): bool
%{

View file

@ -112,19 +112,42 @@ type ModbusTCP_TransportHeader = record {
type Reference = record {
type Reference (header:ModbusTCP_TransportHeader) = record {
refType: uint8;
refNumber: uint32;
wordCount: uint16;
}
&let {
deliver: bool =$context.flow.deliver_ReadSingleReferenceReq(header.tid,header.pid,header.uid,header.fc,refType,refNumber,wordCount);
};
type ReferenceWithData = record {
type ReferenceWithData (header:ModbusTCP_TransportHeader) = record {
refType: uint8;
refNumber: uint32;
wordCount: uint16;
registerValue: uint16[wordCount] &length = 2*wordCount; # TODO: check that the array length is calculated correctly
}
&let {
deliver: bool =$context.flow.deliver_WriteSingleReference(header.tid,header.pid,header.uid,header.fc,refType,refNumber,wordCount,this);
}
;
#Dina modified
type ReferenceResponse(header:ModbusTCP_TransportHeader)=record{
byteCount:uint8;
refType:uint8;
registerValue:uint16[wordCount];
}
&let {
wordCount : uint8 = byteCount/2;
deliver: bool =$context.flow.deliver_ReadSingleReferenceRes(header.tid,header.pid,header.uid,header.fc,byteCount,refType,this);
};
type Exception(len: uint16,header:ModbusTCP_TransportHeader) = record {
code: uint8;
}&let {
@ -147,8 +170,8 @@ type ModbusTCP_RequestPDU = record {
READ_EXCEPTION_STATUS -> readExceptionStatus: ReadExceptionStatusRequest(header.len-2,header);
# Class 2
FORCE_MULTIPLE_COILS -> forceMultipleCoils: ForceMultipleCoilsRequest(header.len-2,header);
READ_GENERAL_REFERENCE -> readGeneralReference: ReadGeneralReferenceRequest(header.len-2);
WRITE_GENERAL_REFERENCE -> writeGeneralReference: WriteGeneralReferenceRequest(header.len-2);
READ_GENERAL_REFERENCE -> readGeneralreference: ReadGeneralReferenceRequest(header.len-2,header);
WRITE_GENERAL_REFERENCE -> writeGeneralReference: WriteGeneralReferenceRequest(header.len-2,header);
MASK_WRITE_REGISTER -> maskWriteRegister: MaskWriteRegisterRequest(header.len-2,header);
READ_WRITE_REGISTERS -> readWriteRegisters: ReadWriteRegistersRequest(header.len-2,header);
READ_FIFO_QUEUE -> readFIFOQueue: ReadFIFOQueueRequest(header.len-2,header);
@ -251,6 +274,8 @@ deliver: bool =$context.flow.deliver_ReadExceptStatReq(header.tid,header.pid,hea
};
# Class 2 requests
#REQUEST FC=15
type ForceMultipleCoilsRequest(len: uint16,header:ModbusTCP_TransportHeader) = record {
referenceNumber: uint16;
bitCount: uint16 &check(bitCount <= 800);
@ -261,20 +286,30 @@ type ForceMultipleCoilsRequest(len: uint16,header:ModbusTCP_TransportHeader) = r
deliver: bool =$context.flow.deliver_ForceMultiCoilsReq(header.tid,header.pid,header.uid,header.fc,referenceNumber,bitCount,byteCount,coils);
};
type ReadGeneralReferenceRequest(len: uint16) = record {
#REQUEST FC=20
type ReadGeneralReferenceRequest(len: uint16,header:ModbusTCP_TransportHeader) = record {
byteCount: uint8;
references: Reference[referenceCount] &length = byteCount;
references: Reference(header)[referenceCount] &length = byteCount;
} &let {
referenceCount: uint8 = byteCount/7;
deliver: bool =$context.flow.deliver_ReadReferenceReq(header.tid,header.pid,header.uid,header.fc,referenceCount,references);
};
type WriteGeneralReferenceRequest(len: uint16) = record {
#REQUEST FC=21
type WriteGeneralReferenceRequest(len: uint16,header:ModbusTCP_TransportHeader) = record {
byteCount: uint8;
references: ReferenceWithData[] &until($input.length() == 0) &length = byteCount;
} &length = len;
references: ReferenceWithData(header)[] &until($input.length() == 0) &length = byteCount;
} &length = len,
&let {
deliver: bool =$context.flow.deliver_WriteReferenceReq(header.tid,header.pid,header.uid,header.fc,byteCount,references);
};
#REQUEST FC=22
#REQUESTeFC=22
type MaskWriteRegisterRequest(len: uint16,header: ModbusTCP_TransportHeader) = record {
referenceNumber: uint16;
andMask: uint16;
@ -323,8 +358,8 @@ type ModbusTCP_ResponsePDU = record {
WRITE_SINGLE_REGISTER -> writeSingleRegister: WriteSingleRegisterResponse(header.len-2,header);
READ_EXCEPTION_STATUS -> readExceptionStatus: ReadExceptionStatusResponse(header.len-2,header);
FORCE_MULTIPLE_COILS -> forceMultipleCoils: ForceMultipleCoilsResponse(header.len-2,header);
READ_GENERAL_REFERENCE -> readGeneralReference: ReadGeneralReferenceResponse(header.len-2);
WRITE_GENERAL_REFERENCE -> writeGeneralReference: WriteGeneralReferenceResponse(header.len-2);
READ_GENERAL_REFERENCE -> readGeneralReference: ReadGeneralReferenceResponse(header.len-2,header);
WRITE_GENERAL_REFERENCE -> writeGeneralReference: WriteGeneralReferenceResponse(header.len-2,header);
MASK_WRITE_REGISTER -> maskWriteRegister: MaskWriteRegisterResponse(header.len-2,header);
READ_WRITE_REGISTERS -> readWriteRegisters: ReadWriteRegistersResponse(header.len-2,header);
READ_FIFO_QUEUE -> readFIFOQueue: ReadFIFOQueueResponse(header.len-2,header);
@ -450,18 +485,31 @@ deliver: bool =$context.flow.deliver_ForceMultiCoilsRes(header.tid,header.pid,he
}
;
type ReadGeneralReferenceResponse(len: uint16) = record {
###RESPONSE FC=20
type ReadGeneralReferenceResponse(len: uint16,header:ModbusTCP_TransportHeader) = record {
byteCount: uint8;
references: bytestring &length = byteCount;
} &length = len;
#references: bytestring &length = byteCount;
#Dina modified
references:ReferenceResponse (header) [] &until($input.length()==0) &length=byteCount;
} &length = len,
&let{
deliver: bool =$context.flow.deliver_ReadReferenceRes(header.tid,header.pid,header.uid,header.fc,byteCount,references);
};
type WriteGeneralReferenceResponse(len: uint16) = record {
###RESPONSE FC=21
type WriteGeneralReferenceResponse(len: uint16,header:ModbusTCP_TransportHeader) = record {
byteCount: uint8;
references: ReferenceWithData[] &until($input.length() == 0) &length = byteCount;
} &length = len;
references: ReferenceWithData(header)[] &until($input.length() == 0) &length = byteCount;
} &length = len,
&let {
deliver: bool =$context.flow.deliver_WriteReferenceRes(header.tid,header.pid,header.uid,header.fc,byteCount,references);
};
###RESPONSE FC=22
###RESPOeSE FC=22
type MaskWriteRegisterResponse(len: uint16,header:ModbusTCP_TransportHeader) = record {
referenceNumber: uint16;
andMask: uint16;