diff --git a/unix/syscall_internal_linux_test.go b/unix/syscall_internal_linux_test.go index 40d3aca8..8af671ef 100644 --- a/unix/syscall_internal_linux_test.go +++ b/unix/syscall_internal_linux_test.go @@ -168,6 +168,24 @@ func Test_anyToSockaddr(t *testing.T) { Name: " ", }, }, + { + name: "AF_CAN", + rsa: sockaddrCANToAny(RawSockaddrCAN{ + Family: AF_CAN, + Ifindex: 12345678, + Addr: [16]byte{ + 0x89, 0x67, 0x45, 0x23, + 0x90, 0x78, 0x56, 0x34, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + }, + }), + sa: &SockaddrCAN{ + Ifindex: 12345678, + RxID: 0x23456789, + TxID: 0x34567890, + }, + }, { name: "AF_MAX EAFNOSUPPORT", rsa: &RawSockaddrAny{ @@ -544,6 +562,62 @@ func TestSockaddrIUCV_sockaddr(t *testing.T) { } } +func TestSockaddrCAN_sockaddr(t *testing.T) { + tests := []struct { + name string + sa *SockaddrCAN + raw *RawSockaddrCAN + err error + }{ + { + name: "with ids", + sa: &SockaddrCAN{ + Ifindex: 12345678, + RxID: 0x23456789, + TxID: 0x34567890, + }, + raw: &RawSockaddrCAN{ + Family: AF_CAN, + Ifindex: 12345678, + Addr: [16]byte{ + 0x89, 0x67, 0x45, 0x23, + 0x90, 0x78, 0x56, 0x34, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + }, + }, + }, + { + name: "negative ifindex", + sa: &SockaddrCAN{ + Ifindex: -1, + }, + err: EINVAL, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + out, l, err := tt.sa.sockaddr() + if err != tt.err { + t.Fatalf("unexpected error: %v, want: %v", err, tt.err) + } + + // Must be 0 on error or a fixed size otherwise. + if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrCAN) { + t.Fatalf("unexpected Socklen: %d", l) + } + + if out != nil { + raw := (*RawSockaddrCAN)(out) + if !reflect.DeepEqual(raw, tt.raw) { + t.Fatalf("unexpected RawSockaddrCAN:\n got: %#v\nwant: %#v", raw, tt.raw) + } + } + }) + } +} + // These helpers explicitly copy the contents of in into out to produce // the correct sockaddr structure, without relying on unsafe casting to // a type of a larger size. @@ -591,3 +665,12 @@ func sockaddrIUCVToAny(in RawSockaddrIUCV) *RawSockaddrAny { ) return &out } + +func sockaddrCANToAny(in RawSockaddrCAN) *RawSockaddrAny { + var out RawSockaddrAny + copy( + (*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:], + (*(*[SizeofSockaddrCAN]byte)(unsafe.Pointer(&in)))[:], + ) + return &out +} diff --git a/unix/syscall_linux.go b/unix/syscall_linux.go index c48f5dda..3e20fcf5 100644 --- a/unix/syscall_linux.go +++ b/unix/syscall_linux.go @@ -1111,6 +1111,21 @@ 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), + } + 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 }