# SPDX-License-Identifier: GPL-2.0-or-later # This file is part of Scapy # See https://scapy.net/ for more information # Copyright (C) 2019 Luis Rosa # scapy.contrib.description = PCOM Protocol # scapy.contrib.status = loads """ PCOM PCOM is a protocol to communicate with Unitronics PLCs either by serial or TCP. Two modes are available, ASCII and Binary. https://unitronicsplc.com/Download/SoftwareUtilities/Unitronics%20PCOM%20Protocol.pdf """ import struct from scapy.packet import Packet, bind_layers from scapy.layers.inet import TCP from scapy.fields import XShortField, ByteEnumField, XByteField, \ StrFixedLenField, StrLenField, LEShortField, \ LEFieldLenField, XLE3BytesField, XLEShortField from scapy.volatile import RandShort from scapy.compat import bytes_encode, orb _protocol_modes = {0x65: "ascii", 0x66: "binary"} _ascii_command_codes = { "ID": "Send Identification Command", "CCR": "Send Start Command", "CCS": "Send Stop Command", "CCE": "Send Reset Command", "CCI": "Send Init Command", "CC": "Reply of Admin Commands (CC*)", "UG": "Get UnitID", "US": "Set UnitID", "RC": "Get RTC", "SC": "Set RTC", "RE": "Read Inputs", "RA": "Read Outputs", "GS": "Read System Bits", "GF": "Read System Integers", "RNH": "Read System Longs", "RNJ": "Read System Double Words", "RB": "Read Memory Bits", "RW": "Read Memory Integers", "RNL": "Read Memory Longs", "RND": "Read Memory Double Words", "RN": "Read Longs / Double Words", "SA": "Write Outputs", "SS": "Write System Bits", "SF": "Write System Integers", "SNH": "Write System Longs", "SNJ": "Write System Double Words", "SB": "Write Memory Bits", "SW": "Write Memory Integers", "SNL": "Write Memory Longs", "SND": "Write Memory Double Words", "SN": "Write Longs / Double Words" } _binary_command_codes = { 0x0c: "Get PLC Name Request", 0x8c: "Get PLC Name Reply", 0x4d: "Read Operands Request", 0xcd: "Read Operands Reply", 0x04: "Read Data Table Request", 0x84: "Read Data Table Reply", 0x44: "Write Data Table Request", 0xc4: "Write Data Table Reply" } class PCOM(Packet): fields_desc = [ XShortField("transId", RandShort()), ByteEnumField("mode", 0x65, _protocol_modes), XByteField("reserved", 0x00), LEShortField("len", None) ] def post_build(self, pkt, pay): if self.len is None and pay: pkt = pkt[:4] + struct.pack("