From Wido Kelling: [Profinet] Updated disecction regarding the IEC 61158

(with a few minor fixes by me).

https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8002

major change:
 reassembling of PNIO fragments (only works if OpenSafty dissector is disabled)

minor changes:
 improved handling of DFP Frames

added / updated
 MRP Block decoding
 ARServerBlock
 ARVendorBlock
 PDInterfaceDataReal
 PDInterfaceAdjust
 PDPortStatistic
 SubdirFrameData corrected display and subblocks added
 PDIRGlobalData complete dissection
 decoding of FrameDataProperties and ARTypes updated to conform the STD
 removed now usuported RTC2 ranges


svn path=/trunk/; revision=46522
This commit is contained in:
Bill Meier 2012-12-12 18:47:59 +00:00
parent f6f46de2ca
commit 708e463c47
8 changed files with 1182 additions and 265 deletions

View File

@ -3477,6 +3477,10 @@ Michal Labedzki <michal.labedzki[at]tieto.com> {
Bluetooth HCI USB transport dissector
}
Wido Kelling <kellingwido[At]aol.com> {
Profinet: Updated disecction regarding the IEC 61158
}
and by:

File diff suppressed because it is too large Load Diff

View File

@ -467,13 +467,13 @@ dissect_PNDCP_Suboption_Device(tvbuff_t *tvb, int offset, packet_info *pinfo,
tvb_memcpy(tvb, (guint8 *) typeofstation, offset, block_length);
typeofstation[block_length] = '\0';
proto_tree_add_string (tree, hf_pn_dcp_suboption_device_typeofstation, tvb, offset, block_length, typeofstation);
pn_append_info(pinfo, dcp_item, ", TypeOfStation");
pn_append_info(pinfo, dcp_item, ", DeviceVendorValue");
proto_item_append_text(block_item, "Device/Manufacturer specific");
if(have_block_qualifier)
proto_item_append_text(block_item, ", BlockQualifier: %s", val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown"));
if(have_block_info)
proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_block_info, "Unknown"));
proto_item_append_text(block_item, ", TypeOfStation: \"%s\"", typeofstation);
proto_item_append_text(block_item, ", DeviceVendorValue: \"%s\"", typeofstation);
offset += block_length;
break;
case(PNDCP_SUBOPTION_DEVICE_NAMEOFSTATION):
@ -998,7 +998,7 @@ proto_register_pn_dcp (void)
{ &hf_pn_dcp_suboption_device,
{ "Suboption", "pn_dcp.suboption_device", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_device), 0x0, NULL, HFILL }},
{ &hf_pn_dcp_suboption_device_typeofstation,
{ "TypeOfStation", "pn_dcp.suboption_device_typeofstation", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ "DeviceVendorValue", "pn_dcp.suboption_device_devicevendorvalue", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_dcp_suboption_device_nameofstation,
{ "NameOfStation", "pn_dcp.suboption_device_nameofstation", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_dcp_suboption_vendor_id,

View File

@ -48,7 +48,10 @@ static int hf_pn_mrp_interval = -1;
static int hf_pn_mrp_transition = -1;
static int hf_pn_mrp_time_stamp = -1;
static int hf_pn_mrp_blocked = -1;
#if 0 /* XXX: not used ? */
static int hf_pn_mrp_manufacturer_oui = -1;
#endif
static int hf_pn_manufacturer_data = -1;
static int hf_pn_mrp_domain_uuid = -1;
static int hf_pn_mrp_oui = -1;
@ -85,6 +88,15 @@ static const value_string pn_mrp_port_role_vals[] = {
{ 0, NULL }
};
static const value_string pn_mrp_role_vals[] = {
{ 0x0000, "Media redundancy disabled" },
{ 0x0001, "Media redundancy client" },
{ 0x0002, "Media redundancy manager" },
{ 0x0003, "Media redundancy manager (auto)" },
/*0x0004 - 0xFFFF Reserved */
{ 0, NULL }
};
static const value_string pn_mrp_ring_state_vals[] = {
{ 0x0000, "Ring open" },
@ -100,6 +112,26 @@ static const value_string pn_mrp_prio_vals[] = {
{ 0, NULL }
};
/* routine disecting an uint16 and returning that item as well */
/* dissect a 16 bit unsigned integer */
int
dissect_pn_uint16_ret_item(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
proto_tree *tree, int hfindex, guint16 *pdata, proto_item ** new_item)
{
guint16 data;
proto_item *item = NULL;
data = tvb_get_ntohs (tvb, offset);
if (tree) {
item = proto_tree_add_uint(tree, hfindex, tvb, offset, 2, data);
}
if (pdata)
*pdata = data;
if(new_item)
*new_item = item;
return offset + 2;
}
@ -124,7 +156,7 @@ dissect_PNMRP_Common(tvbuff_t *tvb, int offset,
return offset;
}
#if 0
static int
dissect_PNMRP_LinkUp(tvbuff_t *tvb, int offset,
packet_info *pinfo, proto_tree *tree, proto_item *item)
@ -155,7 +187,7 @@ dissect_PNMRP_LinkUp(tvbuff_t *tvb, int offset,
return offset;
}
#endif
static int
dissect_PNMRP_LinkDown(tvbuff_t *tvb, int offset,
@ -165,6 +197,7 @@ dissect_PNMRP_LinkDown(tvbuff_t *tvb, int offset,
guint16 port_role;
guint16 interval;
guint16 blocked;
proto_item *sub_item;
/* MRP_SA */
offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_mrp_sa, mac);
@ -173,10 +206,24 @@ dissect_PNMRP_LinkDown(tvbuff_t *tvb, int offset,
offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_port_role, &port_role);
/* MRP_Interval */
offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_interval, &interval);
offset = dissect_pn_uint16_ret_item(tvb, offset, pinfo, tree, hf_pn_mrp_interval, &interval, &sub_item);
if(tree)
{
proto_item_append_text(sub_item,"Interval for next topology change event (in ms)");
if(interval <0x07D1)
proto_item_append_text(sub_item,"Mandatory");
else
proto_item_append_text(sub_item,"Optional");
/* MRP_Blocked */
offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_blocked, &blocked);
offset = dissect_pn_uint16_ret_item(tvb, offset, pinfo, tree, hf_pn_mrp_blocked, &blocked, &sub_item);
if (blocked == 0)
proto_item_append_text(sub_item,"The MRC is not able to receive and forward frames to port in state blocked");
else
if (blocked == 1)
proto_item_append_text(sub_item,"The MRC is able to receive and forward frames to port in state blocked");
else
proto_item_append_text(sub_item,"Reserved");
}
/* Padding */
offset = dissect_pn_align4(tvb, offset, pinfo, tree);
@ -188,6 +235,28 @@ dissect_PNMRP_LinkDown(tvbuff_t *tvb, int offset,
return offset;
}
static char * mrp_Prio2msg(guint16 prio)
{
if (prio == 0x0000)
return(" Highest priority redundancy manager");
if ((prio >= 0x1000) && (prio <= 0x7000))
return(" High priorities");
if (prio == 0x8000)
return(" Default priority for redundancy manager");
if ((prio >= 0x8001) && (prio <= 0x8FFF))
return(" Low priorities for redundancy manager");
if ((prio >= 0x9000) && (prio <= 0x9FFF))
return(" High priorities for redundancy manager (auto)");
if (prio == 0xA000)
return(" Default priority for redundancy manager (auto)");
if ((prio >= 0xA001) && (prio <= 0xF000))
return(" Low priorities for redundancy manager (auto)");
if (prio ==0xFFFF)
return(" Lowest priority for redundancy manager (auto)");
return(" Reserved");
}
static int
dissect_PNMRP_Test(tvbuff_t *tvb, int offset,
@ -198,11 +267,14 @@ dissect_PNMRP_Test(tvbuff_t *tvb, int offset,
guint16 port_role;
guint16 ring_state;
guint16 transition;
guint16 time_stamp;
guint32 time_stamp;
proto_item *sub_item;
/* MRP_Prio */
offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_prio, &prio);
offset = dissect_pn_uint16_ret_item(tvb, offset, pinfo, tree, hf_pn_mrp_prio, &prio, &sub_item);
if(tree)
proto_item_append_text(sub_item, "%s", mrp_Prio2msg(prio));
/* MRP_SA */
offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_mrp_sa, mac);
@ -217,13 +289,13 @@ dissect_PNMRP_Test(tvbuff_t *tvb, int offset,
offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_transition, &transition);
/* MRP_TimeStamp */
offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_time_stamp, &time_stamp);
offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_mrp_time_stamp, &time_stamp);
/* Padding */
offset = dissect_pn_align4(tvb, offset, pinfo, tree);
col_append_str(pinfo->cinfo, COL_INFO, "Test");
if(tree)
proto_item_append_text(item, "Test");
return offset;
@ -237,27 +309,50 @@ dissect_PNMRP_TopologyChange(tvbuff_t *tvb, int offset,
guint16 prio;
guint8 mac[6];
guint16 interval;
proto_item *sub_item;
/* MRP_Prio */
offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_prio, &prio);
offset = dissect_pn_uint16_ret_item(tvb, offset, pinfo, tree, hf_pn_mrp_prio, &prio, &sub_item);
if(tree)
proto_item_append_text(sub_item, "%s", mrp_Prio2msg(prio));
/* MRP_SA */
offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_mrp_sa, mac);
/* MRP_Interval */
offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_interval, &interval);
offset = dissect_pn_uint16_ret_item(tvb, offset, pinfo, tree, hf_pn_mrp_interval, &interval, &sub_item);
if(tree)
{
proto_item_append_text(sub_item," Interval for next topology change event (in ms) ");
if(interval <0x07D1)
proto_item_append_text(sub_item,"Mandatory");
else
proto_item_append_text(sub_item,"Optional");
}
/* Padding */
/*offset = dissect_pn_align4(tvb, offset, pinfo, tree);*/
col_append_str(pinfo->cinfo, COL_INFO, "TopologyChange");
if(tree)
proto_item_append_text(item, "TopologyChange");
return offset;
}
/* "dissect" Manufacture DATA */
static int
dissect_pn_ManuData(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
proto_tree *tree, guint32 length)
{
proto_tree_add_string_format(tree, hf_pn_manufacturer_data, tvb, offset, length, "data",
"MRP_ManufacturerData: %d bytes", length);
return offset + length;
}
static int
dissect_PNMRP_Option(tvbuff_t *tvb, int offset,
@ -274,13 +369,13 @@ dissect_PNMRP_Option(tvbuff_t *tvb, int offset,
{
case OUI_SIEMENS:
proto_item_append_text(item, "Option(SIEMENS)");
/* Padding */
/* No Padding !
if (offset % 4) {
length -= 4 - (offset % 4);
offset = dissect_pn_align4(tvb, offset, pinfo, tree);
}
} */
if(length != 0) {
offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length);
offset = dissect_pn_ManuData(tvb, offset, pinfo, tree, length);
}
col_append_str(pinfo->cinfo, COL_INFO, "Option(Siemens)");
break;
@ -291,8 +386,6 @@ dissect_PNMRP_Option(tvbuff_t *tvb, int offset,
col_append_str(pinfo->cinfo, COL_INFO, "Option");
}
offset += length;
/* Padding */
offset = dissect_pn_align4(tvb, offset, pinfo, tree);
@ -349,11 +442,9 @@ dissect_PNMRP_PDU(tvbuff_t *tvb, int offset,
offset = dissect_PNMRP_TopologyChange(new_tvb, offset, pinfo, tree, item);
break;
case(0x04):
case(0x05): /* dissection of up and down is identical! */
offset = dissect_PNMRP_LinkDown(new_tvb, offset, pinfo, tree, item);
break;
case(0x05):
offset = dissect_PNMRP_LinkUp(new_tvb, offset, pinfo, tree, item);
break;
case(0x7f):
offset = dissect_PNMRP_Option(new_tvb, offset, pinfo, tree, item, length);
break;
@ -398,35 +489,35 @@ proto_register_pn_mrp (void)
{
static hf_register_info hf[] = {
{ &hf_pn_mrp_type,
{ "Type", "pn_mrp.type", FT_UINT8, BASE_HEX, VALS(pn_mrp_block_type_vals), 0x0, NULL, HFILL }},
{ "MRP_TLVHeader.Type", "pn_mrp.type", FT_UINT8, BASE_HEX, VALS(pn_mrp_block_type_vals), 0x0, NULL, HFILL }},
{ &hf_pn_mrp_length,
{ "Length", "pn_mrp.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
{ "MRP_TLVHeader.Length", "pn_mrp.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_mrp_version,
{ "Version", "pn_mrp.version", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
{ "MRP_Version", "pn_mrp.version", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_mrp_sequence_id,
{ "SequenceID", "pn_mrp.sequence_id", FT_UINT16, BASE_HEX, NULL, 0x0, "Unique sequence number to each outstanding service request", HFILL }},
{ "MRP_SequenceID", "pn_mrp.sequence_id", FT_UINT16, BASE_HEX, NULL, 0x0, "Unique sequence number to each outstanding service request", HFILL }},
{ &hf_pn_mrp_sa,
{ "SA", "pn_mrp.sa", FT_ETHER, BASE_NONE, 0x0, 0x0, NULL, HFILL }},
{ "MRP_SA", "pn_mrp.sa", FT_ETHER, BASE_NONE, 0x0, 0x0, NULL, HFILL }},
{ &hf_pn_mrp_prio,
{ "Prio", "pn_mrp.prio", FT_UINT16, BASE_HEX, VALS(pn_mrp_prio_vals), 0x0, NULL, HFILL }},
{ "MRP_Prio", "pn_mrp.prio", FT_UINT16, BASE_HEX, 0, 0x0, NULL, HFILL }},
{ &hf_pn_mrp_port_role,
{ "PortRole", "pn_mrp.port_role", FT_UINT16, BASE_HEX, VALS(pn_mrp_port_role_vals), 0x0, NULL, HFILL }},
{ "MRP_PortRole", "pn_mrp.port_role", FT_UINT16, BASE_HEX, VALS(pn_mrp_port_role_vals), 0x0, NULL, HFILL }},
{ &hf_pn_mrp_ring_state,
{ "RingState", "pn_mrp.ring_state", FT_UINT16, BASE_HEX, VALS(pn_mrp_ring_state_vals), 0x0, NULL, HFILL }},
{ "MRP_RingState", "pn_mrp.ring_state", FT_UINT16, BASE_HEX, VALS(pn_mrp_ring_state_vals), 0x0, NULL, HFILL }},
{ &hf_pn_mrp_interval,
{ "Interval", "pn_mrp.interval", FT_UINT16, BASE_DEC, NULL, 0x0, "Interval for next topology change event (in ms)", HFILL }},
{ "MRP_Interval", "pn_mrp.interval", FT_UINT16, BASE_DEC, NULL, 0x0, "Interval for next topology change event (in ms)", HFILL }},
{ &hf_pn_mrp_transition,
{ "Transition", "pn_mrp.transition", FT_UINT16, BASE_HEX, NULL, 0x0, "Number of transitions between media redundancy lost and ok states", HFILL }},
{ "MRP_Transition", "pn_mrp.transition", FT_UINT16, BASE_HEX, NULL, 0x0, "Number of transitions between media redundancy lost and ok states", HFILL }},
{ &hf_pn_mrp_time_stamp,
{ "TimeStamp", "pn_mrp.time_stamp", FT_UINT16, BASE_HEX, NULL, 0x0, "Actual counter value of 1ms counter", HFILL }},
{ "MRP_TimeStamp [ms]", "pn_mrp.time_stamp", FT_UINT32, BASE_HEX, NULL, 0x0, "Actual counter value of 1ms counter", HFILL }},
{ &hf_pn_mrp_blocked,
{ "Blocked", "pn_mrp.blocked", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_mrp_manufacturer_oui,
{ "ManufacturerOUI", "pn_mrp.manufacturer_oui", FT_UINT24, BASE_HEX, VALS(pn_mrp_oui_vals), 0x0, NULL, HFILL }},
{ "MRP_Blocked", "pn_mrp.blocked", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_manufacturer_data,
{ "MRP_ManufacturerData", "pn_mrp.ManufacturerData", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_mrp_domain_uuid,
{ "DomainUUID", "pn_mrp.domain_uuid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ "MRP_DomainUUID", "pn_mrp.domain_uuid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_mrp_oui,
{ "Organizationally Unique Identifier", "pn_mrp.oui", FT_UINT24, BASE_HEX,
{ "MRP_ManufacturerOUIr", "pn_mrp.oui", FT_UINT24, BASE_HEX,
VALS(pn_mrp_oui_vals), 0x0, NULL, HFILL }},
};

View File

@ -70,6 +70,10 @@ static int hf_pn_ptcp_flags = -1;
static int hf_pn_ptcp_currentutcoffset = -1;
static int hf_pn_ptcp_master_priority1 = -1;
static int hf_pn_ptcp_master_priority_level = -1;
static int hf_pn_ptcp_master_priority1_res = -1;
static int hf_pn_ptcp_master_priority1_act =-1;
static int hf_pn_ptcp_master_priority2 = -1;
static int hf_pn_ptcp_clock_class = -1;
static int hf_pn_ptcp_clock_accuracy = -1;
@ -120,8 +124,32 @@ static const value_string pn_ptcp_oui_vals[] = {
};
static const value_string pn_ptcp_master_prio1_vals[] = {
{ 0x01, "Primary sync. master" },
{ 0x02, "Secondary sync. master" },
{ 0x00, "Sync slave" },
{ 0x01, "Primary master" },
{ 0x02, "Secondary master" },
{ 0x03, "Reserved" },
{ 0x04, "Reserved" },
{ 0x05, "Reserved" },
{ 0x06, "Reserved" },
{ 0x07, "Reserved" },
{ 0, NULL }
};
static const value_string pn_ptcp_master_prio1_levels[] = {
{ 0x00, "Level 0 (highest)" },
{ 0x01, "Level 1" },
{ 0x02, "Level 2" },
{ 0x03, "Level 3" },
{ 0x04, "Level 4" },
{ 0x05, "Level 5" },
{ 0x06, "Level 6" },
{ 0x07, "Level 7 (lowest)" },
{ 0, NULL }
};
static const value_string pn_ptcp_master_prio1_vals_active[] = {
{ 0x00, "inactive" },
{ 0x01, "active" },
{ 0, NULL }
};
@ -279,8 +307,15 @@ dissect_PNPTCP_Master(tvbuff_t *tvb, int offset,
gint16 ClockVariance;
/* MasterPriority1 */
offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority1, &MasterPriority1);
/* MasterPriority1 is a bit field */
/* Bit 0 - 2: PTCP_MasterPriority1.Priority */
dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority1, &MasterPriority1);
/* Bit 3 - 5: PTCP_MasterPriority1.Level */
dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority_level, &MasterPriority1);
/* Bit 6: PTCP_MasterPriority1.Reserved */
dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority1_res, &MasterPriority1);
/* Bit 7: PTCP_MasterPriority1.Active */
offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority1_act, &MasterPriority1);
/* MasterPriority2 */
offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority2, &MasterPriority2);
@ -298,14 +333,26 @@ dissect_PNPTCP_Master(tvbuff_t *tvb, int offset,
offset = dissect_pn_align4(tvb, offset, pinfo, tree);
col_append_fstr(pinfo->cinfo, COL_INFO, ", Prio1=\"%s\"",
val_to_str(MasterPriority1, pn_ptcp_master_prio1_short_vals, "(Reserved: 0x%x)"));
val_to_str(MasterPriority1 & 0x7, pn_ptcp_master_prio1_vals, "(Reserved: 0x%x)"));
if((MasterPriority1 & 0x80) == 0){
proto_item_append_text(item, ": Prio1=\"%s\", Prio2=%s, Clock: Class=\"%s\", Accuracy=%s, Variance=%d",
val_to_str(MasterPriority1, pn_ptcp_master_prio1_short_vals, "(Reserved: 0x%x)"),
val_to_str(MasterPriority1 & 0x7, pn_ptcp_master_prio1_vals, "(Reserved: 0x%x)"),
val_to_str(MasterPriority2, pn_ptcp_master_prio2_vals, "(Reserved: 0x%x)"),
val_to_str(ClockClass, pn_ptcp_clock_class_vals, "(Reserved: 0x%x)"),
val_to_str(ClockAccuracy, pn_ptcp_clock_accuracy_vals, "(Reserved: 0x%x)"),
ClockVariance);
}
else{
col_append_fstr(pinfo->cinfo, COL_INFO, " active");
proto_item_append_text(item, ": Prio1=\"%s\" is active, Prio2=%s, Clock: Class=\"%s\", Accuracy=%s, Variance=%d",
val_to_str(MasterPriority1 & 0x7, pn_ptcp_master_prio1_vals, "(Reserved: 0x%x)"),
val_to_str(MasterPriority2, pn_ptcp_master_prio2_vals, "(Reserved: 0x%x)"),
val_to_str(ClockClass, pn_ptcp_clock_class_vals, "(Reserved: 0x%x)"),
val_to_str(ClockAccuracy, pn_ptcp_clock_accuracy_vals, "(Reserved: 0x%x)"),
ClockVariance);
}
return offset;
}
@ -880,7 +927,13 @@ proto_register_pn_ptcp (void)
{ "CurrentUTCOffset", "pn_ptcp.currentutcoffset", FT_UINT16, BASE_DEC, 0x0, 0x0, NULL, HFILL }},
{ &hf_pn_ptcp_master_priority1,
{ "MasterPriority1", "pn_ptcp.master_priority1", FT_UINT8, BASE_DEC, VALS(pn_ptcp_master_prio1_vals), 0x0, NULL, HFILL }},
{ "MasterPriority1.Priority", "pn_ptcp.master_priority1_prio", FT_UINT8, BASE_HEX, VALS(pn_ptcp_master_prio1_vals), 0x07, NULL, HFILL }},
{ &hf_pn_ptcp_master_priority_level,
{ "MasterPriority1.Level", "pn_ptcp.master_priority1_level", FT_UINT8, BASE_HEX, VALS(pn_ptcp_master_prio1_levels), 0x38, NULL, HFILL }},
{ &hf_pn_ptcp_master_priority1_res,
{ "MasterPriority1.Reserved", "pn_ptcp.master_priority1_res", FT_UINT8, BASE_HEX, 0x0, 0x40, NULL, HFILL }},
{ &hf_pn_ptcp_master_priority1_act,
{ "MasterPriority1.Active", "pn_ptcp.master_priority1_act", FT_UINT8, BASE_HEX, VALS(pn_ptcp_master_prio1_vals_active), 0x80, NULL, HFILL }},
{ &hf_pn_ptcp_master_priority2,
{ "MasterPriority2", "pn_ptcp.master_priority2", FT_UINT8, BASE_DEC, VALS(pn_ptcp_master_prio2_vals), 0x0, NULL, HFILL }},
{ &hf_pn_ptcp_clock_class,

View File

@ -35,6 +35,7 @@
#endif
#include <epan/packet.h>
#include <epan/reassemble.h>
#include <epan/addr_resolv.h>
#include <epan/prefs.h>
#include <epan/strutil.h>
@ -43,10 +44,13 @@
#include <epan/dissectors/packet-dcerpc.h>
#include <epan/crc16-tvb.h>
#include <wsutil/crc16.h>
#include <wsutil/crc16-plain.h>
#include "packet-pn.h"
/* Define the pn-rt proto */
static int proto_pn_rt = -1;
static gboolean pnio_desegment = TRUE;
/* Define many header fields for pn-rt */
static int hf_pn_rt_frame_id = -1;
@ -63,6 +67,8 @@ static int hf_pn_rt_data_status_redundancy = -1;
static int hf_pn_rt_data_status_primary = -1;
static int hf_pn_rt_sf_crc16 = -1;
static int hf_pn_rt_sf_crc16_ok = -1;
static int hf_pn_rt_sf_crc16_null = -1;
static int hf_pn_rt_sf = -1;
static int hf_pn_rt_sf_position = -1;
static int hf_pn_rt_sf_position_control = -1;
@ -111,8 +117,8 @@ static const value_string pn_rt_ds_redundancy[] = {
};
static const value_string pn_rt_frag_status_error[] = {
{ 0x00, "No error" },
{ 0x01, "An error occured, all earlier fragments shall be dropped" },
{ 0x00, "reserved" },
{ 0x01, "reserved: invalid should be zero" },
{ 0, NULL }
};
@ -122,8 +128,6 @@ static const value_string pn_rt_frag_status_more_follows[] = {
{ 0, NULL }
};
static void
dissect_DataStatus(tvbuff_t *tvb, int offset, proto_tree *tree, guint8 u8DataStatus)
{
@ -150,20 +154,53 @@ dissect_DataStatus(tvbuff_t *tvb, int offset, proto_tree *tree, guint8 u8DataSta
}
static gboolean IsDFP_Frame(tvbuff_t *tvb)
static gboolean IsDFP_Frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
guint16 u16SFCRC16;
guint8 u8SFPosition;
guint8 u8SFDataLength = 255;
#if 0 /* XXX: set but not used ? */
guint8 u8SFCycleCounter = 0;
guint8 u8SFDataStatus;
#endif
int offset = 0;
guint32 u32SubStart;
guint16 crc;
gint tvb_len =0;
unsigned char virtualFramebuffer[16];
guint16 u16FrameID;
offset += 2; /*Skip first crc because data is no more available */
/* the sub tvb will NOT contain the frame_id here! */
u16FrameID = GPOINTER_TO_UINT(pinfo->private_data);
/* try to bild a temporaray buffer for generating this CRC */
memcpy(&virtualFramebuffer[0], pinfo->dst.data,6);
memcpy(&virtualFramebuffer[6], pinfo->src.data,6);
virtualFramebuffer[12] = 0x88;
virtualFramebuffer[13] = 0x92;
virtualFramebuffer[15] = (unsigned char) (u16FrameID &0xff);
virtualFramebuffer[14] = (unsigned char) (u16FrameID>>8);
crc = crc16_plain_init();
crc = crc16_plain_update(crc, &virtualFramebuffer[0], 16);
crc = crc16_plain_finalize(crc);
/* can check this CRC only by having built a temporary data buffer out of the pinfo data */
u16SFCRC16 = tvb_get_letohs(tvb, offset);
if(u16SFCRC16 != 0) /* no crc! */
{
if(u16SFCRC16 != crc)
{
proto_item_append_text(tree, ", no packed frame: SFCRC16 is 0x%x should be 0x%x", u16SFCRC16, crc);
return(FALSE);
}
}
/* end of first CRC check */
offset += 2; /*Skip first crc */
tvb_len = tvb_length(tvb);
if(offset + 4 > tvb_len)
return FALSE;
if(tvb_get_letohs(tvb, offset) == 0)
return FALSE; /* no valid DFP frame */
while(1) {
u32SubStart = offset;
@ -177,8 +214,13 @@ static gboolean IsDFP_Frame(tvbuff_t *tvb)
break;
}
#if 0 /* XXX: set but not used ? */
u8SFCycleCounter = tvb_get_guint8(tvb, offset);
#endif
offset += 1;
#if 0 /* XXX: set but not used ? */
u8SFDataStatus = tvb_get_guint8(tvb, offset);
#endif
offset += 1;
offset += u8SFDataLength;
@ -224,12 +266,15 @@ dissect_CSF_SDU_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
u16FrameID = GPOINTER_TO_UINT(pinfo->private_data);
/* possible FrameID ranges for DFP */
if((u16FrameID < 0x100) || (u16FrameID > 0x0fff))
if((u16FrameID < 0x100) || (u16FrameID > 0x0FFF))
return (FALSE);
if (IsDFP_Frame(tvb)) {
if (IsDFP_Frame(tvb, pinfo, tree)) {
/* can't check this CRC, as the checked data bytes are not available */
u16SFCRC16 = tvb_get_letohs(tvb, offset);
proto_tree_add_uint(tree, hf_pn_rt_sf_crc16, tvb, offset, 2, u16SFCRC16);
if(u16SFCRC16 != 0)
proto_tree_add_uint(tree, hf_pn_rt_sf_crc16_ok, tvb, offset, 2, u16SFCRC16);
else
proto_tree_add_uint(tree, hf_pn_rt_sf_crc16_null, tvb, offset, 2, u16SFCRC16);
offset += 2;
while(1) {
@ -293,7 +338,38 @@ dissect_CSF_SDU_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
return FALSE;
}
static void
dissect_pn_rt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
/* for reasemble processing we need some inits.. */
/* Register PNIO defrag table init routine. */
static GHashTable *pdu_frag_table = NULL;
static GHashTable *reasembled_frag_table = NULL;
static dissector_handle_t data_handle;
static dissector_table_t ethertype_subdissector_table;
static guint32 start_frag_OR_ID[16];
static void
pnio_defragment_init(void)
{
guint32 i;
if( reasembled_frag_table != NULL ) {
g_hash_table_destroy( reasembled_frag_table );
reasembled_frag_table = NULL;
}
for (i=0; i < 16;i++) /* init the reasemble help array */
start_frag_OR_ID[i] = 0;
fragment_table_init(&pdu_frag_table);
if (reasembled_frag_table == NULL)
{
reasembled_frag_table = g_hash_table_new(NULL, NULL);
}
}
/* possibly dissect a FRAG_PDU related PN-RT packet */
static gboolean
@ -301,6 +377,10 @@ dissect_FRAG_PDU_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
void *data _U_)
{
guint16 u16FrameID;
guint32 u32FrameKey = 0;
guint32 u32FragID = 0;
guint16 pdu_length = 0;
guint32 u32ReasembleID =0xfedc;
int offset = 0;
proto_item *sub_item;
proto_tree *sub_tree;
@ -308,6 +388,10 @@ dissect_FRAG_PDU_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
proto_item *status_item;
proto_tree *status_tree;
guint8 u8FragStatus;
gboolean bMoreFollows;
guint8 uFragNumber;
fragment_data *pdu_frag;
tvbuff_t *pdu_tvb = NULL;
/* the sub tvb will NOT contain the frame_id here! */
@ -330,23 +414,64 @@ dissect_FRAG_PDU_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
proto_tree_add_uint(status_tree, hf_pn_rt_frag_status_error, tvb, offset, 1, u8FragStatus);
proto_tree_add_uint(status_tree, hf_pn_rt_frag_status_fragment_number, tvb, offset, 1, u8FragStatus);
offset += 1;
proto_item_append_text(status_item, ": Number: %u, %s, %s",
u8FragStatus & 0x3F,
val_to_str( (u8FragStatus & 0x80) >> 7, pn_rt_frag_status_more_follows, "Unknown"),
val_to_str( (u8FragStatus & 0x40) >> 6, pn_rt_frag_status_error, "Unknown"));
uFragNumber = u8FragStatus & 0x3F; /* bits 0 to 5 */
bMoreFollows = (u8FragStatus & 0x80) != 0;
proto_item_append_text(status_item, ": Number: %u, %s",
uFragNumber,
val_to_str( (u8FragStatus & 0x80) >> 7, pn_rt_frag_status_more_follows, "Unknown"));
proto_tree_add_string_format(sub_tree, hf_pn_rt_frag_data, tvb, offset, tvb_length(tvb) - offset, "data",
"FragData: %d bytes", tvb_length(tvb) - offset);
"Fragment Length: %d bytes", tvb_length(tvb) - offset);
col_append_fstr(pinfo->cinfo, COL_INFO," Fragment Length: %d bytes", tvb_length(tvb) - offset);
/* note: the actual defragmentation implementation is still missing here */
dissect_pn_undecoded(tvb, offset, pinfo, sub_tree, tvb_length(tvb) - offset);
dissect_pn_user_data_bytes(tvb, offset, pinfo, sub_tree, tvb_length(tvb) - offset, FRAG_DATA);
if((guint)(tvb_length(tvb) - offset) < (guint)(u8FragDataLength *8)){
proto_item_append_text(status_item, ": FragDataLength out of Framerange -> discarding!");
return (TRUE);
}
/* defragmentation starts here */
if(pnio_desegment)
{
u32FragID = (u16FrameID & 0xf);
if(uFragNumber == 0)
{ /* this is the first "new" fragment, so set up a new key Id */
u32FrameKey = (pinfo->fd->num << 2) | u32FragID;
/* store it in the array */
start_frag_OR_ID[u32FragID] = u32FrameKey;
}
u32ReasembleID = start_frag_OR_ID[u32FragID];
/* use frame data instead of "pnio fraglen" which sets 8 octet steps */
pdu_frag = fragment_add_seq(tvb, offset, pinfo, u32ReasembleID, pdu_frag_table, uFragNumber, (tvb_length(tvb) - offset)/*u8FragDataLength*8*/, bMoreFollows);
if(pdu_frag && !bMoreFollows) /* PDU is complete! and last fragment */
{ /* store this frag as the completed frag in hash table */
g_hash_table_insert(reasembled_frag_table,GUINT_TO_POINTER(pinfo->fd->num),pdu_frag);
start_frag_OR_ID[u32FragID] = 0; /* reset the starting frame counter */
}
if(!bMoreFollows) /* last fragment */
{
pdu_frag = g_hash_table_lookup(reasembled_frag_table,GUINT_TO_POINTER(pinfo->fd->num));
if(pdu_frag) /* found a matching frag dissect it */
{
guint16 type;
pdu_length = pdu_frag->len;
/* create the new tvb for defraged frame */
pdu_tvb = tvb_new_child_real_data(tvb, pdu_frag->data, pdu_length, pdu_length);
/* add the defragmented data to the data source list */
add_new_data_source(pinfo, pdu_tvb, "Reassembled Profinet Frame");
/* PDU is complete: look for the Ethertype and give it to the appropriate dissection routine */
type = tvb_get_ntohs(pdu_tvb, 0);
pdu_tvb = tvb_new_subset_remaining(pdu_tvb, 2);
if (!dissector_try_uint(ethertype_subdissector_table, type, pdu_tvb, pinfo, tree))
call_dissector(data_handle, pdu_tvb, pinfo, tree);
}
}
return TRUE;
}
else
return TRUE;
}
return FALSE;
}
@ -443,7 +568,6 @@ dissect_pn_rt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
pszProtSummary = "Real-Time";
pszProtComment = "0x0082-0x00FF: Reserved ID";
bCyclic = FALSE;
} else if (u16FrameID <= 0x6FF) {
pszProtShort = "PN-RTC3";
pszProtAddInfo = "RTC3, ";
@ -463,28 +587,47 @@ dissect_pn_rt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
pszProtComment = "0x1000-0x7FFF: Reserved ID";
bCyclic = FALSE;
} else if (u16FrameID <= 0xBBFF){
pszProtShort = "PN-RTC2";
pszProtAddInfo = "RTC2, ";
pszProtShort = "PN-RTC1";
pszProtAddInfo = "RTC1, ";
pszProtSummary = "cyclic Real-Time";
pszProtComment = "0x8000-0xBBFF: Real-Time(class=2): non redundant, normal";
pszProtComment = "0x8000-0xBBFF: Real-Time(class=1 unicast): non redundant, normal";
bCyclic = TRUE;
} else if (u16FrameID <= 0xBFFF){
pszProtShort = "PN-RTC2";
pszProtAddInfo = "RTC2, ";
pszProtShort = "PN-RTC1";
pszProtAddInfo = "RTC1, ";
pszProtSummary = "cyclic Real-Time";
pszProtComment = "0xBC00-0xBFFF: Real-Time(class=2 multicast): non redundant, normal";
pszProtComment = "0xBC00-0xBFFF: Real-Time(class=1 multicast): non redundant, normal";
bCyclic = TRUE;
} else if (u16FrameID <= 0xF7FF){
pszProtShort = "PN-RTC1/UDP";
pszProtAddInfo = "RTC1/UDP, ";
/* check if udp frame on PNIO port */
if(pinfo->destport == 0x8892)
{ /* UDP frame */
pszProtShort = "PN-RTCUDP,";
pszProtAddInfo = "RT_CLASS_UDP, ";
pszProtComment = "0xC000-0xF7FF: Real-Time(UDP unicast): Cyclic";
}
else
{ /* layer 2 frame */
pszProtShort = "PN-RT";
pszProtAddInfo = "RTC1(legacy), ";
pszProtComment = "0xC000-0xF7FF: Real-Time(class=1 unicast): Cyclic";
}
pszProtSummary = "cyclic Real-Time";
pszProtComment = "0xC000-0xF7FF: Real-Time(class=1/UDP): Cyclic";
bCyclic = TRUE;
} else if (u16FrameID <= 0xFBFF){
pszProtShort = "PN-RTC1/UDP";
pszProtAddInfo = "Multicast, ";
if(pinfo->destport == 0x8892)
{ /* UDP frame */
pszProtShort = "PN-RTCUDP,";
pszProtAddInfo = "RT_CLASS_UDP, ";
pszProtComment = "0xF800-0xFBFF:: Real-Time(UDP multicast): Cyclic";
}
else
{ /* layer 2 frame */
pszProtShort = "PN-RT";
pszProtAddInfo = "RTC1(legacy), ";
pszProtComment = "0xF800-0xFBFF: Real-Time(class=1 multicast): Cyclic";
}
pszProtSummary = "cyclic Real-Time";
pszProtComment = "0xF800-0xFBFF: Real-Time(class=1/UDP multicast): Cyclic";
bCyclic = TRUE;
} else if (u16FrameID <= 0xFDFF){
pszProtShort = "PN-RTA";
@ -573,8 +716,8 @@ dissect_pn_rt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
bCyclic = FALSE;
} else if (u16FrameID <= 0xFF8F){
pszProtShort = "PN-RT";
pszProtAddInfo = "Fragmentation, ";
pszProtSummary = "Real-Time";
pszProtAddInfo = "";
pszProtSummary = "Fragmentation";
pszProtComment = "0xFF80-0xFF8F: Fragmentation";
bCyclic = FALSE;
} else {
@ -638,7 +781,7 @@ dissect_pn_rt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
pdu_len - 4, 2, u16CycleCounter, "CycleCounter: %u", u16CycleCounter);
/* add data status subtree */
dissect_DataStatus(tvb, pdu_len - 2, tree, u8DataStatus);
dissect_DataStatus(tvb, pdu_len - 2, pn_rt_tree, u8DataStatus);
/* add transfer status */
if (u8TransferStatus) {
@ -705,6 +848,10 @@ proto_register_pn_rt(void)
"SubFrame", "pn_rt.sf", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_rt_sf_crc16, {
"SFCRC16", "pn_rt.sf.crc16", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_rt_sf_crc16_ok, {
"SFCRC16 checked [ok]", "pn_rt.sf.crc16_ok", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_rt_sf_crc16_null, {
"SFCRC16 not checked but ok", "pn_rt.sf.crc16_null", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_rt_sf_position, {
"Position", "pn_rt.sf.position", FT_UINT8, BASE_DEC, NULL, 0x7F, NULL, HFILL }},
{ &hf_pn_rt_sf_position_control, {
@ -714,7 +861,7 @@ proto_register_pn_rt(void)
{ &hf_pn_rt_sf_cycle_counter, {
"CycleCounter", "pn_rt.sf.cycle_counter", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_rt_frag, {
"PROFINET Real-Time Fragment", "pn_rt.frag", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
"PROFINET Fragment", "pn_rt.frag", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_rt_frag_data_length, {
"FragDataLength", "pn_rt.frag_data_length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_rt_frag_status, {
@ -722,11 +869,11 @@ proto_register_pn_rt(void)
{ &hf_pn_rt_frag_status_more_follows, {
"MoreFollows", "pn_rt.frag_status.more_follows", FT_UINT8, BASE_HEX, VALS(pn_rt_frag_status_more_follows), 0x80, NULL, HFILL }},
{ &hf_pn_rt_frag_status_error, {
"Error", "pn_rt.frag_status.error", FT_UINT8, BASE_HEX, VALS(pn_rt_frag_status_error), 0x40, NULL, HFILL }},
"Reserved", "pn_rt.frag_status.error", FT_UINT8, BASE_HEX, VALS(pn_rt_frag_status_error), 0x40, NULL, HFILL }},
{ &hf_pn_rt_frag_status_fragment_number, {
"FragmentNumber (zero based)", "pn_rt.frag_status.fragment_number", FT_UINT8, BASE_DEC, NULL, 0x3F, NULL, HFILL }},
{ &hf_pn_rt_frag_data, {
"FragData", "pn_rt.frag_data", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }},
"FragData", "pn_rt.frag_data", FT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }},
};
static gint *ett[] = {
&ett_pn_rt,
@ -752,10 +899,16 @@ proto_register_pn_rt(void)
"Whether the PN-RT summary line should be shown in the protocol tree",
&pn_rt_summary_in_tree);
prefs_register_bool_preference(pn_rt_module, "desegment",
"reassemble PNIO Fragments",
"Reassemble PNIO Fragments and get them decoded",
&pnio_desegment);
/* register heuristics anchor for payload dissectors */
register_heur_dissector_list("pn_rt", &heur_subdissector_list);
init_pn (proto_pn_rt);
register_init_routine(pnio_defragment_init);
}
@ -772,5 +925,8 @@ proto_reg_handoff_pn_rt(void)
heur_dissector_add("pn_rt", dissect_CSF_SDU_heur, proto_pn_rt);
heur_dissector_add("pn_rt", dissect_FRAG_PDU_heur, proto_pn_rt);
data_handle = find_dissector("data");
ethertype_subdissector_table = find_dissector_table("ethertype");
}

View File

@ -40,6 +40,7 @@ static int hf_pn_padding = -1;
static int hf_pn_undecoded_data = -1;
static int hf_pn_user_data = -1;
static int hf_pn_user_bytes = -1;
static int hf_pn_frag_bytes = -1;
static int hf_pn_malformed = -1;
@ -212,8 +213,11 @@ dissect_pn_undecoded(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
/* "dissect" some user bytes */
int
dissect_pn_user_data_bytes(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
proto_tree *tree, guint32 length, const char *text _U_)
proto_tree *tree, guint32 length, int iSelect)
{
if(iSelect == FRAG_DATA)
proto_tree_add_bytes(tree, hf_pn_frag_bytes, tvb, offset, length, tvb_get_ptr(tvb,offset, length));
else
proto_tree_add_bytes(tree, hf_pn_user_bytes, tvb, offset, length, tvb_get_ptr(tvb,offset, length));
return offset + length;
@ -291,6 +295,8 @@ init_pn (int proto)
{ "User Data", "pn.user_data", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_user_bytes,
{ "Substitute Data", "pn.user_bytes", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_frag_bytes,
{ "Fragment Data", "pn.frag_bytes", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_pn_malformed,
{ "Malformed", "pn_rt.malformed", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}
};

View File

@ -63,8 +63,12 @@ extern int dissect_pn_undecoded(tvbuff_t *tvb, int offset, packet_info *pinfo,
extern int dissect_pn_user_data(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
proto_tree *tree, guint32 length, const char *text);
#define SUBST_DATA 1
#define FRAG_DATA 2
extern int dissect_pn_user_data_bytes(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
proto_tree *tree, guint32 length, const char *text);
proto_tree *tree, guint32 length, int iSelect);
extern int dissect_pn_malformed(tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree *tree, guint32 length);