Home | History | Annotate | Download | only in contrib
      1 # This file is part of Scapy
      2 # Scapy is free software: you can redistribute it and/or modify
      3 # it under the terms of the GNU General Public License as published by
      4 # the Free Software Foundation, either version 2 of the License, or
      5 # any later version.
      6 #
      7 # Scapy is distributed in the hope that it will be useful,
      8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     10 # GNU General Public License for more details.
     11 #
     12 # You should have received a copy of the GNU General Public License
     13 # along with Scapy. If not, see <http://www.gnu.org/licenses/>.
     14 
     15 # Copyright (C) 2016 Gauthier Sebaux
     16 
     17 # scapy.contrib.description = ProfinetIO base layer
     18 # scapy.contrib.status = loads
     19 
     20 """
     21 A simple and non exhaustive Profinet IO layer for scapy
     22 """
     23 
     24 # Scapy imports
     25 from __future__ import absolute_import
     26 from scapy.all import Packet, bind_layers, Ether, UDP
     27 from scapy.fields import XShortEnumField
     28 from scapy.modules.six.moves import range
     29 
     30 # Some constants
     31 PNIO_FRAME_IDS = {
     32     0x0020:"PTCP-RTSyncPDU-followup",
     33     0x0080:"PTCP-RTSyncPDU",
     34     0xFC01:"Alarm High",
     35     0xFE01:"Alarm Low",
     36     0xFEFC:"DCP-Hello-Req",
     37     0xFEFD:"DCP-Get-Set",
     38     0xFEFE:"DCP-Identify-ReqPDU",
     39     0xFEFF:"DCP-Identify-ResPDU",
     40     0xFF00:"PTCP-AnnouncePDU",
     41     0xFF20:"PTCP-FollowUpPDU",
     42     0xFF40:"PTCP-DelayReqPDU",
     43     0xFF41:"PTCP-DelayResPDU-followup",
     44     0xFF42:"PTCP-DelayFuResPDU",
     45     0xFF43:"PTCP-DelayResPDU",
     46     }
     47 for i in range(0x0100, 0x1000):
     48     PNIO_FRAME_IDS[i] = "RT_CLASS_3"
     49 for i in range(0x8000, 0xC000):
     50     PNIO_FRAME_IDS[i] = "RT_CLASS_1"
     51 for i in range(0xC000, 0xFC00):
     52     PNIO_FRAME_IDS[i] = "RT_CLASS_UDP"
     53 for i in range(0xFF80, 0xFF90):
     54     PNIO_FRAME_IDS[i] = "FragmentationFrameID"
     55 
     56 #################
     57 ## PROFINET IO ##
     58 #################
     59 
     60 class ProfinetIO(Packet):
     61     """Basic PROFINET IO dispatcher"""
     62     fields_desc = [XShortEnumField("frameID", 0, PNIO_FRAME_IDS)]
     63     overload_fields = {
     64         Ether: {"type": 0x8892},
     65         UDP: {"dport": 0x8892},
     66         }
     67 
     68     def guess_payload_class(self, payload):
     69         # For frameID in the RT_CLASS_* range, use the RTC packet as payload
     70         if (self.frameID >= 0x0100 and self.frameID < 0x1000) or \
     71                 (self.frameID >= 0x8000 and self.frameID < 0xFC00):
     72             from scapy.contrib.pnio_rtc import PNIORealTime
     73             return PNIORealTime
     74         else:
     75             return Packet.guess_payload_class(self, payload)
     76 
     77 bind_layers(Ether, ProfinetIO, type=0x8892)
     78 bind_layers(UDP, ProfinetIO, dport=0x8892)
     79 
     80