PROFNET IO RTC
PROFINET IO是由实时循环(RTC)层等不同层组成的工业协议,用于数据交换。然而,这个rtc层是有状态的,并且依赖于通过另一层发送的配置:profinet的dce/rpc端点。此配置定义每个交换数据块必须位于RTC中的位置。 data
以及这个相同缓冲区的长度。构建这样的包比其他协议要复杂一些。
RTC数据包
构建RTC时要做的第一件事 data
缓冲区用于实例化表示一段数据的每个Scapy数据包。一些基本数据包包括:
ProfinetIO
:该大楼为PROFINET包挡路。可以位于Ether()或UDP()之上PROFIsafe
:执行功能安全的PROFIsafe配置文件PNIORealTime_IOxS
:IO使用者或提供者状态字节
按如下方式实例化数据包:
>>> load_contrib('pnio')
>>> raw(ProfinetIO()/b'AAA')
b'\x00\x00AAA'
>>> raw(PROFIsafe.build_PROFIsafe_class(PROFIsafeControl, 4)(data = b'AAA', control=0x20, crc=0x424242))
b'AAA\x00 BBB'
>>> hexdump(PNIORealTime_IOxS())
0000 80 .
RTC包
现在可以实例化数据分组,可以构建整个RTC分组。 PNIORealTimeCyclicPDU
包含一个字段 data
这是要添加到缓冲区中的所有数据包的列表,但是,如果没有配置,Scapy将无法剖析它::
>>> load_contrib('pnio')
>>> p=PNIORealTimeCyclicPDU(cycleCounter=1024, data=[
... PNIORealTime_IOxS(),
... PNIORealTimeCyclicPDU.build_fixed_len_raw_type(4)(data = b'AAA') / PNIORealTime_IOxS(),
... PROFIsafe.build_PROFIsafe_class(PROFIsafeControl, 4)(data = b'AAA', control=0x20, crc=0x424242)/PNIORealTime_IOxS(),
... ])
>>> p.show()
###[ PROFINET Real-Time ]###
\data \
|###[ PNIO RTC IOxS ]###
| dataState = good
| instance = subslot
| reserved = 0x0
| extension = 0
|###[ FixedLenRawPacketLen4 ]###
| data = 'AAA'
|###[ PNIO RTC IOxS ]###
| dataState = good
| instance = subslot
| reserved = 0x0
| extension = 0
|###[ PROFISafe Control Message with F_CRC_Seed=0 ]###
| dat( = 'AAA'
| control = Toggle_h
| crc = 0x424242
|###[ PNIO RTC IOxS ]###
| dataState = good
| instance = subslot
| reserved = 0x0
| extension = 0
padding = ''
cycleCounter= 1024
dataStatus= primary+validData+run+no_problem
transferStatus= 0
为了使SCapy能够正确地解析它,还必须配置层,使其知道每个数据在缓冲区中的位置。此配置保存在字典中 conf.contribs["PNIO_RTC"]
可以使用 conf.contribs["PNIO_RTC"].update
方法。字典中的每一项都使用元组 (Ether.src, Ether.dst, ProfinetIO.frameID)
作为关键,能够分离每个通信的配置。然后,每个值是描述数据分组的类的列表。如果我们继续前面的示例,下面是要设置的配置:
>>> e=Ether(src='00:01:02:03:04:05', dst='06:07:08:09:0a:0b') / ProfinetIO(frameID="RT_CLASS_1") / p
>>> e.show2()
###[ Ethernet ]###
dst = 06:07:08:09:0a:0b
src = 00:01:02:03:04:05
type = 0x8892
###[ ProfinetIO ]###
frameID = RT_CLASS_1 (8000)
###[ PROFINET Real-Time ]###
\data \
|###[ PROFINET IO Real Time Cyclic Default Raw Data ]###
| data = '\\x80AAA\x00\\x80AAA\x00 BBB\\x80'
padding = ''
cycleCounter= 1024
dataStatus= primary+validData+run+no_problem
transferStatus= 0
>>> conf.contribs["PNIO_RTC"].update({('00:01:02:03:04:05', '06:07:08:09:0a:0b', 0x8000): [
... PNIORealTime_IOxS,
... PNIORealTimeCyclicPDU.build_fixed_len_raw_type(4),
... PNIORealTime_IOxS,
... PROFIsafe.build_PROFIsafe_class(PROFIsafeControl, 4),
... PNIORealTime_IOxS,
... ]})
>>> e.show2()
###[ Ethernet ]###
dst = 06:07:08:09:0a:0b
src = 00:01:02:03:04:05
type = 0x8892
###[ ProfinetIO ]###
frameID = RT_CLASS_1 (8000)
###[ PROFINET Real-Time ]###
\data \
|###[ PNIO RTC IOxS ]###
| dataState = good
| instance = subslot
| reserved = 0x0
| extension = 0
|###[ FixedLenRawPacketLen4 ]###
| data = 'AAA'
|###[ PNIO RTC IOxS ]###
| dataState = good
| instance = subslot
| reserved = 0x0
| extension = 0
|###[ PROFISafe Control Message with F_CRC_Seed=0 ]###
| data = 'AAA'
| control = Toggle_h
| crc = 0x424242
|###[ PNIO RTC IOxS ]###
| dataState = good
| instance = subslot
| reserved = 0x0
| extension = 0
padding = ''
cycleCounter= 1024
dataStatus= primary+validData+run+no_problem
transferStatus= 0
如果没有为给定偏移量配置数据包,则默认为 PNIORealTimeCyclicDefaultRawData
。