linux-can / can-utils

Linux-CAN / SocketCAN user space applications
2.39k stars 711 forks source link

CAN-J1939 documentation #164

Open josemic opened 4 years ago

josemic commented 4 years ago

I am currently enhacing the open source socketCAN test port for the eclipse titan ttcn compiler with j1939 support. (TTCN is a protocol testing language used in the telecummunication industry and is very well suited for testing j1939 and isobus.). elinux.org/TTCN Here I read the documentation and still have questions. These questions I collect in this issue in order to fix the j1939 documentation (can-j1939-kickstart.md and can-j1939.md kernel Documentation/networking/j1939.rst).

1)

int j1939_promisc = 1; // value range 0=deactivate??, 1= activate
res = setsockopt(sock, SOL_CAN_J1939, SO_J1939_PROMISC, &j1939_promisc, sizeof(j1939_promisc));
if (res < 0)
            error(1, errno, "setsockopt j1939_promisc %u", j1939_promisc);  

Question: Can promicous mode be deactivated with j1939_promisc = 0

2)

int j1939_prio = 1; // value range: 0..7
res = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO, &j1939_prio, sizeof(j1939_prio));
if (res < 0)
            error(1, errno, "setsockopt j1939_send_prio %u", j1939_prio);   

Question: Here I can set the priority for the socket. What is the default value?

3)

int pkt_len // value range: ????
res = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, pkt_len, sizeof(pkt_len));
if (res < 0)
            error(1, errno, "setsockopt rcvbuf %u", pkt_len);

Question: What is the purpose of setting the receive buffer? Isobus as far as I know supports extended transport protocol with (2²⁴-1)*7= 117440505 Bytes How do I send and receive such long packages?

4)

int val = 1; // value range: 1
res = setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &val, sizeof(val));
if (res < 0)
            error(1, errno, "setsockopt timestamp");

Question:

5)

const char *device;
res = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device));
if (res < 0)
        err(1, "bindtodevice %s", device);

Question:

marckleinebudde commented 4 years ago

Can promicous mode be deactivated with j1939_promisc = 0

Yes

marckleinebudde commented 4 years ago

Here I can set the priority for the socket.

Yes

What is the default value?

6, see https://elixir.bootlin.com/linux/v5.4/source/net/can/j1939/socket.c#L391

marckleinebudde commented 4 years ago

What is the purpose of setting the receive buffer?

Usually, you set the max size of RX data that could be on the fly in the socket. But I think the j1939 stack currently ignores this value.

Isobus as far as I know supports extended transport protocol with (2²⁴-1)*7= 117440505 Bytes

yes

How do I send and receive such long packages?

Just use the normal read()/write() send()/recv() and similar functions. However when sending you have to check the return value. If the functions returns less bytes than you have tried to send initially, you have to send the remaining bytes.

marckleinebudde commented 4 years ago

What is a device? Is this "vcan0"?

The device is the CAN interface you want to use. vcan0 is usually the name of the first virtual CAN interface you have created.

What is the purpose of SO_BINDTODEVICE?

It's obsolete. See https://github.com/linux-can/can-utils/pull/180

What is the difference between bind & setsockopt(..,SO_BINDTODEVICE,..)?

bind() is mandatory, SO_BINDTODEVICE is obsolete.

olerem commented 4 years ago

What is the result of setting the timestamp?

If timestamps are enabled, kernel will add additional information to skbs. With this information you can get status of current session. For example on sending long ETP session you will a message over MSG_ERRQUEUE for each transferred and confirmed TP-sized block. Please see jcat.c for examples.

How is the timestamp read?

You need to use recvmsg() with MSG_ERRQUEUE flag set. This example can be take from jcat.c as well.

josemic commented 4 years ago

From #182:

A (E)TP message contains the total size in the fist packet. This is why you have to call send() with total size of your message. Callingsend() with the remaining bytes, doesn't start a new message, the data is queued for the current running message transfer.

However, there is currently no way to abort the currently transferred message.

Note: there are certain limitations to the j1939 (E)TP, you can only have one TP and one ETP transfer ongoing between two ECUs. A j1939 CAN frame is identified by src dst and pgn. TP uses two pgns, while ETP uses another pair.

This needs to be documented.

marckleinebudde commented 4 years ago

Feel free to send a patch against the linux kernel or the j1939 quickstart.

josemic commented 4 years ago

