4242
4343"""
4444from scapy .config import conf
45- from scapy .layers .dot11 import Packet
46- from scapy .layers .l2 import Ether , Dot1Q , bind_layers , \
47- BitField , StrLenField , ByteEnumField , BitEnumField , \
48- BitFieldLenField , ShortField , Scapy_Exception , \
49- XStrLenField , ByteField , EnumField , ThreeBytesField
45+ from scapy .error import log_runtime , Scapy_Exception
46+ from scapy .layers .l2 import Ether , Dot1Q
47+ from scapy .fields import MACField , IPField , BitField , \
48+ StrLenField , ByteEnumField , BitEnumField , \
49+ EnumField , ThreeBytesField , BitFieldLenField , \
50+ ShortField , XStrLenField
51+ from scapy .packet import Packet , Padding , bind_layers
5052from scapy .modules .six .moves import range
5153from scapy .data import ETHER_TYPES
5254from scapy .compat import orb
@@ -282,6 +284,48 @@ def dissection_done(self, pkt):
282284
283285 super (LLDPDU , self ).dissection_done (pkt )
284286
287+ def _check (self ):
288+ """Overwrited by LLDPU objects"""
289+ pass
290+
291+ def post_dissect (self , s ):
292+ self ._check ()
293+ return super (LLDPDU , self ).post_dissect (s )
294+
295+ def do_build (self ):
296+ self ._check ()
297+ return super (LLDPDU , self ).do_build ()
298+
299+ class _LLDPidField (StrLenField ):
300+ """Class that selects the type of the ID field depending
301+ on the type of `subtype`"""
302+ __slots__ = StrLenField .__slots__ + ["subtypes_dict" ]
303+
304+ def __init__ (self , name , default , subtypes_dict , * args , ** kargs ):
305+ self .subtypes_dict = subtypes_dict
306+ super (_LLDPidField , self ).__init__ (name , default , * args , ** kargs )
307+
308+ def m2i (self , pkt , x ):
309+ cls = self .subtypes_dict .get (pkt .subtype , StrLenField )
310+ try :
311+ return (cls .m2i .__func__ if six .PY2 else cls .m2i )(self , pkt , x )
312+ except :
313+ log_runtime .exception ("Failed to dissect " + self .name + " ! " )
314+ return StrLenField .m2i (self , pkt , x )
315+
316+ def i2m (self , pkt , x ):
317+ cls = self .subtypes_dict .get (pkt .subtype , StrLenField )
318+ try :
319+ return (cls .i2m .__func__ if six .PY2 else cls .i2m )(self , pkt , x )
320+ except :
321+ log_runtime .exception ("Failed to build " + self .name + " ! " )
322+ return StrLenField .i2m (self , pkt , x )
323+
324+ def _ldp_id_adjustlen (pkt , x ):
325+ """Return the length of the `id` field,
326+ according to its real encoded type"""
327+ f , v = pkt .getfield_and_val ('id' )
328+ return len (_LLDPidField .i2m (f , pkt , v )) + 1
285329
286330class LLDPDUChassisID (LLDPDU ):
287331 """
@@ -299,6 +343,11 @@ class LLDPDUChassisID(LLDPDU):
299343 range (0x08 , 0xff ): 'reserved'
300344 }
301345
346+ LLDP_CHASSIS_ID_TLV_SUBTYPES_FIELDS = {
347+ 0x04 : MACField ,
348+ 0x05 : IPField ,
349+ }
350+
302351 SUBTYPE_RESERVED = 0x00
303352 SUBTYPE_CHASSIS_COMPONENT = 0x01
304353 SUBTYPE_INTERFACE_ALIAS = 0x02
@@ -311,9 +360,9 @@ class LLDPDUChassisID(LLDPDU):
311360 fields_desc = [
312361 BitEnumField ('_type' , 0x01 , 7 , LLDPDU .TYPES ),
313362 BitFieldLenField ('_length' , None , 9 , length_of = 'id' ,
314- adjust = lambda pkt , x : len (pkt . id ) + 1 ),
363+ adjust = lambda pkt , x : _ldp_id_adjustlen (pkt , x ) ),
315364 ByteEnumField ('subtype' , 0x00 , LLDP_CHASSIS_ID_TLV_SUBTYPES ),
316- XStrLenField ('id' , '' , length_from = lambda pkt : pkt ._length - 1 )
365+ _LLDPidField ('id' , '' , LLDP_CHASSIS_ID_TLV_SUBTYPES_FIELDS , length_from = lambda pkt : pkt ._length - 1 )
317366 ]
318367
319368 def _check (self ):
@@ -323,14 +372,6 @@ def _check(self):
323372 if conf .contribs ['LLDP' ].strict_mode () and not self .id :
324373 raise LLDPInvalidLengthField ('id must be >= 1 characters long' )
325374
326- def post_dissect (self , s ):
327- self ._check ()
328- return super (LLDPDUChassisID , self ).post_dissect (s )
329-
330- def do_build (self ):
331- self ._check ()
332- return super (LLDPDUChassisID , self ).do_build ()
333-
334375
335376class LLDPDUPortID (LLDPDU ):
336377 """
@@ -348,6 +389,11 @@ class LLDPDUPortID(LLDPDU):
348389 range (0x08 , 0xff ): 'reserved'
349390 }
350391
392+ LLDP_PORT_ID_TLV_SUBTYPES = {
393+ 0x03 : MACField ,
394+ 0x04 : IPField ,
395+ }
396+
351397 SUBTYPE_RESERVED = 0x00
352398 SUBTYPE_INTERFACE_ALIAS = 0x01
353399 SUBTYPE_PORT_COMPONENT = 0x02
@@ -360,9 +406,9 @@ class LLDPDUPortID(LLDPDU):
360406 fields_desc = [
361407 BitEnumField ('_type' , 0x02 , 7 , LLDPDU .TYPES ),
362408 BitFieldLenField ('_length' , None , 9 , length_of = 'id' ,
363- adjust = lambda pkt , x : len (pkt . id ) + 1 ),
409+ adjust = lambda pkt , x : _ldp_id_adjustlen (pkt , x ) ),
364410 ByteEnumField ('subtype' , 0x00 , LLDP_PORT_ID_TLV_SUBTYPES ),
365- StrLenField ('id' , '' , length_from = lambda pkt : pkt ._length - 1 )
411+ _LLDPidField ('id' , '' , LLDP_PORT_ID_TLV_SUBTYPES , length_from = lambda pkt : pkt ._length - 1 )
366412 ]
367413
368414 def _check (self ):
@@ -372,14 +418,6 @@ def _check(self):
372418 if conf .contribs ['LLDP' ].strict_mode () and not self .id :
373419 raise LLDPInvalidLengthField ('id must be >= 1 characters long' )
374420
375- def post_dissect (self , s ):
376- self ._check ()
377- return super (LLDPDUPortID , self ).post_dissect (s )
378-
379- def do_build (self ):
380- self ._check ()
381- return super (LLDPDUPortID , self ).do_build ()
382-
383421
384422class LLDPDUTimeToLive (LLDPDU ):
385423 """
@@ -399,15 +437,6 @@ def _check(self):
399437 raise LLDPInvalidLengthField ('length must be 2 - got '
400438 '{}' .format (self ._length ))
401439
402- def post_dissect (self , s ):
403- self ._check ()
404- return super (LLDPDUTimeToLive , self ).post_dissect (s )
405-
406- def do_build (self ):
407- self ._check ()
408- return super (LLDPDUTimeToLive , self ).do_build ()
409-
410-
411440class LLDPDUEndOfLLDPDU (LLDPDU ):
412441 """
413442 ieee 802.1ab-2016 - sec. 8.5.1 / p. 26
@@ -428,14 +457,6 @@ def _check(self):
428457 raise LLDPInvalidLengthField ('length must be 0 - got '
429458 '{}' .format (self ._length ))
430459
431- def post_dissect (self , s ):
432- self ._check ()
433- return super (LLDPDUEndOfLLDPDU , self ).post_dissect (s )
434-
435- def do_build (self ):
436- self ._check ()
437- return super (LLDPDUEndOfLLDPDU , self ).do_build ()
438-
439460
440461class LLDPDUPortDescription (LLDPDU ):
441462 """
@@ -519,14 +540,6 @@ def _check(self):
519540 raise LLDPInvalidLengthField ('length must be 4 - got '
520541 '{}' .format (self ._length ))
521542
522- def post_dissect (self , s ):
523- self ._check ()
524- return super (LLDPDUSystemCapabilities , self ).post_dissect (s )
525-
526- def do_build (self ):
527- self ._check ()
528- return super (LLDPDUSystemCapabilities , self ).do_build ()
529-
530543
531544class LLDPDUManagementAddress (LLDPDU ):
532545 """
@@ -659,14 +672,6 @@ def _check(self):
659672 'management address must be 1..31 characters long - '
660673 'got string of size {}' .format (management_address_len ))
661674
662- def post_dissect (self , s ):
663- self ._check ()
664- return super (LLDPDUManagementAddress , self ).post_dissect (s )
665-
666- def do_build (self ):
667- self ._check ()
668- return super (LLDPDUManagementAddress , self ).do_build ()
669-
670675
671676class ThreeBytesEnumField (EnumField , ThreeBytesField ):
672677
0 commit comments