esp32_bluetooth_classic_sni.../libs/scapy/contrib/mac_control.py
Matheus Eduardo Garbelini 86890704fd initial commit
todo: add documentation & wireshark dissector
2021-08-31 19:51:03 +08:00

251 lines
7.8 KiB
Python
Executable file

# scapy.contrib.description = MACControl
# scapy.contrib.status = loads
"""
MACControl
~~~~~~~~~~
:author: Thomas Tannhaeuser, hecke@naberius.de
:license: GPLv2
This module is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This module is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
:description:
This module provides Scapy layers for the MACControl protocol messages:
- Pause
- Gate
- Report
- Register/REQ/ACK
- Class Based Flow Control
normative references:
- IEEE 802.3x
:NOTES:
- this is based on the MACControl dissector used by Wireshark
(https://github.com/wireshark/wireshark/blob/master/epan/dissectors/packet-maccontrol.c)
"""
from scapy.compat import orb
from scapy.data import ETHER_TYPES
from scapy.error import Scapy_Exception
from scapy.fields import IntField, ByteField, ByteEnumField, ShortField, BitField # noqa: E501
from scapy.layers.dot11 import Packet
from scapy.layers.l2 import Ether, Dot1Q, bind_layers
MAC_CONTROL_ETHER_TYPE = 0x8808
ETHER_TYPES['MAC_CONTROL'] = MAC_CONTROL_ETHER_TYPE
ETHER_SPEED_MBIT_10 = 0x01
ETHER_SPEED_MBIT_100 = 0x02
ETHER_SPEED_MBIT_1000 = 0x04
class MACControl(Packet):
DEFAULT_DST_MAC = "01:80:c2:00:00:01"
OP_CODE_PAUSE = 0x0001
OP_CODE_GATE = 0x0002
OP_CODE_REPORT = 0x0003
OP_CODE_REGISTER_REQ = 0x0004
OP_CODE_REGISTER = 0x0005
OP_CODE_REGISTER_ACK = 0x0006
OP_CODE_CLASS_BASED_FLOW_CONTROL = 0x0101
OP_CODES = {
OP_CODE_PAUSE: 'pause',
OP_CODE_GATE: 'gate',
OP_CODE_REPORT: 'report',
OP_CODE_REGISTER_REQ: 'register req',
OP_CODE_REGISTER: 'register',
OP_CODE_REGISTER_ACK: 'register_ack',
OP_CODE_CLASS_BASED_FLOW_CONTROL: 'class based flow control'
}
'''
flags used by Register* messages
'''
FLAG_REGISTER = 0x01
FLAG_DEREGISTER = 0x02
FLAG_ACK = 0x03
FLAG_NACK = 0x04
REGISTER_FLAGS = {
FLAG_REGISTER: 'register',
FLAG_DEREGISTER: 'deregister',
FLAG_ACK: 'ack',
FLAG_NACK: 'nack'
}
def guess_payload_class(self, payload):
try:
op_code = (orb(payload[0]) << 8) + orb(payload[1])
return MAC_CTRL_CLASSES[op_code]
except KeyError:
pass
return Packet.guess_payload_class(self, payload)
def _get_underlayers_size(self):
"""
get the total size of all under layers
:return: number of bytes
"""
under_layer = self.underlayer
under_layers_size = 0
while under_layer and isinstance(under_layer, Dot1Q):
under_layers_size += 4
under_layer = under_layer.underlayer
if under_layer and isinstance(under_layer, Ether):
# ether header len + FCS len
under_layers_size += 14 + 4
return under_layers_size
def post_build(self, pkt, pay):
"""
add padding to the frame if required.
note that padding is only added if pay is None/empty. this allows us to add # noqa: E501
any payload after the MACControl* PDU if needed (piggybacking).
"""
if not pay:
under_layers_size = self._get_underlayers_size()
frame_size = (len(pkt) + under_layers_size)
if frame_size < 64:
return pkt + b'\x00' * (64 - frame_size)
return pkt + pay
class MACControlInvalidSpeedException(Scapy_Exception):
pass
class MACControlPause(MACControl):
fields_desc = [
ShortField("_op_code", MACControl.OP_CODE_PAUSE),
ShortField("pause_time", 0),
]
def get_pause_time(self, speed=ETHER_SPEED_MBIT_1000):
"""
get pause time for given link speed in seconds
:param speed: select link speed to get the pause time for, must be ETHER_SPEED_MBIT_[10,100,1000] # noqa: E501
:return: pause time in seconds
:raises MACControlInvalidSpeedException: on invalid speed selector
"""
try:
return self.pause_time * {
ETHER_SPEED_MBIT_10: (0.0000001 * 512),
ETHER_SPEED_MBIT_100: (0.00000001 * 512),
ETHER_SPEED_MBIT_1000: (0.000000001 * 512 * 2)
}[speed]
except KeyError:
raise MACControlInvalidSpeedException('Invalid speed selector given. ' # noqa: E501
'Must be one of ETHER_SPEED_MBIT_[10,100,1000]') # noqa: E501
class MACControlGate(MACControl):
fields_desc = [
ShortField("_op_code", MACControl.OP_CODE_GATE),
IntField("timestamp", 0)
]
class MACControlReport(MACControl):
fields_desc = [
ShortField("_op_code", MACControl.OP_CODE_REPORT),
IntField("timestamp", 0),
ByteEnumField('flags', 0, MACControl.REGISTER_FLAGS),
ByteField('pending_grants', 0)
]
class MACControlRegisterReq(MACControl):
fields_desc = [
ShortField("_op_code", MACControl.OP_CODE_REGISTER_REQ),
IntField("timestamp", 0),
ShortField('assigned_port', 0),
ByteEnumField('flags', 0, MACControl.REGISTER_FLAGS),
ShortField('sync_time', 0),
ByteField('echoed_pending_grants', 0)
]
class MACControlRegister(MACControl):
fields_desc = [
ShortField("_op_code", MACControl.OP_CODE_REGISTER),
IntField("timestamp", 0),
ByteEnumField('flags', 0, MACControl.REGISTER_FLAGS),
ShortField('echoed_assigned_port', 0),
ShortField('echoed_sync_time', 0)
]
class MACControlRegisterAck(MACControl):
fields_desc = [
ShortField("_op_code", MACControl.OP_CODE_REGISTER_ACK),
IntField("timestamp", 0),
ByteEnumField('flags', 0, MACControl.REGISTER_FLAGS),
ShortField('echoed_assigned_port', 0),
ShortField('echoed_sync_time', 0)
]
class MACControlClassBasedFlowControl(MACControl):
fields_desc = [
ShortField("_op_code", MACControl.OP_CODE_CLASS_BASED_FLOW_CONTROL),
ByteField("_reserved", 0),
BitField('c7_enabled', 0, 1),
BitField('c6_enabled', 0, 1),
BitField('c5_enabled', 0, 1),
BitField('c4_enabled', 0, 1),
BitField('c3_enabled', 0, 1),
BitField('c2_enabled', 0, 1),
BitField('c1_enabled', 0, 1),
BitField('c0_enabled', 0, 1),
ShortField('c0_pause_time', 0),
ShortField('c1_pause_time', 0),
ShortField('c2_pause_time', 0),
ShortField('c3_pause_time', 0),
ShortField('c4_pause_time', 0),
ShortField('c5_pause_time', 0),
ShortField('c6_pause_time', 0),
ShortField('c7_pause_time', 0)
]
MAC_CTRL_CLASSES = {
MACControl.OP_CODE_PAUSE: MACControlPause,
MACControl.OP_CODE_GATE: MACControlGate,
MACControl.OP_CODE_REPORT: MACControlReport,
MACControl.OP_CODE_REGISTER_REQ: MACControlRegisterReq,
MACControl.OP_CODE_REGISTER: MACControlRegister,
MACControl.OP_CODE_REGISTER_ACK: MACControlRegisterAck,
MACControl.OP_CODE_CLASS_BASED_FLOW_CONTROL: MACControlClassBasedFlowControl # noqa: E501
}
bind_layers(Ether, MACControl, type=MAC_CONTROL_ETHER_TYPE)
bind_layers(Dot1Q, MACControl, type=MAC_CONTROL_ETHER_TYPE)