1136 lines
44 KiB
ReStructuredText
1136 lines
44 KiB
ReStructuredText
.. SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||
|
||
===================
|
||
J1939 Documentation
|
||
===================
|
||
|
||
Overview / What Is J1939
|
||
========================
|
||
|
||
SAE J1939 defines a higher layer protocol on CAN. It implements a more
|
||
sophisticated addressing scheme and extends the maximum packet size above 8
|
||
bytes. Several derived specifications exist, which differ from the original
|
||
J1939 on the application level, like MilCAN A, NMEA2000, and especially
|
||
ISO-11783 (ISOBUS). This last one specifies the so-called ETP (Extended
|
||
Transport Protocol), which has been included in this implementation. This
|
||
results in a maximum packet size of ((2 ^ 24) - 1) * 7 bytes == 111 MiB.
|
||
|
||
Specifications used
|
||
-------------------
|
||
|
||
* SAE J1939-21 : data link layer
|
||
* SAE J1939-81 : network management
|
||
* ISO 11783-6 : Virtual Terminal (Extended Transport Protocol)
|
||
|
||
.. _j1939-motivation:
|
||
|
||
Motivation
|
||
==========
|
||
|
||
Given the fact there's something like SocketCAN with an API similar to BSD
|
||
sockets, we found some reasons to justify a kernel implementation for the
|
||
addressing and transport methods used by J1939.
|
||
|
||
* **Addressing:** when a process on an ECU communicates via J1939, it should
|
||
not necessarily know its source address. Although, at least one process per
|
||
ECU should know the source address. Other processes should be able to reuse
|
||
that address. This way, address parameters for different processes
|
||
cooperating for the same ECU, are not duplicated. This way of working is
|
||
closely related to the UNIX concept, where programs do just one thing and do
|
||
it well.
|
||
|
||
* **Dynamic addressing:** Address Claiming in J1939 is time critical.
|
||
Furthermore, data transport should be handled properly during the address
|
||
negotiation. Putting this functionality in the kernel eliminates it as a
|
||
requirement for _every_ user space process that communicates via J1939. This
|
||
results in a consistent J1939 bus with proper addressing.
|
||
|
||
* **Transport:** both TP & ETP reuse some PGNs to relay big packets over them.
|
||
Different processes may thus use the same TP & ETP PGNs without actually
|
||
knowing it. The individual TP & ETP sessions _must_ be serialized
|
||
(synchronized) between different processes. The kernel solves this problem
|
||
properly and eliminates the serialization (synchronization) as a requirement
|
||
for _every_ user space process that communicates via J1939.
|
||
|
||
J1939 defines some other features (relaying, gateway, fast packet transport,
|
||
...). In-kernel code for these would not contribute to protocol stability.
|
||
Therefore, these parts are left to user space.
|
||
|
||
The J1939 sockets operate on CAN network devices (see SocketCAN). Any J1939
|
||
user space library operating on CAN raw sockets will still operate properly.
|
||
Since such a library does not communicate with the in-kernel implementation, care
|
||
must be taken that these two do not interfere. In practice, this means they
|
||
cannot share ECU addresses. A single ECU (or virtual ECU) address is used by
|
||
the library exclusively, or by the in-kernel system exclusively.
|
||
|
||
J1939 concepts
|
||
==============
|
||
|
||
Data Sent to the J1939 Stack
|
||
----------------------------
|
||
|
||
The data buffers sent to the J1939 stack from user space are not CAN frames
|
||
themselves. Instead, they are payloads that the J1939 stack converts into
|
||
proper CAN frames based on the size of the buffer and the type of transfer. The
|
||
size of the buffer influences how the stack processes the data and determines
|
||
the internal code path used for the transfer.
|
||
|
||
**Handling of Different Buffer Sizes:**
|
||
|
||
- **Buffers with a size of 8 bytes or less:**
|
||
|
||
- These are handled as simple sessions internally within the stack.
|
||
|
||
- The stack converts the buffer directly into a single CAN frame without
|
||
fragmentation.
|
||
|
||
- This type of transfer does not require an actual client (receiver) on the
|
||
receiving side.
|
||
|
||
- **Buffers up to 1785 bytes:**
|
||
|
||
- These are automatically handled as J1939 Transport Protocol (TP) transfers.
|
||
|
||
- Internally, the stack splits the buffer into multiple 8-byte CAN frames.
|
||
|
||
- TP transfers can be unicast or broadcast.
|
||
|
||
- **Broadcast TP:** Does not require a receiver on the other side and can be
|
||
used in broadcast scenarios.
|
||
|
||
- **Unicast TP:** Requires an active receiver (client) on the other side to
|
||
acknowledge the transfer.
|
||
|
||
- **Buffers from 1786 bytes up to 111 MiB:**
|
||
|
||
- These are handled as ISO 11783 Extended Transport Protocol (ETP) transfers.
|
||
|
||
- ETP transfers are used for larger payloads and are split into multiple CAN
|
||
frames internally.
|
||
|
||
- **ETP transfers (unicast):** Require a receiver on the other side to
|
||
process the incoming data and acknowledge each step of the transfer.
|
||
|
||
- ETP transfers cannot be broadcast like TP transfers, and always require a
|
||
receiver for operation.
|
||
|
||
**Non-Blocking Operation with `MSG_DONTWAIT`:**
|
||
|
||
The J1939 stack supports non-blocking operation when used in combination with
|
||
the `MSG_DONTWAIT` flag. In this mode, the stack attempts to take as much data
|
||
as the available memory for the socket allows. It returns the amount of data
|
||
that was successfully taken, and it is the responsibility of user space to
|
||
monitor this value and handle partial transfers.
|
||
|
||
- If the stack cannot take the entire buffer, it returns the number of bytes
|
||
successfully taken, and user space should handle the remainder.
|
||
|
||
- **Error handling:** When using `MSG_DONTWAIT`, the user must rely on the
|
||
error queue to detect transfer errors. See the **SO_J1939_ERRQUEUE** section
|
||
for details on how to subscribe to error notifications. Without the error
|
||
queue, there is no other way for user space to be notified of transfer errors
|
||
during non-blocking operations.
|
||
|
||
**Behavior and Requirements:**
|
||
|
||
- **Simple transfers (<= 8 bytes):** Do not require a receiver on the other
|
||
side, making them easy to send without needing address claiming or
|
||
coordination with a destination.
|
||
|
||
- **Unicast TP/ETP:** Requires a receiver on the other side to complete the
|
||
transfer. The receiver must acknowledge the transfer for the session to
|
||
proceed successfully.
|
||
|
||
- **Broadcast TP:** Allows sending data without a receiver, but only works for
|
||
TP transfers. ETP cannot be broadcast and always needs a receiving client.
|
||
|
||
These different behaviors depend heavily on the size of the buffer provided to
|
||
the stack, and the appropriate transport mechanism (TP or ETP) is selected
|
||
based on the payload size. The stack automatically manages the fragmentation
|
||
and reassembly of large payloads and ensures that the correct CAN frames are
|
||
generated and transmitted for each session.
|
||
|
||
PGN
|
||
---
|
||
|
||
The J1939 protocol uses the 29-bit CAN identifier with the following structure:
|
||
|
||
============ ============== ====================
|
||
29 bit CAN-ID
|
||
--------------------------------------------------
|
||
Bit positions within the CAN-ID
|
||
--------------------------------------------------
|
||
28 ... 26 25 ... 8 7 ... 0
|
||
============ ============== ====================
|
||
Priority PGN SA (Source Address)
|
||
============ ============== ====================
|
||
|
||
The PGN (Parameter Group Number) is a number to identify a packet. The PGN
|
||
is composed as follows:
|
||
|
||
============ ============== ================= =================
|
||
PGN
|
||
------------------------------------------------------------------
|
||
Bit positions within the CAN-ID
|
||
------------------------------------------------------------------
|
||
25 24 23 ... 16 15 ... 8
|
||
============ ============== ================= =================
|
||
R (Reserved) DP (Data Page) PF (PDU Format) PS (PDU Specific)
|
||
============ ============== ================= =================
|
||
|
||
In J1939-21 distinction is made between PDU1 format (where PF < 240) and PDU2
|
||
format (where PF >= 240). Furthermore, when using the PDU2 format, the PS-field
|
||
contains a so-called Group Extension, which is part of the PGN. When using PDU2
|
||
format, the Group Extension is set in the PS-field.
|
||
|
||
============== ========================
|
||
PDU1 Format (specific) (peer to peer)
|
||
----------------------------------------
|
||
Bit positions within the CAN-ID
|
||
----------------------------------------
|
||
23 ... 16 15 ... 8
|
||
============== ========================
|
||
00h ... EFh DA (Destination address)
|
||
============== ========================
|
||
|
||
============== ========================
|
||
PDU2 Format (global) (broadcast)
|
||
----------------------------------------
|
||
Bit positions within the CAN-ID
|
||
----------------------------------------
|
||
23 ... 16 15 ... 8
|
||
============== ========================
|
||
F0h ... FFh GE (Group Extension)
|
||
============== ========================
|
||
|
||
On the other hand, when using PDU1 format, the PS-field contains a so-called
|
||
Destination Address, which is _not_ part of the PGN. When communicating a PGN
|
||
from user space to kernel (or vice versa) and PDU1 format is used, the PS-field
|
||
of the PGN shall be set to zero. The Destination Address shall be set
|
||
elsewhere.
|
||
|
||
Regarding PGN mapping to 29-bit CAN identifier, the Destination Address shall
|
||
be get/set from/to the appropriate bits of the identifier by the kernel.
|
||
|
||
|
||
Addressing
|
||
----------
|
||
|
||
Both static and dynamic addressing methods can be used.
|
||
|
||
For static addresses, no extra checks are made by the kernel and provided
|
||
addresses are considered right. This responsibility is for the OEM or system
|
||
integrator.
|
||
|
||
For dynamic addressing, so-called Address Claiming, extra support is foreseen
|
||
in the kernel. In J1939 any ECU is known by its 64-bit NAME. At the moment of
|
||
a successful address claim, the kernel keeps track of both NAME and source
|
||
address being claimed. This serves as a base for filter schemes. By default,
|
||
packets with a destination that is not locally will be rejected.
|
||
|
||
Mixed mode packets (from a static to a dynamic address or vice versa) are
|
||
allowed. The BSD sockets define separate API calls for getting/setting the
|
||
local & remote address and are applicable for J1939 sockets.
|
||
|
||
Filtering
|
||
---------
|
||
|
||
J1939 defines white list filters per socket that a user can set in order to
|
||
receive a subset of the J1939 traffic. Filtering can be based on:
|
||
|
||
* SA
|
||
* SOURCE_NAME
|
||
* PGN
|
||
|
||
When multiple filters are in place for a single socket, and a packet comes in
|
||
that matches several of those filters, the packet is only received once for
|
||
that socket.
|
||
|
||
How to Use J1939
|
||
================
|
||
|
||
API Calls
|
||
---------
|
||
|
||
On CAN, you first need to open a socket for communicating over a CAN network.
|
||
To use J1939, ``#include <linux/can/j1939.h>``. From there, ``<linux/can.h>`` will be
|
||
included too. To open a socket, use:
|
||
|
||
.. code-block:: C
|
||
|
||
s = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
|
||
|
||
J1939 does use ``SOCK_DGRAM`` sockets. In the J1939 specification, connections are
|
||
mentioned in the context of transport protocol sessions. These still deliver
|
||
packets to the other end (using several CAN packets). ``SOCK_STREAM`` is not
|
||
supported.
|
||
|
||
After the successful creation of the socket, you would normally use the ``bind(2)``
|
||
and/or ``connect(2)`` system call to bind the socket to a CAN interface. After
|
||
binding and/or connecting the socket, you can ``read(2)`` and ``write(2)`` from/to the
|
||
socket or use ``send(2)``, ``sendto(2)``, ``sendmsg(2)`` and the ``recv*()`` counterpart
|
||
operations on the socket as usual. There are also J1939 specific socket options
|
||
described below.
|
||
|
||
In order to send data, a ``bind(2)`` must have been successful. ``bind(2)`` assigns a
|
||
local address to a socket.
|
||
|
||
Different from CAN is that the payload data is just the data that get sends,
|
||
without its header info. The header info is derived from the sockaddr supplied
|
||
to ``bind(2)``, ``connect(2)``, ``sendto(2)`` and ``recvfrom(2)``. A ``write(2)`` with size 4 will
|
||
result in a packet with 4 bytes.
|
||
|
||
The sockaddr structure has extensions for use with J1939 as specified below:
|
||
|
||
.. code-block:: C
|
||
|
||
struct sockaddr_can {
|
||
sa_family_t can_family;
|
||
int can_ifindex;
|
||
union {
|
||
struct {
|
||
__u64 name;
|
||
/* pgn:
|
||
* 8 bit: PS in PDU2 case, else 0
|
||
* 8 bit: PF
|
||
* 1 bit: DP
|
||
* 1 bit: reserved
|
||
*/
|
||
__u32 pgn;
|
||
__u8 addr;
|
||
} j1939;
|
||
} can_addr;
|
||
}
|
||
|
||
``can_family`` & ``can_ifindex`` serve the same purpose as for other SocketCAN sockets.
|
||
|
||
``can_addr.j1939.pgn`` specifies the PGN (max 0x3ffff). Individual bits are
|
||
specified above.
|
||
|
||
``can_addr.j1939.name`` contains the 64-bit J1939 NAME.
|
||
|
||
``can_addr.j1939.addr`` contains the address.
|
||
|
||
The ``bind(2)`` system call assigns the local address, i.e. the source address when
|
||
sending packages. If a PGN during ``bind(2)`` is set, it's used as a RX filter.
|
||
I.e. only packets with a matching PGN are received. If an ADDR or NAME is set
|
||
it is used as a receive filter, too. It will match the destination NAME or ADDR
|
||
of the incoming packet. The NAME filter will work only if appropriate Address
|
||
Claiming for this name was done on the CAN bus and registered/cached by the
|
||
kernel.
|
||
|
||
On the other hand ``connect(2)`` assigns the remote address, i.e. the destination
|
||
address. The PGN from ``connect(2)`` is used as the default PGN when sending
|
||
packets. If ADDR or NAME is set it will be used as the default destination ADDR
|
||
or NAME. Further a set ADDR or NAME during ``connect(2)`` is used as a receive
|
||
filter. It will match the source NAME or ADDR of the incoming packet.
|
||
|
||
Both ``write(2)`` and ``send(2)`` will send a packet with local address from ``bind(2)`` and the
|
||
remote address from ``connect(2)``. Use ``sendto(2)`` to overwrite the destination
|
||
address.
|
||
|
||
If ``can_addr.j1939.name`` is set (!= 0) the NAME is looked up by the kernel and
|
||
the corresponding ADDR is used. If ``can_addr.j1939.name`` is not set (== 0),
|
||
``can_addr.j1939.addr`` is used.
|
||
|
||
When creating a socket, reasonable defaults are set. Some options can be
|
||
modified with ``setsockopt(2)`` & ``getsockopt(2)``.
|
||
|
||
RX path related options:
|
||
|
||
- ``SO_J1939_FILTER`` - configure array of filters
|
||
- ``SO_J1939_PROMISC`` - disable filters set by ``bind(2)`` and ``connect(2)``
|
||
|
||
By default no broadcast packets can be send or received. To enable sending or
|
||
receiving broadcast packets use the socket option ``SO_BROADCAST``:
|
||
|
||
.. code-block:: C
|
||
|
||
int value = 1;
|
||
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value));
|
||
|
||
The following diagram illustrates the RX path:
|
||
|
||
.. code::
|
||
|
||
+--------------------+
|
||
| incoming packet |
|
||
+--------------------+
|
||
|
|
||
V
|
||
+--------------------+
|
||
| SO_J1939_PROMISC? |
|
||
+--------------------+
|
||
| |
|
||
no | | yes
|
||
| |
|
||
.---------' `---------.
|
||
| |
|
||
+---------------------------+ |
|
||
| bind() + connect() + | |
|
||
| SOCK_BROADCAST filter | |
|
||
+---------------------------+ |
|
||
| |
|
||
|<---------------------'
|
||
V
|
||
+---------------------------+
|
||
| SO_J1939_FILTER |
|
||
+---------------------------+
|
||
|
|
||
V
|
||
+---------------------------+
|
||
| socket recv() |
|
||
+---------------------------+
|
||
|
||
TX path related options:
|
||
``SO_J1939_SEND_PRIO`` - change default send priority for the socket
|
||
|
||
Message Flags during send() and Related System Calls
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
``send(2)``, ``sendto(2)`` and ``sendmsg(2)`` take a 'flags' argument. Currently
|
||
supported flags are:
|
||
|
||
* ``MSG_DONTWAIT``, i.e. non-blocking operation.
|
||
|
||
recvmsg(2)
|
||
^^^^^^^^^^
|
||
|
||
In most cases ``recvmsg(2)`` is needed if you want to extract more information than
|
||
``recvfrom(2)`` can provide. For example package priority and timestamp. The
|
||
Destination Address, name and packet priority (if applicable) are attached to
|
||
the msghdr in the ``recvmsg(2)`` call. They can be extracted using ``cmsg(3)`` macros,
|
||
with ``cmsg_level == SOL_J1939 && cmsg_type == SCM_J1939_DEST_ADDR``,
|
||
``SCM_J1939_DEST_NAME`` or ``SCM_J1939_PRIO``. The returned data is a ``uint8_t`` for
|
||
``priority`` and ``dst_addr``, and ``uint64_t`` for ``dst_name``.
|
||
|
||
.. code-block:: C
|
||
|
||
uint8_t priority, dst_addr;
|
||
uint64_t dst_name;
|
||
|
||
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
||
switch (cmsg->cmsg_level) {
|
||
case SOL_CAN_J1939:
|
||
if (cmsg->cmsg_type == SCM_J1939_DEST_ADDR)
|
||
dst_addr = *CMSG_DATA(cmsg);
|
||
else if (cmsg->cmsg_type == SCM_J1939_DEST_NAME)
|
||
memcpy(&dst_name, CMSG_DATA(cmsg), cmsg->cmsg_len - CMSG_LEN(0));
|
||
else if (cmsg->cmsg_type == SCM_J1939_PRIO)
|
||
priority = *CMSG_DATA(cmsg);
|
||
break;
|
||
}
|
||
}
|
||
|
||
setsockopt(2)
|
||
^^^^^^^^^^^^^
|
||
|
||
The ``setsockopt(2)`` function is used to configure various socket-level
|
||
options for J1939 communication. The following options are supported:
|
||
|
||
``SO_J1939_FILTER``
|
||
~~~~~~~~~~~~~~~~~~~
|
||
|
||
The ``SO_J1939_FILTER`` option is essential when the default behavior of
|
||
``bind(2)`` and ``connect(2)`` is insufficient for specific use cases. By
|
||
default, ``bind(2)`` and ``connect(2)`` allow a socket to be associated with a
|
||
single unicast or broadcast address. However, there are scenarios where finer
|
||
control over the incoming messages is required, such as filtering by Parameter
|
||
Group Number (PGN) rather than by addresses.
|
||
|
||
For example, in a system where multiple types of J1939 messages are being
|
||
transmitted, a process might only be interested in a subset of those messages,
|
||
such as specific PGNs, and not want to receive all messages destined for its
|
||
address or broadcast to the bus.
|
||
|
||
By applying the ``SO_J1939_FILTER`` option, you can filter messages based on:
|
||
|
||
- **Source Address (SA)**: Filter messages coming from specific source
|
||
addresses.
|
||
|
||
- **Source Name**: Filter messages coming from ECUs with specific NAME
|
||
identifiers.
|
||
|
||
- **Parameter Group Number (PGN)**: Focus on receiving messages with specific
|
||
PGNs, filtering out irrelevant ones.
|
||
|
||
This filtering mechanism is particularly useful when:
|
||
|
||
- You want to receive a subset of messages based on their PGNs, even if the
|
||
address is the same.
|
||
|
||
- You need to handle both broadcast and unicast messages but only care about
|
||
certain message types or parameters.
|
||
|
||
- The ``bind(2)`` and ``connect(2)`` functions only allow binding to a single
|
||
address, which might not be sufficient if the process needs to handle multiple
|
||
PGNs but does not want to open multiple sockets.
|
||
|
||
To remove existing filters, you can pass ``optval == NULL`` or ``optlen == 0``
|
||
to ``setsockopt(2)``. This will clear all currently set filters. If you want to
|
||
**update** the set of filters, you must pass the updated filter set to
|
||
``setsockopt(2)``, as the new filter set will **replace** the old one entirely.
|
||
This behavior ensures that any previous filter configuration is discarded and
|
||
only the new set is applied.
|
||
|
||
Example of removing all filters:
|
||
|
||
.. code-block:: c
|
||
|
||
setsockopt(sock, SOL_CAN_J1939, SO_J1939_FILTER, NULL, 0);
|
||
|
||
**Maximum number of filters:** The maximum amount of filters that can be
|
||
applied using ``SO_J1939_FILTER`` is defined by ``J1939_FILTER_MAX``, which is
|
||
set to 512. This means you can configure up to 512 individual filters to match
|
||
your specific filtering needs.
|
||
|
||
Practical use case: **Monitoring Address Claiming**
|
||
|
||
One practical use case is monitoring the J1939 address claiming process by
|
||
filtering for specific PGNs related to address claiming. This allows a process
|
||
to monitor and handle address claims without processing unrelated messages.
|
||
|
||
Example:
|
||
|
||
.. code-block:: c
|
||
|
||
struct j1939_filter filt[] = {
|
||
{
|
||
.pgn = J1939_PGN_ADDRESS_CLAIMED,
|
||
.pgn_mask = J1939_PGN_PDU1_MAX,
|
||
}, {
|
||
.pgn = J1939_PGN_REQUEST,
|
||
.pgn_mask = J1939_PGN_PDU1_MAX,
|
||
}, {
|
||
.pgn = J1939_PGN_ADDRESS_COMMANDED,
|
||
.pgn_mask = J1939_PGN_MAX,
|
||
},
|
||
};
|
||
setsockopt(sock, SOL_CAN_J1939, SO_J1939_FILTER, &filt, sizeof(filt));
|
||
|
||
In this example, the socket will only receive messages with the PGNs related to
|
||
address claiming: ``J1939_PGN_ADDRESS_CLAIMED``, ``J1939_PGN_REQUEST``, and
|
||
``J1939_PGN_ADDRESS_COMMANDED``. This is particularly useful in scenarios where
|
||
you want to monitor and process address claims without being overwhelmed by
|
||
other traffic on the J1939 network.
|
||
|
||
``SO_J1939_PROMISC``
|
||
~~~~~~~~~~~~~~~~~~~~
|
||
|
||
The ``SO_J1939_PROMISC`` option enables socket-level promiscuous mode. When
|
||
this option is enabled, the socket will receive all J1939 traffic, regardless
|
||
of any filters set by ``bind()`` or ``connect()``. This is analogous to
|
||
enabling promiscuous mode for an Ethernet interface, where all traffic on the
|
||
network segment is captured.
|
||
|
||
However, **`SO_J1939_FILTER` has a higher priority** compared to
|
||
``SO_J1939_PROMISC``. This means that even in promiscuous mode, you can reduce
|
||
the number of packets received by applying specific filters with
|
||
`SO_J1939_FILTER`. The filters will limit which packets are passed to the
|
||
socket, allowing for more refined traffic selection while promiscuous mode is
|
||
active.
|
||
|
||
The acceptable value size for this option is ``sizeof(int)``, and the value is
|
||
only differentiated between `0` and non-zero. A value of `0` disables
|
||
promiscuous mode, while any non-zero value enables it.
|
||
|
||
This combination can be useful for debugging or monitoring specific types of
|
||
traffic while still capturing a broad set of messages.
|
||
|
||
Example:
|
||
|
||
.. code-block:: c
|
||
|
||
int value = 1;
|
||
setsockopt(sock, SOL_CAN_J1939, SO_J1939_PROMISC, &value, sizeof(value));
|
||
|
||
In this example, setting ``value`` to any non-zero value (e.g., `1`) enables
|
||
promiscuous mode, allowing the socket to receive all J1939 traffic on the
|
||
network.
|
||
|
||
``SO_BROADCAST``
|
||
~~~~~~~~~~~~~~~~
|
||
|
||
The ``SO_BROADCAST`` option enables the sending and receiving of broadcast
|
||
messages. By default, broadcast messages are disabled for J1939 sockets. When
|
||
this option is enabled, the socket will be allowed to send and receive
|
||
broadcast packets on the J1939 network.
|
||
|
||
Due to the nature of the CAN bus as a shared medium, all messages transmitted
|
||
on the bus are visible to all participants. In the context of J1939,
|
||
broadcasting refers to using a specific destination address field, where the
|
||
destination address is set to a value that indicates the message is intended
|
||
for all participants (usually a global address such as 0xFF). Enabling the
|
||
broadcast option allows the socket to send and receive such broadcast messages.
|
||
|
||
The acceptable value size for this option is ``sizeof(int)``, and the value is
|
||
only differentiated between `0` and non-zero. A value of `0` disables the
|
||
ability to send and receive broadcast messages, while any non-zero value
|
||
enables it.
|
||
|
||
Example:
|
||
|
||
.. code-block:: c
|
||
|
||
int value = 1;
|
||
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value));
|
||
|
||
In this example, setting ``value`` to any non-zero value (e.g., `1`) enables
|
||
the socket to send and receive broadcast messages.
|
||
|
||
``SO_J1939_SEND_PRIO``
|
||
~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
The ``SO_J1939_SEND_PRIO`` option sets the priority of outgoing J1939 messages
|
||
for the socket. In J1939, messages can have different priorities, and lower
|
||
numerical values indicate higher priority. This option allows the user to
|
||
control the priority of messages sent from the socket by adjusting the priority
|
||
bits in the CAN identifier.
|
||
|
||
The acceptable value **size** for this option is ``sizeof(int)``, and the value
|
||
is expected to be in the range of 0 to 7, where `0` is the highest priority,
|
||
and `7` is the lowest. By default, the priority is set to `6` if this option is
|
||
not explicitly configured.
|
||
|
||
Note that the priority values `0` and `1` can only be set if the process has
|
||
the `CAP_NET_ADMIN` capability. These are reserved for high-priority traffic
|
||
and require administrative privileges.
|
||
|
||
Example:
|
||
|
||
.. code-block:: c
|
||
|
||
int prio = 3; // Priority value between 0 (highest) and 7 (lowest)
|
||
setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO, &prio, sizeof(prio));
|
||
|
||
In this example, the priority is set to `3`, meaning the outgoing messages will
|
||
be sent with a moderate priority level.
|
||
|
||
``SO_J1939_ERRQUEUE``
|
||
~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
The ``SO_J1939_ERRQUEUE`` option enables the socket to receive error messages
|
||
from the error queue, providing diagnostic information about transmission
|
||
failures, protocol violations, or other issues that occur during J1939
|
||
communication. Once this option is set, user space is required to handle
|
||
``MSG_ERRQUEUE`` messages.
|
||
|
||
Setting ``SO_J1939_ERRQUEUE`` to ``0`` will purge any currently present error
|
||
messages in the error queue. When enabled, error messages can be retrieved
|
||
using the ``recvmsg(2)`` system call.
|
||
|
||
When subscribing to the error queue, the following error events can be
|
||
accessed:
|
||
|
||
- **``J1939_EE_INFO_TX_ABORT``**: Transmission abort errors.
|
||
- **``J1939_EE_INFO_RX_RTS``**: Reception of RTS (Request to Send) control
|
||
frames.
|
||
- **``J1939_EE_INFO_RX_DPO``**: Reception of data packets with Data Page Offset
|
||
(DPO).
|
||
- **``J1939_EE_INFO_RX_ABORT``**: Reception abort errors.
|
||
|
||
The error queue can be used to correlate errors with specific message transfer
|
||
sessions using the session ID (``tskey``). The session ID is assigned via the
|
||
``SOF_TIMESTAMPING_OPT_ID`` flag, which is set by enabling the
|
||
``SO_TIMESTAMPING`` option.
|
||
|
||
If ``SO_J1939_ERRQUEUE`` is activated, the user is required to pull messages
|
||
from the error queue, meaning that using plain ``recv(2)`` is not sufficient
|
||
anymore. The user must use ``recvmsg(2)`` with appropriate flags to handle
|
||
error messages. Failure to do so can result in the socket becoming blocked with
|
||
unprocessed error messages in the queue.
|
||
|
||
It is **recommended** that ``SO_J1939_ERRQUEUE`` be used in combination with
|
||
``SO_TIMESTAMPING`` in most cases. This enables proper error handling along
|
||
with session tracking and timestamping, providing a more detailed analysis of
|
||
message transfers and errors.
|
||
|
||
The acceptable value **size** for this option is ``sizeof(int)``, and the value
|
||
is only differentiated between ``0`` and non-zero. A value of ``0`` disables
|
||
error queue reception and purges any existing error messages, while any
|
||
non-zero value enables it.
|
||
|
||
Example:
|
||
|
||
.. code-block:: c
|
||
|
||
int enable = 1; // Enable error queue reception
|
||
setsockopt(sock, SOL_CAN_J1939, SO_J1939_ERRQUEUE, &enable, sizeof(enable));
|
||
|
||
// Enable timestamping with session tracking via tskey
|
||
int timestamping = SOF_TIMESTAMPING_OPT_ID | SOF_TIMESTAMPING_TX_ACK |
|
||
SOF_TIMESTAMPING_TX_SCHED |
|
||
SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_OPT_CMSG;
|
||
setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, ×tamping,
|
||
sizeof(timestamping));
|
||
|
||
When enabled, error messages can be retrieved using ``recvmsg(2)``. By
|
||
combining ``SO_J1939_ERRQUEUE`` with ``SO_TIMESTAMPING`` (with
|
||
``SOF_TIMESTAMPING_OPT_ID`` and ``SOF_TIMESTAMPING_OPT_CMSG`` enabled), the
|
||
user can track message transfers, retrieve precise timestamps, and correlate
|
||
errors with specific sessions.
|
||
|
||
For more information on enabling timestamps and session tracking, refer to the
|
||
`SO_TIMESTAMPING` section.
|
||
|
||
``SO_TIMESTAMPING``
|
||
~~~~~~~~~~~~~~~~~~~
|
||
|
||
The ``SO_TIMESTAMPING`` option allows the socket to receive timestamps for
|
||
various events related to message transmissions and receptions in J1939. This
|
||
option is often used in combination with ``SO_J1939_ERRQUEUE`` to provide
|
||
detailed diagnostic information, session tracking, and precise timing data for
|
||
message transfers.
|
||
|
||
In J1939, all payloads provided by user space, regardless of size, are
|
||
processed by the kernel as **sessions**. This includes both single-frame
|
||
messages (up to 8 bytes) and multi-frame protocols such as the Transport
|
||
Protocol (TP) and Extended Transport Protocol (ETP). Even for small,
|
||
single-frame messages, the kernel creates a session to manage the transmission
|
||
and reception. The concept of sessions allows the kernel to manage various
|
||
aspects of the protocol, such as reassembling multi-frame messages and tracking
|
||
the status of transmissions.
|
||
|
||
When receiving extended error messages from the error queue, the error
|
||
information is delivered through a `struct sock_extended_err`, accessible via
|
||
the control message (``cmsg``) retrieved using the ``recvmsg(2)`` system call.
|
||
|
||
There are two typical origins for the extended error messages in J1939:
|
||
|
||
1. ``serr->ee_origin == SO_EE_ORIGIN_TIMESTAMPING``:
|
||
|
||
In this case, the `serr->ee_info` field will contain one of the following
|
||
timestamp types:
|
||
|
||
- ``SCM_TSTAMP_SCHED``: This timestamp is valid for Extended Transport
|
||
Protocol (ETP) transfers and simple transfers (8 bytes or less). It
|
||
indicates when a message or set of frames has been scheduled for
|
||
transmission.
|
||
|
||
- For simple transfers (8 bytes or less), it marks the point when the
|
||
message is queued and ready to be sent onto the CAN bus.
|
||
|
||
- For ETP transfers, it is sent after receiving a CTS (Clear to Send)
|
||
frame on the sender side, indicating that a new set of frames has been
|
||
scheduled for transmission.
|
||
|
||
- The Transport Protocol (TP) case is currently not implemented for this
|
||
timestamp.
|
||
|
||
- On the receiver side, the counterpart to this event for ETP is
|
||
represented by the ``J1939_EE_INFO_RX_DPO`` message, which indicates the
|
||
reception of a Data Page Offset (DPO) control frame.
|
||
|
||
- ``SCM_TSTAMP_ACK``: This timestamp indicates the acknowledgment of the
|
||
message or session.
|
||
|
||
- For simple transfers (8 bytes or less), it marks when the message has
|
||
been sent and an echo confirmation has been received from the CAN
|
||
controller, indicating that the frame was transmitted onto the bus.
|
||
|
||
- For multi-frame transfers (TP or ETP), it signifies that the entire
|
||
session has been acknowledged, typically after receiving the End of
|
||
Message Acknowledgment (EOMA) packet.
|
||
|
||
2. ``serr->ee_origin == SO_EE_ORIGIN_LOCAL``:
|
||
|
||
In this case, the `serr->ee_info` field will contain one of the following
|
||
J1939 stack-specific message types:
|
||
|
||
- ``J1939_EE_INFO_TX_ABORT``: This message indicates that the transmission
|
||
of a message or session was aborted. The cause of the abort can come from
|
||
various sources:
|
||
|
||
- **CAN stack failure**: The J1939 stack was unable to pass the frame to
|
||
the CAN framework for transmission.
|
||
|
||
- **Echo failure**: The J1939 stack did not receive an echo confirmation
|
||
from the CAN controller, meaning the frame may not have been successfully
|
||
transmitted to the CAN bus.
|
||
|
||
- **Protocol-level issues**: For multi-frame transfers (TP/ETP), this
|
||
could include protocol-related errors, such as an abort signaled by the
|
||
receiver or a timeout at the protocol level, which causes the session to
|
||
terminate prematurely.
|
||
|
||
- The corresponding error code is stored in ``serr->ee_data``
|
||
(``session->err`` on kernel side), providing additional details about
|
||
the specific reason for the abort.
|
||
|
||
- ``J1939_EE_INFO_RX_RTS``: This message indicates that the J1939 stack has
|
||
received a Request to Send (RTS) control frame, signaling the start of a
|
||
multi-frame transfer using the Transport Protocol (TP) or Extended
|
||
Transport Protocol (ETP).
|
||
|
||
- It informs the receiver that the sender is ready to transmit a
|
||
multi-frame message and includes details about the total message size
|
||
and the number of frames to be sent.
|
||
|
||
- Statistics such as ``J1939_NLA_TOTAL_SIZE``, ``J1939_NLA_PGN``,
|
||
``J1939_NLA_SRC_NAME``, and ``J1939_NLA_DEST_NAME`` are provided along
|
||
with the ``J1939_EE_INFO_RX_RTS`` message, giving detailed information
|
||
about the incoming transfer.
|
||
|
||
- ``J1939_EE_INFO_RX_DPO``: This message indicates that the J1939 stack has
|
||
received a Data Page Offset (DPO) control frame, which is part of the
|
||
Extended Transport Protocol (ETP).
|
||
|
||
- The DPO frame signals the continuation of an ETP multi-frame message by
|
||
indicating the offset position in the data being transferred. It helps
|
||
the receiver manage large data sets by identifying which portion of the
|
||
message is being received.
|
||
|
||
- It is typically paired with a corresponding ``SCM_TSTAMP_SCHED`` event
|
||
on the sender side, which indicates when the next set of frames is
|
||
scheduled for transmission.
|
||
|
||
- This event includes statistics such as ``J1939_NLA_BYTES_ACKED``, which
|
||
tracks the number of bytes acknowledged up to that point in the session.
|
||
|
||
- ``J1939_EE_INFO_RX_ABORT``: This message indicates that the reception of a
|
||
multi-frame message (Transport Protocol or Extended Transport Protocol) has
|
||
been aborted.
|
||
|
||
- The abort can be triggered by protocol-level errors such as timeouts, an
|
||
unexpected frame, or a specific abort request from the sender.
|
||
|
||
- This message signals that the receiver cannot continue processing the
|
||
transfer, and the session is terminated.
|
||
|
||
- The corresponding error code is stored in ``serr->ee_data``
|
||
(``session->err`` on kernel side ), providing further details about the
|
||
reason for the abort, such as protocol violations or timeouts.
|
||
|
||
- After receiving this message, the receiver discards the partially received
|
||
frames, and the multi-frame session is considered incomplete.
|
||
|
||
In both cases, if ``SOF_TIMESTAMPING_OPT_ID`` is enabled, ``serr->ee_data``
|
||
will be set to the session’s unique identifier (``session->tskey``). This
|
||
allows user space to track message transfers by their session identifier across
|
||
multiple frames or stages.
|
||
|
||
In all other cases, ``serr->ee_errno`` will be set to ``ENOMSG``, except for
|
||
the ``J1939_EE_INFO_TX_ABORT`` and ``J1939_EE_INFO_RX_ABORT`` cases, where the
|
||
kernel sets ``serr->ee_data`` to the error stored in ``session->err``. All
|
||
protocol-specific errors are converted to standard kernel error values and
|
||
stored in ``session->err``. These error values are unified across system calls
|
||
and ``serr->ee_errno``. Some of the known error values are described in the
|
||
`Error Codes in the J1939 Stack` section.
|
||
|
||
When the `J1939_EE_INFO_RX_RTS` message is provided, it will include the
|
||
following statistics for multi-frame messages (TP and ETP):
|
||
|
||
- ``J1939_NLA_TOTAL_SIZE``: Total size of the message in the session.
|
||
- ``J1939_NLA_PGN``: Parameter Group Number (PGN) identifying the message type.
|
||
- ``J1939_NLA_SRC_NAME``: 64-bit name of the source ECU.
|
||
- ``J1939_NLA_DEST_NAME``: 64-bit name of the destination ECU.
|
||
- ``J1939_NLA_SRC_ADDR``: 8-bit source address of the sending ECU.
|
||
- ``J1939_NLA_DEST_ADDR``: 8-bit destination address of the receiving ECU.
|
||
|
||
- For other messages (including single-frame messages), only the following
|
||
statistic is included:
|
||
|
||
- ``J1939_NLA_BYTES_ACKED``: Number of bytes successfully acknowledged in the
|
||
session.
|
||
|
||
The key flags for ``SO_TIMESTAMPING`` include:
|
||
|
||
- ``SOF_TIMESTAMPING_OPT_ID``: Enables the use of a unique session identifier
|
||
(``tskey``) for each transfer. This identifier helps track message transfers
|
||
and errors as distinct sessions in user space. When this option is enabled,
|
||
``serr->ee_data`` will be set to ``session->tskey``.
|
||
|
||
- ``SOF_TIMESTAMPING_OPT_CMSG``: Sends timestamp information through control
|
||
messages (``struct scm_timestamping``), allowing the application to retrieve
|
||
timestamps alongside the data.
|
||
|
||
- ``SOF_TIMESTAMPING_TX_SCHED``: Provides the timestamp for when a message is
|
||
scheduled for transmission (``SCM_TSTAMP_SCHED``).
|
||
|
||
- ``SOF_TIMESTAMPING_TX_ACK``: Provides the timestamp for when a message
|
||
transmission is fully acknowledged (``SCM_TSTAMP_ACK``).
|
||
|
||
- ``SOF_TIMESTAMPING_RX_SOFTWARE``: Provides timestamps for reception-related
|
||
events (e.g., ``J1939_EE_INFO_RX_RTS``, ``J1939_EE_INFO_RX_DPO``,
|
||
``J1939_EE_INFO_RX_ABORT``).
|
||
|
||
These flags enable detailed monitoring of message lifecycles, including
|
||
transmission scheduling, acknowledgments, reception timestamps, and gathering
|
||
detailed statistics about the communication session, especially for multi-frame
|
||
payloads like TP and ETP.
|
||
|
||
Example:
|
||
|
||
.. code-block:: c
|
||
|
||
// Enable timestamping with various options, including session tracking and
|
||
// statistics
|
||
int sock_opt = SOF_TIMESTAMPING_OPT_CMSG |
|
||
SOF_TIMESTAMPING_TX_ACK |
|
||
SOF_TIMESTAMPING_TX_SCHED |
|
||
SOF_TIMESTAMPING_OPT_ID |
|
||
SOF_TIMESTAMPING_RX_SOFTWARE;
|
||
|
||
setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &sock_opt, sizeof(sock_opt));
|
||
|
||
|
||
|
||
Dynamic Addressing
|
||
------------------
|
||
|
||
Distinction has to be made between using the claimed address and doing an
|
||
address claim. To use an already claimed address, one has to fill in the
|
||
``j1939.name`` member and provide it to ``bind(2)``. If the name had claimed an address
|
||
earlier, all further messages being sent will use that address. And the
|
||
``j1939.addr`` member will be ignored.
|
||
|
||
An exception on this is PGN 0x0ee00. This is the "Address Claim/Cannot Claim
|
||
Address" message and the kernel will use the ``j1939.addr`` member for that PGN if
|
||
necessary.
|
||
|
||
To claim an address following code example can be used:
|
||
|
||
.. code-block:: C
|
||
|
||
struct sockaddr_can baddr = {
|
||
.can_family = AF_CAN,
|
||
.can_addr.j1939 = {
|
||
.name = name,
|
||
.addr = J1939_IDLE_ADDR,
|
||
.pgn = J1939_NO_PGN, /* to disable bind() rx filter for PGN */
|
||
},
|
||
.can_ifindex = if_nametoindex("can0"),
|
||
};
|
||
|
||
bind(sock, (struct sockaddr *)&baddr, sizeof(baddr));
|
||
|
||
/* for Address Claiming broadcast must be allowed */
|
||
int value = 1;
|
||
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value));
|
||
|
||
/* configured advanced RX filter with PGN needed for Address Claiming */
|
||
const struct j1939_filter filt[] = {
|
||
{
|
||
.pgn = J1939_PGN_ADDRESS_CLAIMED,
|
||
.pgn_mask = J1939_PGN_PDU1_MAX,
|
||
}, {
|
||
.pgn = J1939_PGN_REQUEST,
|
||
.pgn_mask = J1939_PGN_PDU1_MAX,
|
||
}, {
|
||
.pgn = J1939_PGN_ADDRESS_COMMANDED,
|
||
.pgn_mask = J1939_PGN_MAX,
|
||
},
|
||
};
|
||
|
||
setsockopt(sock, SOL_CAN_J1939, SO_J1939_FILTER, &filt, sizeof(filt));
|
||
|
||
uint64_t dat = htole64(name);
|
||
const struct sockaddr_can saddr = {
|
||
.can_family = AF_CAN,
|
||
.can_addr.j1939 = {
|
||
.pgn = J1939_PGN_ADDRESS_CLAIMED,
|
||
.addr = J1939_NO_ADDR,
|
||
},
|
||
};
|
||
|
||
/* Afterwards do a sendto(2) with data set to the NAME (Little Endian). If the
|
||
* NAME provided, does not match the j1939.name provided to bind(2), EPROTO
|
||
* will be returned.
|
||
*/
|
||
sendto(sock, dat, sizeof(dat), 0, (const struct sockaddr *)&saddr, sizeof(saddr));
|
||
|
||
If no-one else contests the address claim within 250ms after transmission, the
|
||
kernel marks the NAME-SA assignment as valid. The valid assignment will be kept
|
||
among other valid NAME-SA assignments. From that point, any socket bound to the
|
||
NAME can send packets.
|
||
|
||
If another ECU claims the address, the kernel will mark the NAME-SA expired.
|
||
No socket bound to the NAME can send packets (other than address claims). To
|
||
claim another address, some socket bound to NAME, must ``bind(2)`` again, but with
|
||
only ``j1939.addr`` changed to the new SA, and must then send a valid address claim
|
||
packet. This restarts the state machine in the kernel (and any other
|
||
participant on the bus) for this NAME.
|
||
|
||
``can-utils`` also include the ``j1939acd`` tool, so it can be used as code example or as
|
||
default Address Claiming daemon.
|
||
|
||
Send Examples
|
||
-------------
|
||
|
||
Static Addressing
|
||
^^^^^^^^^^^^^^^^^
|
||
|
||
This example will send a PGN (0x12300) from SA 0x20 to DA 0x30.
|
||
|
||
Bind:
|
||
|
||
.. code-block:: C
|
||
|
||
struct sockaddr_can baddr = {
|
||
.can_family = AF_CAN,
|
||
.can_addr.j1939 = {
|
||
.name = J1939_NO_NAME,
|
||
.addr = 0x20,
|
||
.pgn = J1939_NO_PGN,
|
||
},
|
||
.can_ifindex = if_nametoindex("can0"),
|
||
};
|
||
|
||
bind(sock, (struct sockaddr *)&baddr, sizeof(baddr));
|
||
|
||
Now, the socket 'sock' is bound to the SA 0x20. Since no ``connect(2)`` was called,
|
||
at this point we can use only ``sendto(2)`` or ``sendmsg(2)``.
|
||
|
||
Send:
|
||
|
||
.. code-block:: C
|
||
|
||
const struct sockaddr_can saddr = {
|
||
.can_family = AF_CAN,
|
||
.can_addr.j1939 = {
|
||
.name = J1939_NO_NAME;
|
||
.addr = 0x30,
|
||
.pgn = 0x12300,
|
||
},
|
||
};
|
||
|
||
sendto(sock, dat, sizeof(dat), 0, (const struct sockaddr *)&saddr, sizeof(saddr));
|
||
|
||
|
||
Error Codes in the J1939 Stack
|
||
------------------------------
|
||
|
||
This section lists all potential kernel error codes that can be exposed to user
|
||
space when interacting with the J1939 stack. It includes both standard error
|
||
codes and those derived from protocol-specific abort codes.
|
||
|
||
- ``EAGAIN``: Operation would block; retry may succeed. One common reason is
|
||
that an active TP or ETP session exists, and an attempt was made to start a
|
||
new overlapping TP or ETP session between the same peers.
|
||
|
||
- ``ENETDOWN``: Network is down. This occurs when the CAN interface is switched
|
||
to the "down" state.
|
||
|
||
- ``ENOBUFS``: No buffer space available. This error occurs when the CAN
|
||
interface's transmit (TX) queue is full, and no more messages can be queued.
|
||
|
||
- ``EOVERFLOW``: Value too large for defined data type. In J1939, this can
|
||
happen if the requested data lies outside of the queued buffer. For example,
|
||
if a CTS (Clear to Send) requests an offset not available in the kernel buffer
|
||
because user space did not provide enough data.
|
||
|
||
- ``EBUSY``: Device or resource is busy. For example, this occurs if an
|
||
identical session is already active and the stack is unable to recover from
|
||
the condition.
|
||
|
||
- ``EACCES``: Permission denied. This error can occur, for example, when
|
||
attempting to send broadcast messages, but the socket is not configured with
|
||
``SO_BROADCAST``.
|
||
|
||
- ``EADDRNOTAVAIL``: Address not available. This error occurs in cases such as:
|
||
|
||
- When attempting to use ``getsockname(2)`` to retrieve the peer's address,
|
||
but the socket is not connected.
|
||
|
||
- When trying to send data to or from a NAME, but address claiming for the
|
||
NAME was not performed or detected by the stack.
|
||
|
||
- ``EBADFD``: File descriptor in bad state. This error can occur if:
|
||
|
||
- Attempting to send data to an unbound socket.
|
||
|
||
- The socket is bound but has no source name, and the source address is
|
||
``J1939_NO_ADDR``.
|
||
|
||
- The ``can_ifindex`` is incorrect.
|
||
|
||
- ``EFAULT``: Bad address. Occurs mostly when the stack can't copy from or to a
|
||
sockptr, when there is insufficient data from user space, or when the buffer
|
||
provided by user space is not large enough for the requested data.
|
||
|
||
- ``EINTR``: A signal occurred before any data was transmitted; see ``signal(7)``.
|
||
|
||
- ``EINVAL``: Invalid argument passed. For example:
|
||
|
||
- ``msg->msg_namelen`` is less than ``J1939_MIN_NAMELEN``.
|
||
|
||
- ``addr->can_family`` is not equal to ``AF_CAN``.
|
||
|
||
- An incorrect PGN was provided.
|
||
|
||
- ``ENODEV``: No such device. This happens when the CAN network device cannot
|
||
be found for the provided ``can_ifindex`` or if ``can_ifindex`` is 0.
|
||
|
||
- ``ENOMEM``: Out of memory. Typically related to issues with memory allocation
|
||
in the stack.
|
||
|
||
- ``ENOPROTOOPT``: Protocol not available. This can occur when using
|
||
``getsockopt(2)`` or ``setsockopt(2)`` if the requested socket option is not
|
||
available.
|
||
|
||
- ``EDESTADDRREQ``: Destination address required. This error occurs:
|
||
|
||
- In the case of ``connect(2)``, if the ``struct sockaddr *uaddr`` is ``NULL``.
|
||
|
||
- In the case of ``send*(2)``, if there is an attempt to send an ETP message
|
||
to a broadcast address.
|
||
|
||
- ``EDOM``: Argument out of domain. This error may happen if attempting to send
|
||
a TP or ETP message to a PGN that is reserved for control PGNs for TP or ETP
|
||
operations.
|
||
|
||
- ``EIO``: I/O error. This can occur if the amount of data provided to the
|
||
socket for a TP or ETP session does not match the announced amount of data for
|
||
the session.
|
||
|
||
- ``ENOENT``: No such file or directory. This can happen when the stack
|
||
attempts to transfer CTS or EOMA but cannot find a matching receiving socket
|
||
anymore.
|
||
|
||
- ``ENOIOCTLCMD``: No ioctls are available for the socket layer.
|
||
|
||
- ``EPERM``: Operation not permitted. For example, this can occur if a
|
||
requested action requires ``CAP_NET_ADMIN`` privileges.
|
||
|
||
- ``ENETUNREACH``: Network unreachable. Most likely, this occurs when frames
|
||
cannot be transmitted to the CAN bus.
|
||
|
||
- ``ETIME``: Timer expired. This can happen if a timeout occurs while
|
||
attempting to send a simple message, for example, when an echo message from
|
||
the controller is not received.
|
||
|
||
- ``EPROTO``: Protocol error.
|
||
|
||
- Used for various protocol-level errors in J1939, including:
|
||
|
||
- Duplicate sequence number.
|
||
|
||
- Unexpected EDPO or ECTS packet.
|
||
|
||
- Invalid PGN or offset in EDPO/ECTS.
|
||
|
||
- Number of EDPO packets exceeded CTS allowance.
|
||
|
||
- Any other protocol-level error.
|
||
|
||
- ``EMSGSIZE``: Message too long.
|
||
|
||
- ``ENOMSG``: No message available.
|
||
|
||
- ``EALREADY``: The ECU is already engaged in one or more connection-managed
|
||
sessions and cannot support another.
|
||
|
||
- ``EHOSTUNREACH``: A timeout occurred, and the session was aborted.
|
||
|
||
- ``EBADMSG``: CTS (Clear to Send) messages were received during an active data
|
||
transfer, causing an abort.
|
||
|
||
- ``ENOTRECOVERABLE``: The maximum retransmission request limit was reached,
|
||
and the session cannot recover.
|
||
|
||
- ``ENOTCONN``: An unexpected data transfer packet was received.
|
||
|
||
- ``EILSEQ``: A bad sequence number was received, and the software could not
|
||
recover.
|
||
|