linux-can / can-utils

Linux-CAN / SocketCAN user space applications
2.36k stars 708 forks source link

Not really an issue: Workflow of TP -> incorrect PGN response in CM-Message #288

Open TSsimon opened 3 years ago

TSsimon commented 3 years ago

Hello everyone,

i got a quesition about the workflow of the J1939 TP. I'm about writing a script which is automatically responding a message > 8 Bytes after reading the 0xEA00 (RequestPGN). If i read the J1939 Documentation correctly the Request-PGN must have the requested PGN in the data-field.

So if responding some dummy data with "sendto" the TP seems to work correctly but the connection management message doesn't contain the requested PGN

Skript flow: 1) Initalize struct sockaddr_can (sockname/peername) 2) open socket 3) setsockopt(->Broadcast) 4) bind(->sockname) 5) Recvfrom() IF PGN==0xEA00 read requested pgn close(sock) 5.5 generate dummy data

6) Reinitalize struct sockaddr_can (sockname/peername) 7) open socket 8) setsockopt(->Broadcast) 9) bind(->sockname) 10) sendto( dummy-Data)

My questions: why the CM-Message doesn't contain the requested PGN? why the CM-Message was sended three times?

source-code:

`

    sockname.can_ifindex = 4;
    sockname.can_addr.j1939.addr = 0x00;
    sockname.can_addr.j1939.pgn = J1939_NO_PGN;
    sockname.can_addr.j1939.name = J1939_NO_NAME;

    peername.can_ifindex = 4;
    peername.can_addr.j1939.addr = 0x00;
    peername.can_addr.j1939.pgn = J1939_NO_PGN;
    peername.can_addr.j1939.name = J1939_NO_NAME;

    /*SOCKET OPEN*/
    sock = ret = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
    printf("SOCKET:OPEN() %d\n",sock);
    if (ret < 0)
            err(1, "socket(j1939)");

    /*SOCKET SET SOCKOPT*/
    ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
                    &todo_broadcast, sizeof(todo_broadcast));
    printf("SOCKET:SETSOCKETOPT() %d\n",sock);
    if (ret < 0)
            err(1, "setsockopt: filed to set broadcast");

    /*SOCKET BIND*/
    ret = bind(sock, (void *)&sockname, sizeof(sockname));
    printf("SOCKET:BIND() %d\n",ret);
    if (ret < 0 )
            err(1, "bind(): failed to bind socket");

     pgn_filt = 0xEA00;

     if (peername.can_addr.j1939.pgn == pgn_filt){
            printf("REQUEST : %d Byte\n", ret);

            dp = dat;
            req_pgn = *(dp+2);
            req_pgn = req_pgn << 8;
            req_pgn |= *(dp+2-1);
            req_pgn = req_pgn << 8;
            req_pgn |= *(dp+2-2);
            printf("%06x\n",req_pgn);
            close(sock);

            sockname.can_ifindex = 4;
            sockname.can_addr.j1939.addr = 0x00;
            sockname.can_addr.j1939.pgn = J1939_NO_PGN;
            sockname.can_addr.j1939.name = J1939_NO_NAME;

            peername.can_ifindex = 4;
            peername.can_addr.j1939.addr = 0x00;
            peername.can_addr.j1939.pgn = req_pgn;
            peername.can_addr.j1939.name = J1939_NO_NAME;

            /*SOCKET OPEN*/
            sock = ret = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
            printf("SOCKET:OPEN() %d\n",sock);
            if (ret < 0)
                    err(1, "socket(j1939)");

            /*SOCKET SET SOCKOPT*/
            ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
                            &todo_broadcast, sizeof(todo_broadcast));
            printf("SOCKET:SETSOCKETOPT() %d\n",sock);
            if (ret < 0)
                    err(1, "setsockopt: filed to set broadcast");

            /*SOCKET BIND*/
            ret = bind(sock, (void *)&sockname, sizeof(sockname));
            printf("SOCKET:BIND() %d\n",ret);
            if (ret < 0 )
                    err(1, "bind(): failed to bind socket");

            memset(&dat, 0xFF, sizeof(dat));

            dat[0] = 87;
            dat[1] = 65;
            dat[2] = 85;
            dat[3] = 90;
            dat[4] = 90;
            dat[5] = 90;
            dat[6] = 56;
            dat[7] = 80;
            dat[8] = 51;
            dat[9] = 53;
            dat[10] = 65;
            dat[11] = 49;
            dat[12] = 55;
            dat[13] = 49;
            dat[14] = 49;
            dat[15] = 53;
            dat[16] = 48;

            /*sendto*/
            ret = sendto(sock, dat, 16, 0,
                            (void *)&peername, sizeof(peername));

`

candump: `

             can0  18EA0000   [8]  00 EC FE FF FF FF FF FF
             can0  18EC0000   [8]  10 10 00 03 03 00 00 04
             can0  18EC0000   [8]  11 03 01 FF FF 00 00 04

             can0  18EB0000   [8]  01 57 41 55 5A 5A 5A 38
             can0  18EB0000   [8]  02 50 33 35 41 31 37 31
             can0  18EB0000   [8]  03 31 35 FF FF FF FF FF

             can0  18EC0000   [8]  13 10 00 03 FF 00 00 04

`

hope someone can help me out :)

olerem commented 3 years ago

Hi @TSsimon , please take a look at this topic https://github.com/linux-can/can-utils/issues/228 I hope it answers your question

TSsimon commented 3 years ago

Thanks for your Attention @olerem ! If I understand correctly the implemented Type of SAE J1939 Transport Protocol is the RTS/CTS Type ? Is there a setting to receive TP.DT Messages without handshake?

thanks!

olerem commented 3 years ago

On the top level (from socket point of view) you do not deal with TP/ETPs at all. If you send() 8byte, the stack will send simple message. if you send more than 8 byte, the stack will send TP (all what for TP is needed) or if it is more than max TP size, it will send ETP message. See: https://github.com/linux-can/can-utils/blob/master/can-j1939-kickstart.md#larger-packets

With this tool, you can send any supported amount of data over CAN: https://github.com/linux-can/can-utils/blob/master/j1939cat.c