Skip to content

Commit

Permalink
feat: implement SetListenOnlyMode()
Browse files Browse the repository at this point in the history
  • Loading branch information
ardrabczyk authored and Edholm committed Sep 26, 2023
1 parent 38b311b commit e243d3d
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 0 deletions.
27 changes: 27 additions & 0 deletions pkg/candevice/device_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,33 @@ func TestSetUpDown(t *testing.T) {
}
}

func TestSetListenOnlyMode(t *testing.T) {
d, err := New("can0")
if err != nil {
t.Fatal("couldn't set up device:", err)
}
defer d.SetDown()

if err := d.SetListenOnlyMode(true); err != nil {
t.Fatal(err)
}

// Set ListenOnly mode on device which is up
if err := d.SetUp(); err != nil {
t.Fatal(err)
}
if err := d.SetListenOnlyMode(false); err == nil {
t.Fatal("setting ListenOnly mode on device which is up succeeded")
}
if err := d.SetDown(); err != nil {
t.Fatal(err)
}

if err := d.SetListenOnlyMode(false); err != nil {
t.Fatal(err)
}
}

func setBitrate(d *Device, bitrate uint32) error {
if err := d.SetBitrate(bitrate); err != nil {
return err
Expand Down
74 changes: 74 additions & 0 deletions pkg/candevice/device_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,57 @@ func (d *Device) Bitrate() (uint32, error) {
return d.li.info.BitTiming.Bitrate, nil
}

func (d *Device) SetListenOnlyMode(mode bool) error {
c, err := netlink.Dial(unix.NETLINK_ROUTE, &netlink.Config{})
if err != nil {
return fmt.Errorf("couldn't dial netlink socket: %w", err)
}
defer c.Close()

ifi := &ifInfoMsg{
unix.IfInfomsg{Index: d.index},
}
req, err := d.newRequest(unix.RTM_NEWLINK, ifi)
if err != nil {
return fmt.Errorf("couldn't create netlink request: %w", err)
}

li := &linkInfoMsg{
linkType: canLinkType,
}

li.info, err = d.getCurrentParametersForSet()
if err != nil {
return fmt.Errorf("couldn't get current parameters: %w", err)
}

if mode {
li.info.CtrlMode.Mask |= unix.CAN_CTRLMODE_LISTENONLY
li.info.CtrlMode.Flags |= unix.CAN_CTRLMODE_LISTENONLY
} else {
li.info.CtrlMode.Mask |= unix.CAN_CTRLMODE_LISTENONLY
li.info.CtrlMode.Flags = 0
}

ae := netlink.NewAttributeEncoder()
ae.Nested(unix.IFLA_LINKINFO, li.encode)
liData, err := ae.Encode()
if err != nil {
return fmt.Errorf("couldn't encode message: %w", err)
}

req.Data = append(req.Data, liData...)

res, err := c.Execute(req)
if err != nil {
return fmt.Errorf("couldn't set listen-only mode: %w", err)
}
if len(res) > 1 {
return fmt.Errorf("expected 1 message, got %d", len(res))
}
return nil
}

func (d *Device) SetBitrate(bitrate uint32) error {
c, err := netlink.Dial(unix.NETLINK_ROUTE, &netlink.Config{})
if err != nil {
Expand All @@ -148,6 +199,12 @@ func (d *Device) SetBitrate(bitrate uint32) error {
li := &linkInfoMsg{
linkType: canLinkType,
}

li.info, err = d.getCurrentParametersForSet()
if err != nil {
return fmt.Errorf("couldn't get current parameters: %w", err)
}

li.info.BitTiming.Bitrate = bitrate
ae := netlink.NewAttributeEncoder()
ae.Nested(unix.IFLA_LINKINFO, li.encode)
Expand Down Expand Up @@ -214,6 +271,15 @@ func (d *Device) updateInfo() error {
return nil
}

func (d *Device) getCurrentParametersForSet() (Info, error) {
i, err := d.Info()
if err != nil {
return Info{}, err
}

return Info{BitTiming: BitTiming{unix.CANBitTiming{Bitrate: i.BitTiming.Bitrate}}, CtrlMode: i.CtrlMode}, nil
}

func (d *Device) newRequest(typ netlink.HeaderType, ifi *ifInfoMsg) (netlink.Message, error) {
req := netlink.Message{
Header: netlink.Header{
Expand Down Expand Up @@ -364,6 +430,13 @@ type CtrlMode struct {
unix.CANCtrlMode
}

func (cm *CtrlMode) marshalBinary() []byte {
buf := make([]byte, sizeOfCtrlMode)
nlenc.PutUint32(buf[0:4], cm.Mask)
nlenc.PutUint32(buf[4:8], cm.Flags)
return buf
}

func (cm *CtrlMode) unmarshalBinary(data []byte) error {
if len(data) != sizeOfCtrlMode {
return fmt.Errorf(
Expand Down Expand Up @@ -441,6 +514,7 @@ func (i *Info) decode(nad *netlink.AttributeDecoder) error {
// TODO: add more structures as needed.
func (i *Info) encode(nae *netlink.AttributeEncoder) error {
nae.Bytes(unix.IFLA_CAN_BITTIMING, i.BitTiming.marshalBinary())
nae.Bytes(unix.IFLA_CAN_CTRLMODE, i.CtrlMode.marshalBinary())
return nil
}

Expand Down
4 changes: 4 additions & 0 deletions pkg/candevice/device_others.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ func (d *Device) SetBitrate(_ uint32) error {
return NotSupportedError{}
}

func (d *Device) SetListenOnlyMode(mode bool) error {
return NotSupportedError{}
}

type Info struct{}

func (d *Device) Info() (Info, error) {
Expand Down

0 comments on commit e243d3d

Please sign in to comment.