Note: there are certain limitations to the j1939 (E)TP, you can only have one TP and one ETP transfer ongoing between two ECUs. A j1939 CAN frame is identified by src dst and pgn. TP uses two pgns, while ETP uses another pair.

  1. Is this an (E)TP limitation in the specification of the standards or is this a limitation of the j1939 (E)TP implementation in the linux kernel?
  2. What happens if there is a currently ongoing (E)TP transfer and a new transfer is started. During tests I did not notice any problems.
josemic commented 4 years ago

@marckleinebudde:

Feel free to send a patch against the linux kernel ...

What is the best way to send a patch against the linux kernel? The linux kernel torvalds/linux does not accept pull requests. Shall I create issues and pull requests in linux-can/linux?

josemic commented 4 years ago

@olerem :

What is the result of setting the timestamp?

If timestamps are enabled, kernel will add additional information to skbs. With this information you can get status of current session. For example on sending long ETP session you will a message over MSG_ERRQUEUE for each transferred and confirmed TP-sized block. Please see jcat.c for examples.

How is the timestamp read?

You need to use recvmsg() with MSG_ERRQUEUE flag set. This example can be take from jcat.c as well.

I am a little clueless with this example in j1939cat.c and in Linux/documentation/networking:

.. 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;
    }
}

Could you extend it with recvmsg-call and with getting the priority and the timestamp including MSG_ERRQUEUE? So we can update the documentation?

marckleinebudde commented 4 years ago

Note: there are certain limitations to the j1939 (E)TP, you can only have one TP and one ETP transfer ongoing between two ECUs. A j1939 CAN frame is identified by src dst and pgn. TP uses two pgns, while ETP uses another pair.

1. Is this an (E)TP limitation in the specification of the standards or is this a limitation of the j1939 (E)TP implementation in the linux kernel?

It's a limitation by the standard.

2. What happens if there is a currently ongoing (E)TP transfer and a new transfer is started. During tests I did not notice any problems.

I think @olerem can answer this.

marckleinebudde commented 4 years ago

@marckleinebudde:

Feel free to send a patch against the linux kernel ...

What is the best way to send a patch against the linux kernel?

Send a patch to the "linux-can@vger.kernel.org" mailing list. Use git send-mail for this.

The linux kernel torvalds/linux does not accept pull requests.

ACK

Shall I create issues and pull requests in linux-can/linux?

Preferred way is sending a patch to the mailing list. But if this is too complicated, send a pull request against https://github.com/linux-can/linux/. Please be sure that you use you real name as the author of the patch and have Signed-off-by in the patch description. The Signed-off-by can be created with git commit -s. For details see https://github.com/torvalds/linux/blob/master/Documentation/process/submitting-patches.rst#developers-certificate-of-origin-11

josemic commented 4 years ago

@marckleinebudde : I have tried to fork on github https://github.com/linux-can/linux/ however that was not possible, as I had already forked torvalds/linux. I have now created a first trival patch (patch-1), however I can not create a pull request against linux-can/linux, it is only possible to create a pull request against repository torvalds/linux or my repository. https://github.com/josemic/linux/branches. What shall I do? Here is the pull request: https://github.com/josemic/linux/pull/1

marckleinebudde commented 4 years ago

I can pull from your repo directly if you want. Please add a patch description, as mainline will only take patches with proper description. In this case something like:

Change name of jacd to j1939acd, as it been renames in the can-utils repo, to avoid name collisions.

josemic commented 4 years ago

@marckleinebudde : Please review patch-1 to patch-4 in josemic/linux repository. Do you need further changes of commit messages?

josemic commented 4 years ago

The documentation does not describe how to get the currently used Source Address via the socket interface, when using e.g. j1939acd. The Linux can j1939 implementation encapsualtes this nicely, however in the Isobus software does use the SA e.g. to determine the currently active working set master, when sending a vtStatusReq message as broadcast. Thus the receiver needs to know, it's current SA. One way I could imagine to handle this, is not to use the capsualted j1939acd-interface, but to implement something own, which provides an external interface.

olerem commented 4 years ago

@josemic , currently it is not implemented. Kernel interface can be potentially extended to dump all, or translate on request NAME to Address. As long as it is not done, this should be done in user space by extending j1939acd or implementing this functionality in own application. Suddenly I can't spend enough time on this stack. The situation can be changed if we will get some customer who has interest on it.

josemic commented 4 years ago

@olerem, a Kernel interface to translate a NAME to its current address, would be fine. Until that happens, I could rewrite the j1939acd in TTCN and extend it with an interface to querry the current address of the name.