Skip to content

Commit a8b5c0e

Browse files
committed
feat(link): add a FRAD dissector for Frame Relay over LinuxSLL (#2460)
Part of #2460's five arphrd_type follow-ups: LinuxSLL/LinuxSLL2 fell back to Raw for ARPHRD_FRAD, the narrowest of the five, since no Frame Relay dissector existed. - Add pcapkit.protocols.link.frad.FRAD, parsing the Q.922 address, control field and NLPID of RFC 2427's multiprotocol encapsulation (obsoleting RFC 1490), both the direct-NLPID and SNAP-encapsulated forms. - Wire LinuxSLL1/LinuxSLL2 to dispatch ARPHRD_FRAD to it instead of Raw. - Direct NLPID 0xCC/0x8E dispatch onward to IPv4/IPv6; a SNAP header with OUI 00-00-00 dispatches by its PID through the EtherType registry Ethernet/VLAN/LinuxSLL already share (reaching ARP, among others). Every other NLPID, and a SNAP header naming a bridged medium, stays Raw. - Add tests/protocols/link/test_frad_unit.py; move ARPHRD_FRAD out of the LinuxSLL "kept raw" sweep into its own dispatch test; add two FRAD cases to the short-read round-trip sweep. - Register FRAD in every export registry it was missing from: pcapkit, pcapkit.all, pcapkit.protocols, and the data/schema registries under pcapkit.protocols.{data,schema}[.link]. - Add NOT_A_COPY entries to the #1739 constant-sweep test for FRAD's bit offsets and field bounds that coincidentally match homed RFC constants. Build: mypy and pylint clean; FRAD, LinuxSLL, export-registry, #1739 sweep, and protocol-convention test suites all pass.
1 parent 57ff1c8 commit a8b5c0e

22 files changed

Lines changed: 987 additions & 14 deletions

‎CHANGELOG.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
Wave 2 of the roadmap, per the contributing docs' enhancement-proposal page: the protocol pairs that wanted a shared abstract base, and the two that simply had no dissector at all.
44

5+
- **Added** -- `FRAD`, a dissector for Frame Relay's multiprotocol encapsulation ([RFC 2427](https://datatracker.ietf.org/doc/html/rfc2427), obsoleting [RFC 1490](https://datatracker.ietf.org/doc/html/rfc1490)). `LinuxSLL`/ `LinuxSLL1`/ `LinuxSLL2` dispatch to it for the `ARPHRD_FRAD` case instead of falling back to `Raw`; the direct NLPID and SNAP-encapsulated forms both dispatch onward, to IPv4/IPv6 and (via the EtherType registry every Ethernet/VLAN/LinuxSLL frame shares) ARP among others. The first of [#2460](https://github.com/JarryShaw/PyPCAPKit/issues/2460)'s five `arphrd_type` follow-ups to get a dissector; the other four (`NETLINK`, `IPGRE`/`IP6GRE`, `IEEE80211_RADIOTAP`) remain `Raw`.
6+
57
---
68

79
Full changelog: <https://jarryshaw.github.io/PyPCAPKit/changelog.html>

‎docs/source/changelog/1.6.0.rst‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,16 @@
44
Wave 2 of the roadmap, per the contributing docs' enhancement-proposal page: the
55
protocol pairs that wanted a shared abstract base, and the two that simply had
66
no dissector at all.
7+
8+
* **Added** -- :class:`~pcapkit.protocols.link.frad.FRAD`, a dissector for Frame
9+
Relay's multiprotocol encapsulation (:rfc:`2427`, obsoleting :rfc:`1490`).
10+
:class:`~pcapkit.protocols.link.linux_sll.LinuxSLL`/
11+
:class:`~pcapkit.protocols.link.linux_sll1.LinuxSLL1`/
12+
:class:`~pcapkit.protocols.link.linux_sll2.LinuxSLL2` dispatch to it for the
13+
``ARPHRD_FRAD`` case instead of falling back to
14+
:class:`~pcapkit.protocols.misc.raw.Raw`; the direct NLPID and SNAP-encapsulated
15+
forms both dispatch onward, to IPv4/IPv6 and (via the EtherType registry every
16+
Ethernet/VLAN/LinuxSLL frame shares) ARP among others. The first of :issue:`2460`'s
17+
five ``arphrd_type`` follow-ups to get a dissector; the other four
18+
(``NETLINK``, ``IPGRE``/``IP6GRE``, ``IEEE80211_RADIOTAP``) remain
19+
:class:`~pcapkit.protocols.misc.raw.Raw`.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
FRAD - Frame Relay Access Device
2+
=================================
3+
4+
.. module:: pcapkit.protocols.link.frad
5+
6+
:mod:`pcapkit.protocols.link.frad` contains
7+
:class:`~pcapkit.protocols.link.frad.FRAD`
8+
only, which implements the extractor for Frame Relay's multiprotocol
9+
encapsulation [*]_, as seen on a ``LINKTYPE_LINUX_SLL``/``LINKTYPE_LINUX_SLL2``
10+
capture whose ``arphrd_type`` is ``ARPHRD_FRAD``. Its structure, the Q.922
11+
LAPF address onward with no trailing FCS, is described as below:
12+
13+
.. table::
14+
15+
====== ==== ================= ==========================================
16+
Octets Bits Name Description
17+
====== ==== ================= ==========================================
18+
0 0 ``frad.addr`` Q.922 Address (2-octet form)
19+
2 16 ``frad.control`` Control (``0x03``, UI, for data traffic)
20+
3 24 ``frad.nlpid`` NLPID, or the ``0x00`` pad ahead of a SNAP
21+
header
22+
====== ==== ================= ==========================================
23+
24+
When ``nlpid`` is the ``0x00`` pad marker, a further NLPID octet (``0x80``
25+
for SNAP), a 3-octet OUI and a 2-octet PID follow, kept as ``frad.ext_nlpid``,
26+
``frad.oui`` and ``frad.pid``.
27+
28+
.. autoclass:: pcapkit.protocols.link.frad.FRAD
29+
:no-members:
30+
:show-inheritance:
31+
32+
.. autoproperty:: name
33+
.. autoproperty:: alias
34+
.. autoproperty:: length
35+
.. autoproperty:: protocol
36+
37+
.. automethod:: id
38+
39+
.. automethod:: read
40+
.. automethod:: make
41+
42+
.. automethod:: __length_hint__
43+
.. automethod:: __index__
44+
45+
.. automethod:: _make_data
46+
.. automethod:: _import_next_layer
47+
48+
.. autoattribute:: __proto__
49+
:no-value:
50+
51+
Header Schemas
52+
--------------
53+
54+
.. module:: pcapkit.protocols.schema.link.frad
55+
56+
.. autoclass:: pcapkit.protocols.schema.link.frad.FRAD
57+
:members:
58+
:show-inheritance:
59+
60+
Data Models
61+
-----------
62+
63+
.. module:: pcapkit.protocols.data.link.frad
64+
65+
.. autoclass:: pcapkit.protocols.data.link.frad.FRAD
66+
:members:
67+
:show-inheritance:
68+
69+
.. rubric:: Footnotes
70+
71+
.. [*] :rfc:`2427` (obsoleting :rfc:`1490`)

‎docs/source/pcapkit/protocols/link/index.rst‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ link layer, with detailed implementation and methods.
2424
link
2525
ethernet
2626
arp
27+
frad
2728
l2tp
2829
l2tpv2
2930
linux_sll

‎pcapkit/__init__.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@
111111
'NoPayload', # No Payload
112112
'Raw', # Raw Packet
113113

114-
'ARP', 'C_Tag', 'Ethernet', 'InARP', 'L2TP', # Link Layer
114+
'ARP', 'C_Tag', 'Ethernet', 'FRAD', 'InARP', 'L2TP', # Link Layer
115115
'L2TPv2', 'LinuxSLL', 'LinuxSLL1', 'LinuxSLL2', 'Loopback', 'S_Tag', 'VLAN',
116116

117117
'AH', 'ESP', 'IP', 'IPsec', 'IPv4', 'IPv6', 'IPX', # Internet Layer

‎pcapkit/all.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@
119119
'PCAPNG', # PCAPNG Format
120120
'NoPayload', # No Payload
121121
'Raw', # Raw Packet
122-
'ARP', 'C_Tag', 'Ethernet', 'InARP', 'L2TP', 'L2TPv2', 'LinuxSLL', 'LinuxSLL1',
122+
'ARP', 'C_Tag', 'Ethernet', 'FRAD', 'InARP', 'L2TP', 'L2TPv2', 'LinuxSLL', 'LinuxSLL1',
123123
'LinuxSLL2', 'Loopback', 'S_Tag', 'VLAN', # Link Layer
124124
'AH', 'ESP', 'IP', 'IPsec', 'IPv4', 'IPv6', 'IPX', # Internet Layer
125125
'HIP', 'HOPOPT', 'IPv6_Ext', 'IPv6_Frag', 'IPv6_Opts', 'IPv6_Route', 'MH',

‎pcapkit/protocols/__init__.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
'Raw',
5151

5252
# Link Layer
53-
'ARP', 'C_Tag', 'Ethernet', 'InARP', 'L2TP', 'L2TPv2', 'LinuxSLL', 'LinuxSLL1',
53+
'ARP', 'C_Tag', 'Ethernet', 'FRAD', 'InARP', 'L2TP', 'L2TPv2', 'LinuxSLL', 'LinuxSLL1',
5454
'LinuxSLL2', 'Loopback', 'S_Tag', 'VLAN',
5555

5656
# Internet Layer

‎pcapkit/protocols/data/__init__.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@
6262
# Ethernet Protocol
6363
'Ethernet',
6464

65+
# Frame Relay Access Device
66+
'FRAD',
67+
6568
# Layer Two Tunnelling Protocol
6669
'L2TP', 'L2TP_Flags',
6770

‎pcapkit/protocols/data/link/__init__.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
# Ethernet Protocol
1010
from pcapkit.protocols.data.link.ethernet import Ethernet
1111

12+
# Frame Relay Access Device
13+
from pcapkit.protocols.data.link.frad import FRAD
14+
1215
# Layer Two Tunnelling Protocol
1316
from pcapkit.protocols.data.link.l2tp import L2TP
1417
from pcapkit.protocols.data.link.l2tp import Flags as L2TP_Flags
@@ -31,6 +34,9 @@
3134
# Ethernet Protocol
3235
'Ethernet',
3336

37+
# Frame Relay Access Device
38+
'FRAD',
39+
3440
# Layer Two Tunnelling Protocol
3541
'L2TP', 'L2TP_Flags',
3642

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# -*- coding: utf-8 -*-
2+
"""data models for Frame Relay Access Device (FRAD) frames"""
3+
4+
from typing import TYPE_CHECKING
5+
6+
from pcapkit.corekit.infoclass import info_final
7+
from pcapkit.protocols.data.protocol import Protocol
8+
9+
if TYPE_CHECKING:
10+
from typing import Optional
11+
12+
__all__ = ['FRAD']
13+
14+
15+
@info_final
16+
class FRAD(Protocol):
17+
"""Data model for a Frame Relay Access Device (FRAD) frame."""
18+
19+
#: Data Link Connection Identifier, from the Q.922 address field.
20+
dlci: 'int'
21+
#: Command/response indication bit.
22+
cr: 'int'
23+
#: Forward explicit congestion notification.
24+
fecn: 'int'
25+
#: Backward explicit congestion notification.
26+
becn: 'int'
27+
#: Discard eligibility.
28+
de: 'int'
29+
#: Control field; ``0x03`` (UI) for ordinary data traffic.
30+
control: 'int'
31+
#: NLPID selecting the encapsulated protocol, with any ``0x00`` pad
32+
#: already resolved to the real value that followed it.
33+
nlpid: 'int'
34+
#: SNAP OUI, present only when :attr:`nlpid` is ``0x80``.
35+
snap_oui: 'Optional[bytes]'
36+
#: SNAP PID, present only when :attr:`nlpid` is ``0x80``.
37+
snap_pid: 'Optional[int]'
38+
#: Header length, in octets -- 4 for a direct NLPID, 5 with the pad byte,
39+
#: or 10 with the SNAP header besides.
40+
len: 'int'
41+
42+
if TYPE_CHECKING:
43+
def __init__(self, dlci: 'int', cr: 'int', fecn: 'int', becn: 'int', de: 'int', # pylint: disable=unused-argument,super-init-not-called
44+
control: 'int', nlpid: 'int', snap_oui: 'Optional[bytes]', # pylint: disable=unused-argument
45+
snap_pid: 'Optional[int]', len: 'int') -> 'None': ... # pylint: disable=unused-argument,redefined-builtin

0 commit comments

Comments
 (0)