Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

J1939 Sockets: getsockname returns PGN used in the call to connect and not bind #377

Open
derek-will opened this issue Sep 3, 2022 · 6 comments
Assignees

Comments

@derek-will
Copy link

I was utilizing the J1939 sockets recently and I noticed something that didn't align with my expectations.

When I call getsockname on a bound J1939 socket, the sockaddr_can structure that is returned will have the PGN field populated with the value set during the call to connect. I looked into /net/can/j1939/socket.c to see what was going on.

The pgn_rx_filter field of the j1939_sock structure is set using the PGN in the address structure passed to bind.

/* set default transmit pgn */
if (j1939_pgn_is_valid(addr->can_addr.j1939.pgn))
    jsk->pgn_rx_filter = addr->can_addr.j1939.pgn;
jsk->addr.src_name = addr->can_addr.j1939.name;
jsk->addr.sa = addr->can_addr.j1939.addr;

The pgn field of the encapsulated j1939_addr structure is only set using the PGN in the address structure passed to connect.

jsk->addr.dst_name = addr->can_addr.j1939.name;
jsk->addr.da = addr->can_addr.j1939.addr;

if (j1939_pgn_is_valid(addr->can_addr.j1939.pgn))
	jsk->addr.pgn = addr->can_addr.j1939.pgn;

When we call getsockname or getpeername it is always the PGN which was passed into the call to connect that is retrieved.

addr->can_family = AF_CAN;
addr->can_ifindex = jsk->ifindex;
addr->can_addr.j1939.pgn = jsk->addr.pgn;
if (peer) {
	addr->can_addr.j1939.name = jsk->addr.dst_name;
	addr->can_addr.j1939.addr = jsk->addr.da;
} else {
	addr->can_addr.j1939.name = jsk->addr.src_name;
	addr->can_addr.j1939.addr = jsk->addr.sa;
}

For getpeername this behavior is expected, but for getsockname this is not what I would expect. From the getsockname(2) man page:

getsockname() returns the current address to which the socket sockfd is bound, in the buffer pointed to by addr.

This function is useful for debugging what was previously set in the call to bind, but in the case of J1939 sockets it is slightly less representative due to how the PGN is stored and later retrieved. What is the rationalization behind this deviation in behavior?

@derek-will derek-will changed the title J1939 Sockets: getsockname returns PGN of remote address and not the local address J1939 Sockets: getsockname returns PGN used in the call to connect and not bind Sep 3, 2022
@hartkopp hartkopp assigned olerem and hartkopp and unassigned olerem and hartkopp Sep 4, 2022
@hartkopp
Copy link
Member

hartkopp commented Sep 4, 2022

Hi @derek-will ,
usually these kind of discussions are better asked on the linux-can mailing list, as it hits the kernel implementation and not the tools.

But I added @olerem and @kurt-vd here, that know best about the j1939 sockets.
So they can decide where to follow up with the discussion ;-)

@hartkopp hartkopp assigned olerem and unassigned olerem Sep 4, 2022
@kurt-vd
Copy link
Contributor

kurt-vd commented Sep 5, 2022

Hey,

In contrast to IP networking, on which BSD socket API's are based, J1939 packets have no source and destination PGN, just a PGN.
This makes you would get (I suppose) the same PGN in both getsockname() and getpeername()

This also affects the way you set this PGN, it can come from info during bind(), connect() or sendto(), all these calls apply to the same PGN.

Can you elaborate on what your expections were?

@marckleinebudde
Copy link
Member

ACK - TCP uses a 4-tuple (source IP, source port, destination IP, destination port) as the demux key to identify appropriate socket. In j1939 there is only 3-tuple (source address, destination address and pgn).

@derek-will
Copy link
Author

Can you elaborate on what your expectations were?

My expectation was that the same address information that was passed into bind would be retrieved by a call to getsockname.

I understand the point that there is no source or destination PGN, but getsockname represents a useful function for verifying what was passed into the bind call earlier and is the behavior stated in the man page for the function. For better or worse, a PGN is passed in along with the source address and source name during the call to bind. The pgn_rx_filter is set using that aforementioned PGN and unfortunately there is no method to retrieve (for debugging or other purposes) that PGN field unless it is locally cached in the application.

Can you see where I am coming from?

@olerem
Copy link
Contributor

olerem commented Sep 5, 2022

Hm, you have right. It is good to know what RX filter is configured, but this is not single rx filter used by the stack. We have SO_J1939_FILTER as well and there is no option to read it too.

@kurt-vd
Copy link
Contributor

kurt-vd commented Sep 5, 2022

  1. I doubt that this mapping is 1-to-1 in IP networks. You can use auto-bind features on tcp or udp, or even no bind at all, and you will get the final socket name after sending the first packet.
    After a bind() call, like to 0.0.0.0, I'm not sure if you get the same values in getsockname() back.

  2. If you never overrule the PGN (use invalid PGN in sendto and connect, you get back the same PGN in getsockname as in bind(). And yes, the J1939 semantics are a little different than those described in the man page which are focused on IP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants