267 lines
7.2 KiB
Text
267 lines
7.2 KiB
Text
|
% EtherCat test campaign
|
||
|
|
||
|
#
|
||
|
# execute test:
|
||
|
# $ test/run_tests -P "load_contrib('ethercat')" -t scapy/contrib/ethercat.uts
|
||
|
#
|
||
|
|
||
|
+ LEBitFields
|
||
|
= regression test
|
||
|
|
||
|
TEST_SAMPLE_ENUM = {
|
||
|
0x01: 'one',
|
||
|
0x02: 'two',
|
||
|
0x03: 'three',
|
||
|
0x04: 'four',
|
||
|
0x05: 'five',
|
||
|
0x06: 'six',
|
||
|
0x07: 'seven'
|
||
|
}
|
||
|
|
||
|
class BitFieldUserExampleLE(Packet):
|
||
|
|
||
|
fields_desc = [
|
||
|
LEBitEnumField('a', 0, 2, TEST_SAMPLE_ENUM),
|
||
|
LEBitField('b', 0, 18),
|
||
|
LEBitField('c', 0, 5),
|
||
|
LEBitField('d', 0, 23),
|
||
|
]
|
||
|
|
||
|
class BitFieldUserExample(Packet):
|
||
|
|
||
|
fields_desc = [
|
||
|
BitEnumField('a', 0, 2, TEST_SAMPLE_ENUM),
|
||
|
BitField('b', 0, 18),
|
||
|
BitField('c', 0, 5),
|
||
|
BitField('d', 0, 23),
|
||
|
]
|
||
|
|
||
|
test_data = [
|
||
|
{
|
||
|
'a':0x01,
|
||
|
'b':0x00,
|
||
|
'c':0x00,
|
||
|
'd':0x123456
|
||
|
},
|
||
|
{
|
||
|
'a': 0x00,
|
||
|
'b': 0b111111111111111111,
|
||
|
'c': 0x00,
|
||
|
'd': 0x112233
|
||
|
},
|
||
|
{
|
||
|
'a': 0x00,
|
||
|
'b': 0x00,
|
||
|
'c': 0x01,
|
||
|
'd': 0x00
|
||
|
},
|
||
|
]
|
||
|
|
||
|
for data in test_data:
|
||
|
bf_le = BitFieldUserExampleLE(**data)
|
||
|
bf = BitFieldUserExample(**data)
|
||
|
# rebuild big-endian and little-endian bitfields from its own binary expressions
|
||
|
bf_le = BitFieldUserExampleLE(bf_le.do_build())
|
||
|
bf = BitFieldUserExample(bf.do_build())
|
||
|
''' disabled as only required for 'visual debugging'
|
||
|
from scapy.compat import raw
|
||
|
# dump content for debugging
|
||
|
bitstr = ''
|
||
|
hexstr = ''
|
||
|
for i in bytearray(raw(bf)):
|
||
|
bitstr += '{:08b} '.format(i)
|
||
|
hexstr += '{:02x} '.format(i)
|
||
|
print('BE - BITS: {} HEX: {} ({})'.format(bitstr, hexstr, data))
|
||
|
bitstr = ''
|
||
|
hexstr = ''
|
||
|
for i in bytearray(raw(bf_le)):
|
||
|
bitstr += '{:08b} '.format(i)
|
||
|
hexstr += '{:02x} '.format(i)
|
||
|
print('LE - BITS: {} HEX: {} ({})'.format(bitstr, hexstr, data))
|
||
|
'''
|
||
|
# compare values
|
||
|
for key in data:
|
||
|
assert(getattr(bf,key) == data[key])
|
||
|
assert (getattr(bf_le, key) == data[key])
|
||
|
|
||
|
= Avoid mix of LEBitFields and BitFields
|
||
|
|
||
|
TEST_SAMPLE_ENUM = {
|
||
|
0x01: 'one',
|
||
|
0x02: 'two',
|
||
|
0x03: 'three',
|
||
|
0x04: 'four',
|
||
|
0x05: 'five',
|
||
|
0x06: 'six',
|
||
|
0x07: 'seven'
|
||
|
}
|
||
|
|
||
|
class MissingFieldSameLEFieldTypes(Packet):
|
||
|
|
||
|
fields_desc = [
|
||
|
LEBitEnumField('a', 0, 2, TEST_SAMPLE_ENUM),
|
||
|
LEBitField('b', 0, 18),
|
||
|
]
|
||
|
|
||
|
try:
|
||
|
frm = MissingFieldSameLEFieldTypes().build()
|
||
|
assert False
|
||
|
except LEBitFieldSequenceException:
|
||
|
pass
|
||
|
|
||
|
|
||
|
class MissingFieldDifferentLEFieldTypes(Packet):
|
||
|
|
||
|
fields_desc = [
|
||
|
LEBitEnumField('a', 0, 2, TEST_SAMPLE_ENUM),
|
||
|
LEBitField('b', 0, 18),
|
||
|
]
|
||
|
|
||
|
try:
|
||
|
frm = MissingFieldDifferentLEFieldTypes().build()
|
||
|
assert False
|
||
|
except LEBitFieldSequenceException:
|
||
|
pass
|
||
|
|
||
|
|
||
|
class MixedBitFieldTypesLEBE(Packet):
|
||
|
|
||
|
fields_desc = [
|
||
|
LEBitField('a', 0, 12),
|
||
|
BitField('b', 0, 4),
|
||
|
]
|
||
|
|
||
|
try:
|
||
|
frm = MixedBitFieldTypesLEBE().build()
|
||
|
assert False
|
||
|
except LEBitFieldSequenceException:
|
||
|
pass
|
||
|
|
||
|
|
||
|
class MixedBitFieldTypesBELE(Packet):
|
||
|
|
||
|
fields_desc = [
|
||
|
BitField('b', 0, 4),
|
||
|
LEBitField('a', 0, 12),
|
||
|
]
|
||
|
|
||
|
try:
|
||
|
frm = MixedBitFieldTypesBELE().build()
|
||
|
assert False
|
||
|
except LEBitFieldSequenceException:
|
||
|
pass
|
||
|
|
||
|
################################################
|
||
|
+ EtherCat header layer handling
|
||
|
= EtherCat and padding
|
||
|
|
||
|
frm = Ether() / EtherCat()
|
||
|
# even with padding the length must be zero
|
||
|
# the Ether(do_build()) forces the calculation of all (post_build generated) fields
|
||
|
frm = Ether(frm.do_build())
|
||
|
assert(frm[EtherCat].length == 0)
|
||
|
assert(len(frm) == 60)
|
||
|
frm = Ether()/Dot1Q()/Dot1Q()/EtherCat()
|
||
|
frm = Ether()/EtherCat()
|
||
|
assert(len(frm) == 60)
|
||
|
frm = Ether(frm.do_build())
|
||
|
assert(frm[EtherCat].length == 0)
|
||
|
|
||
|
= EtherCat and RawPayload
|
||
|
|
||
|
frm=Ether()/EtherCat()/Raw(b'0123456789')
|
||
|
assert(len(frm) == 60)
|
||
|
frm = Ether(frm.do_build())
|
||
|
assert(frm[EtherCat].length == 10)
|
||
|
frm = Ether()/EtherCat()/Raw(b'012345678901234567890123456789012345678901234567890123456789')
|
||
|
frm = Ether(frm.do_build())
|
||
|
assert(len(frm) == 76)
|
||
|
assert(frm[EtherCat].length == 60)
|
||
|
|
||
|
= EtherCat - test invalid length detection
|
||
|
|
||
|
nums_11_bits = [random.randint(0, 65535) & 0b11111111111 for dummy in range(0, 23)]
|
||
|
nums_4_bits = [random.randint(0, 16) & 0b1111 for dummy in range(0, 23)]
|
||
|
|
||
|
frm = Ether()/EtherCat()/EtherCatAPRD(adp=0x1234, ado=0x5678, irq=0xbad0, wkc=0xbeef, data=[1]*2035, c=1)
|
||
|
frm = Ether(frm.do_build())
|
||
|
assert(frm[EtherCat].length == 2047)
|
||
|
assert(len(frm[EtherCatAPRD].data) == 2035)
|
||
|
assert(frm[EtherCatAPRD].c == 1)
|
||
|
|
||
|
data_oversized = False
|
||
|
try:
|
||
|
frm = Ether()/EtherCat()/EtherCatAPRD(adp=0x1234, ado=0x5678, irq=0xbad0, wkc=0xbeef, data=[2]*2048, c=1)
|
||
|
frm = Ether(frm.do_build())
|
||
|
except ValueError as err:
|
||
|
data_oversized = True
|
||
|
assert('data size' in str(err))
|
||
|
|
||
|
assert(data_oversized == True)
|
||
|
dlpdu_oversized = False
|
||
|
try:
|
||
|
frm = Ether()/EtherCat()/EtherCatAPRD(adp=0x1234, ado=0x5678, irq=0xbad0, wkc=0xbeef, data=[2]*2036, c=1)
|
||
|
frm = Ether(frm.do_build())
|
||
|
except ValueError as err:
|
||
|
dlpdu_oversized = True
|
||
|
assert('EtherCat message' in str(err))
|
||
|
|
||
|
assert(dlpdu_oversized == True)
|
||
|
|
||
|
frm = Ether()/EtherCat(_reserved=1)/EtherCatAPRD(adp=0x1234, ado=0x5678, irq=0xbad0, wkc=0xbeef, data=[3], c=0)
|
||
|
frm = Ether(frm.do_build())
|
||
|
assert(frm[EtherCatAPRD].c == 0)
|
||
|
|
||
|
|
||
|
assert(frm[EtherCat]._reserved == 0)
|
||
|
|
||
|
= EtherCat and Type12 DLPDU layers
|
||
|
|
||
|
for type_id in EtherCat.ETHERCAT_TYPE12_DLPDU_TYPES:
|
||
|
data = [random.randint(0, 255) for dummy in range(random.randint(1, 10))]
|
||
|
frm = Ether() / EtherCat() / EtherCat.ETHERCAT_TYPE12_DLPDU_TYPES[type_id](data= data)
|
||
|
frm = Ether(frm.do_build())
|
||
|
# expect to have one layer of current Type12 DLPDU type
|
||
|
dlpdu_lyr = frm[EtherCat.ETHERCAT_TYPE12_DLPDU_TYPES[type_id]]
|
||
|
assert(dlpdu_lyr.data == data)
|
||
|
|
||
|
= EtherCat and Type12 DLPDU layer using structure used for physical and broadcast addressing
|
||
|
|
||
|
# the code is the same for all layer sharing this structure - no need to test em all
|
||
|
test_data = [121,99,110,104,114,109,58,41]
|
||
|
frm = Ether()/EtherCat()/EtherCatAPRD(adp=0x1234, ado=0x5678, irq=0xbad0, wkc=0xbeef, data=test_data)
|
||
|
frm = Ether(frm.do_build())
|
||
|
aprd_lyr = frm[EtherCatAPRD]
|
||
|
assert(aprd_lyr.adp == 0x1234)
|
||
|
assert(aprd_lyr.ado == 0x5678)
|
||
|
assert(aprd_lyr.irq == 0xbad0)
|
||
|
assert(aprd_lyr.wkc == 0xbeef)
|
||
|
assert(aprd_lyr.data == test_data)
|
||
|
|
||
|
= EtherCat and Type12 DLPDU layer using structure used for logical addressing
|
||
|
|
||
|
test_data = [116,104,101,116,97,111,105,115,103,114,101,97,116]
|
||
|
frm = Ether() / EtherCat() / EtherCatLRD(adr=0x11223344, irq=0xbad0, wkc=0xbeef, data=test_data)
|
||
|
frm = Ether(frm.do_build())
|
||
|
aprd_lyr = frm[EtherCatLRD]
|
||
|
assert (aprd_lyr.adr == 0x11223344)
|
||
|
assert (aprd_lyr.irq == 0xbad0)
|
||
|
assert (aprd_lyr.wkc == 0xbeef)
|
||
|
assert (aprd_lyr.data == test_data)
|
||
|
|
||
|
= EtherCat and randomly stacked Type12 DLPDU layers
|
||
|
|
||
|
for outer_dummy in range(10):
|
||
|
frm = Ether()/EtherCat()
|
||
|
layer_ids = []
|
||
|
for inner_dummy in range(random.randint(1, 20)):
|
||
|
layer_id = random.choice(list(EtherCat.ETHERCAT_TYPE12_DLPDU_TYPES))
|
||
|
layer_ids.append(layer_id)
|
||
|
frm = frm / EtherCat.ETHERCAT_TYPE12_DLPDU_TYPES[layer_id]()
|
||
|
# build frame and convert back
|
||
|
frm = Ether(frm.do_build())
|
||
|
idx = 0
|
||
|
for layer_id in layer_ids:
|
||
|
assert(type(EtherCat.ETHERCAT_TYPE12_DLPDU_TYPES[layer_id]()) == type(frm[2 + idx]))
|
||
|
idx += 1
|