Skip to content

Commit 71ac357

Browse files
speakinghedgeguedou
authored andcommitted
Fix lldp org specific dissection clean #1151 (#1154)
* add a 3 byte enum field #1151 required to show the names of the organizations used in LLDP org specific TLVs * add generic organization specific LLDP type #1151 implements generic encoding of org specific TLVs and dumps the payload as hex-string * sanitize guess_payload for LLDPDUs #1151 * cleanup guess_payload_class() #1151 * keep ThreeBytesEnumField local in lldp #1151 as it is not used yet anywhere else. * use raw layer given by conf #1151 * remove unused imports #1151
1 parent 865300d commit 71ac357

3 files changed

Lines changed: 86 additions & 9 deletions

File tree

scapy/contrib/lldp.py

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
- IEEE 802.1AB 2016 - LLDP protocol, topology and MIB description
2929
3030
:TODO:
31-
- organization specific TLV e.g. ProfiNet
31+
- organization specific TLV e.g. ProfiNet (see LLDPDUGenericOrganisationSpecific for a starting point)
3232
3333
:NOTES:
3434
- you can find the layer configuration options at the end of this file
@@ -45,11 +45,11 @@
4545
from scapy.layers.dot11 import Packet
4646
from scapy.layers.l2 import Ether, Dot1Q, bind_layers, \
4747
BitField, StrLenField, ByteEnumField, BitEnumField, \
48-
BitFieldLenField, ShortField, Padding, Scapy_Exception, \
49-
XStrLenField
48+
BitFieldLenField, ShortField, Scapy_Exception, \
49+
XStrLenField, ByteField, EnumField, ThreeBytesField
5050
from scapy.modules.six.moves import range
5151
from scapy.data import ETHER_TYPES
52-
from scapy.compat import orb, raw
52+
from scapy.compat import orb
5353

5454
LLDP_NEAREST_BRIDGE_MAC = '01:80:c2:00:00:0e'
5555
LLDP_NEAREST_NON_TPMR_BRIDGE_MAC = '01:80:c2:00:00:03'
@@ -123,8 +123,11 @@ class LLDPDU(Packet):
123123

124124
def guess_payload_class(self, payload):
125125
# type is a 7-bit bitfield spanning bits 1..7 -> div 2
126-
lldpdu_tlv_type = orb(payload[0]) // 2
127-
return LLDPDU_CLASS_TYPES[lldpdu_tlv_type]
126+
try:
127+
lldpdu_tlv_type = orb(payload[0]) // 2
128+
return LLDPDU_CLASS_TYPES.get(lldpdu_tlv_type, conf.raw_layer)
129+
except IndexError:
130+
return conf.raw_layer
128131

129132
@staticmethod
130133
def _dot1q_headers_size(layer):
@@ -664,6 +667,38 @@ def do_build(self):
664667
self._check()
665668
return super(LLDPDUManagementAddress, self).do_build()
666669

670+
671+
class ThreeBytesEnumField(EnumField, ThreeBytesField):
672+
673+
def __init__(self, name, default, enum):
674+
EnumField.__init__(self, name, default, enum, "!I")
675+
676+
677+
class LLDPDUGenericOrganisationSpecific(LLDPDU):
678+
679+
ORG_UNIQUE_CODE_PNO = 0x000ecf
680+
ORG_UNIQUE_CODE_IEEE_802_1 = 0x0080c2
681+
ORG_UNIQUE_CODE_IEEE_802_3 = 0x00120f
682+
ORG_UNIQUE_CODE_TIA_TR_41_MED = 0x0012bb
683+
ORG_UNIQUE_CODE_HYTEC = 0x30b216
684+
685+
ORG_UNIQUE_CODES = {
686+
ORG_UNIQUE_CODE_PNO: "PROFIBUS International (PNO)",
687+
ORG_UNIQUE_CODE_IEEE_802_1: "IEEE 802.1",
688+
ORG_UNIQUE_CODE_IEEE_802_3: "IEEE 802.3",
689+
ORG_UNIQUE_CODE_TIA_TR_41_MED: "TIA TR-41 Committee . Media Endpoint Discovery",
690+
ORG_UNIQUE_CODE_HYTEC: "Hytec Geraetebau GmbH"
691+
}
692+
693+
fields_desc = [
694+
BitEnumField('_type', 127, 7, LLDPDU.TYPES),
695+
BitFieldLenField('_length', None, 9, length_of='data', adjust=lambda pkt, x: len(pkt.data) + 4),
696+
ThreeBytesEnumField('org_code', 0, ORG_UNIQUE_CODES),
697+
ByteField('subtype', 0x00),
698+
XStrLenField('data', '', length_from=lambda pkt: pkt._length - 4)
699+
]
700+
701+
# 0x09 .. 0x7e is reserved for future standardization and for now treated as Raw() data
667702
LLDPDU_CLASS_TYPES = {
668703
0x00: LLDPDUEndOfLLDPDU,
669704
0x01: LLDPDUChassisID,
@@ -674,8 +709,7 @@ def do_build(self):
674709
0x06: LLDPDUSystemDescription,
675710
0x07: LLDPDUSystemCapabilities,
676711
0x08: LLDPDUManagementAddress,
677-
range(0x09, 0x7e): None, # reserved - future standardization
678-
127: None # organisation specific TLV
712+
127: LLDPDUGenericOrganisationSpecific
679713
}
680714

