diff --git a/interface_linux.go b/interface_linux.go index 209606b..c5a57a8 100644 --- a/interface_linux.go +++ b/interface_linux.go @@ -1,9 +1,6 @@ package socketcan import ( - "fmt" - "unsafe" - "golang.org/x/sys/unix" ) @@ -12,24 +9,6 @@ func getIfIndex(itf Interface, ifName string) (int, error) { if err != nil { return 0, err } - if len(ifNameRaw) > unix.IFNAMSIZ { - return 0, fmt.Errorf("Maximum ifname length is %d characters", unix.IFNAMSIZ) - } - - type ifreq struct { - Name [unix.IFNAMSIZ]byte - Index int - } - var ifReq ifreq fd := itf.SocketFD() - copy(ifReq.Name[:], ifNameRaw) - _, _, errno := unix.Syscall(unix.SYS_IOCTL, - uintptr(fd), - unix.SIOCGIFINDEX, - uintptr(unsafe.Pointer(&ifReq))) - if errno != 0 { - return 0, fmt.Errorf("ioctl: %v", errno) - } - - return ifReq.Index, nil + return IoctlGetIfIndex(fd, ifNameRaw) } diff --git a/ioctl_linux.go b/ioctl_linux.go new file mode 100644 index 0000000..95d6986 --- /dev/null +++ b/ioctl_linux.go @@ -0,0 +1,51 @@ +/** + * Special ioctl commands for supporting the unix interface + * to SocketCAN interface. + * + */ + +package socketcan + +import ( + "fmt" + "syscall" + "unsafe" + + "golang.org/x/sys/unix" +) + +// Unfortunately - this is not made public in the "unix" library so, +// making ioctl requests is hard. I've manually recreated it here. +func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) { + _, _, e1 := syscall.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) + if e1 != 0 { + err = error(e1) + } + return +} + +func IoctlGetIfIndex(fd int, ifNameRaw []byte) (int, error) { + type ifreq struct { + Name [unix.IFNAMSIZ]byte + Index int + } + var ifReq ifreq + + if len(ifNameRaw) > unix.IFNAMSIZ { + return -1, fmt.Errorf("Maximum ifname length is %d characters", unix.IFNAMSIZ) + } + + copy(ifReq.Name[:], ifNameRaw) + err := ioctlPtr(fd, unix.SIOCGIFINDEX, unsafe.Pointer(&ifReq)); + if err != nil { + return -1, err + } + + return ifReq.Index, nil +} + +func IoctlGetTimeval(fd int) (*syscall.Timeval, error) { + var value syscall.Timeval + err := ioctlPtr(fd, syscall.SIOCGSTAMP, unsafe.Pointer(&value)); + return &value, err +} diff --git a/raw_interface.go b/raw_interface.go index 7b48bf7..698b92b 100644 --- a/raw_interface.go +++ b/raw_interface.go @@ -4,4 +4,5 @@ type RawInterface interface { Send(CanFrame) error Receive() (CanFrame, error) Close() error + GetTimestamp() (int64, error) } diff --git a/raw_interface_linux.go b/raw_interface_linux.go index bd7ffc4..7c2cba5 100644 --- a/raw_interface_linux.go +++ b/raw_interface_linux.go @@ -62,6 +62,21 @@ func (itf *rawInterface) Receive() (CanFrame, error) { return f, nil } +/** Request the timestamp for the last read CAN frame. + * This method must be called immediately after the last + * frame was read. + * @return The timestamp is in CLOCK_MONOTONIC domain in + * nanoseconds. + */ +func (itf *rawInterface) GetTimestamp() (int64, error) { + timeVal, err := IoctlGetTimeval(itf.fd) + if err != nil { + return -1, err + } + + return timeVal.Nano(), nil +} + func IsClosedInterfaceError(err error) bool { errno, ok := err.(syscall.Errno) if ok == false { diff --git a/raw_interface_stub.go b/raw_interface_stub.go index 04a6cd1..ebae199 100644 --- a/raw_interface_stub.go +++ b/raw_interface_stub.go @@ -28,6 +28,10 @@ func (itf *rawInterfaceStub) Receive() (CanFrame, error) { return f, nil } +func (itf *rawInterface) GetTimestamp() (int64, error) { + return 0, nil; +} + func IsClosedInterfaceError(err error) bool { return false }