blob: b911831b7172631cd66422c0db6db2ba441872c7 [file] [log] [blame]
# -*- coding: utf-8 -*-
from __future__ import print_function
from __future__ import absolute_import
import struct
from . import dpkt
from . import stp
class LLC(dpkt.Packet):
"""802.2 Logical Link Control (LLC) data communication protocol.
Attributes:
__hdr__ = (
('dsap', 'B', 0xaa), # Destination Service Access Point
('ssap', 'B', 0xaa), # Source Service Access Point
('ctl', 'B', 3) # Control Byte
)
"""
__hdr__ = (
('dsap', 'B', 0xaa), # Destination Service Access Point
('ssap', 'B', 0xaa), # Source Service Access Point
('ctl', 'B', 3) # Control Byte
)
@property
def is_snap(self):
return self.dsap == self.ssap == 0xaa
def unpack(self, buf):
from .ethernet import Ethernet, ETH_TYPE_IP, ETH_TYPE_IPX
dpkt.Packet.unpack(self, buf)
if self.is_snap:
self.oui, self.type = struct.unpack('>IH', b'\x00' + self.data[:5])
self.data = self.data[5:]
try:
self.data = Ethernet.get_type(self.type)(self.data)
setattr(self, self.data.__class__.__name__.lower(), self.data)
except (KeyError, dpkt.UnpackError):
pass
else:
# non-SNAP
if self.dsap == 0x06: # SAP_IP
self.data = self.ip = Ethernet.get_type(ETH_TYPE_IP)(self.data)
elif self.dsap == 0x10 or self.dsap == 0xe0: # SAP_NETWARE{1,2}
self.data = self.ipx = Ethernet.get_type(ETH_TYPE_IPX)(self.data)
elif self.dsap == 0x42: # SAP_STP
self.data = self.stp = stp.STP(self.data)
def pack_hdr(self):
buf = dpkt.Packet.pack_hdr(self)
if self.is_snap: # add SNAP sublayer
oui = getattr(self, 'oui', 0)
_type = getattr(self, 'type', 0)
if not _type and isinstance(self.data, dpkt.Packet):
from .ethernet import Ethernet
try:
_type = Ethernet.get_type_rev(self.data.__class__)
except KeyError:
pass
buf += struct.pack('>IH', oui, _type)[1:]
return buf
def __len__(self): # add 5 bytes of SNAP header if needed
return self.__hdr_len__ + 5 * int(self.is_snap) + len(self.data)
def test_llc():
from . import ip
from . import ethernet
s = (b'\xaa\xaa\x03\x00\x00\x00\x08\x00\x45\x00\x00\x28\x07\x27\x40\x00\x80\x06\x1d'
b'\x39\x8d\xd4\x37\x3d\x3f\xf5\xd1\x69\xc0\x5f\x01\xbb\xb2\xd6\xef\x23\x38\x2b'
b'\x4f\x08\x50\x10\x42\x04\xac\x17\x00\x00')
llc_pkt = LLC(s)
ip_pkt = llc_pkt.data
assert isinstance(ip_pkt, ip.IP)
assert llc_pkt.type == ethernet.ETH_TYPE_IP
assert ip_pkt.dst == b'\x3f\xf5\xd1\x69'
assert str(llc_pkt) == str(s)
assert len(llc_pkt) == len(s)
# construction with SNAP header
llc_pkt = LLC(ssap=0xaa, dsap=0xaa, data=ip.IP(s[8:]))
assert str(llc_pkt) == str(s)
# no SNAP
llc_pkt = LLC(ssap=6, dsap=6, data=ip.IP(s[8:]))
assert isinstance(llc_pkt.data, ip.IP)
assert str(llc_pkt) == str(b'\x06\x06\x03' + s[8:])
def test_unpack_sap_ip():
from binascii import unhexlify
from . import ip
buf_llc = unhexlify(
'06' # dsap (SAP_IP)
'aa' # ssap
'03' # ctl
)
buf_ip = unhexlify(
'45' # _v_hl
'00' # tos
'0014' # len
'0000' # id
'0000' # off
'80' # ttl
'06' # p
'd47e' # sum
'11111111' # src
'22222222' # dst
)
buf = buf_llc + buf_ip
llc = LLC(buf)
assert isinstance(llc.data, ip.IP)
def test_unpack_exception_handling():
from binascii import unhexlify
buf_llc = unhexlify(
'aa' # dsap (SAP_IP)
'aa' # ssap
'03' # ctl
'111111' # oui
'2222' # type (not valid ethertype)
)
llc = LLC(buf_llc)
assert not isinstance(llc.data, dpkt.Packet)
def test_pack_hdr_invalid_class():
from binascii import unhexlify
class InvalidClass(dpkt.Packet):
__hdr__ = (('test', 'B', 0x22),)
llc = LLC(dsap=0xaa, ssap=0xaa, ctl=3, oui=0x111111, data=InvalidClass())
correct = unhexlify(
'aa' # dsap
'aa' # ssap
'03' # ctl
'111111' # oui
'0000' # type
'22' # data in test class header
)
assert bytes(llc) == correct