You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2022/11/22 13:25:19 UTC
[plc4x] branch develop updated: feat(plc4go/bacnet): progress on network stack
This is an automated email from the ASF dual-hosted git repository.
sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/develop by this push:
new 09796b07b2 feat(plc4go/bacnet): progress on network stack
09796b07b2 is described below
commit 09796b07b20a52f4cf244e798a3a5579a48b9ded
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Tue Nov 22 14:25:11 2022 +0100
feat(plc4go/bacnet): progress on network stack
---
plc4go/internal/bacnetip/ApplicationLayer.go | 16 +-
.../bacnetip/BACnetVirtualLinkLayerService.go | 6 +-
plc4go/internal/bacnetip/CommunicationsModule.go | 8 +-
plc4go/internal/bacnetip/MessageCodec.go | 2 +-
plc4go/internal/bacnetip/NetworkService.go | 424 +++++++++++++++++++--
plc4go/internal/bacnetip/PDU.go | 83 ++--
plc4go/internal/bacnetip/Settings.go | 38 ++
7 files changed, 489 insertions(+), 88 deletions(-)
diff --git a/plc4go/internal/bacnetip/ApplicationLayer.go b/plc4go/internal/bacnetip/ApplicationLayer.go
index 1f5ac4e167..2d7f279317 100644
--- a/plc4go/internal/bacnetip/ApplicationLayer.go
+++ b/plc4go/internal/bacnetip/ApplicationLayer.go
@@ -96,7 +96,7 @@ type SSM struct {
ssmSAP SSMSAPRequirements
- pduAddress Address
+ pduAddress *Address
deviceInfo *DeviceInfo
invokeId uint8
@@ -121,10 +121,10 @@ type SSM struct {
maxApduLengthAccepted readWriteModel.MaxApduLengthAccepted
}
-func NewSSM(sap SSMSAPRequirements, pduAddress Address) (SSM, error) {
+func NewSSM(sap SSMSAPRequirements, pduAddress *Address) (SSM, error) {
log.Debug().Interface("sap", sap).Interface("pdu_address", pduAddress).Msg("init")
var deviceInfo *DeviceInfo
- deviceInfoTemp, ok := sap.GetDeviceInfoCache().GetDeviceInfo(DeviceInfoCacheKey{PduSource: &pduAddress})
+ deviceInfoTemp, ok := sap.GetDeviceInfoCache().GetDeviceInfo(DeviceInfoCacheKey{PduSource: pduAddress})
if ok {
deviceInfo = &deviceInfoTemp
}
@@ -377,7 +377,7 @@ type ClientSSM struct {
SSM
}
-func NewClientSSM(sap SSMSAPRequirements, pduAddress Address) (*ClientSSM, error) {
+func NewClientSSM(sap SSMSAPRequirements, pduAddress *Address) (*ClientSSM, error) {
log.Debug().Interface("sap", sap).Interface("pduAddress", pduAddress).Msg("init")
ssm, err := NewSSM(sap, pduAddress)
if err != nil {
@@ -417,8 +417,7 @@ func (c *ClientSSM) Request(apdu _PDU) error {
log.Debug().Msgf("request\n%c", apdu)
// make sure it has a good source and destination
- nullAddress, _ := NewAddress()
- apdu = NewPDUFromPDU(apdu, WithPDUSource(*nullAddress), WithPDUDestination(c.pduAddress))
+ apdu = NewPDUFromPDU(apdu, WithPDUSource(nil), WithPDUDestination(c.pduAddress))
// send it via the device
return c.ssmSAP.Request(apdu)
@@ -533,8 +532,7 @@ func (c *ClientSSM) Response(apdu _PDU) error {
log.Debug().Msgf("response\n%c", apdu)
// make sure it has a good source and destination
- nullAddress, _ := NewAddress()
- apdu = NewPDUFromPDU(apdu, WithPDUSource(c.pduAddress), WithPDUDestination(*nullAddress))
+ apdu = NewPDUFromPDU(apdu, WithPDUSource(c.pduAddress), WithPDUDestination(nil))
// send it to the application
return c.ssmSAP.SapResponse(apdu)
@@ -951,7 +949,7 @@ type ServerSSM struct {
segmentedResponseAccepted bool
}
-func NewServerSSM(sap SSMSAPRequirements, pduAddress Address) (*ServerSSM, error) {
+func NewServerSSM(sap SSMSAPRequirements, pduAddress *Address) (*ServerSSM, error) {
log.Debug().Interface("sap", sap).Interface("pduAddress", pduAddress).Msg("init")
ssm, err := NewSSM(sap, pduAddress)
if err != nil {
diff --git a/plc4go/internal/bacnetip/BACnetVirtualLinkLayerService.go b/plc4go/internal/bacnetip/BACnetVirtualLinkLayerService.go
index 70104186ec..9e7212872a 100644
--- a/plc4go/internal/bacnetip/BACnetVirtualLinkLayerService.go
+++ b/plc4go/internal/bacnetip/BACnetVirtualLinkLayerService.go
@@ -121,7 +121,7 @@ func NewUDPMultiplexer(address interface{}, noBroadcast bool) (*UDPMultiplexer,
log.Debug().Msgf("address: %v", u.address)
log.Debug().Msgf("addrTuple: %v", u.addrTuple)
log.Debug().Msgf("addrBroadcastTuple: %v", u.addrBroadcastTuple)
- //log.Debug().Msgf("route_aware: %v", settings.RouteAware)
+ log.Debug().Msgf("route_aware: %v", settings.RouteAware)
// create and bind direct address
var err error
@@ -176,7 +176,7 @@ func (m *UDPMultiplexer) Indication(server *_MultiplexServer, pdu _PDU) error {
pduDestination := pdu.GetPDUDestination()
// broadcast message
- var dest Address
+ var dest *Address
if pduDestination.AddrType == LOCAL_BROADCAST_ADDRESS {
// interface might not support broadcasts
if m.addrBroadcastTuple == nil {
@@ -187,7 +187,7 @@ func (m *UDPMultiplexer) Indication(server *_MultiplexServer, pdu _PDU) error {
if err != nil {
return errors.Wrap(err, "error getting address from tuple")
}
- dest = *address
+ dest = address
log.Debug().Msgf("requesting local broadcast: %v", dest)
} else if pduDestination.AddrType == LOCAL_STATION_ADDRESS {
dest = pduDestination
diff --git a/plc4go/internal/bacnetip/CommunicationsModule.go b/plc4go/internal/bacnetip/CommunicationsModule.go
index 95d9e8c89c..c666e2d2ff 100644
--- a/plc4go/internal/bacnetip/CommunicationsModule.go
+++ b/plc4go/internal/bacnetip/CommunicationsModule.go
@@ -43,16 +43,16 @@ func init() {
// TODO: implement me
type _PCI struct {
pduUserData interface{}
- pduSource Address
- pduDestination Address
+ pduSource *Address
+ pduDestination *Address
}
-func _New_PCI(pduUserData interface{}, pduSource Address, pduDestination Address) *_PCI {
+func _New_PCI(pduUserData interface{}, pduSource *Address, pduDestination *Address) *_PCI {
return &_PCI{pduUserData, pduSource, pduDestination}
}
func (p *_PCI) String() string {
- return fmt.Sprintf("pduUserData:\n%s\n, pduSource: %s, pduDestination: %s", p.pduUserData, &p.pduSource, &p.pduDestination)
+ return fmt.Sprintf("pduUserData:\n%s\n, pduSource: %s, pduDestination: %s", p.pduUserData, p.pduSource, p.pduDestination)
}
// _Client is an interface used for documentation
diff --git a/plc4go/internal/bacnetip/MessageCodec.go b/plc4go/internal/bacnetip/MessageCodec.go
index 2cc5735f0b..a037367ae5 100644
--- a/plc4go/internal/bacnetip/MessageCodec.go
+++ b/plc4go/internal/bacnetip/MessageCodec.go
@@ -96,7 +96,7 @@ func (m *ApplicationLayerMessageCodec) Send(message spi.Message) error {
if err2 != nil {
panic(err2)
}
- iocb, err := NewIOCB(NewPDU(message, WithPDUDestination(*address)), m.remoteAddress)
+ iocb, err := NewIOCB(NewPDU(message, WithPDUDestination(address)), m.remoteAddress)
if err != nil {
return errors.Wrap(err, "error creating IOCB")
}
diff --git a/plc4go/internal/bacnetip/NetworkService.go b/plc4go/internal/bacnetip/NetworkService.go
index a0b1c80142..c00ff11c04 100644
--- a/plc4go/internal/bacnetip/NetworkService.go
+++ b/plc4go/internal/bacnetip/NetworkService.go
@@ -21,20 +21,92 @@ package bacnetip
import (
"fmt"
+ readWriteModel "github.com/apache/plc4x/plc4go/protocols/bacnetip/readwrite/model"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
+ "math"
)
+type RouterStatus uint8
+
+const (
+ ROUTER_AVAILABLE RouterStatus = iota // normal
+ ROUTER_BUSY // router is busy
+ ROUTER_DISCONNECTED // could make a connection, but hasn't
+ ROUTER_UNREACHABLE // temporarily unreachable
+)
+
+func (r RouterStatus) String() string {
+ switch r {
+ case ROUTER_AVAILABLE:
+ return "ROUTER_AVAILABLE"
+ case ROUTER_BUSY:
+ return "ROUTER_BUSY"
+ case ROUTER_DISCONNECTED:
+ return "ROUTER_DISCONNECTED"
+ case ROUTER_UNREACHABLE:
+ return "ROUTER_UNREACHABLE"
+ default:
+ return "Unknown"
+ }
+}
+
+type RouterInfo struct {
+ snet *uint16
+ address Address
+ dnets map[*uint16]RouterStatus
+}
+
+func (r RouterInfo) String() string {
+ return fmt.Sprintf("%#q", r)
+}
+
+type RouterInfoCache struct {
+ routers map[*uint16]*RouterInfo // TODO: snet -> {Address: RouterInfo}
+ pathInfo map[*uint16]*RouterInfo // TODO: (snet, dnet) -> RouterInfo
+}
+
+func NewRouterInfoCache() *RouterInfoCache {
+ log.Debug().Msg("NewRouterInfoCache")
+ return &RouterInfoCache{
+ routers: map[*uint16]*RouterInfo{},
+ pathInfo: map[*uint16]*RouterInfo{},
+ }
+}
+
+func (n *RouterInfoCache) GetRouterInfo(*uint16, *uint16) *RouterInfo {
+ panic("not implemented yet")
+ return nil
+}
+
+func (n *RouterInfoCache) UpdateRouterInfo(*uint16, interface{}, interface{}) error {
+ panic("not implemented yet")
+ return nil
+}
+
+func (n *RouterInfoCache) UpdateRouterStatus(*uint16, *Address, []*uint16) {
+ panic("not implemented yet")
+}
+
+func (n *RouterInfoCache) DeleteRouterInfo(*uint16, interface{}, interface{}) error {
+ panic("not implemented yet")
+ return nil
+}
+
+func (n *RouterInfoCache) UpdateSourceNetwork() {
+ panic("not implemented yet")
+}
+
// TODO: implement me
type NetworkAdapter struct {
*Client
adapterSAP *NetworkServiceAccessPoint
- adapterNet interface{}
+ adapterNet *uint16
adapterAddr *Address
adapterNetConfigured *int
}
-func NewNetworkAdapter(sap *NetworkServiceAccessPoint, net interface{}, addr *Address, cid *int) (*NetworkAdapter, error) {
+func NewNetworkAdapter(sap *NetworkServiceAccessPoint, net *uint16, addr *Address, cid *int) (*NetworkAdapter, error) {
n := &NetworkAdapter{
adapterSAP: sap,
adapterNet: net,
@@ -55,28 +127,35 @@ func NewNetworkAdapter(sap *NetworkServiceAccessPoint, net interface{}, addr *Ad
// Confirmation Decode upstream PDUs and pass them up to the service access point.
func (n *NetworkAdapter) Confirmation(npdu _PDU) error {
- log.Debug().Msgf("confirmation\n%s\n%s", npdu, n.adapterNet)
+ log.Debug().Msgf("confirmation\n%s\n%d", npdu, n.adapterNet)
- // TODO: we need generics otherwise this won't work at all here
- return n.adapterSAP.ProcessNPDU(npdu)
+ return n.adapterSAP.ProcessNPDU(n, npdu)
}
// ProcessNPDU Encode NPDUs from the service access point and send them downstream.
func (n *NetworkAdapter) ProcessNPDU(npdu _PDU) error {
- log.Debug().Msgf("ProcessNPDU\n%s\n(net=%s)", npdu, n.adapterNet)
+ log.Debug().Msgf("ProcessNPDU\n%s\n(net=%d)", npdu, n.adapterNet)
return n.Request(npdu)
}
+func (n *NetworkAdapter) EstablishConnectionToNetwork(net interface{}) error {
+ panic("not implemented yet")
+}
+
+func (n *NetworkAdapter) DisconnectConnectionToNetwork(net interface{}) error {
+ panic("not implemented yet")
+}
+
type NetworkServiceAccessPoint struct {
*ServiceAccessPoint
*Server
- adapters map[string]*NetworkAdapter
- routerInfoCache interface{}
- pendingNets map[string]interface{}
+ adapters map[*uint16]*NetworkAdapter
+ routerInfoCache *RouterInfoCache
+ pendingNets map[*uint16][]_PDU
localAdapter *NetworkAdapter
}
-func NewNetworkServiceAccessPoint(routerInfoCache interface{}, sapID *int, sid *int) (*NetworkServiceAccessPoint, error) {
+func NewNetworkServiceAccessPoint(routerInfoCache *RouterInfoCache, sapID *int, sid *int) (*NetworkServiceAccessPoint, error) {
n := &NetworkServiceAccessPoint{}
var err error
n.ServiceAccessPoint, err = NewServiceAccessPoint(sapID, n)
@@ -89,16 +168,16 @@ func NewNetworkServiceAccessPoint(routerInfoCache interface{}, sapID *int, sid *
}
// map of directly connected networks
- n.adapters = make(map[string]*NetworkAdapter)
+ n.adapters = make(map[*uint16]*NetworkAdapter)
// use the provided cache or make a default one
if routerInfoCache == nil {
- // TODO: create a new cache
+ routerInfoCache = NewRouterInfoCache()
}
n.routerInfoCache = routerInfoCache
// map to a list of application layer packets waiting for a path
- n.pendingNets = make(map[string]interface{})
+ n.pendingNets = make(map[*uint16][]_PDU)
return n, nil
}
@@ -120,12 +199,11 @@ func NewNetworkServiceAccessPoint(routerInfoCache interface{}, sapID *int, sid *
Called for applications or routers, bind to the network, send up
APDUs with a metching address.
*/
-func (n *NetworkServiceAccessPoint) bind(server _Server, net interface{}, address *Address) error {
+func (n *NetworkServiceAccessPoint) bind(server _Server, net *uint16, address *Address) error {
log.Debug().Msgf("bind %v net=%v address=%v", server, net, address)
- netKey := fmt.Sprintf("%v", net)
// make sure this hasn't already been called with this network
- if _, ok := n.adapters[netKey]; ok {
+ if _, ok := n.adapters[net]; ok {
return errors.Errorf("Allready bound: %v", net)
}
// create an adapter object, add it to our map
@@ -133,8 +211,8 @@ func (n *NetworkServiceAccessPoint) bind(server _Server, net interface{}, addres
if err != nil {
return errors.Wrap(err, "error creating adapter")
}
- n.adapters[netKey] = adapter
- log.Debug().Msgf("adapter: %v, %v", netKey, adapter)
+ n.adapters[net] = adapter
+ log.Debug().Msgf("adapter: %v, %v", net, adapter)
// if the address was given, make it the "local" one
if address != nil {
@@ -156,28 +234,320 @@ func (n *NetworkServiceAccessPoint) bind(server _Server, net interface{}, addres
return bind(adapter, server)
}
-func (n *NetworkServiceAccessPoint) UpdateRouterReference() error {
- panic("not implemented yet")
+// UpdateRouterReference Update references to routers.
+func (n *NetworkServiceAccessPoint) UpdateRouterReference(snet *uint16, address, dnets interface{}) error {
+ log.Debug().Msgf("UpdateRouterReference %d %s %d", snet, address, dnets)
+
+ // see if we have an adapter for the snet
+ _, ok := n.adapters[snet]
+ if !ok {
+ return errors.Errorf("no adapter for network: %d", snet)
+ }
+
+ // pass this along to the cache
+ return n.routerInfoCache.UpdateRouterInfo(snet, address, dnets)
}
-func (n *NetworkServiceAccessPoint) DeleteRouterReference() error {
- panic("not implemented yet")
+// DeleteRouterReference Delete references to routers/networks.
+func (n *NetworkServiceAccessPoint) DeleteRouterReference(snet *uint16, address, dnets interface{}) error {
+ log.Debug().Msgf("NetworkServiceAccessPoint %d %s %s", snet, address, dnets)
+
+ // see if we have an adapter for the snet
+ _, ok := n.adapters[snet]
+ if !ok {
+ return errors.Errorf("no adapter for network: %d", snet)
+ }
+
+ //pass this along to the cache
+ return n.routerInfoCache.DeleteRouterInfo(snet, address, dnets)
}
-func (n *NetworkServiceAccessPoint) Indication(npdu _PDU) error {
+func (n *NetworkServiceAccessPoint) Indication(pdu _PDU) error {
+ log.Debug().Msgf("Indication:\n%s", pdu)
+
+ // make sure our configuration is OK
+ if len(n.adapters) == 0 {
+ return errors.New("no adapters")
+ }
+
+ // get the local adapter
+ localAdapter := n.localAdapter
+ log.Debug().Msgf("localAdapter: %s", localAdapter)
+
+ // get the apdu
+ apdu := pdu.GetMessage().(readWriteModel.APDU)
+
+ // build a npdu
+ pduDestination := pdu.GetPDUDestination()
+
+ // the hop count always starts out big
+ hopCount := uint8(0xff)
+
+ // if this is route aware, use it for the destination
+ if settings.RouteAware && pduDestination.AddrRoute != nil {
+ // always a local station for now, in theory this could also be
+ // a local broadcast address, remote station, or remote broadcast
+ // but that is not supported by the patterns
+ if pduDestination.AddrRoute.AddrType != LOCAL_STATION_ADDRESS {
+ panic("Route must be of type local station")
+ }
+
+ var dadr *Address
+ switch pduDestination.AddrType {
+ case REMOTE_STATION_ADDRESS, REMOTE_BROADCAST_ADDRESS, GLOBAL_BROADCAST_ADDRESS:
+ dadr = pduDestination.AddrRoute
+ }
+
+ pdu.SetPDUDestination(pduDestination.AddrRoute)
+ npdu, err := buildNPDU(hopCount, nil, dadr, pdu.GetExpectingReply(), pdu.GetNetworkPriority(), apdu)
+ if err != nil {
+ return errors.Wrap(err, "error building NPDU")
+ }
+ return localAdapter.ProcessNPDU(NewPDUFromPDUWithNewMessage(pdu, npdu))
+ }
+
+ // local stations given to local adapter
+ if pduDestination.AddrType == LOCAL_STATION_ADDRESS {
+ npdu, err := buildNPDU(hopCount, nil, nil, pdu.GetExpectingReply(), pdu.GetNetworkPriority(), apdu)
+ if err != nil {
+ return errors.Wrap(err, "error building NPDU")
+ }
+ return localAdapter.ProcessNPDU(NewPDUFromPDUWithNewMessage(pdu, npdu))
+ }
+
+ // local broadcast given to local adapter
+ if pduDestination.AddrType == LOCAL_BROADCAST_ADDRESS {
+ npdu, err := buildNPDU(hopCount, nil, nil, pdu.GetExpectingReply(), pdu.GetNetworkPriority(), apdu)
+ if err != nil {
+ return errors.Wrap(err, "error building NPDU")
+ }
+ return localAdapter.ProcessNPDU(NewPDUFromPDUWithNewMessage(pdu, npdu))
+ }
+
+ // global broadcast
+ if pduDestination.AddrType == GLOBAL_BROADCAST_ADDRESS {
+ pdu.SetPDUDestination(NewLocalBroadcast(nil))
+ npdu, err := buildNPDU(hopCount, nil, pduDestination, pdu.GetExpectingReply(), pdu.GetNetworkPriority(), apdu)
+ if err != nil {
+ return errors.Wrap(err, "error building NPDU")
+ }
+
+ // send it to all of connected adapters
+ for _, xadapter := range n.adapters {
+ if err := xadapter.ProcessNPDU(NewPDUFromPDUWithNewMessage(pdu, npdu)); err != nil {
+ return errors.Wrap(err, "error processing NPDU")
+ }
+ }
+ return nil
+ }
+
+ // remote broadcast
+ switch pduDestination.AddrType {
+ case REMOTE_BROADCAST_ADDRESS, REMOTE_STATION_ADDRESS:
+ default:
+ return errors.Errorf("invalid destination address type: %s", pduDestination.AddrType)
+ }
+
+ dnet := pduDestination.AddrNet
+ log.Debug().Msgf("dnet %d", dnet)
+
+ // if the network matches the local adapter it's local
+ if dnet == localAdapter.adapterNet {
+ switch pduDestination.AddrType {
+ case REMOTE_STATION_ADDRESS:
+ log.Debug().Msg("mapping remote station to local station")
+ localStation, err := NewLocalStation(pduDestination.AddrAddress, nil)
+ if err != nil {
+ return errors.Wrap(err, "error building local station")
+ }
+ pdu.SetPDUDestination(localStation)
+ case REMOTE_BROADCAST_ADDRESS:
+ pdu.SetPDUDestination(NewLocalBroadcast(nil))
+ default:
+ return errors.New("Addressing problem")
+ }
+ npdu, err := buildNPDU(hopCount, nil, pduDestination, pdu.GetExpectingReply(), pdu.GetNetworkPriority(), apdu)
+ if err != nil {
+ return errors.Wrap(err, "error building NPDU")
+ }
+
+ return localAdapter.ProcessNPDU(NewPDUFromPDUWithNewMessage(pdu, npdu))
+ }
+
+ // get it ready to send when the path is found
+ pdu.SetPDUDestination(nil)
+
+ npdu, err := buildNPDU(hopCount, nil, pduDestination, pdu.GetExpectingReply(), pdu.GetNetworkPriority(), apdu)
+ if err != nil {
+ return errors.Wrap(err, "error building NPDU")
+ }
+
+ // we might already be waiting for a path for this network
+ if pendingNet, ok := n.pendingNets[dnet]; ok {
+ log.Debug().Msg("already waiting for a path")
+ var pdu _PDU = NewPDUFromPDUWithNewMessage(pdu, npdu)
+ n.pendingNets[dnet] = append(pendingNet, pdu)
+ return nil
+ }
+
+ // look for routing information from the network of one of our adapters to the destination network
+ var routerInfo *RouterInfo
+ var snetAdapter *NetworkAdapter
+ for snet, adapter := range n.adapters {
+ routerInfo = n.routerInfoCache.GetRouterInfo(snet, dnet)
+ if routerInfo != nil {
+ snetAdapter = adapter
+ break
+ }
+ }
+
+ // if there is info, we have a path
+ if routerInfo != nil {
+ log.Debug().Msgf("routerInfo found %s", routerInfo)
+
+ // check the path status
+ dnetStatus := routerInfo.dnets[dnet]
+ log.Debug().Msgf("dnetStatus %s", dnetStatus)
+
+ // fix the destination
+ pdu.SetPDUDestination(&routerInfo.address)
+
+ // send it along
+ return snetAdapter.ProcessNPDU(NewPDUFromPDUWithNewMessage(pdu, npdu))
+ } else {
+ log.Debug().Msg("no known path to network")
+
+ // add it to the list of packets waiting for the network
+ netList := append(n.pendingNets[dnet], NewPDUFromPDUWithNewMessage(pdu, npdu))
+ n.pendingNets[dnet] = netList
+
+ // build a request for the network and send it to all the adapters
+ whoIsRouterToNetwork := readWriteModel.NewNLMWhoIsRouterToNetwork(dnet, 0)
+
+ // send it to all the adapters
+ for _, adapter := range n.adapters {
+ if err := n.SapIndicationWithAdapter(adapter, NewPDU(whoIsRouterToNetwork, WithPDUDestination(NewLocalBroadcast(nil)))); err != nil {
+ return errors.Wrap(err, "error doing SapIndication")
+ }
+ }
+ }
+
panic("not implemented yet")
}
-func (n *NetworkServiceAccessPoint) ProcessNPDU(npdu _PDU) error {
- panic("not implemented yet")
+func buildNPDU(hopCount uint8, source *Address, destination *Address, expectingReply bool, networkPriority readWriteModel.NPDUNetworkPriority, apdu readWriteModel.APDU) (readWriteModel.NPDU, error) {
+ sourceSpecified := source != nil
+ var sourceNetworkAddress *uint16
+ var sourceLength *uint8
+ var sourceAddress []uint8
+ if sourceSpecified {
+ sourceSpecified = true
+ sourceNetworkAddress = source.AddrNet
+ sourceLengthValue := *source.AddrLen
+ if sourceLengthValue > math.MaxUint8 {
+ return nil, errors.New("source address length overflows")
+ }
+ sourceLengthValueUint8 := uint8(sourceLengthValue)
+ sourceLength = &sourceLengthValueUint8
+ sourceAddress = source.AddrAddress
+ if sourceLengthValueUint8 == 0 {
+ // If we define the len 0 we must not send the array
+ sourceAddress = nil
+ }
+ }
+ destinationSpecified := destination != nil
+ var destinationNetworkAddress *uint16
+ var destinationLength *uint8
+ var destinationAddress []uint8
+ if destinationSpecified {
+ destinationSpecified = true
+ destinationNetworkAddress = destination.AddrNet
+ destinationLengthValue := *destination.AddrLen
+ if destinationLengthValue > math.MaxUint8 {
+ return nil, errors.New("source address length overflows")
+ }
+ destinationLengthValueUint8 := uint8(destinationLengthValue)
+ destinationLength = &destinationLengthValueUint8
+ destinationAddress = destination.AddrAddress
+ if destinationLengthValueUint8 == 0 {
+ // If we define the len 0 we must not send the array
+ destinationAddress = nil
+ }
+ }
+ control := readWriteModel.NewNPDUControl(false, destinationSpecified, sourceSpecified, expectingReply, networkPriority)
+ return readWriteModel.NewNPDU(1, control, destinationNetworkAddress, destinationLength, destinationAddress, sourceNetworkAddress, sourceLength, sourceAddress, &hopCount, nil, apdu, 0), nil
+}
+
+func (n *NetworkServiceAccessPoint) ProcessNPDU(adapter *NetworkAdapter, pdu _PDU) error {
+ log.Debug().Msgf("ProcessNPDU %s, %s", adapter, pdu)
+
+ // make sure our configuration is OK
+ if len(n.adapters) == 0 {
+ return errors.New("no adapters")
+ }
+
+ npdu := pdu.GetMessage().(readWriteModel.NPDU)
+
+ var snet *uint16
+ // check for source routing
+ if npdu.GetControl().GetSourceSpecified() {
+ log.Debug().Msg("check source path")
+
+ // see if this is attempting to spoof a directly connected network
+ snet = npdu.GetSourceNetworkAddress()
+ if _, ok := n.adapters[snet]; !ok {
+ log.Warn().Msg("path error (1)")
+ return nil
+ }
+
+ // pass this new path along to the cache
+ n.routerInfoCache.UpdateRouterStatus(adapter.adapterNet, pdu.GetPDUSource(), []*uint16{snet})
+ }
+
+ var (
+ processLocally bool
+ forwardMessage bool
+ )
+ // check for destination routing
+ if npdu.GetControl().GetDestinationSpecified() {
+ log.Debug().Msg("no DADR")
+
+ processLocally = adapter == n.localAdapter || npdu.GetControl().GetMessageTypeFieldPresent()
+ forwardMessage = false
+ }
+ // TODO: we need the type from the DADR which we don't have in our readwrite.NPDU so we might need a special _NPDU
+
+ panic("implement me")
+ _ = processLocally
+ _ = forwardMessage
+ return nil
}
func (n *NetworkServiceAccessPoint) SapIndication(npdu _PDU) error {
- panic("not implemented yet")
+ panic("unused")
+}
+
+func (n *NetworkServiceAccessPoint) SapIndicationWithAdapter(adapter *NetworkAdapter, npdu _PDU) error {
+ log.Debug().Msgf("SapIndication %s %s", adapter, npdu)
+
+ // encode it as a generic NPDU
+ // TODO: we don't need that as a npdu is a npdu
+
+ // tell the adapter to process the NPDU
+ return adapter.ProcessNPDU(npdu)
}
func (n *NetworkServiceAccessPoint) SapConfirmation(npdu _PDU) error {
- panic("not implemented yet")
+ panic("unused")
+}
+
+func (n *NetworkServiceAccessPoint) SapConfirmationWithAdapter(adapter *NetworkAdapter, npdu _PDU) error {
+ log.Debug().Msgf("SapConfirmationWithAdapter %s %s", adapter, npdu)
+
+ // encode it as a generic NPDU
+ // TODO: we don't need that as a npdu is a npdu
+
+ return adapter.ProcessNPDU(npdu)
}
type NetworkServiceElement struct {
diff --git a/plc4go/internal/bacnetip/PDU.go b/plc4go/internal/bacnetip/PDU.go
index 1ea8bed052..a468c9caf4 100644
--- a/plc4go/internal/bacnetip/PDU.go
+++ b/plc4go/internal/bacnetip/PDU.go
@@ -96,7 +96,7 @@ type Address struct {
AddrNet *uint16
AddrAddress []byte
AddrLen *uint32
- AddrRoute *uint32
+ AddrRoute *Address
AddrIP *uint32
AddrMask *uint32
@@ -333,12 +333,8 @@ func uint32ToIpv4(number uint32) net.IP {
return ipv4
}
-type LocalStation struct {
- Address
-}
-
-func NewLocalStation(addr interface{}, route *uint32) (*LocalStation, error) {
- l := &LocalStation{}
+func NewLocalStation(addr interface{}, route *Address) (*Address, error) {
+ l := &Address{}
l.AddrType = LOCAL_STATION_ADDRESS
l.AddrRoute = route
@@ -361,12 +357,8 @@ func NewLocalStation(addr interface{}, route *uint32) (*LocalStation, error) {
return l, nil
}
-type RemoteStation struct {
- Address
-}
-
-func NewRemoteStation(net *uint16, addr interface{}, route *uint32) (*RemoteStation, error) {
- l := &RemoteStation{}
+func NewRemoteStation(net *uint16, addr interface{}, route *Address) (*Address, error) {
+ l := &Address{}
l.AddrType = REMOTE_STATION_ADDRESS
l.AddrNet = net
l.AddrRoute = route
@@ -390,38 +382,26 @@ func NewRemoteStation(net *uint16, addr interface{}, route *uint32) (*RemoteStat
return l, nil
}
-type LocalBroadcast struct {
- Address
-}
-
-func NewLocalBroadcast(route *uint32) (*LocalBroadcast, error) {
- l := &LocalBroadcast{}
+func NewLocalBroadcast(route *Address) *Address {
+ l := &Address{}
l.AddrType = LOCAL_BROADCAST_ADDRESS
l.AddrRoute = route
- return l, nil
-}
-
-type RemoteBroadcast struct {
- Address
+ return l
}
-func NewRemoteBroadcast(net *uint16, route *uint32) (*RemoteBroadcast, error) {
- r := &RemoteBroadcast{}
+func NewRemoteBroadcast(net *uint16, route *Address) *Address {
+ r := &Address{}
r.AddrType = REMOTE_BROADCAST_ADDRESS
r.AddrNet = net
r.AddrRoute = route
- return r, nil
+ return r
}
-type GlobalBroadcast struct {
- Address
-}
-
-func NewGlobalBroadcast(route *uint32) (*GlobalBroadcast, error) {
- g := &GlobalBroadcast{}
+func NewGlobalBroadcast(route *Address) *Address {
+ g := &Address{}
g.AddrType = GLOBAL_BROADCAST_ADDRESS
g.AddrRoute = route
- return g, nil
+ return g
}
type PCI struct {
@@ -434,7 +414,7 @@ func (p *PCI) String() string {
return fmt.Sprintf("PCI{%s, expectingReply: %t, networkPriority: %s}", p._PCI, p.expectingReply, p.networkPriority)
}
-func NewPCI(msg spi.Message, pduSource Address, pduDestination Address, expectingReply bool, networkPriority readWriteModel.NPDUNetworkPriority) *PCI {
+func NewPCI(msg spi.Message, pduSource *Address, pduDestination *Address, expectingReply bool, networkPriority readWriteModel.NPDUNetworkPriority) *PCI {
return &PCI{
_New_PCI(msg, pduSource, pduDestination),
expectingReply,
@@ -445,8 +425,9 @@ func NewPCI(msg spi.Message, pduSource Address, pduDestination Address, expectin
type _PDU interface {
spi.Message
GetMessage() spi.Message
- GetPDUSource() Address
- GetPDUDestination() Address
+ GetPDUSource() *Address
+ GetPDUDestination() *Address
+ SetPDUDestination(*Address)
GetExpectingReply() bool
GetNetworkPriority() readWriteModel.NPDUNetworkPriority
}
@@ -457,10 +438,9 @@ type PDU struct {
}
func NewPDU(msg spi.Message, pduOptions ...PDUOption) *PDU {
- nullAddress, _ := NewAddress()
p := &PDU{
msg,
- NewPCI(msg, *nullAddress, *nullAddress, false, readWriteModel.NPDUNetworkPriority_NORMAL_MESSAGE),
+ NewPCI(msg, nil, nil, false, readWriteModel.NPDUNetworkPriority_NORMAL_MESSAGE),
}
for _, option := range pduOptions {
option(p)
@@ -480,7 +460,18 @@ func NewPDUFromPDU(pdu _PDU, pduOptions ...PDUOption) *PDU {
return p
}
-func NewPDUWithAllOptions(msg spi.Message, pduSource Address, pduDestination Address, expectingReply bool, networkPriority readWriteModel.NPDUNetworkPriority) *PDU {
+func NewPDUFromPDUWithNewMessage(pdu _PDU, msg spi.Message, pduOptions ...PDUOption) *PDU {
+ p := &PDU{
+ msg,
+ NewPCI(msg, pdu.GetPDUSource(), pdu.GetPDUDestination(), pdu.GetExpectingReply(), pdu.GetNetworkPriority()),
+ }
+ for _, option := range pduOptions {
+ option(p)
+ }
+ return p
+}
+
+func NewPDUWithAllOptions(msg spi.Message, pduSource *Address, pduDestination *Address, expectingReply bool, networkPriority readWriteModel.NPDUNetworkPriority) *PDU {
return &PDU{
msg,
NewPCI(msg, pduSource, pduDestination, expectingReply, networkPriority),
@@ -489,13 +480,13 @@ func NewPDUWithAllOptions(msg spi.Message, pduSource Address, pduDestination Add
type PDUOption func(pdu *PDU)
-func WithPDUSource(pduSource Address) PDUOption {
+func WithPDUSource(pduSource *Address) PDUOption {
return func(pdu *PDU) {
pdu.pduSource = pduSource
}
}
-func WithPDUDestination(pduDestination Address) PDUOption {
+func WithPDUDestination(pduDestination *Address) PDUOption {
return func(pdu *PDU) {
pdu.pduDestination = pduDestination
}
@@ -517,14 +508,18 @@ func (p *PDU) GetMessage() spi.Message {
return p.Message
}
-func (p *PDU) GetPDUSource() Address {
+func (p *PDU) GetPDUSource() *Address {
return p.pduSource
}
-func (p *PDU) GetPDUDestination() Address {
+func (p *PDU) GetPDUDestination() *Address {
return p.pduDestination
}
+func (p *PDU) SetPDUDestination(destination *Address) {
+ p.pduDestination = destination
+}
+
func (p *PDU) GetExpectingReply() bool {
return p.expectingReply
}
diff --git a/plc4go/internal/bacnetip/Settings.go b/plc4go/internal/bacnetip/Settings.go
new file mode 100644
index 0000000000..d27cc72c71
--- /dev/null
+++ b/plc4go/internal/bacnetip/Settings.go
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package bacnetip
+
+type Settings struct {
+ Debug bool
+ Color bool
+ DebugFile string
+ MaxBytes uint
+ BackupCount uint
+ RouteAware bool
+}
+
+var settings = Settings{
+ Debug: false,
+ Color: false,
+ DebugFile: "",
+ MaxBytes: 1048576,
+ BackupCount: 5,
+ RouteAware: false,
+}