Skip to content
10 changes: 8 additions & 2 deletions docs/source/ext.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,17 @@ The following table shows all available protocol classes in :mod:`pcapkit`:
+ Link Layer +----------------+-----------------------+-------------------------------------------------------------+
| (:class:`~pcapkit.protocols.link.link.Link` subclasses) | :class:`pcapkit.protocols.link.ethernet.Ethernet` |
+ +----------------+-----------------------+-------------------------------------------------------------+
| | :class:`pcapkit.protocols.link.l2tp.L2TP` |
| | | :class:`pcapkit.protocols.link.l2tp.L2TP` |
+ + +-----------------------+-------------------------------------------------------------+
| | L2TP Family | :class:`pcapkit.protocols.link.l2tpv2.L2TPv2` |
+ +----------------+-----------------------+-------------------------------------------------------------+
| | :class:`pcapkit.protocols.link.ospf.OSPF` |
+ +----------------+-----------------------+-------------------------------------------------------------+
| | :class:`pcapkit.protocols.link.vlan.VLAN` |
| | | :class:`pcapkit.protocols.link.vlan.VLAN` |
+ + +-----------------------+-------------------------------------------------------------+
| | VLAN Family | :class:`pcapkit.protocols.link.c_tag.C_Tag` |
+ + +-----------------------+-------------------------------------------------------------+
| | | :class:`pcapkit.protocols.link.s_tag.S_Tag` |
+------------------------------------------------------------------+----------------+-----------------------+-------------------------------------------------------------+
| | | :class:`pcapkit.protocols.internet.ip.IP` |
+ + +-----------------------+-------------------------------------------------------------+
Expand Down
11 changes: 11 additions & 0 deletions docs/source/pcapkit/protocols/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ diagram of the class hierarchy of :mod:`pcapkit.protocols`:
RARP --> DRARP
end
end

subgraph vlan [VLAN Family]
VLAN --> C_Tag & S_Tag
end

subgraph l2tp [L2TP Family]
L2TP --> L2TPv2
end
end

subgraph internet [Internet Layer]
Expand Down Expand Up @@ -100,8 +108,11 @@ diagram of the class hierarchy of :mod:`pcapkit.protocols`:
click Link "/pcapkit/protocols/link/link.html#pcapkit.protocols.link.Link"
click Ethernet "/pcapkit/protocols/link/ethernet.html#pcapkit.protocols.link.ethernet.Ethernet"
click L2TP "/pcapkit/protocols/link/l2tp.html#pcapkit.protocols.link.l2tp.L2TP"
click L2TPv2 "/pcapkit/protocols/link/l2tpv2.html#pcapkit.protocols.link.l2tpv2.L2TPv2"
click OSPF "/pcapkit/protocols/link/ospf.html#pcapkit.protocols.link.ospf.OSPF"
click VLAN "/pcapkit/protocols/link/vlan.html#pcapkit.protocols.link.vlan.VLAN"
click C_Tag "/pcapkit/protocols/link/c_tag.html#pcapkit.protocols.link.c_tag.C_Tag"
click S_Tag "/pcapkit/protocols/link/s_tag.html#pcapkit.protocols.link.s_tag.S_Tag"
click ARP "/pcapkit/protocols/link/arp.html#pcapkit.protocols.link.arp.ARP"
click InARP "/pcapkit/protocols/link/arp.html#pcapkit.protocols.link.arp.InARP"
click RARP "/pcapkit/protocols/link/rarp.html#pcapkit.protocols.link.rarp.RARP"
Expand Down
39 changes: 39 additions & 0 deletions docs/source/pcapkit/protocols/link/c_tag.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
C_Tag - 802.1Q Customer VLAN Tag Type
=====================================

.. module:: pcapkit.protocols.link.c_tag

:mod:`pcapkit.protocols.link.c_tag` contains
:class:`~pcapkit.protocols.link.c_tag.C_Tag` only, which implements extractor for
the 802.1Q Customer VLAN Tag Type (C-Tag, formerly the Q-Tag) [*]_, EtherType
``0x8100``.

