# This file is part of Scapy # Scapy is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # any later version. # # Scapy is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Scapy. If not, see . # Copyright (C) 2016 Gauthier Sebaux # scapy.contrib.description = ProfinetIO base layer # scapy.contrib.status = loads """ A simple and non exhaustive Profinet IO layer for scapy """ # Scapy imports from __future__ import absolute_import from scapy.all import Packet, bind_layers, Ether, UDP from scapy.fields import XShortEnumField from scapy.modules.six.moves import range # Some constants PNIO_FRAME_IDS = { 0x0020:"PTCP-RTSyncPDU-followup", 0x0080:"PTCP-RTSyncPDU", 0xFC01:"Alarm High", 0xFE01:"Alarm Low", 0xFEFC:"DCP-Hello-Req", 0xFEFD:"DCP-Get-Set", 0xFEFE:"DCP-Identify-ReqPDU", 0xFEFF:"DCP-Identify-ResPDU", 0xFF00:"PTCP-AnnouncePDU", 0xFF20:"PTCP-FollowUpPDU", 0xFF40:"PTCP-DelayReqPDU", 0xFF41:"PTCP-DelayResPDU-followup", 0xFF42:"PTCP-DelayFuResPDU", 0xFF43:"PTCP-DelayResPDU", } for i in range(0x0100, 0x1000): PNIO_FRAME_IDS[i] = "RT_CLASS_3" for i in range(0x8000, 0xC000): PNIO_FRAME_IDS[i] = "RT_CLASS_1" for i in range(0xC000, 0xFC00): PNIO_FRAME_IDS[i] = "RT_CLASS_UDP" for i in range(0xFF80, 0xFF90): PNIO_FRAME_IDS[i] = "FragmentationFrameID" ################# ## PROFINET IO ## ################# class ProfinetIO(Packet): """Basic PROFINET IO dispatcher""" fields_desc = [XShortEnumField("frameID", 0, PNIO_FRAME_IDS)] overload_fields = { Ether: {"type": 0x8892}, UDP: {"dport": 0x8892}, } def guess_payload_class(self, payload): # For frameID in the RT_CLASS_* range, use the RTC packet as payload if (self.frameID >= 0x0100 and self.frameID < 0x1000) or \ (self.frameID >= 0x8000 and self.frameID < 0xFC00): from scapy.contrib.pnio_rtc import PNIORealTime return PNIORealTime else: return Packet.guess_payload_class(self, payload) bind_layers(Ether, ProfinetIO, type=0x8892) bind_layers(UDP, ProfinetIO, dport=0x8892)