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 }