• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1% PNIO RPC layer test campaign
2
3+ Syntax check
4= Import the PNIO RPC layer
5from scapy.layers.dcerpc import *
6from scapy.contrib.pnio import *
7from scapy.contrib.pnio_rpc import *
8
9= Check that we have UUIDs
10
11for v in RPC_INTERFACE_UUID.values():
12    assert isinstance(v, UUID)
13
14+ Check Block
15
16= Block default values
17bytes(Block()) == bytearray.fromhex('000000020100')
18
19= Block basic example
20bytes(Block(load=b'\x01\x02\x03')) == bytearray.fromhex('000000050100010203')
21
22= Block has no payload (only padding)
23p = Block(bytearray.fromhex('000000050100010203040506'))
24p == Block(block_length=5, load=b'\x01\x02\x03') / conf.padding_layer(b'\x04\x05\x06')
25
26
27####################################################################
28####################################################################
29
30+ Check IODControlReq
31
32= IODControlReq default values
33bytes(IODControlReq()) == bytearray.fromhex('0000001c01000000000000000000000000000000000000000000000000000000')
34
35= IODControlReq basic example (IODControlReq PrmEnd control)
36bytes(IODControlReq(ARUUID='01234567-89ab-cdef-0123-456789abcdef', SessionKey=2, ControlCommand_PrmEnd=1)) == bytearray.fromhex('0110001c010000000123456789abcdef0123456789abcdef0002000000010000')
37
38= IODControlReq dissection
39p = IODControlReq(bytearray.fromhex('0118001c010000000123456789abcdef0123456789abcdef0005000000400000ef'))
40p == IODControlReq(ARUUID='01234567-89ab-cdef-0123-456789abcdef', SessionKey=5, ControlCommand_PrmBegin=1, block_type='IODBlockReq_connect_begin', block_length=28, padding=b'\0\0') / conf.padding_layer(b'\xef')
41
42= IODControlReq response
43p = p.get_response()
44p == IODControlRes(ARUUID='01234567-89ab-cdef-0123-456789abcdef', SessionKey=5, block_type='IODBlockRes_connect_begin')
45
46####################################################################
47
48+ Check IODControlRes
49
50= IODControlRes default values
51bytes(IODControlRes()) == bytearray.fromhex('8110001c01000000000000000000000000000000000000000000000000080000')
52
53= IODControlRes basic example (IODControlRes PrmEnd control)
54bytes(IODControlRes(ARUUID='01234567-89ab-cdef-0123-456789abcdef', SessionKey=2, block_type='IODBlockRes_connect_end')) == bytearray.fromhex('8110001c010000000123456789abcdef0123456789abcdef0002000000080000')
55
56= IODControlRes dissection
57p = IODControlRes(bytearray.fromhex('8118001c010000000123456789abcdef0123456789abcdef0005000000080000ef'))
58p == IODControlRes(ARUUID='01234567-89ab-cdef-0123-456789abcdef', SessionKey=5, block_type='IODBlockRes_connect_begin', block_length=28, padding=b'\0\0') / conf.padding_layer(b'\xef')
59
60
61####################################################################
62####################################################################
63
64+ Check IODWriteReq
65
66= IODWriteReq default values
67bytes(IODWriteReq()) == bytearray.fromhex('0008003c010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
68
69= IODWriteReq basic example
70bytes(IODWriteReq(
71  ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=1, API=1, slotNumber=2, subslotNumber=3,
72  index=0x4321
73  ) / b'\xab\xcd'
74  ) == bytearray.fromhex('0008003c010000010123456789abcdef0123456789abcdef00000001000200030000432100000002000000000000000000000000000000000000000000000000abcd')
75
76= IODWriteReq dissection
77p = IODWriteReq(bytearray.fromhex('0008003c010000010123456789abcdef0123456789abcdef00000001000200030000432100000002000000000000000000000000000000000000000000000000abcdef'))
78p == IODWriteReq(ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=1, API=1, slotNumber=2, subslotNumber=3,
79  index=0x4321, block_length=60, recordDataLength=2, padding='\0\0', RWPadding=b'\0'*24
80  ) / b'\xab\xcd' / conf.padding_layer(b'\xef')
81
82= IODWriteReq response
83p = p.get_response()
84p == IODWriteRes(ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=1, API=1, slotNumber=2, subslotNumber=3,
85  index=0x4321)
86
87####################################################################
88
89+ Check IODWriteRes
90
91= IODWriteRes default values
92bytes(IODWriteRes()) == bytearray.fromhex('8008003c010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
93
94= IODWriteRes basic example
95bytes(IODWriteRes(
96  ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=1, API=1, slotNumber=2, subslotNumber=3,
97  index=0x4321
98  )) == bytearray.fromhex('8008003c010000010123456789abcdef0123456789abcdef00000001000200030000432100000000000000000000000000000000000000000000000000000000')
99
100= IODWriteRes dissection
101p = IODWriteRes(bytearray.fromhex('8008003c010000010123456789abcdef0123456789abcdef00000001000200030000432100000000000000000000000000000000000000000000000000000000ef'))
102p == IODWriteRes(ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=1, API=1, slotNumber=2, subslotNumber=3,
103  index=0x4321, recordDataLength=0, block_length=60, padding=b'\0\0', RWPadding=b'\0'*16
104  ) / conf.padding_layer(b'\xef')
105
106
107####################################################################
108####################################################################
109
110+ Check IODWriteMultipleReq
111
112#########
113= IODWriteMultipleReq default values
114bytes(IODWriteMultipleReq()) == bytearray.fromhex('0008003c0100000000000000000000000000000000000000ffffffffffffffff0000e04000000000000000000000000000000000000000000000000000000000')
115
116#########
117= IODWriteMultipleReq basic example
118bytes(IODWriteMultipleReq(ARUUID='01234567-89ab-cdef-0123-456789abcdef', blocks=[
119  IODWriteReq(
120    ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=1, API=1, slotNumber=2, subslotNumber=3,
121    index=0x4321
122    ) / b'\xab\xcd',
123  IODWriteReq(
124    ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=2, API=2, slotNumber=3, subslotNumber=4,
125    index=0x1234
126    ) / b'\x01\x02',
127  ])
128  ) == bytearray.fromhex('0008003c010000000123456789abcdef0123456789abcdefffffffffffffffff0000e04000000086000000000000000000000000000000000000000000000000') + \
129       bytearray.fromhex('0008003c010000010123456789abcdef0123456789abcdef00000001000200030000432100000002000000000000000000000000000000000000000000000000abcd') + b'\0\0' + \
130       bytearray.fromhex('0008003c010000020123456789abcdef0123456789abcdef000000020003000400001234000000020000000000000000000000000000000000000000000000000102')
131
132#########
133= IODWriteMultipleReq dissection
134p = IODWriteMultipleReq(
135  bytearray.fromhex('0008003c010000000123456789abcdef0123456789abcdefffffffffffffffff0000e04000000086000000000000000000000000000000000000000000000000') + \
136  bytearray.fromhex('0008003c010000010123456789abcdef0123456789abcdef00000001000200030000432100000002000000000000000000000000000000000000000000000000abcd') + b'\0\0' + \
137  bytearray.fromhex('0008003c010000020123456789abcdef0123456789abcdef000000020003000400001234000000020000000000000000000000000000000000000000000000000102') + b'\xef'
138  )
139p == IODWriteMultipleReq(ARUUID='01234567-89ab-cdef-0123-456789abcdef', recordDataLength=0x86,
140  padding=b'\0'*2, RWPadding=b'\0'*24, block_length=60, blocks=[
141    IODWriteReq(
142      ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=1, API=1, slotNumber=2, subslotNumber=3,
143      index=0x4321, recordDataLength=2, padding=b'\0'*2, RWPadding=b'\0'*24, block_length=60
144      ) / b'\xab\xcd',
145    IODWriteReq(
146      ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=2, API=2, slotNumber=3, subslotNumber=4,
147      index=0x1234, recordDataLength=2, padding=b'\0'*2, RWPadding=b'\0'*24, block_length=60
148      ) / b'\x01\x02',
149    ]) / conf.padding_layer(b'\xef')
150
151#########
152= IODWriteMultipleReq response
153p = p.get_response()
154p == IODWriteMultipleRes(ARUUID='01234567-89ab-cdef-0123-456789abcdef', blocks=[
155  IODWriteRes(
156    ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=1, API=1, slotNumber=2, subslotNumber=3,
157    index=0x4321
158    ),
159  IODWriteRes(
160    ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=2, API=2, slotNumber=3, subslotNumber=4,
161    index=0x1234
162    ),
163  ])
164
165
166####################################################################
167
168+ Check IODWriteMultipleRes
169
170= IODWriteMultipleRes default values
171bytes(IODWriteMultipleRes()) == bytearray.fromhex('8008003c0100000000000000000000000000000000000000ffffffffffffffff0000e04000000000000000000000000000000000000000000000000000000000')
172
173= IODWriteMultipleRes basic example
174bytes(IODWriteMultipleRes(ARUUID='01234567-89ab-cdef-0123-456789abcdef', blocks=[
175  IODWriteRes(
176    ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=1, API=1, slotNumber=2, subslotNumber=3,
177    index=0x4321
178    ),
179  IODWriteRes(
180    ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=2, API=2, slotNumber=3, subslotNumber=4,
181    index=0x1234
182    ),
183  ])
184  ) == bytearray.fromhex('8008003c010000000123456789abcdef0123456789abcdefffffffffffffffff0000e04000000080000000000000000000000000000000000000000000000000') + \
185       bytearray.fromhex('8008003c010000010123456789abcdef0123456789abcdef00000001000200030000432100000000000000000000000000000000000000000000000000000000') + \
186       bytearray.fromhex('8008003c010000020123456789abcdef0123456789abcdef00000002000300040000123400000000000000000000000000000000000000000000000000000000')
187
188= IODWriteMultipleRes dissection
189p = IODWriteMultipleRes(
190  bytearray.fromhex('8008003c010000000123456789abcdef0123456789abcdefffffffffffffffff0000e04000000080000000000000000000000000000000000000000000000000') + \
191  bytearray.fromhex('8008003c010000010123456789abcdef0123456789abcdef00000001000200030000432100000000000000000000000000000000000000000000000000000000') + \
192  bytearray.fromhex('8008003c010000020123456789abcdef0123456789abcdef00000002000300040000123400000000000000000000000000000000000000000000000000000000') + b'\xef'
193  )
194p == IODWriteMultipleRes(ARUUID='01234567-89ab-cdef-0123-456789abcdef', recordDataLength=0x80,
195  padding=b'\0'*2, RWPadding=b'\0'*16, block_length=60, blocks=[
196    IODWriteRes(
197      ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=1, API=1, slotNumber=2, subslotNumber=3,
198      index=0x4321, recordDataLength=0, padding=b'\0'*2, RWPadding=b'\0'*16, block_length=60
199      ),
200    IODWriteRes(
201      ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=2, API=2, slotNumber=3, subslotNumber=4,
202      index=0x1234, recordDataLength=0, padding=b'\0'*2, RWPadding=b'\0'*16, block_length=60
203      ),
204    ]) / conf.padding_layer(b'\xef')
205
206
207####################################################################
208
209+ Check IODReadReq
210
211= IODReadReq default values
212bytes(IODReadReq()) == bytearray.fromhex('0009003c010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
213
214= IODReadReq basic example
215bytes(IODReadReq(
216  ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=1, API=1, slotNumber=2, subslotNumber=3,
217  index=0x4321)
218  ) == bytearray.fromhex('0009003c010000010123456789abcdef0123456789abcdef00000001000200030000432100000000000000000000000000000000000000000000000000000000')
219
220= IODReadReq dissection
221p = IODReadReq(bytearray.fromhex('0009003c010000010123456789abcdef0123456789abcdef00000001000200030000432100000002000000000000000000000000000000000000000000000000abcdef'))
222p == IODReadReq(ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=1, API=1, slotNumber=2, subslotNumber=3,
223  index=0x4321, block_length=60, recordDataLength=2, padding='\0\0', RWPadding=b'\0'*24
224  ) / b'\xab\xcd' / conf.padding_layer(b'\xef')
225
226= IODReadReq response
227p = p.get_response()
228p == IODReadRes(ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=1, API=1, slotNumber=2, subslotNumber=3,
229  index=0x4321)
230
231
232####################################################################
233
234+ Check IODReadRes
235
236= IODReadRes default values
237bytes(IODReadRes()) == bytearray.fromhex('8009003c010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
238
239= IODReadRes basic example
240bytes(IODReadRes(
241    ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=1, API=1, slotNumber=2, subslotNumber=3,
242    index=0x4321)) == bytearray.fromhex('8009003c010000010123456789abcdef0123456789abcdef00000001000200030000432100000000000000000000000000000000000000000000000000000000')
243
244= IODReadRes dissection
245
246p = IODReadRes(bytearray.fromhex('8009003c010000010123456789abcdef0123456789abcdef00000001000200030000432100000000000000000000000000000000000000000000000000000000ef'))
247p == IODReadRes(
248    ARUUID='01234567-89ab-cdef-0123-456789abcdef', seqNum=1, API=1, slotNumber=2, subslotNumber=3,
249    index=0x4321, recordDataLength=0, block_length=60, padding=b'\0\0', RWPadding=b'\0'*20
250    ) / conf.padding_layer(b'\xef')
251
252
253####################################################################
254####################################################################
255
256+ Check I&M
257
258= IM0Block default values
259raw(IM0Block()) == bytearray.fromhex('002000380100000000000000000000000000000000000000000000000000000000000000000000000000000000005600000000000000000001010000')
260
261= IM0Block basic example
262raw(IM0Block(OrderID='foobar', IMSerialNumber='ABCDEF1234567890')) == bytearray.fromhex('0020003801000000666f6f62617200000000000000000000000000004142434445463132333435363738393000005600000000000000000001010000')
263
264= IM1Block default values
265raw(IM1Block()) == bytearray.fromhex('002100380100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
266
267= IM2Block default values
268raw(IM2Block()) == bytearray.fromhex('00220012010000000000000000000000000000000000')
269
270= IM3Block default values
271raw(IM3Block()) == bytearray.fromhex('002300380100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
272
273= IM4Block default values
274raw(IM4Block()) == bytearray.fromhex('002400380100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
275
276
277####################################################################
278####################################################################
279
280+ Check ARBlockReq
281
282= ARBlockReq default values
283bytes(ARBlockReq()) == bytearray.fromhex('0101003601000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000103e888920000')
284
285= ARBlockReq basic example
286bytes(ARBlockReq(
287  ARType='IOCARSingle', ARUUID='01234567-89ab-cdef-0123-456789abcdef', SessionKey=1,
288  CMInitiatorObjectUUID='dea00000-6c97-11d1-8271-010203040506', ARProperties_ParametrizationServer='CM_Initator',
289  CMInitiatorStationName='plc1')
290  ) == bytearray.fromhex('0101003a010000010123456789abcdef0123456789abcdef0001000000000000dea000006c9711d182710102030405060000001103e888920004') + b'plc1'
291
292= ARBlockReq dissection
293p = ARBlockReq(bytearray.fromhex('0101003a010000010123456789abcdef0123456789abcdef0001010203040506dea000006c9711d182710102030405060000001103e888920004') + b'plc1' + b'\xef')
294p == ARBlockReq(
295  ARType='IOCARSingle', ARUUID='01234567-89ab-cdef-0123-456789abcdef', SessionKey=1,
296  CMInitiatorObjectUUID='dea00000-6c97-11d1-8271-010203040506', ARProperties_ParametrizationServer='CM_Initator',
297  CMInitiatorMacAdd='01:02:03:04:05:06', StationNameLength=4, CMInitiatorStationName='plc1', block_length=58
298  ) / conf.padding_layer(b'\xef')
299
300= ARBlockReq response
301p = p.get_response()
302p == ARBlockRes(ARType='IOCARSingle', ARUUID='01234567-89ab-cdef-0123-456789abcdef', SessionKey=1)
303
304####################################################################
305
306+ Check ARBlockRes
307
308= ARBlockRes default values
309bytes(ARBlockRes()) == bytearray.fromhex('8101001e010000010000000000000000000000000000000000000000000000008892')
310
311= ARBlockRes basic example
312bytes(
313  ARBlockRes(ARType='IOCARSingle', ARUUID='01234567-89ab-cdef-0123-456789abcdef', SessionKey=1)
314  ) == bytearray.fromhex('8101001e010000010123456789abcdef0123456789abcdef00010000000000008892')
315
316= ARBlockRes dissection
317p = ARBlockRes(bytearray.fromhex('8101001e010000010123456789abcdef0123456789abcdef00010102030405068892ef'))
318p == ARBlockRes(
319  ARType='IOCARSingle', ARUUID='01234567-89ab-cdef-0123-456789abcdef', SessionKey=1,
320  CMResponderMacAdd='01:02:03:04:05:06', block_length=30) / conf.padding_layer(b'\xef')
321
322
323####################################################################
324####################################################################
325
326+ Check IOCRBlockReq
327
328= IOCRBlockReq default values
329bytes(IOCRBlockReq()) == bytearray.fromhex('0102002a010000010001889200000000002880000020002000010000ffffffff000a000ac0000000000000000000')
330
331= IOCRAPI default values
332bytes(IOCRAPI()) == bytearray.fromhex('0000000000000000')
333
334= IOCRAPIObject default values
335bytes(IOCRAPIObject()) == bytearray.fromhex('000000000000')
336
337= IOCRBlockReq basic example
338p = IOCRBlockReq(
339  IOCRType='OutputCR', IOCRReference=1, SendClockFactor=2,
340  ReductionRatio=32, DataLength=47, FrameID=0x8014,
341  APIs=[
342    IOCRAPI(
343      API=4,
344      IODataObjects=[
345        IOCRAPIObject(SlotNumber=2, SubslotNumber=1, FrameOffset=0),
346        IOCRAPIObject(SlotNumber=1, SubslotNumber=1, FrameOffset=9),
347        ]
348      ),
349    IOCRAPI(
350      API=0,
351      IODataObjects=[
352        IOCRAPIObject(SlotNumber=3, SubslotNumber=1, FrameOffset=15),
353        ],
354      IOCSs=[
355        IOCRAPIObject(SlotNumber=3, SubslotNumber=1, FrameOffset=4),
356        ],
357      ),
358    ]
359  )
360bytes(p) == \
361  bytearray.fromhex('01020052010000020001889200000000002f80140002002000010000ffffffff000a000ac0000000000000000002' + \
362    '0000000400020002000100000001000100090000' + \
363    '00000000000100030001000f0001000300010004')
364
365= IOCRBlockReq dissection
366p = IOCRBlockReq(
367  bytearray.fromhex('01020052010000020001889200000000002f80140002002000010000ffffffff000a000ac0000102030405060002' + \
368    '0000000400020002000100000001000100090000' + \
369    '00000000000100030001000f0001000300010004') + b'\xef')
370p == IOCRBlockReq(
371  IOCRType='OutputCR', IOCRReference=1, SendClockFactor=2, IOCRMulticastMACAdd='01:02:03:04:05:06',
372  ReductionRatio=32, DataLength=47, FrameID=0x8014, block_length=82,
373  NumberOfAPIs=2, APIs=[
374    IOCRAPI(
375      API=4,
376      NumberOfIODataObjects=2, IODataObjects=[
377        IOCRAPIObject(SlotNumber=2, SubslotNumber=1, FrameOffset=0),
378        IOCRAPIObject(SlotNumber=1, SubslotNumber=1, FrameOffset=9),
379        ],
380      NumberOfIOCS=0
381      ),
382    IOCRAPI(
383      API=0,
384      NumberOfIODataObjects=1, IODataObjects=[
385        IOCRAPIObject(SlotNumber=3, SubslotNumber=1, FrameOffset=15),
386        ],
387      NumberOfIOCS=1, IOCSs=[
388        IOCRAPIObject(SlotNumber=3, SubslotNumber=1, FrameOffset=4),
389        ],
390      ),
391    ]
392  ) / conf.padding_layer(b'\xef')
393
394= IOCRBlockReq response
395p = p.get_response()
396p == IOCRBlockRes(IOCRType='OutputCR', IOCRReference=1, FrameID=0x8014)
397
398####################################################################
399
400+ Check IOCRBlockRes
401
402= IOCRBlockRes default values
403bytes(IOCRBlockRes()) == bytearray.fromhex('810200080100000100018000')
404
405= IOCRBlockRes basic example
406bytes(
407  IOCRBlockRes(IOCRType='InputCR', IOCRReference=2, FrameID=0x8014)
408  ) == bytearray.fromhex('810200080100000100028014')
409
410= IOCRBlockRes dissection
411p = IOCRBlockRes(bytearray.fromhex('810200080100000100028014ef'))
412p == IOCRBlockRes(IOCRType='InputCR', IOCRReference=2, FrameID=0x8014,
413  block_length=8) / conf.padding_layer(b'\xef')
414
415
416####################################################################
417####################################################################
418
419+ Check ExpectedSubmoduleBlockReq
420
421= ExpectedSubmoduleBlockReq default values
422bytes(ExpectedSubmoduleBlockReq()) == bytearray.fromhex('0104000401000000')
423
424= ExpectedSubmoduleAPI default values
425bytes(ExpectedSubmoduleAPI()) == bytearray.fromhex('0000000000000000000000000000')
426
427= ExpectedSubmodule default values
428bytes(ExpectedSubmodule()) == bytearray.fromhex('0000000000000000')
429
430= ExpectedSubmoduleDataDescription default values
431bytes(ExpectedSubmoduleDataDescription()) == bytearray.fromhex('000000000000')
432
433= ExpectedSubmoduleBlockReq basic example
434p = ExpectedSubmoduleBlockReq(
435  APIs=[
436    ExpectedSubmoduleAPI(
437      API=4, SlotNumber=2, ModuleIdentNumber=0x08c4,
438      Submodules=[
439        ExpectedSubmodule(
440          SubslotNumber=1, SubmoduleIdentNumber=0x0123,
441          SubmoduleProperties_Type='INPUT_OUTPUT',
442          DataDescription=[
443            ExpectedSubmoduleDataDescription(
444              DataDescription='Output',
445              SubmoduleDataLength=5,
446              LengthIOPS=2, LengthIOCS=0
447              ),
448            ExpectedSubmoduleDataDescription(
449              DataDescription='Input',
450              SubmoduleDataLength=3,
451              LengthIOPS=1, LengthIOCS=2
452              )
453            ]
454          ),
455        ]
456      ),
457    ]
458  )
459bytes(p) == \
460  bytearray.fromhex('0104002601000001') + \
461    bytearray.fromhex('000000040002000008c400000001') + \
462      bytearray.fromhex('0001000001230003') + \
463        bytearray.fromhex('000200050002') + \
464        bytearray.fromhex('000100030201')
465
466= ExpectedSubmoduleBlockReq dissection
467p = ExpectedSubmoduleBlockReq(
468  bytearray.fromhex('0104002601000001') + \
469    bytearray.fromhex('000000040002000008c400000001') + \
470      bytearray.fromhex('0001000001230003') + \
471        bytearray.fromhex('000200050002') + \
472        bytearray.fromhex('000100030201') + b'\xef'
473  )
474p == ExpectedSubmoduleBlockReq(block_length=38,
475  NumberOfAPIs=1, APIs=[
476    ExpectedSubmoduleAPI(
477      API=4, SlotNumber=2, ModuleIdentNumber=0x08c4,
478      NumberOfSubmodules=1 ,Submodules=[
479        ExpectedSubmodule(
480          SubslotNumber=1, SubmoduleIdentNumber=0x0123,
481          SubmoduleProperties_Type='INPUT_OUTPUT',
482          DataDescription=[
483            ExpectedSubmoduleDataDescription(
484              DataDescription='Output',
485              SubmoduleDataLength=5,
486              LengthIOPS=2, LengthIOCS=0
487              ),
488            ExpectedSubmoduleDataDescription(
489              DataDescription='Input',
490              SubmoduleDataLength=3,
491              LengthIOPS=1, LengthIOCS=2
492              )
493            ]
494          ),
495        ]
496      ),
497    ]
498  ) / conf.padding_layer(b'\xef')
499
500
501####################################################################
502####################################################################
503
504+ Check AlarmCRBlockReq
505
506= AlarmCRBlockReq default values
507bytes(AlarmCRBlockReq()) == bytearray.fromhex('010300160100000188920000000000010003000300c8c000a000')
508
509= AlarmCRBlockReq with transport
510bytes(AlarmCRBlockReq(AlarmCRProperties_Transport=1)) == bytearray.fromhex('010300160100000108004000000000010003000300c8c000a000')
511
512= AlarmCRBlockReq dissection
513p = AlarmCRBlockReq(bytearray.fromhex('010300160100000188920000000000010003000300c8c000a000'))
514p[AlarmCRBlockReq].AlarmCRType == 0x0001
515p[AlarmCRBlockReq].LocalAlarmReference == 0x0003
516
517= AlarmCRBlockReq response
518p = p.get_response()
519p == AlarmCRBlockRes(AlarmCRType=0x0001, LocalAlarmReference=0x0003)
520
521+ Check AlarmCRBlockRes
522
523= AlarmCRBlockRes default values
524bytes(AlarmCRBlockRes()) == bytearray.fromhex('810300080100000100000000')
525
526= AlarmCRBlockRes dissection
527p = AlarmCRBlockRes(bytearray.fromhex('810300080100000100030000'))
528p[AlarmCRBlockRes].AlarmCRType == 0x0001
529p[AlarmCRBlockRes].LocalAlarmReference == 0x0003
530
531
532####################################################################
533####################################################################
534
535+ Check PNIOServiceReqPDU
536
537= PNIOServiceReqPDU basic example
538* PNIOServiceReqPDU must always be placed above a DCE/RPC layer as it requires the endianness field
539p = DceRpc4() / PNIOServiceReqPDU(blocks=[
540  Block(load=b'\x01\x02')
541  ])
542s = bytes(p)
543# Remove the random UUID part before comparison
544assert s[:18] + s[24:] == b'\x04\x00\x00\x00\x10\x00\x00\x00\x00\x00\xa0\xde\x97l\xd1\x11\x82q\x01\x00\xa0\xde\x97l\xd1\x11\x82q\x00\xa0$B\xdf}\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x1c\x00\x00\x00\x00\x00\x08\x00\x00\x00\x08\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x04\x01\x00\x01\x02'
545
546= PNIOServiceReqPDU dissection
547p = DceRpc4(
548  bytes(bytearray.fromhex('0400000000000000dea000006c9711d18271010203040506dea000016c9711d1827100a02442df7d000000000000000000000000000000000000000000000001000000000000ffffffff001c00000000' + \
549    '0000000f000000080000000f0000000000000008' + \
550    '0000000401000102ef')
551  ))
552bytes(p.payload) == bytes(PNIOServiceReqPDU(args_length=8, args_max=15, max_count=15, actual_count=8,
553  blocks=[
554    Block(block_length=4, load=b'\x01\x02')
555    ]
556  ) / b'\xef')
557
558
559####################################################################
560####################################################################
561
562+ Check PNIOServiceResPDU
563
564= PNIOServiceResPDU basic example
565* PNIOServiceResPDU must always be placed above a DCE/RPC layer as it requires the endianness field
566p = DceRpc4() / PNIOServiceResPDU(blocks=[
567  Block(load=b'\x01\x02')
568  ])
569s = bytes(p)
570# Remove the random UUID part before comparison
571assert s[:18] + s[24:] == b'\x04\x02\x00\x00\x10\x00\x00\x00\x00\x00\xa0\xde\x97l\xd1\x11\x82q\x02\x00\xa0\xde\x97l\xd1\x11\x82q\x00\xa0$B\xdf}\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x04\x01\x00\x01\x02'
572
573= PNIOServiceResPDU dissection
574p = DceRpc4(
575  bytes(bytearray.fromhex('0402000000000000dea000006c9711d18271010203040506dea000026c9711d1827100a02442df7d000000000000000000000000000000000000000000000001000000000000ffffffff001c00000000' + \
576    '00001234000000080000000f0000000000000008' + \
577    '0000000401000102ef')
578  ))
579bytes(p.payload) == bytes(PNIOServiceResPDU(status=0x1234, args_length=8, max_count=15, actual_count=8,
580  blocks=[
581    Block(block_length=4, load=b'\x01\x02')
582    ]
583  ) / b'\xef')
584
585####################################################################
586##                      Some usual examples                       ##
587####################################################################
588
589+ Check some basic examples
590
591#### Connect Request
592= A PNIO RPC Connect Request
593p = DceRpc4(
594  endian='little', opnum=0, seqnum=0,
595  object='dea00000-6c97-11d1-8271-010203040506',
596  act_id='01234567-89ab-cdef-0123-456789abcdef'
597  ) / PNIOServiceReqPDU(
598  blocks=[
599    # AR block
600    ARBlockReq(
601      ARType='IOCARSingle', ARUUID='fedcba98-7654-3210-fedc-ba9876543210', SessionKey=0,
602      CMInitiatorMacAdd='01:02:03:04:05:06', CMInitiatorStationName='plc-1',
603      CMInitiatorObjectUUID='dea00000-6c97-11d1-8271-010203040506', ARProperties_ParametrizationServer='CM_Initator'
604      ),
605    # IO CR input block
606    IOCRBlockReq(
607      IOCRType='InputCR', IOCRReference=1, SendClockFactor=2,
608      ReductionRatio=32, DataLength=40,
609      APIs=[
610        IOCRAPI(
611          API=0,
612          IODataObjects=[
613            IOCRAPIObject(SlotNumber=3, SubslotNumber=1,FrameOffset=15),
614            ],
615          IOCSs=[
616            IOCRAPIObject(SlotNumber=3, SubslotNumber=1,FrameOffset=4),
617            ],
618          ),
619        ]
620      ),
621    # IO CR output block
622    IOCRBlockReq(
623      IOCRType='OutputCR', IOCRReference=2, SendClockFactor=8, ReductionRatio=32,
624      DataLength=52, FrameID=0xffff,
625      APIs=[
626        IOCRAPI(
627          API=0,
628          IODataObjects=[
629            IOCRAPIObject(SlotNumber=3, SubslotNumber=1,FrameOffset=0),
630            IOCRAPIObject(SlotNumber=1, SubslotNumber=2,FrameOffset=9),
631            ],
632          ),
633        ]
634      ),
635    # List of expected submodules
636    ExpectedSubmoduleBlockReq(
637      APIs=[
638        ExpectedSubmoduleAPI(
639          API=0, SlotNumber=3, ModuleIdentNumber=0x08c4,
640          Submodules=[
641            ExpectedSubmodule(
642              SubslotNumber=1, SubmoduleIdentNumber=0x0124,
643              SubmoduleProperties_Type='INPUT_OUTPUT',
644              DataDescription=[
645                ExpectedSubmoduleDataDescription(
646                  DataDescription='Output',
647                  SubmoduleDataLength=3,
648                  LengthIOPS=1, LengthIOCS=1
649                  ),
650                ExpectedSubmoduleDataDescription(
651                  DataDescription='Input',
652                  SubmoduleDataLength=5,
653                  LengthIOPS=2, LengthIOCS=0
654                  )
655                ]
656              ),
657            ]
658          ),
659        ]
660      ),
661    ExpectedSubmoduleBlockReq(
662      APIs=[
663        ExpectedSubmoduleAPI(
664          API=0, SlotNumber=1, ModuleIdentNumber=0x08c3,
665          Submodules=[
666            ExpectedSubmodule(
667              SubslotNumber=2, SubmoduleIdentNumber=0x0424,
668              SubmoduleProperties_Type='OUTPUT',
669              DataDescription=[
670                ExpectedSubmoduleDataDescription(
671                  DataDescription='Output',
672                  SubmoduleDataLength=5,
673                  LengthIOPS=1, LengthIOCS=0
674                  )
675                ]
676              ),
677            ]
678          ),
679        ]
680      ),
681    ]
682  )
683bytes(p) == bytearray.fromhex(
684  '04000000100000000000a0de976cd11182710102030405060100a0de976cd111827100a02442df7d67452301ab89efcd0123456789abcdef0000000001000000000000000000ffffffff250100000000' + \
685  '1101000011010000110100000000000011010000' + \
686    '0101003b01000001fedcba9876543210fedcba98765432100000010203040506dea000006c9711d182710102030405060000001103e888920005') + b'plc-1' + \
687    bytearray.fromhex('0102003e010000010001889200000000002880000002002000010000ffffffff000a000ac0000000000000000001' + \
688      '00000000000100030001000f0001000300010004' + \
689    '0102003e0100000200028892000000000034ffff0008002000010000ffffffff000a000ac0000000000000000001' + \
690      '0000000000020003000100000001000200090000' + \
691    '0104002601000001000000000003000008c400000001' + \
692      '0001000001240003' + \
693        '000200030101' + \
694        '000100050002' + \
695    '0104002001000001000000000001000008c300000001' + \
696      '0002000004240002' + \
697        '000200050001')
698
699
700#### Write Request
701= A PNIO RPC Write Request
702p = DceRpc4(
703  endian='little', opnum=2, seqnum=1,
704  object='dea00000-6c97-11d1-8271-010203040506',
705  act_id='01234567-89ab-cdef-0123-456789abcdef'
706  ) / PNIOServiceReqPDU(
707  blocks=[
708    IODWriteMultipleReq(
709      seqNum=0, ARUUID='fedcba98-7654-3210-fedc-ba9876543210', blocks=[
710        IODWriteReq(
711          seqNum=1, API=0, slotNumber=1, subslotNumber=1, index=0x123,
712          ARUUID='fedcba98-7654-3210-fedc-ba9876543210'
713          ) / b'\x01\x02',
714        IODWriteReq(
715          seqNum=2, API=0, slotNumber=3, subslotNumber=1,
716          ARUUID='fedcba98-7654-3210-fedc-ba9876543210'
717          ) / FParametersBlock(
718            F_CRC_Seed=1, F_CRC_Length='CRC-24', F_Source_Add=0xc1, F_Dest_Add=0xc2,
719            F_WD_Time=500, F_Par_CRC=0x1234
720            ),
721        ]
722      )
723    ]
724  )
725bytes(p) == bytearray.fromhex(
726  '04000000100000000000a0de976cd11182710102030405060100a0de976cd111827100a02442df7d67452301ab89efcd0123456789abcdef0000000001000000010000000200ffffffffe20000000000' + \
727  'ce000000ce000000ce00000000000000ce000000' + \
728    '0008003c01000000fedcba9876543210fedcba9876543210ffffffffffffffff0000e0400000008e' + '00' * 24 + \
729      '0008003c01000001fedcba9876543210fedcba987654321000000000000100010000012300000002' + '00' * 24 + \
730        '01020000' + \
731      '0008003c01000002fedcba9876543210fedcba98765432100000000000030001000001000000000a' + '00' * 24 + \
732        '484000c100c201f41234')
733
734
735#### PrmEnd control Request
736= A PNIO RPC PrmEnd Control Request
737p = DceRpc4(
738  endian='little', opnum=0, seqnum=2,
739  object='dea00000-6c97-11d1-8271-010203040506',
740  act_id='01234567-89ab-cdef-0123-456789abcdef'
741  ) / PNIOServiceReqPDU(
742  blocks=[
743    IODControlReq(ARUUID='fedcba98-7654-3210-fedc-ba9876543210', SessionKey=0, ControlCommand_PrmEnd=1)
744    ]
745  )
746bytes(p) == bytearray.fromhex(
747  '04000000100000000000a0de976cd11182710102030405060100a0de976cd111827100a02442df7d67452301ab89efcd0123456789abcdef0000000001000000020000000000ffffffff340000000000' + \
748  '2000000020000000200000000000000020000000' + \
749    '0110001c01000000fedcba9876543210fedcba98765432100000000000010000')
750
751#### ApplicationReady control Request
752= A PNIO RPC PrmEnd Control Request
753p = DceRpc4(
754  endian='little', opnum=0, seqnum=0,
755  object='dea00000-6c97-11d1-8271-060504030201',
756  act_id='01020304-0506-0708-090a-0b0c0d0e0f00',
757  if_id=RPC_INTERFACE_UUID['UUID_IO_ControllerInterface'],
758  ) / PNIOServiceReqPDU(
759  blocks=[
760    IODControlReq(ARUUID='fedcba98-7654-3210-fedc-ba9876543210', SessionKey=0, ControlCommand_ApplicationReady=1)
761    ]
762  )
763bytes(p) == bytearray.fromhex(
764  '04000000100000000000a0de976cd11182710605040302010200a0de976cd111827100a02442df7d0403020106050807090a0b0c0d0e0f000000000001000000000000000000ffffffff340000000000' + \
765  '2000000020000000200000000000000020000000' + \
766    '0112001c01000000fedcba9876543210fedcba98765432100000000000020000')
767
768
769### PNIO Alarms
770
771= PNIO Alarm decoding (Alarm_Low)
772
773p = Ether(b'\x00\x11\x22\x33\x44\x55' \
774          b'\x00\x66\x77\x88\x99\xaa' \
775          b'\x81\x00\xa0\x00' \
776          b'\x88\x92' \
777          b'\xfe\x01' \
778          b'\x00\x03\x00\x03\x11\x11\xff\xff\xff\xfe\x00\x36' \
779          b'\x00\x02\x00\x32\x01\x00\x00\x01\x00\x00\x00\x00\x00' \
780          b'\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x08\x00' \
781          b'\x81\x00\x0f\x00\x00\x08\x01\x00\x00\x00\x00\x00\x00\x02' \
782          b'\x80\x02\x00\x0f\x2c\x00\x00\x05\x80\x00\x00\x00\x00\x22')
783assert p[ProfinetIO].frameID == 0xfe01
784assert isinstance(p[ProfinetIO].payload, Alarm_Low)
785assert p[AlarmNotification_Low].block_type == 0x0002
786assert isinstance(p[AlarmNotification_Low].AlarmPayload[0], MaintenanceItem)
787assert p[MaintenanceItem].UserStructureIdentifier == 0x8100
788assert isinstance(p[AlarmNotification_Low].AlarmPayload[1], DiagnosisItem)
789assert p[DiagnosisItem].UserStructureIdentifier == 0x8002
790
791= PNIO Alarm decoding (Alarm_High)
792p = Ether(b'\x00\x11\x22\x33\x44\x55' \
793          b'\x00\x66\x77\x88\x99\xaa' \
794          b'\x81\x00\xa0\x00' \
795          b'\x88\x92' \
796          b'\xfc\x01' \
797          b'\x00\x03\x00\x03\x11\x11\xff\xff\xff\xfe\x00\x36' \
798          b'\x00\x02\x00\x32\x01\x00\x00\x01\x00\x00\x00\x00\x00' \
799          b'\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x08\x00' \
800          b'\x81\x00\x0f\x00\x00\x08\x01\x00\x00\x00\x00\x00\x00\x02' \
801          b'\x80\x02\x00\x0f\x2c\x00\x00\x05\x80\x00\x00\x00\x00\x22')
802assert p[ProfinetIO].frameID == 0xfc01
803assert isinstance(p[ProfinetIO].payload, Alarm_High)
804assert p[AlarmNotification_High].block_type == 0x0002
805assert isinstance(p[AlarmNotification_High].AlarmPayload[0], MaintenanceItem)
806assert p[MaintenanceItem].UserStructureIdentifier == 0x8100
807assert isinstance(p[AlarmNotification_High].AlarmPayload[1], DiagnosisItem)
808assert p[DiagnosisItem].UserStructureIdentifier ==  0x8002
809
810= PNIO Alarm DiagnosisItem
811
812p = AlarmNotification_Low(AlarmPayload=[MaintenanceItem(), DiagnosisItem()])
813assert raw(p) == bytearray.fromhex('0002002c0100000000000000000000000000000000000000000000000000000001000000000000000000000000000000')
814
815= PNIO Alarm UploadRetrievalItem
816
817p = AlarmNotification_Low(AlarmPayload=[MaintenanceItem(), UploadRetrievalItem()])
818assert raw(p) == bytearray.fromhex('00020036010000000000000000000000000000000000000000000000000000000100000000000000000000000000010000000000000000000000')
819
820= PNIO Alarm iParameterItem
821p = AlarmNotification_Low(AlarmPayload=[MaintenanceItem(), iParameterItem()])
822assert raw(p) == bytearray.fromhex('0002003e0100000000000000000000000000000000000000000000000000000001000000000000000000000000000100000000000000000000000000000000000000')
823
824= PNIO Alarm RS_AlarmItem
825p = AlarmNotification_Low(AlarmPayload=[MaintenanceItem(), RS_AlarmItem()])
826assert raw(p) == bytearray.fromhex('0002002801000000000000000000000000000000000000000000000000000000010000000000000000000000')
827
828= PNIO Alarm PRAL_AlarmItem
829p = AlarmNotification_Low(AlarmPayload=[MaintenanceItem(), PRAL_AlarmItem()])
830assert raw(p) == bytearray.fromhex('0002002e01000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000')
831
832= PNIO PDPortDataAdjust Decoding
833raw = bytearray.fromhex('0402280000000000dea000006c9711d182710001000305f9dea000016' \
834                        'c9711d1827100a02442df7d0777bc51ddaa4d07addb7075183fc28b00' \
835                        '00000000000001000000000002ffffffff007c0000000000000000000' \
836                        '000680000004000000000000000688009003c0100000002ba501cd47e' \
837                        '40d3a0b545fd4ac70eb900000000000080020000802f0000002800000' \
838                        '000000000000000000000000000000000000000000002020024010000' \
839                        '00000080020224000c010000000000000100000000021b00080100000' \
840                        '000010000')
841p = DceRpc4(raw)
842assert p[PDPortDataAdjust].subslotNumber == 0x8002
843assert p[AdjustPeerToPeerBoundary].peerToPeerBoundary == 0x1
844assert LINKSTATE_LINK[p[AdjustLinkState].LinkState] == 'Up'
845