# 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 <http://www.gnu.org/licenses/>.
|
|
# 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)
|