Its structure, and all of its parsing and construction, come from
:class:`~pcapkit.protocols.link.vlan.VLAN`; this class adds only the tag's own
identity -- :attr:`~pcapkit.protocols.link.c_tag.C_Tag.name`,
:attr:`~pcapkit.protocols.link.c_tag.C_Tag.alias`,
:attr:`~pcapkit.protocols.link.c_tag.C_Tag.info_name` -- and its registry index.

It lives in a module of its own rather than beside
:class:`~pcapkit.protocols.link.s_tag.S_Tag` because the two are reached through
*different* registry indices, ``0x8100`` against ``0x88A8``, which is the
project's rule for when protocols share a module. Contrast
:class:`~pcapkit.protocols.link.arp.InARP`, which shares
:mod:`~pcapkit.protocols.link.arp` with :class:`~pcapkit.protocols.link.arp.ARP`
precisely because it inherits its index.

.. autoclass:: pcapkit.protocols.link.c_tag.C_Tag
:no-members:
:show-inheritance:

.. autoproperty:: name
.. autoproperty:: alias
.. autoproperty:: info_name

.. automethod:: id

.. automethod:: __index__

.. rubric:: Footnotes

.. [*] https://en.wikipedia.org/wiki/IEEE_802.1Q
3 changes: 3 additions & 0 deletions docs/source/pcapkit/protocols/link/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ link layer, with detailed implementation and methods.
arp
rarp
l2tp
l2tpv2
ospf
vlan
c_tag
s_tag

.. todo::

Expand Down
138 changes: 60 additions & 78 deletions docs/source/pcapkit/protocols/link/l2tp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,93 +4,75 @@ L2TP - Layer Two Tunnelling Protocol
.. module:: pcapkit.protocols.link.l2tp

:mod:`pcapkit.protocols.link.l2tp` contains
:class:`~pcapkit.protocols.link.l2tp.L2TP` only,
which implements extractor for Layer Two Tunnelling
Protocol (L2TP) [*]_, whose structure is described
as below:

.. table::

======= ===== ===================== ==========================================
Octets Bits Name Description
======= ===== ===================== ==========================================
0 0 ``l2tp.flags`` Flags and Version Info
------- ----- --------------------- ------------------------------------------
0 0 ``l2tp.flags.type`` Type (control / data)
------- ----- --------------------- ------------------------------------------
0 1 ``l2tp.flags.len`` Length
------- ----- --------------------- ------------------------------------------
0 2 Reserved (must be zero ``x00``)
------- ----- --------------------- ------------------------------------------
0 4 ``l2tp.flags.seq`` Sequence
------- ----- --------------------- ------------------------------------------
0 5 Reserved (must be zero ``x00``)
------- ----- --------------------- ------------------------------------------
0 6 ``l2tp.flags.offset`` Offset
------- ----- --------------------- ------------------------------------------
0 7 ``l2tp.flags.prio`` Priority
------- ----- --------------------- ------------------------------------------
1 8 Reserved (must be zero ``x00``)
------- ----- --------------------- ------------------------------------------
1 12 ``l2tp.version`` Version (``2``)
------- ----- --------------------- ------------------------------------------
2 16 ``l2tp.length`` Length (optional by ``len``)
------- ----- --------------------- ------------------------------------------
4 32 ``l2tp.tunnelid`` Tunnel ID
------- ----- --------------------- ------------------------------------------
6 48 ``l2tp.sessionid`` Session ID
------- ----- --------------------- ------------------------------------------
8 64 ``l2tp.ns`` Sequence Number (optional by ``seq``)
------- ----- --------------------- ------------------------------------------
10 80 ``l2tp.nr`` Next Sequence Number (optional by ``seq``)
------- ----- --------------------- ------------------------------------------
12 96 ``l2tp.offset`` Offset Size (optional by ``offset``)
======= ===== ===================== ==========================================
:class:`~pcapkit.protocols.link.l2tp.L2TP` only, an abstract base class for the
Layer Two Tunnelling Protocol family [*]_. The concrete versions live in modules
of their own:

.. list-table::
:header-rows: 1

