[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20110427090011.GE757@kurt.e-circ.dyndns.org>
Date: Wed, 27 Apr 2011 11:00:11 +0200
From: Kurt Van Dijck <kurt.van.dijck@....be>
To: socketcan-core@...ts.berlios.de, netdev@...r.kernel.org
Subject: [PATCH v4 4/5] can-j1939: add documentation
Add documentation of the SAE J1939 protocol stack
Signed-off-by: Kurt Van Dijck <kurt.van.dijck@....be>
---
Documentation/networking/j1939.txt | 576 ++++++++++++++++++++++++++++++++++++
MAINTAINERS | 8 +
2 files changed, 584 insertions(+), 0 deletions(-)
create mode 100644 Documentation/networking/j1939.txt
diff --git a/Documentation/networking/j1939.txt b/Documentation/networking/j1939.txt
new file mode 100644
index 0000000..ef0a963
--- /dev/null
+++ b/Documentation/networking/j1939.txt
@@ -0,0 +1,576 @@
+============================================================================
+
+j1939.txt
+
+Readme file for the J1939 Protocol
+
+This file contains
+
+ 1 Overview / What is j1939
+ 1.1 specifications used
+
+ 2 Motivation
+
+ 3 J1939 concepts
+ 3.1 socket type
+ 3.2 addressing
+ 3.3 priority
+ 3.4 PGN
+ 3.5 filtering
+ 3.6 destinations with dynamic address
+
+ 4 How to use J1939
+ 4.1 rtnetlink interface
+ 4.2 API calls
+ 4.2.1 Message flags during sendmsg
+ 4.2.2 SCM_J1939_DEST_ADDR & SCM_J1939_DEST_NAME
+ 4.2.3 SCM_J1939_PRIORITY
+ 4.3 Dynamic addressing
+ 4.4 Send Examples
+ 4.4.1 Static address
+ 4.4.2 Dynamic address
+ 4.4.3 Mixed mode
+
+ 5 socket options
+ 5.1 SO_J1939_FILTER
+ 5.2 SO_J1939_PROMISC
+ 5.3 SO_J1939_RECV_OWN
+ 5.4 SO_J1939_SEND_PRIO
+
+ 6 can-j1939 procfs interface
+ 6.1 /proc/net/can-j1939/ecu
+ 6.2 /proc/net/can-j1939/filter
+ 6.3 /proc/net/can-j1939/sock
+ 6.4 /proc/net/can-j1939/transport
+
+ 7 can-j1939 SYSCTL
+ 7.1 /proc/sys/net/can-j1939/transport_max_payload_in_bytes
+ 7.2 /proc/sys/net/can-j1939/transport_cts_nr_of_frames
+ 7.3 /proc/sys/net/can-j1939/transport_tx_retry_ms
+
+ 8 Credits
+
+============================================================================
+
+1. Introduction
+--------------------------------
+
+ 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 exists, which differ from the
+ original j1939 on the application level, like MilCAN, 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 inclusion results in a maximum packet size of
+ ((2^24)-1)*7 bytes
+
+
+1.1 specifications used
+
+ SAE J1939-21 : data link layer
+ SAE J1939-81 : network management
+ ISO 11783-6 : Virtual Terminal (Extended Transport Protocol)
+
+
+2. 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 1 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 1 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 these
+ functionality in the kernel eliminates this functionality as a requirement
+ for _every_ userspace process that communicates via J1939. This results in
+ a consistent J1939 bus with proper addressing.
+
+ * transport:
+ Both TP & ETP reuse some PGN's to relay big packets over them. Different
+ processes may thus use the same TP & ETP PGN's without actually knowing it.
+ The individual TP & ETP sessions _must_ be serialized (synchronised)
+ between different processes. The kernel solves this problem properly, and
+ eliminates the serialisation (synchronisation) as a requirement for
+ _every_ userspace 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 userspace.
+
+ The j1939 sockets operate on CAN network devices (see SocketCAN). Any j1939
+ userspace 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 2 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.
+
+
+3. J1939 concepts
+--------------------------------
+
+3.1 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 userspace 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 apropriate bits of the identifier by the kernel.
+
+
+3.2 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 forseen
+ in the kernel. In J1939 any ECU is known by it's 64-bit NAME. At the moment
+ of succesfull 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 soon after
+ reception.
+
+ Mixed mode packets (from a static to a dynamic address or vice versa) are
+ allowed. The BSD sockets define seperate API calls for getting/setting the
+ local & remote address and are applicable for J1939 sockets.
+
+
+3.3 Filtering
+
+ Similar to SocketCAN, j1939 defines filters per socket that a user can set
+ in order to receive a subset of the j1939 traffic. Filtering can base on
+ * SA
+ * NAME
+ * PGN
+
+ There is a semantic difference with SocketCAN with regard to filtering.
+ 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.
+ The rationale behind this difference originates in the filter capabilities.
+ Where SocketCAN filters on only 1 orthogonal (can id), J1939 can filter
+ on 3 orthogonal properties (sa, name, pgn).
+
+ When a filter on the SA is set, j1939 traffic with a matching SA, but with
+ its NAME set (aka having claimed SA successfully) will match, although
+ the filter would not match its NAME.
+
+ Filtering on priority is _not_ supported.
+
+
+4. How to use J1939
+--------------------------------
+
+4.1 rtnetlink interface
+
+ Per default j1939 is not active. Specifying can_ifindex != 0 in bind(2)
+ or connect(2) needs an active j1939 on that interface. You must have done
+ $ ip link set canX j1939 on
+ on that interface.
+
+ $ ip link set canX j1939 down
+ disables j1939 on canX.
+
+ Assigning addresses is done via
+ $ ip addr add dev canX j1939 0xXX
+ statically or
+ $ ip addr add dev canX j1939 name 0xXX
+ dynamically. In the latter case, address claiming must take place
+ before other traffic can leave.
+
+ Removing addresses is done similarly via
+ $ ip addr del dev canX j1939 0xXX
+ $ ip addr del dev canX j1939 name 0xXX
+
+ A static address cannot be assigned together with a 64bit name.
+
+4.2 API calls
+
+ Like TCP/IP and CAN, you first need to open a socket for communicating over a
+ CAN network. To use j1939, include <include/linux/j1939.h>. From there,
+ <include/linux/can.h> will be included too.
+ To open a socket, you would write
+
+ 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 never appropriate.
+
+ 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
+ (which is different from TCP/IP due to different addressing) 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 succeeded. bind(2) assigns a local
+ address to a socket. For this to succeed, you can only choose addresses
+ that have been assigned earlier (see 4.1). When an empty address is assigned
+ (ie. SA=0xff && name=0), a default is taken for the device that is bound to.
+
+ 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:
+ struct sockaddr_can {
+ sa_family_t can_family;
+ int can_ifindex;
+ union {
+ struct {
+ __u64 name;
+ __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 source address.
+
+ When sending data, the source address is applied as follows: If
+ can_addr.j1939.name != 0 the NAME is looked up by the kernel and the
+ corresponding Source Address is used. If can_addr.j1939.name == 0,
+ can_addr.j1939.addr is used.
+
+ After a bind(2), the local address is assigned, i.e. the source address.
+ After a connect(2), the remote address is assigned, i.e. the destination
+ address.
+
+ Both write(2) and send(2) will send a packet with local address from bind,
+ remote address from connect(2). When the address was not set, a broadcast is
+ sent. The PGN is used from bind(2) or overruled with sendto(2), which will
+ override the destination address when valid, and the PGN when valid.
+
+ Both read(2) and recv(2) will receive packets matching the sockets filters.
+ recvfrom(2) will receive these packets with originator's address.
+
+ When creating a socket, reasonable defaults have been set. Some options can be
+ modified with setsockopt(2) & getsockopt(2).
+
+4.2.1 Message flags during sendmsg
+
+ send(2), sendto(2) and sendmsg(2) take a 'flags' argument. J1939 interpretes
+ these flags during outgoing traffic:
+
+ * MSG_DONTWAIT determines nonblocking operation. When a packet must wait for
+ any reason, -EAGAIN is returned.
+
+ * MSG_SYN
+ Packets flagged with MSG_SYN will wait for all pending packets on a socket
+ to be sent before trying to send. This means that if a socket just started
+ a Transport Protocol session, a packet with MSG_SYN will wait for that
+ session to complete before proceeding.
+ Traffic without MSG_SYN (on that very same socket) will still continue.
+
+4.2.2 SCM_J1939_DEST_ADDR & SCM_J1939_DEST_NAME
+
+ Different received j1939 packets could have had different destionations:
+ - broadcast packet, i.e. no destination address
+ - destination address that matches the sockets local address
+ - destination address that matches _a_ local address on the system, and the
+ socket had no local address defined.
+ - SO_J1939_PROMISC was set
+
+ The destination address & destination name (if applicable) are attached
+ to the msghdr in the recvmsg(2) call. It can be extracted using cmsg(3) macros,
+ with cmsg_level == SOL_J1939 && cmsg_type == SCM_J1939_DEST_ADDR
+ or SCM_J1939_DEST_NAME. The returned data is a uint8_t/uint64_t.
+
+4.2.3 SCM_J1939_PRIORITY
+
+ Attached to the msghdr is also the packet's priority on the bus. This is a
+ uint8_t, packed as cmsg_type == SCM_J1939_PRIORITY.
+
+4.3 Dynamic Addressing
+
+ Distinction has to be made in and 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 PGN's 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 when the kernel will use the j1939.addr member for that
+ pgn if necessary.
+
+ To claim an address, bind(2) with:
+ j1939.pgn set to 0x0ee00
+ j1939.addr set to the desired Source Address.
+ j1939.name set to the NAME you want the Source Address to claim to.
+
+ Afterwards do a write(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. One might use sendto(2) also to send the Addres Claim. In
+ that case, the j1939.addr member must be set to the broadcast address (255)
+ and the j1939.pgn must be set to 0x0ee00. If This combination is not given,
+ EPROTO is returned.
+
+ If no-one else contest 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.
+
+
+4.4 Send Examples
+
+4.4.1 Static addressing
+
+ This example will send a pgn (0x12300) from SA 0x20 to DA 0x30.
+
+ Add the address to the system:
+ $ ip addr add j1939 0x20 dev can0
+
+ Bind:
+ struct sockaddr_can addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.can_ifindex = ifindex("can0"); // ifindex is a substitute.
+ addr.can_addr.j1939.name = J1939_NO_NAME;
+ addr.can_addr.j1939.addr = 0x20;
+ addr.can_addr.j1939.pgn = J1939_NO_PGN;
+
+ bind(sk, (void *)&addr, sizeof(addr));
+
+ Now, the socket 'sk' is bound to the address 0x20. Since no pgn
+ was specified during bound, a pgn will be necessary during sendto() operations.
+ Alternatively, specifying addr.can_addr.j1939.pgn during bind() allows
+ for using send() & write(), since a default pgn (the pgn specified during bind())
+ can be used then.
+
+ Send:
+ struct sockaddr_can addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.can_addr.j1939.name = J1939_NO_NAME;
+ addr.can_addr.j1939.addr = 0x30;
+ addr.can_addr.j1939.pgn = 0x12300;
+ // addr.can_ifindex is not necessary here.
+
+ sendto(sk, data, sizeof(data), 0, (void *)&addr, sizeof(addr));
+
+4.4.2 Dynamic addressing
+
+ This example will send a pgn (0x12300) from 12345678 to 9ABCDEF
+
+ Add the name to the system:
+ $ ip addr add j1939 name 12345678 dev can0
+
+ Start an address claiming daemon (e.g. jacd)
+ $ jacd -r 0x20-0x30 12345678 can0 &
+
+ Bind:
+ struct sockaddr_can addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.can_ifindex = ifindex("can0"); // ifindex is a substitute.
+ addr.can_addr.j1939.name = 0x12345678ULL;
+ addr.can_addr.j1939.addr = J1939_NO_ADDR;
+ addr.can_addr.j1939.pgn = J1939_NO_PGN;
+
+ bind(sk, (void *)&addr, sizeof(addr));
+
+ Send:
+ struct sockaddr_can addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.can_addr.j1939.name = 0x9ABCDEFULL;
+ addr.can_addr.j1939. = J1939_NO_ADDR;
+ addr.can_addr.j1939.pgn = 0x12300;
+
+ sendto(sk, data, sizeof(data), 0, (void *)&addr, sizeof(addr));
+
+4.4.3 Mixed mode
+
+ A scenario that sends a packet from a static address to a dynamic address
+ or vice versa is called 'mixed mode' here.
+
+ Combining the setup of the static address with a sendto() to a dynamic
+ address from the above examples is legal, and implements such mixed mode
+ addressing. The same applies for the setup of the dynamic address combined
+ with the sendto() towards a dynamic address.
+
+
+5 Socket Options
+--------------------------------
+
+ j1939 sockets have some options that are configurable via setsockopt(2).
+ Each of those options is initialized with a reasonable default.
+
+
+5.1 SO_J1939_FILTER
+
+ As mentioned above, J1939 supports filtering in both NAME, Source Address
+ and PGN. All members must match.
+
+ struct j1939_filter filter = {
+ .name = ...
+ .name_mask = ...
+ .addr = ...
+ .addr_mask = ...
+ .pgn = ...
+ .pgn_mask = ...
+ }
+
+ setsockopt(s, SOL_CAN_J1939, SO_J1939_FILTER, &filter, sizeof(filter));
+
+
+5.2 SO_J1939_PROMISC
+
+ When set, j1939 will receive all packets, not just those with a destination
+ on the local system.
+ default off.
+
+ int promisc = 1; /* 0 = disabled (default), 1 = enabled */
+
+ setsockopt(s, SOL_CAN_J1939, SO_J1939_PROMISC, &promisc, sizeof(promisc));
+
+
+5.3 SO_J1939_RECV_OWN
+
+ All the sent j1939 packets are looped back in the system.
+ The reception of the j1939 packets on the same socket that was
+ sending the j1939 packet is assumed to be unwanted and therefore
+ disabled by default. This default behaviour may be changed on
+ demand:
+
+ int recv_own_msgs = 1; /* 0 = disabled (default), 1 = enabled */
+
+ setsockopt(s, SOL_CAN_J1939, SO_J1939_RECV_OWN,
+ &recv_own_msgs, sizeof(recv_own_msgs));
+
+
+5.4 SO_J1939_SEND_PRIO
+
+ To set the priority field for outgoing packets, the SO_J1939_SEND_PRIO can
+ be changed. This int field specifies the priority that will be used.
+ j1939 defines a priority between 0 and 7 inclusive,
+ with 7 the lowest priority.
+ Per default, the priority is set to 6 (conforming J1939).
+ This priority socket option operates on the same value that is modified
+ with
+
+ setsockopt(s, SOL_SOCKET, SO_PRIORITY, &pri, sizeof(pri))
+
+ socketoption, with a difference that SOL_SOCKET/SO_PRIORITY is defined with
+ 0 the lowest priority. SOL_CAN_J1939/SO_J1939_SEND_PRIO inverts this value
+ for you.
+
+
+6. /proc/net/can-j1939 Interface.
+--------------------------------
+
+ Files giving you a view on the in-kernel operation of J1939 are located at:
+ /proc/net/j1939.
+
+6.1 /proc/net/can-j1939/ecu
+
+ This file gives an overview of the known ECU's to the kernel.
+ - iface : network interface they operate on.
+ - SA : current address.
+ - name : 64bit NAME
+ - flags : 'L' = local, 'R' = remote
+
+6.2 /proc/net/can-j1939/filter
+
+6.3 /proc/net/can-j1939/sock
+
+ This file gives a list of all j1939 sockets currently open.
+ - iface : network interface
+ - flags :
+ 'b' : bound
+ 'c' : connected
+ 'P' : PROMISC
+ 'o' : RECV_OWN
+ 'd' : RECV_DEST
+ 'p' : RECV_PRIO
+ - local: [NAME],SA
+ - remote: [NAME]/MASK,DA
+ - pgn : PGN
+ - prio : priority
+ - pending : # packets pending (see MSG_SYN on 4.2.1)
+
+6.4 /proc/net/can-j1939/transport
+
+ This file shows a list of pending transport sessions
+ - iface
+ - src : XX (addr) or XXXXXXXXXXXXXXXX (name)
+ - dst : XX or XXXXXXXXXXXXXXXX or '-' (broadcast)
+ - pgn :
+ - done/total : current # transferred bytes / total
+
+
+7. /proc/sys/net/can-j1939 - SYSCTL
+--------------------------------
+
+ Via these sysctl files, some parameters of the j1939 module can be tuned.
+
+7.1 /proc/sys/net/can-j1939/transport_max_payload_in_bytes [int]
+
+ Is the maximum packet size to accept on both transmit & receive side.
+ Bigger packets will be rejected (local sender), aborted (local receiver)
+ or ignored (broadcasts & remote recievers in PROMISC).
+
+7.2 /proc/sys/net/can-j1939/transport_cts_nr_frames [int]
+
+ Controls the number of packets to allow between consecutive CTS frames
+ (default 255).
+ This number is communicated within the CTS frame from receiver to transmitter.
+ Setting this has effect on received transport sessions only.
+
+7.3 /proc/sys/net/can-j1939/transport_tx_retry_ms [int]
+
+ Controls how many time to wait before retrying to send an individual TP
+ flow or data packet after transmission failure (default 20).
+
+
+8. Credits
+--------------------------------
+
+ Kurt Van Dijck (j1939 core, transport protocol, API)
+ Pieter Beyens (j1939 core, address claiming)
+
diff --git a/MAINTAINERS b/MAINTAINERS
index b5266ad..ec7b016 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1648,6 +1648,14 @@ F: include/linux/can/error.h
F: include/linux/can/netlink.h
F: include/linux/can/platform/
+CAN-J1939 NETWORK LAYER
+M: Kurt Van Dijck <kurt.van.dijck@....be>
+L: socketcan-core@...ts.berlios.de
+L: netdev@...r.kernel.org
+S: Maintained
+F: net/can/j1939/
+F: include/linux/can/j1939.h
+
CELL BROADBAND ENGINE ARCHITECTURE
M: Arnd Bergmann <arnd@...db.de>
L: linuxppc-dev@...ts.ozlabs.org
--
1.7.2.5
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists