github.com/blueinnovationsgroup/can-go@v0.0.0-20230518195432-d0567cda0028/pkg/candevice/device_linux.go (about)

     1  //go:build linux && go1.18
     2  
     3  package candevice
     4  
     5  import (
     6  	"fmt"
     7  	"net"
     8  	"unsafe"
     9  
    10  	"github.com/mdlayher/netlink"
    11  	"github.com/mdlayher/netlink/nlenc"
    12  	"golang.org/x/sys/unix"
    13  )
    14  
    15  const canLinkType = "can"
    16  
    17  const (
    18  	StateErrorActive  = unix.CAN_STATE_ERROR_ACTIVE
    19  	StateErrorWarning = unix.CAN_STATE_ERROR_WARNING
    20  	StateErrorPassive = unix.CAN_STATE_ERROR_PASSIVE
    21  	StateBusOff       = unix.CAN_STATE_BUS_OFF
    22  	StateStopped      = unix.CAN_STATE_STOPPED
    23  	StateSleeping     = unix.CAN_STATE_SLEEPING
    24  	StateMax          = unix.CAN_STATE_MAX
    25  
    26  	sizeOfBitTiming        = int(unsafe.Sizeof(BitTiming{}))
    27  	sizeOfBitTimingConst   = int(unsafe.Sizeof(BitTimingConst{}))
    28  	sizeOfClock            = int(unsafe.Sizeof(Clock{}))
    29  	sizeOfCtrlMode         = int(unsafe.Sizeof(CtrlMode{}))
    30  	sizeOfBusErrorCounters = int(unsafe.Sizeof(BusErrorCounters{}))
    31  	sizeOfStats            = int(unsafe.Sizeof(Stats{}))
    32  )
    33  
    34  type Device struct {
    35  	ifname string
    36  	index  int32
    37  	li     linkInfoMsg
    38  	ifi    ifInfoMsg
    39  }
    40  
    41  // Creates a handle to a CAN device specified by name, e.g. can0.
    42  func New(deviceName string) (*Device, error) {
    43  	iface, err := net.InterfaceByName(deviceName)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	d := &Device{
    48  		index: int32(iface.Index),
    49  	}
    50  	if err := d.updateInfo(); err != nil {
    51  		return nil, err
    52  	}
    53  	return d, nil
    54  }
    55  
    56  func (d *Device) IsUp() (bool, error) {
    57  	if err := d.updateInfo(); err != nil {
    58  		return false, err
    59  	}
    60  	if d.ifi.Flags&unix.IFF_UP != 0 {
    61  		return true, nil
    62  	}
    63  	return false, nil
    64  }
    65  
    66  // Corresponds to "ip link set up".
    67  func (d *Device) SetUp() error {
    68  	c, err := netlink.Dial(unix.NETLINK_ROUTE, &netlink.Config{})
    69  	if err != nil {
    70  		return fmt.Errorf("couldn't dial netlink socket: %w", err)
    71  	}
    72  	defer c.Close()
    73  
    74  	ifi := &ifInfoMsg{
    75  		unix.IfInfomsg{
    76  			Index:  d.index,
    77  			Flags:  unix.IFF_UP,
    78  			Change: unix.IFF_UP,
    79  		},
    80  	}
    81  	req, err := d.newRequest(unix.RTM_NEWLINK, ifi)
    82  	if err != nil {
    83  		return fmt.Errorf("couldn't create netlink request: %w", err)
    84  	}
    85  
    86  	res, err := c.Execute(req)
    87  	if err != nil {
    88  		return fmt.Errorf("couldn't set link up: %w", err)
    89  	}
    90  	if len(res) > 1 {
    91  		return fmt.Errorf("expected 1 message, got %d", len(res))
    92  	}
    93  	return nil
    94  }
    95  
    96  // Corresponds to "ip link set down".
    97  func (d *Device) SetDown() error {
    98  	c, err := netlink.Dial(unix.NETLINK_ROUTE, &netlink.Config{})
    99  	if err != nil {
   100  		return fmt.Errorf("couldn't dial netlink socket: %w", err)
   101  	}
   102  	defer c.Close()
   103  
   104  	ifi := &ifInfoMsg{
   105  		unix.IfInfomsg{
   106  			Index:  d.index,
   107  			Flags:  0,
   108  			Change: unix.IFF_UP,
   109  		},
   110  	}
   111  	req, err := d.newRequest(unix.RTM_NEWLINK, ifi)
   112  	if err != nil {
   113  		return fmt.Errorf("couldn't create netlink request: %w", err)
   114  	}
   115  
   116  	res, err := c.Execute(req)
   117  	if err != nil {
   118  		return fmt.Errorf("couldn't set link down: %w", err)
   119  	}
   120  	if len(res) > 1 {
   121  		return fmt.Errorf("expected 1 message, got %d", len(res))
   122  	}
   123  	return nil
   124  }
   125  
   126  func (d *Device) Bitrate() (uint32, error) {
   127  	if err := d.updateInfo(); err != nil {
   128  		return 0, fmt.Errorf("couldn't retrieve bitrate: %w", err)
   129  	}
   130  	return d.li.info.BitTiming.Bitrate, nil
   131  }
   132  
   133  func (d *Device) SetBitrate(bitrate uint32) error {
   134  	c, err := netlink.Dial(unix.NETLINK_ROUTE, &netlink.Config{})
   135  	if err != nil {
   136  		return fmt.Errorf("couldn't dial netlink socket: %w", err)
   137  	}
   138  	defer c.Close()
   139  
   140  	ifi := &ifInfoMsg{
   141  		unix.IfInfomsg{Index: d.index},
   142  	}
   143  	req, err := d.newRequest(unix.RTM_NEWLINK, ifi)
   144  	if err != nil {
   145  		return fmt.Errorf("couldn't create netlink request: %w", err)
   146  	}
   147  
   148  	li := &linkInfoMsg{
   149  		linkType: canLinkType,
   150  	}
   151  	li.info.BitTiming.Bitrate = bitrate
   152  	ae := netlink.NewAttributeEncoder()
   153  	ae.Nested(unix.IFLA_LINKINFO, li.encode)
   154  	liData, err := ae.Encode()
   155  	if err != nil {
   156  		return fmt.Errorf("couldn't encode message: %w", err)
   157  	}
   158  	req.Data = append(req.Data, liData...)
   159  
   160  	res, err := c.Execute(req)
   161  	if err != nil {
   162  		return fmt.Errorf("couldn't set bitrate: %w", err)
   163  	}
   164  	if len(res) > 1 {
   165  		return fmt.Errorf("expected 1 message, got %d", len(res))
   166  	}
   167  	return nil
   168  }
   169  
   170  type Info struct {
   171  	BitTiming        BitTiming
   172  	BitTimingConst   BitTimingConst
   173  	Clock            Clock
   174  	CtrlMode         CtrlMode
   175  	BusErrorCounters BusErrorCounters
   176  
   177  	State     uint32
   178  	RestartMs uint32
   179  }
   180  
   181  func (d *Device) Info() (Info, error) {
   182  	if err := d.updateInfo(); err != nil {
   183  		return Info{}, err
   184  	}
   185  	return d.li.info, nil
   186  }
   187  
   188  func (d *Device) updateInfo() error {
   189  	c, err := netlink.Dial(unix.NETLINK_ROUTE, &netlink.Config{})
   190  	if err != nil {
   191  		return fmt.Errorf("couldn't dial netlink socket: %w", err)
   192  	}
   193  	defer c.Close()
   194  
   195  	ifi := &ifInfoMsg{
   196  		unix.IfInfomsg{Index: d.index},
   197  	}
   198  	req, err := d.newRequest(unix.RTM_GETLINK, ifi)
   199  	if err != nil {
   200  		return fmt.Errorf("couldn't create netlink request: %w", err)
   201  	}
   202  
   203  	res, err := c.Execute(req)
   204  	if err != nil {
   205  		return fmt.Errorf("couldn't retrieve link info: %w", err)
   206  	}
   207  	if len(res) > 1 {
   208  		return fmt.Errorf("expected 1 message, got %d", len(res))
   209  	}
   210  
   211  	if err := d.unmarshalBinary(res[0].Data); err != nil {
   212  		return fmt.Errorf("couldn't decode info: %w", err)
   213  	}
   214  	return nil
   215  }
   216  
   217  func (d *Device) newRequest(typ netlink.HeaderType, ifi *ifInfoMsg) (netlink.Message, error) {
   218  	req := netlink.Message{
   219  		Header: netlink.Header{
   220  			Flags: netlink.Request | netlink.Acknowledge,
   221  			Type:  typ,
   222  		},
   223  	}
   224  	msg := ifi.marshalBinary()
   225  	req.Data = append(req.Data, msg...)
   226  	return req, nil
   227  }
   228  
   229  func (d *Device) unmarshalBinary(data []byte) error {
   230  	if err := d.ifi.unmarshalBinary(data[:unix.SizeofIfInfomsg]); err != nil {
   231  		return fmt.Errorf("couldn't unmarshal ifInfoMsg: %w", err)
   232  	}
   233  
   234  	ad, err := netlink.NewAttributeDecoder(data[unix.SizeofIfInfomsg:])
   235  	if err != nil {
   236  		return err
   237  	}
   238  	if d.ifi.Type != unix.ARPHRD_CAN {
   239  		return fmt.Errorf("not a CAN interface")
   240  	}
   241  	for ad.Next() {
   242  		switch ad.Type() {
   243  		case unix.IFLA_IFNAME:
   244  			d.ifname = ad.String()
   245  		case unix.IFLA_LINKINFO:
   246  			ad.Nested(d.li.decode)
   247  		default:
   248  		}
   249  	}
   250  	if err := ad.Err(); err != nil {
   251  		return fmt.Errorf("couldn't decode link: %w", err)
   252  	}
   253  	return nil
   254  }
   255  
   256  type ifInfoMsg struct {
   257  	unix.IfInfomsg
   258  }
   259  
   260  func (ifi *ifInfoMsg) marshalBinary() []byte {
   261  	buf := make([]byte, unix.SizeofIfInfomsg)
   262  	buf[0] = ifi.Family
   263  	buf[1] = 0 // reserved
   264  	nlenc.PutUint16(buf[2:4], ifi.Type)
   265  	nlenc.PutInt32(buf[4:8], ifi.Index)
   266  	nlenc.PutUint32(buf[8:12], ifi.Flags)
   267  	nlenc.PutUint32(buf[12:16], ifi.Change)
   268  	return buf
   269  }
   270  
   271  func (ifi *ifInfoMsg) unmarshalBinary(data []byte) error {
   272  	if len(data) != unix.SizeofIfInfomsg {
   273  		return fmt.Errorf(
   274  			"data is not a valid ifInfoMsg, expected: %d bytes, got: %d bytes",
   275  			unix.SizeofIfInfomsg,
   276  			len(data),
   277  		)
   278  	}
   279  	ifi.Family = nlenc.Uint8(data[0:1])
   280  	ifi.Type = nlenc.Uint16(data[2:4])
   281  	ifi.Index = nlenc.Int32(data[4:8])
   282  	ifi.Flags = nlenc.Uint32(data[8:12])
   283  	ifi.Change = nlenc.Uint32(data[12:16])
   284  	return nil
   285  }
   286  
   287  type BitTiming struct {
   288  	unix.CANBitTiming
   289  }
   290  
   291  func (bt *BitTiming) marshalBinary() []byte {
   292  	buf := make([]byte, sizeOfBitTiming)
   293  	nlenc.PutUint32(buf[0:4], bt.Bitrate)
   294  	nlenc.PutUint32(buf[4:8], bt.Sample_point)
   295  	nlenc.PutUint32(buf[8:12], bt.Tq)
   296  	nlenc.PutUint32(buf[12:16], bt.Prop_seg)
   297  	nlenc.PutUint32(buf[16:20], bt.Phase_seg1)
   298  	nlenc.PutUint32(buf[20:24], bt.Phase_seg2)
   299  	nlenc.PutUint32(buf[24:28], bt.Sjw)
   300  	nlenc.PutUint32(buf[28:32], bt.Brp)
   301  	return buf
   302  }
   303  
   304  func (bt *BitTiming) unmarshalBinary(data []byte) error {
   305  	if len(data) != sizeOfBitTiming {
   306  		return fmt.Errorf(
   307  			"data is not a valid BitTiming, expected: %d bytes, got: %d bytes",
   308  			sizeOfBitTiming,
   309  			len(data),
   310  		)
   311  	}
   312  	bt.Bitrate = nlenc.Uint32(data[0:4])
   313  	bt.Sample_point = nlenc.Uint32(data[4:8])
   314  	bt.Tq = nlenc.Uint32(data[8:12])
   315  	bt.Prop_seg = nlenc.Uint32(data[12:16])
   316  	bt.Phase_seg1 = nlenc.Uint32(data[16:20])
   317  	bt.Phase_seg2 = nlenc.Uint32(data[20:24])
   318  	bt.Sjw = nlenc.Uint32(data[24:28])
   319  	bt.Brp = nlenc.Uint32(data[28:32])
   320  	return nil
   321  }
   322  
   323  type BitTimingConst struct {
   324  	unix.CANBitTimingConst
   325  }
   326  
   327  func (btc *BitTimingConst) unmarshalBinary(data []byte) error {
   328  	if len(data) != sizeOfBitTimingConst {
   329  		return fmt.Errorf(
   330  			"data is not a valid BitTimingConst, expected: %d bytes, got: %d bytes",
   331  			sizeOfBitTimingConst,
   332  			len(data),
   333  		)
   334  	}
   335  	copy(btc.Name[:], data[0:16])
   336  	btc.Tseg1_min = nlenc.Uint32(data[16:20])
   337  	btc.Tseg1_max = nlenc.Uint32(data[20:24])
   338  	btc.Tseg2_min = nlenc.Uint32(data[24:28])
   339  	btc.Tseg2_max = nlenc.Uint32(data[28:32])
   340  	btc.Sjw_max = nlenc.Uint32(data[32:36])
   341  	btc.Brp_min = nlenc.Uint32(data[36:40])
   342  	btc.Brp_max = nlenc.Uint32(data[40:44])
   343  	btc.Brp_inc = nlenc.Uint32(data[44:48])
   344  	return nil
   345  }
   346  
   347  type Clock struct {
   348  	unix.CANClock
   349  }
   350  
   351  func (c *Clock) unmarshalBinary(data []byte) error {
   352  	if len(data) != sizeOfClock {
   353  		return fmt.Errorf(
   354  			"data is not a valid Clock, expected: %d bytes, got: %d bytes",
   355  			sizeOfClock,
   356  			len(data),
   357  		)
   358  	}
   359  	c.Freq = nlenc.Uint32(data)
   360  	return nil
   361  }
   362  
   363  type CtrlMode struct {
   364  	unix.CANCtrlMode
   365  }
   366  
   367  func (cm *CtrlMode) unmarshalBinary(data []byte) error {
   368  	if len(data) != sizeOfCtrlMode {
   369  		return fmt.Errorf(
   370  			"data is not a valid CtrlMode, expected: %d bytes, got: %d bytes",
   371  			sizeOfCtrlMode,
   372  			len(data),
   373  		)
   374  	}
   375  	cm.Mask = nlenc.Uint32(data[0:4])
   376  	cm.Flags = nlenc.Uint32(data[4:8])
   377  	return nil
   378  }
   379  
   380  type BusErrorCounters struct {
   381  	unix.CANBusErrorCounters
   382  }
   383  
   384  func (bec *BusErrorCounters) unmarshalBinary(data []byte) error {
   385  	if len(data) != sizeOfBusErrorCounters {
   386  		return fmt.Errorf(
   387  			"data is not a valid BusErrorCounters, expected: %d bytes, got: %d bytes",
   388  			sizeOfBusErrorCounters,
   389  			len(data),
   390  		)
   391  	}
   392  	bec.Txerr = nlenc.Uint16(data[0:2])
   393  	bec.Rxerr = nlenc.Uint16(data[2:4])
   394  	return nil
   395  }
   396  
   397  type Stats struct {
   398  	unix.CANDeviceStats
   399  }
   400  
   401  func (s *Stats) unmarshalBinary(data []byte) error {
   402  	if len(data) != sizeOfStats {
   403  		return fmt.Errorf(
   404  			"data is not a valid Stats, expected: %d bytes, got: %d bytes",
   405  			sizeOfStats,
   406  			len(data),
   407  		)
   408  	}
   409  	s.Bus_error = nlenc.Uint32(data[0:4])
   410  	s.Error_warning = nlenc.Uint32(data[4:8])
   411  	s.Error_passive = nlenc.Uint32(data[8:12])
   412  	s.Bus_off = nlenc.Uint32(data[12:16])
   413  	s.Arbitration_lost = nlenc.Uint32(data[16:20])
   414  	s.Restarts = nlenc.Uint32(data[20:24])
   415  	return nil
   416  }
   417  
   418  func (i *Info) decode(nad *netlink.AttributeDecoder) error {
   419  	var err error
   420  	for nad.Next() {
   421  		switch nad.Type() {
   422  		case unix.IFLA_CAN_BITTIMING:
   423  			err = i.BitTiming.unmarshalBinary(nad.Bytes())
   424  		case unix.IFLA_CAN_BITTIMING_CONST:
   425  			err = i.BitTimingConst.unmarshalBinary(nad.Bytes())
   426  		case unix.IFLA_CAN_CLOCK:
   427  			err = i.Clock.unmarshalBinary(nad.Bytes())
   428  		case unix.IFLA_CAN_CTRLMODE:
   429  			err = i.CtrlMode.unmarshalBinary(nad.Bytes())
   430  		case unix.IFLA_CAN_BERR_COUNTER:
   431  			err = i.BusErrorCounters.unmarshalBinary(nad.Bytes())
   432  		default:
   433  		}
   434  		if err != nil {
   435  			return err
   436  		}
   437  	}
   438  	return nil
   439  }
   440  
   441  // TODO: add more structures as needed.
   442  func (i *Info) encode(nae *netlink.AttributeEncoder) error {
   443  	nae.Bytes(unix.IFLA_CAN_BITTIMING, i.BitTiming.marshalBinary())
   444  	return nil
   445  }
   446  
   447  type linkInfoMsg struct {
   448  	linkType string
   449  	info     Info
   450  	stats    Stats
   451  }
   452  
   453  func (li *linkInfoMsg) decode(nad *netlink.AttributeDecoder) error {
   454  	var err error
   455  	for nad.Next() {
   456  		switch nad.Type() {
   457  		case unix.IFLA_INFO_KIND:
   458  			li.linkType = nad.String()
   459  			if li.linkType != canLinkType {
   460  				return fmt.Errorf("not a CAN interface")
   461  			}
   462  		case unix.IFLA_INFO_DATA:
   463  			nad.Nested(li.info.decode)
   464  		case unix.IFLA_INFO_XSTATS:
   465  			err = li.stats.unmarshalBinary(nad.Bytes())
   466  		default:
   467  		}
   468  		if err != nil {
   469  			return err
   470  		}
   471  	}
   472  
   473  	return nil
   474  }
   475  
   476  func (li *linkInfoMsg) encode(nae *netlink.AttributeEncoder) error {
   477  	nae.String(unix.IFLA_INFO_KIND, li.linkType)
   478  	nae.Nested(unix.IFLA_INFO_DATA, li.info.encode)
   479  	return nil
   480  }