681715
class LLDPConfiguration(object):

scapy/contrib/lldp.uts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,47 @@ assert frm[LLDPDUSystemName].system_name == b'things will'
228228
assert frm[LLDPDUManagementAddress].object_id == b'burn'
229229
assert frm[LLDPDUSystemDescription].description == b'without tests.'
230230
assert frm[LLDPDUPortDescription].description == b'always!'
231+
232+
+ organisation specific layers
233+
234+
= ThreeBytesEnumField tests
235+
236+
three_b_enum_field = ThreeBytesEnumField('test', 0x00,
237+
{
238+
0x0e: 'fourteen',
239+
0x00: 'zero',
240+
0x5566: 'five-six',
241+
0x0e0000: 'fourteen-zero-zero',
242+
0x0e0100: 'fourteen-one-zero',
243+
0x112233: '1#2#3'
244+
})
245+
246+
assert(three_b_enum_field.i2repr(None, 0) == 'zero')
247+
assert(three_b_enum_field.i2repr(None, 0x0e) == 'fourteen')
248+
assert(three_b_enum_field.i2repr(None, 0x5566) == 'five-six')
249+
assert(three_b_enum_field.i2repr(None, 0x112233) == '1#2#3')
250+
assert(three_b_enum_field.i2repr(None, 0x0e0000) == 'fourteen-zero-zero')
251+
assert(three_b_enum_field.i2repr(None, 0x0e0100) == 'fourteen-one-zero')
252+
assert(three_b_enum_field.i2repr(None, 0x01) == '1')
253+
assert(three_b_enum_field.i2repr(None, 0x49763) == '300899')
254+
255+
= LLDPDUGenericOrganisationSpecific tests
256+
257+
frm = Ether(src='01:01:01:01:01:01', dst=LLDP_NEAREST_BRIDGE_MAC)/\
258+
LLDPDUChassisID(subtype=LLDPDUChassisID.SUBTYPE_MAC_ADDRESS, id=b'\x06\x05\x04\x03\x02\x01')/\
259+
LLDPDUPortID(subtype=LLDPDUPortID.SUBTYPE_MAC_ADDRESS, id=b'\x01\x02\x03\x04\x05\x06')/\
260+
LLDPDUTimeToLive()/\
261+
LLDPDUGenericOrganisationSpecific(org_code=LLDPDUGenericOrganisationSpecific.ORG_UNIQUE_CODE_PNO,
262+
subtype=0x42,
263+
data=b'FooBar'*5
264+
)/\
265+
LLDPDUEndOfLLDPDU()
266+
267+
frm = frm.build()
268+
frm = Ether(frm)
269+
org_spec_layer = frm[LLDPDUGenericOrganisationSpecific]
270+
assert(org_spec_layer)
271+
assert(org_spec_layer._type == 127)
272+
assert(org_spec_layer.org_code == LLDPDUGenericOrganisationSpecific.ORG_UNIQUE_CODE_PNO)
273+
assert(org_spec_layer.subtype == 0x42)
274+
assert(org_spec_layer._length == 34)

scapy/fields.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1157,7 +1157,6 @@ def i2repr_one(self, pkt, x):
11571157
return ret
11581158
return lhex(x)
11591159

1160-
11611160
class _MultiEnumField(_EnumField):
11621161
def __init__(self, name, default, enum, depends_on, fmt = "H"):
11631162

0 commit comments

Comments
 (0)