* - Version
- Class
- Specification
* - L2TPv2
- :class:`~pcapkit.protocols.link.l2tpv2.L2TPv2`
- :rfc:`2661`

Only L2TPv2 is implemented.

The base deliberately carries **no header parsing at all**, in the way
:class:`~pcapkit.protocols.internet.ip.IP` carries none for its family. That is
not tidiness: the versions genuinely do not share a header. All that is common
across them is the *first 16-bit word carrying a version nibble at bits 12-15*;
everything after it differs, so a base that parsed further would be assuming one
version's layout for all of them.

What the family still wants
---------------------------

**L2TPv3** [:rfc:`3931`] has a different session header and a different control
message header from v2, and is reachable two ways -- over UDP port 1701 like v2,
and directly over IP as **protocol number 115**. That second route is why
:attr:`Internet.__proto__ <pcapkit.protocols.internet.internet.Internet.__proto__>`
leaves 115 unbound today: the binding waits on an ``L2TPv3`` class, not on a
different framing decision. It also means v3 is the first member of this family
to have a real :meth:`~pcapkit.protocols.protocol.ProtocolBase.__index__`, and so
the first that must have a module of its own under the project's one-module-per-index
rule.

**L2F** [:rfc:`2341`] is reached when the version nibble reads ``1``. It is *not*
an earlier version of L2TP: :rfc:`2661` §3.1 requires ``Ver`` to be 2 and reserves
the value 1 "to permit detection of L2F packets should they arrive intermixed with
L2TP packets". L2F is a separate protocol with its own header. It is therefore to
be implemented as ``L2F``, the canonical name, carrying ``L2TPv1`` only as an
alias in its :meth:`~pcapkit.protocols.protocol.ProtocolBase.id` -- the same
relationship HTTP/3 has to QUIC. c.f.
:meth:`HTTPv1.id <pcapkit.protocols.application.httpv1.HTTP.id>` for how a
version-flavoured alias is spelled: canonical name first, alias second, since
callers take element zero as canonical.

Selecting a version
-------------------

Nothing dispatches on the version nibble yet, because only one version exists.
When a second lands, the mechanism it wants already has a precedent in
:class:`~pcapkit.protocols.application.http.HTTP`, which reads a version and
delegates to a per-version class. L2TP is the easier case:
:meth:`HTTP._guess_version <pcapkit.protocols.application.http.HTTP._guess_version>`
has to *trial-parse* each candidate because the wire format carries no version
field, whereas L2TP states its version explicitly in those four bits. So a
deterministic switch on ``Ver`` is enough, and no new registry is needed.

.. autoclass:: pcapkit.protocols.link.l2tp.L2TP
:no-members:
:show-inheritance:

.. autoproperty:: name
.. autoproperty:: length
.. autoproperty:: type
.. autoproperty:: info_name

.. automethod:: read
.. automethod:: make

.. automethod:: _make_data
.. automethod:: id

.. automethod:: __index__

Header Schemas
--------------

.. module:: pcapkit.protocols.schema.link.l2tp

.. autoclass:: pcapkit.protocols.schema.link.l2tp.L2TP
:members:
:show-inheritance:

Type Stubs
~~~~~~~~~~

.. autoclass:: pcapkit.protocols.schema.link.l2tp.FlagsType
:members:
:show-inheritance:

Data Models
-----------

.. module:: pcapkit.protocols.data.link.l2tp

.. autoclass:: pcapkit.protocols.data.link.l2tp.L2TP
:members:
:show-inheritance:

.. autoclass:: pcapkit.protocols.data.link.l2tp.Flags
:members:
:show-inheritance:

.. rubric:: Footnotes

.. [*] https://en.wikipedia.org/wiki/Layer_2_Tunneling_Protocol
114 changes: 114 additions & 0 deletions docs/source/pcapkit/protocols/link/l2tpv2.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
L2TPv2 - Layer Two Tunnelling Protocol version 2
================================================

.. module:: pcapkit.protocols.link.l2tpv2

