| .. 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 is 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 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 |
| ============== |
| |
| PGN |
| --- |
| |
| The PGN (Parameter Group Number) is a number to identify a packet. The PGN |
| is composed as follows: |
| 1 bit : Reserved Bit |
| 1 bit : Data Page |
| 8 bits : PF (PDU Format) |
| 8 bits : PS (PDU Specific) |
| |
| In J1939-21 distinction is made between PDU1 format (where PF < 240) and PDU2 |
| format (where PF >= 240). Furthermore, when using 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. |
| |
| 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 visa versa) and PDU2 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 it's 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 send, |
| without it's 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; |
| } |
| } |
| |
| 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 jacd 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; |
| .pgn = 0x30, |
| .addr = 0x12300, |
| }, |
| }; |
| |
| sendto(sock, dat, sizeof(dat), 0, (const struct sockaddr *)&saddr, sizeof(saddr)); |