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