mirror of
https://github.com/golang/sys.git
synced 2026-02-08 03:36:03 +03:00
unix: add J1939 protocol support on socketcan interface
Fixes golang/go#42797
Change-Id: Ia7be73e53438dec80903c95de0e6829005741a0f
GitHub-Last-Rev: bc35835339
GitHub-Pull-Request: golang/sys#91
Reviewed-on: https://go-review.googlesource.com/c/sys/+/272767
Run-TryBot: Matt Layher <mdlayher@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
Reviewed-by: Matt Layher <mdlayher@gmail.com>
Trust: Tobias Klauser <tobias.klauser@gmail.com>
This commit is contained in:
@@ -169,7 +169,7 @@ func Test_anyToSockaddr(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AF_CAN",
|
||||
name: "AF_CAN CAN_RAW",
|
||||
rsa: sockaddrCANToAny(RawSockaddrCAN{
|
||||
Family: AF_CAN,
|
||||
Ifindex: 12345678,
|
||||
@@ -185,6 +185,27 @@ func Test_anyToSockaddr(t *testing.T) {
|
||||
RxID: 0xAAAAAAAA,
|
||||
TxID: 0xBBBBBBBB,
|
||||
},
|
||||
skt: SocketSpec{domain: AF_CAN, typ: SOCK_RAW, protocol: CAN_RAW},
|
||||
},
|
||||
{
|
||||
name: "AF_CAN CAN_J1939",
|
||||
rsa: sockaddrCANToAny(RawSockaddrCAN{
|
||||
Family: AF_CAN,
|
||||
Ifindex: 12345678,
|
||||
Addr: [16]byte{
|
||||
0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xBB, 0xBB, 0xBB, 0xBB,
|
||||
0xCC, 0x00, 0x00, 0x00,
|
||||
},
|
||||
}),
|
||||
sa: &SockaddrCANJ1939{
|
||||
Ifindex: 12345678,
|
||||
Name: 0xAAAAAAAAAAAAAAAA,
|
||||
PGN: 0xBBBBBBBB,
|
||||
Addr: 0xCC,
|
||||
},
|
||||
skt: SocketSpec{domain: AF_CAN, typ: SOCK_DGRAM, protocol: CAN_J1939},
|
||||
},
|
||||
{
|
||||
name: "AF_MAX EAFNOSUPPORT",
|
||||
@@ -205,10 +226,16 @@ func Test_anyToSockaddr(t *testing.T) {
|
||||
if tt.skt.domain != 0 {
|
||||
fd, err = Socket(tt.skt.domain, tt.skt.typ, tt.skt.protocol)
|
||||
// Some sockaddr types need specific kernel modules running: if these
|
||||
// are not present we'll get EPROTONOSUPPORT back when trying to create
|
||||
// the socket. Skip the test in this situation.
|
||||
// are not present we'll get EPROTONOSUPPORT/EAFNOSUPPORT back when
|
||||
// trying to create the socket. Skip the test in this situation.
|
||||
if err == EPROTONOSUPPORT {
|
||||
t.Skip("socket family/protocol not supported by kernel")
|
||||
} else if err == EAFNOSUPPORT {
|
||||
t.Skip("socket address family not supported by kernel")
|
||||
} else if err == EACCES {
|
||||
// Some platforms might require elevated privileges to perform
|
||||
// actions on sockets. Skip the test in this situation.
|
||||
t.Skip("socket operation not permitted")
|
||||
} else if err != nil {
|
||||
t.Fatalf("socket(%v): %v", tt.skt, err)
|
||||
}
|
||||
|
||||
@@ -641,6 +641,36 @@ func (sa *SockaddrCAN) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
||||
return unsafe.Pointer(&sa.raw), SizeofSockaddrCAN, nil
|
||||
}
|
||||
|
||||
// SockaddrCANJ1939 implements the Sockaddr interface for AF_CAN using J1939
|
||||
// protocol (https://en.wikipedia.org/wiki/SAE_J1939). For more information
|
||||
// on the purposes of the fields, check the official linux kernel documentation
|
||||
// available here: https://www.kernel.org/doc/Documentation/networking/j1939.rst
|
||||
type SockaddrCANJ1939 struct {
|
||||
Ifindex int
|
||||
Name uint64
|
||||
PGN uint32
|
||||
Addr uint8
|
||||
raw RawSockaddrCAN
|
||||
}
|
||||
|
||||
func (sa *SockaddrCANJ1939) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
||||
if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff {
|
||||
return nil, 0, EINVAL
|
||||
}
|
||||
sa.raw.Family = AF_CAN
|
||||
sa.raw.Ifindex = int32(sa.Ifindex)
|
||||
n := (*[8]byte)(unsafe.Pointer(&sa.Name))
|
||||
for i := 0; i < 8; i++ {
|
||||
sa.raw.Addr[i] = n[i]
|
||||
}
|
||||
p := (*[4]byte)(unsafe.Pointer(&sa.PGN))
|
||||
for i := 0; i < 4; i++ {
|
||||
sa.raw.Addr[i+8] = p[i]
|
||||
}
|
||||
sa.raw.Addr[12] = sa.Addr
|
||||
return unsafe.Pointer(&sa.raw), SizeofSockaddrCAN, nil
|
||||
}
|
||||
|
||||
// SockaddrALG implements the Sockaddr interface for AF_ALG type sockets.
|
||||
// SockaddrALG enables userspace access to the Linux kernel's cryptography
|
||||
// subsystem. The Type and Name fields specify which type of hash or cipher
|
||||
@@ -1150,20 +1180,43 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
|
||||
return sa, nil
|
||||
|
||||
case AF_CAN:
|
||||
pp := (*RawSockaddrCAN)(unsafe.Pointer(rsa))
|
||||
sa := &SockaddrCAN{
|
||||
Ifindex: int(pp.Ifindex),
|
||||
proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rx := (*[4]byte)(unsafe.Pointer(&sa.RxID))
|
||||
for i := 0; i < 4; i++ {
|
||||
rx[i] = pp.Addr[i]
|
||||
}
|
||||
tx := (*[4]byte)(unsafe.Pointer(&sa.TxID))
|
||||
for i := 0; i < 4; i++ {
|
||||
tx[i] = pp.Addr[i+4]
|
||||
}
|
||||
return sa, nil
|
||||
|
||||
pp := (*RawSockaddrCAN)(unsafe.Pointer(rsa))
|
||||
|
||||
switch proto {
|
||||
case CAN_J1939:
|
||||
sa := &SockaddrCANJ1939{
|
||||
Ifindex: int(pp.Ifindex),
|
||||
}
|
||||
name := (*[8]byte)(unsafe.Pointer(&sa.Name))
|
||||
for i := 0; i < 8; i++ {
|
||||
name[i] = pp.Addr[i]
|
||||
}
|
||||
pgn := (*[4]byte)(unsafe.Pointer(&sa.PGN))
|
||||
for i := 0; i < 4; i++ {
|
||||
pgn[i] = pp.Addr[i+8]
|
||||
}
|
||||
addr := (*[1]byte)(unsafe.Pointer(&sa.Addr))
|
||||
addr[0] = pp.Addr[12]
|
||||
return sa, nil
|
||||
default:
|
||||
sa := &SockaddrCAN{
|
||||
Ifindex: int(pp.Ifindex),
|
||||
}
|
||||
rx := (*[4]byte)(unsafe.Pointer(&sa.RxID))
|
||||
for i := 0; i < 4; i++ {
|
||||
rx[i] = pp.Addr[i]
|
||||
}
|
||||
tx := (*[4]byte)(unsafe.Pointer(&sa.TxID))
|
||||
for i := 0; i < 4; i++ {
|
||||
tx[i] = pp.Addr[i+4]
|
||||
}
|
||||
return sa, nil
|
||||
}
|
||||
}
|
||||
return nil, EAFNOSUPPORT
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user