:mod:`pcapkit.protocols.link.l2tpv2` contains
:class:`~pcapkit.protocols.link.l2tpv2.L2TPv2` only, which implements extractor
for the Layer Two Tunnelling Protocol version 2 (L2TPv2) [*]_ as specified by
:rfc:`2661` -- a 16-bit tunnel ID and a 16-bit session ID, with the version nibble
reading ``2``. It is dispatched from
:attr:`UDP.__proto__ <pcapkit.protocols.transport.udp.UDP.__proto__>` at port
1701. Its structure is described as below:

.. table::

======= ===== ===================== ==========================================
Octets Bits Name Description
======= ===== ===================== ==========================================
0 0 ``l2tp.flags`` Flags and Version Info
------- ----- --------------------- ------------------------------------------
0 0 ``l2tp.flags.type`` Type (control / data)
------- ----- --------------------- ------------------------------------------
0 1 ``l2tp.flags.len`` Length
------- ----- --------------------- ------------------------------------------
0 2 Reserved (must be zero ``x00``)
------- ----- --------------------- ------------------------------------------
0 4 ``l2tp.flags.seq`` Sequence
------- ----- --------------------- ------------------------------------------
0 5 Reserved (must be zero ``x00``)
------- ----- --------------------- ------------------------------------------
0 6 ``l2tp.flags.offset`` Offset
------- ----- --------------------- ------------------------------------------
0 7 ``l2tp.flags.prio`` Priority
------- ----- --------------------- ------------------------------------------
1 8 Reserved (must be zero ``x00``)
------- ----- --------------------- ------------------------------------------
1 12 ``l2tp.version`` Version (``2``)
------- ----- --------------------- ------------------------------------------
2 16 ``l2tp.length`` Length (optional by ``len``)
------- ----- --------------------- ------------------------------------------
4 32 ``l2tp.tunnelid`` Tunnel ID
------- ----- --------------------- ------------------------------------------
6 48 ``l2tp.sessionid`` Session ID
------- ----- --------------------- ------------------------------------------
8 64 ``l2tp.ns`` Sequence Number (optional by ``seq``)
------- ----- --------------------- ------------------------------------------
10 80 ``l2tp.nr`` Next Sequence Number (optional by ``seq``)
------- ----- --------------------- ------------------------------------------
12 96 ``l2tp.offset`` Offset Size (optional by ``offset``)
======= ===== ===================== ==========================================

.. note::

The parsed datagram appears under ``l2tp``, not ``l2tpv2``:
:attr:`~pcapkit.protocols.link.l2tp.L2TP.info_name` is declared on the
version-agnostic base so that a consumer finds the data at the same key
whichever version was on the wire. The version is reported by
:attr:`~pcapkit.protocols.link.l2tpv2.L2TPv2.alias` instead.

IANA protocol number 115 (``L2TP``) is deliberately left unbound. It
references :rfc:`3931`, i.e. **L2TPv3**, whose session and control message
headers are a different shape -- so the binding waits on an ``L2TPv3`` class
rather than on this one. See :mod:`pcapkit.protocols.link.l2tp`.

.. autoclass:: pcapkit.protocols.link.l2tpv2.L2TPv2
:no-members:
:show-inheritance:

.. autoproperty:: name
.. autoproperty:: alias
.. autoproperty:: version
.. autoproperty:: length
.. autoproperty:: type

.. automethod:: id
.. automethod:: read
.. automethod:: make

.. automethod:: _make_data

.. automethod:: __index__

Header Schemas
--------------

.. module:: pcapkit.protocols.schema.link.l2tp

.. autoclass:: pcapkit.protocols.schema.link.l2tp.L2TP
:members:
:show-inheritance:

Type Stubs
~~~~~~~~~~

.. autoclass:: pcapkit.protocols.schema.link.l2tp.FlagsType
:members:
:show-inheritance:

Data Models
-----------

.. module:: pcapkit.protocols.data.link.l2tp

.. autoclass:: pcapkit.protocols.data.link.l2tp.L2TP
:members:
:show-inheritance:

.. autoclass:: pcapkit.protocols.data.link.l2tp.Flags
:members:
:show-inheritance:

.. rubric:: Footnotes

.. [*] https://en.wikipedia.org/wiki/Layer_2_Tunneling_Protocol
Loading