os-ken/os_ken/lib/packet/llc.py

323 lines
10 KiB
Python

# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Logical Link Control(LLC, IEEE 802.2) parser/serializer
http://standards.ieee.org/getieee802/download/802.2-1998.pdf
LLC format::
+-----------------+--------------+
| DSAP address | 8 bits |
+-----------------+--------------+
| SSAP address | 8 bits |
+-----------------+--------------+
| Control | 8 or 16 bits |
+-----------------+--------------+
DSAP address field::
LSB
+-----+---+---+---+---+---+---+---+
| I/G | D | D | D | D | D | D | D |
+-----+---+---+---+---+---+---+---+
I/G bit = 0 : Individual DSAP
I/G bit = 1 : Group DSA
D : DSAP address
SSAP address field::
LSB
+-----+---+---+---+---+---+---+---+
| C/R | S | S | S | S | S | S | S |
+-----+---+---+---+---+---+---+---+
C/R bit = 0 : Command
C/R bit = 1 : Response
S : SSAP address
Control field:
Information transfer
command/response
(I-format PDU)::
1 2 3 4 5 6 7 8 9 10-16
+---+---+---+---+---+---+---+---+-----+------+
| 0 | N(S) | P/F | N(R) |
+---+---+---+---+---+---+---+---+-----+------+
Supervisory
commands/responses
(S-format PDUs)::
1 2 3 4 5 6 7 8 9 10-16
+---+---+---+---+---+---+---+---+-----+------+
| 1 0 | S S | 0 0 0 0 | P/F | N(R) |
+---+---+---+---+---+---+---+---+-----+------+
Unnumbered
commands/responses
(U-format PDUs)::
1 2 3 4 5 6 7 8
+---+---+----+---+-----+---+----+---+
| 1 1 | M1 M1 | P/F | M2 M2 M2 |
+---+---+----+---+-----+---+----+---+
N(S) : sender send sequence number (Bit 2=lower-order-bit)
N(R) : sender receive sequence number (Bit 10=lower-order-bit)
S : supervisory function bit
M1/M2: modifier function bit
P/F : poll bit - command LLC PDUs
final bit - response LLC PDUs
"""
import struct
from . import bpdu
from . import packet_base
from os_ken.lib import stringify
SAP_BPDU = 0x42
class llc(packet_base.PacketBase):
"""LLC(IEEE 802.2) header encoder/decoder class.
An instance has the following attributes at least.
Most of them are same to the on-wire counterparts but in host byte
order.
__init__ takes the corresponding args in this order.
.. tabularcolumns:: |l|L|
=============== ===============================================
Attribute Description
=============== ===============================================
dsap_addr Destination service access point address field \
includes I/G bit at least significant bit.
ssap_addr Source service access point address field \
includes C/R bit at least significant bit.
control Control field \
[16 bits for formats that include sequence \
numbering, and 8 bits for formats that do not]. \
Either os_ken.lib.packet.llc.ControlFormatI or \
os_ken.lib.packet.llc.ControlFormatS or \
os_ken.lib.packet.llc.ControlFormatU object.
=============== ===============================================
"""
_PACK_STR = '!BB'
_PACK_LEN = struct.calcsize(_PACK_STR)
_CTR_TYPES = {}
_CTR_PACK_STR = '!2xB'
_MIN_LEN = _PACK_LEN
@staticmethod
def register_control_type(register_cls):
llc._CTR_TYPES[register_cls.TYPE] = register_cls
return register_cls
def __init__(self, dsap_addr, ssap_addr, control):
super(llc, self).__init__()
assert getattr(control, 'TYPE', None) in self._CTR_TYPES
self.dsap_addr = dsap_addr
self.ssap_addr = ssap_addr
self.control = control
@classmethod
def parser(cls, buf):
assert len(buf) >= cls._PACK_LEN
(dsap_addr, ssap_addr) = struct.unpack_from(cls._PACK_STR, buf)
(control,) = struct.unpack_from(cls._CTR_PACK_STR, buf)
ctrl = cls._get_control(control)
control, information = ctrl.parser(buf[cls._PACK_LEN:])
return (cls(dsap_addr, ssap_addr, control),
cls.get_packet_type(dsap_addr), information)
def serialize(self, payload, prev):
addr = struct.pack(self._PACK_STR, self.dsap_addr, self.ssap_addr)
control = self.control.serialize()
return addr + control
@classmethod
def _get_control(cls, buf):
key = buf & 0b1 if buf & 0b1 == ControlFormatI.TYPE else buf & 0b11
return cls._CTR_TYPES[key]
@llc.register_control_type
class ControlFormatI(stringify.StringifyMixin):
"""LLC sub encoder/decoder class for control I-format field.
An instance has the following attributes at least.
Most of them are same to the on-wire counterparts but in host byte
order.
__init__ takes the corresponding args in this order.
======================== ===============================
Attribute Description
======================== ===============================
send_sequence_number sender send sequence number
pf_bit poll/final bit
receive_sequence_number sender receive sequence number
======================== ===============================
"""
TYPE = 0b0
_PACK_STR = '!H'
_PACK_LEN = struct.calcsize(_PACK_STR)
def __init__(self, send_sequence_number=0, pf_bit=0,
receive_sequence_number=0):
super(ControlFormatI, self).__init__()
self.send_sequence_number = send_sequence_number
self.pf_bit = pf_bit
self.receive_sequence_number = receive_sequence_number
@classmethod
def parser(cls, buf):
assert len(buf) >= cls._PACK_LEN
(control,) = struct.unpack_from(cls._PACK_STR, buf)
assert (control >> 8) & 0b1 == cls.TYPE
send_sequence_number = (control >> 9) & 0b1111111
pf_bit = (control >> 8) & 0b1
receive_sequence_number = (control >> 1) & 0b1111111
return cls(send_sequence_number, pf_bit,
receive_sequence_number), buf[cls._PACK_LEN:]
def serialize(self):
control = (self.send_sequence_number << 9 |
self.TYPE << 8 |
self.receive_sequence_number << 1 |
self.pf_bit)
return struct.pack(self._PACK_STR, control)
@llc.register_control_type
class ControlFormatS(stringify.StringifyMixin):
"""LLC sub encoder/decoder class for control S-format field.
An instance has the following attributes at least.
Most of them are same to the on-wire counterparts but in host byte
order.
__init__ takes the corresponding args in this order.
======================== ===============================
Attribute Description
======================== ===============================
supervisory_function supervisory function bit
pf_bit poll/final bit
receive_sequence_number sender receive sequence number
======================== ===============================
"""
TYPE = 0b01
_PACK_STR = '!H'
_PACK_LEN = struct.calcsize(_PACK_STR)
def __init__(self, supervisory_function=0, pf_bit=0,
receive_sequence_number=0):
super(ControlFormatS, self).__init__()
self.supervisory_function = supervisory_function
self.pf_bit = pf_bit
self.receive_sequence_number = receive_sequence_number
@classmethod
def parser(cls, buf):
assert len(buf) >= cls._PACK_LEN
(control,) = struct.unpack_from(cls._PACK_STR, buf)
assert (control >> 8) & 0b11 == cls.TYPE
supervisory_function = (control >> 10) & 0b11
pf_bit = (control >> 8) & 0b1
receive_sequence_number = (control >> 1) & 0b1111111
return cls(supervisory_function, pf_bit,
receive_sequence_number), buf[cls._PACK_LEN:]
def serialize(self):
control = (self.supervisory_function << 10 |
self.TYPE << 8 |
self.receive_sequence_number << 1 |
self.pf_bit)
return struct.pack(self._PACK_STR, control)
@llc.register_control_type
class ControlFormatU(stringify.StringifyMixin):
"""LLC sub encoder/decoder class for control U-format field.
An instance has the following attributes at least.
Most of them are same to the on-wire counterparts but in host byte
order.
__init__ takes the corresponding args in this order.
======================== ===============================
Attribute Description
======================== ===============================
modifier_function1 modifier function bit
pf_bit poll/final bit
modifier_function2 modifier function bit
======================== ===============================
"""
TYPE = 0b11
_PACK_STR = '!B'
_PACK_LEN = struct.calcsize(_PACK_STR)
def __init__(self, modifier_function1=0, pf_bit=0, modifier_function2=0):
super(ControlFormatU, self).__init__()
self.modifier_function1 = modifier_function1
self.pf_bit = pf_bit
self.modifier_function2 = modifier_function2
@classmethod
def parser(cls, buf):
assert len(buf) >= cls._PACK_LEN
(control,) = struct.unpack_from(cls._PACK_STR, buf)
assert control & 0b11 == cls.TYPE
modifier_function1 = (control >> 2) & 0b11
pf_bit = (control >> 4) & 0b1
modifier_function2 = (control >> 5) & 0b111
return cls(modifier_function1, pf_bit,
modifier_function2), buf[cls._PACK_LEN:]
def serialize(self):
control = (self.modifier_function2 << 5 |
self.pf_bit << 4 |
self.modifier_function1 << 2 |
self.TYPE)
return struct.pack(self._PACK_STR, control)
llc.register_packet_type(bpdu.bpdu, SAP_BPDU)
llc.set_classes(llc._CTR_TYPES)