bettercap/modules/can/can_dbc.go
2024-08-31 14:01:40 +02:00

174 lines
3.3 KiB
Go

package can
import (
"fmt"
"os"
"sync"
"github.com/evilsocket/islazy/str"
"go.einride.tech/can/pkg/descriptor"
)
type DBC struct {
sync.RWMutex
path string
db *descriptor.Database
}
func (dbc *DBC) Loaded() bool {
dbc.RLock()
defer dbc.RUnlock()
return dbc.db != nil
}
func (dbc *DBC) LoadFile(mod *CANModule, path string) error {
input, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("can't read %s: %v", path, err)
}
return dbc.LoadData(mod, path, input)
}
func (dbc *DBC) LoadData(mod *CANModule, name string, input []byte) error {
dbc.Lock()
defer dbc.Unlock()
mod.Debug("compiling %s ...", name)
result, err := dbcCompile(name, input)
if err != nil {
return fmt.Errorf("can't compile %s: %v", name, err)
}
for _, warning := range result.Warnings {
mod.Warning("%v", warning)
}
dbc.path = name
dbc.db = result.Database
mod.Info("%s loaded", name)
return nil
}
func (dbc *DBC) Parse(mod *CANModule, msg *Message) bool {
dbc.RLock()
defer dbc.RUnlock()
// did we load any DBC database?
if dbc.db == nil {
return false
}
// if the database contains this message id
if message, found := dbc.db.Message(msg.Frame.ID); found {
msg.Name = message.Name
// find source full info in DBC nodes
sourceName := message.SenderNode
sourceDesc := ""
if sender, found := dbc.db.Node(message.SenderNode); found {
sourceName = sender.Name
sourceDesc = sender.Description
}
// add CAN source if new
_, msg.Source = mod.Session.CAN.AddIfNew(sourceName, sourceDesc, msg.Frame.Data[:])
// parse signals
for _, signal := range message.Signals {
var value string
if signal.Length <= 32 && signal.IsFloat {
value = fmt.Sprintf("%f", signal.UnmarshalFloat(msg.Frame.Data))
} else if signal.Length == 1 {
value = fmt.Sprintf("%v", signal.UnmarshalBool(msg.Frame.Data))
} else if signal.IsSigned {
value = fmt.Sprintf("%d", signal.UnmarshalSigned(msg.Frame.Data))
} else {
value = fmt.Sprintf("%d", signal.UnmarshalUnsigned(msg.Frame.Data))
}
msg.Signals[signal.Name] = str.Trim(fmt.Sprintf("%s %s", value, signal.Unit))
}
return true
}
return false
}
func (dbc *DBC) MessagesBySender(senderId string) []*descriptor.Message {
dbc.RLock()
defer dbc.RUnlock()
fromSender := make([]*descriptor.Message, 0)
if dbc.db == nil {
return fromSender
}
for _, msg := range dbc.db.Messages {
if msg.SenderNode == senderId {
fromSender = append(fromSender, msg)
}
}
return fromSender
}
func (dbc *DBC) MessageById(frameID uint32) *descriptor.Message {
dbc.RLock()
defer dbc.RUnlock()
if dbc.db == nil {
return nil
}
if message, found := dbc.db.Message(frameID); found {
return message
}
return nil
}
func (dbc *DBC) Messages() []*descriptor.Message {
dbc.RLock()
defer dbc.RUnlock()
if dbc.db == nil {
return nil
}
return dbc.db.Messages
}
func (dbc *DBC) AvailableMessages() []string {
avail := []string{}
for _, msg := range dbc.Messages() {
avail = append(avail, fmt.Sprintf("%d (%s)", msg.ID, msg.Name))
}
return avail
}
func (dbc *DBC) Senders() []string {
dbc.RLock()
defer dbc.RUnlock()
senders := make([]string, 0)
if dbc.db == nil {
return senders
}
uniq := make(map[string]bool)
for _, msg := range dbc.db.Messages {
uniq[msg.SenderNode] = true
}
for sender, _ := range uniq {
senders = append(senders, sender)
}
return senders
}