#580 supervisor wired comms networking logic

This commit is contained in:
Mikayla 2025-06-28 17:17:31 +00:00
parent 4a7fc6200e
commit 391b68d357
9 changed files with 177 additions and 143 deletions

View File

@ -249,6 +249,8 @@ function comms.scada_packet()
---@nodiscard ---@nodiscard
function public.raw_sendable() return self.raw end function public.raw_sendable() return self.raw end
---@nodiscard
function public.interface() return self.modem_msg_in.iface end
---@nodiscard ---@nodiscard
function public.local_channel() return self.modem_msg_in.s_channel end function public.local_channel() return self.modem_msg_in.s_channel end
---@nodiscard ---@nodiscard

View File

@ -212,6 +212,13 @@ end
--#region ENUMERATION TYPES --#region ENUMERATION TYPES
---@enum LISTEN_MODE
types.LISTEN_MODE = {
WIRELESS = 0,
WIRED = 1,
ALL = 2
}
---@enum TEMP_SCALE ---@enum TEMP_SCALE
types.TEMP_SCALE = { types.TEMP_SCALE = {
KELVIN = 1, KELVIN = 1,

View File

@ -24,7 +24,7 @@ local t_pack = table.pack
local util = {} local util = {}
-- scada-common version -- scada-common version
util.version = "1.5.3" util.version = "1.5.4"
util.TICK_TIME_S = 0.05 util.TICK_TIME_S = 0.05
util.TICK_TIME_MS = 50 util.TICK_TIME_MS = 50

View File

@ -5,6 +5,7 @@
local log = require("scada-common.log") local log = require("scada-common.log")
local ppm = require("scada-common.ppm") local ppm = require("scada-common.ppm")
local tcd = require("scada-common.tcd") local tcd = require("scada-common.tcd")
local types = require("scada-common.types")
local util = require("scada-common.util") local util = require("scada-common.util")
local facility = require("supervisor.config.facility") local facility = require("supervisor.config.facility")
@ -97,11 +98,15 @@ local tmp_cfg = {
RTU_Timeout = nil, ---@type number RTU_Timeout = nil, ---@type number
CRD_Timeout = nil, ---@type number CRD_Timeout = nil, ---@type number
PKT_Timeout = nil, ---@type number PKT_Timeout = nil, ---@type number
WirelessModem = true, ---@type boolean
WiredModem = false, ---@type string|false WiredModem = false, ---@type string|false
WirelessModem = false, ---@type boolean PLC_Listen = 0, ---@type LISTEN_MODE
RTU_Listen = 0, ---@type LISTEN_MODE
CRD_Listen = 0, ---@type LISTEN_MODE
PocketEnabled = true, ---@type boolean
PocketTest = true, ---@type boolean
TrustedRange = nil, ---@type number TrustedRange = nil, ---@type number
AuthKey = nil, ---@type string|nil AuthKey = nil, ---@type string|nil
PocketTest = true, ---@type boolean
LogMode = 0, ---@type LOG_MODE LogMode = 0, ---@type LOG_MODE
LogPath = "", LogPath = "",
LogDebug = false, LogDebug = false,
@ -134,11 +139,15 @@ local fields = {
{ "RTU_Timeout", "RTU Connection Timeout", 5 }, { "RTU_Timeout", "RTU Connection Timeout", 5 },
{ "CRD_Timeout", "CRD Connection Timeout", 5 }, { "CRD_Timeout", "CRD Connection Timeout", 5 },
{ "PKT_Timeout", "PKT Connection Timeout", 5 }, { "PKT_Timeout", "PKT Connection Timeout", 5 },
{ "WiredModem", "Wired Modem", false }, { "WirelessModem", "Wireless/Ender Comms Modem", true },
{ "WirelessModem", "Pocket Wireless/Ender Modem", true }, { "WiredModem", "Wired Comms Modem", false },
{ "PLC_Listen", "PLC Listen Mode", types.LISTEN_MODE.WIRELESS },
{ "RTU_Listen", "RTU Gateway Listen Mode", types.LISTEN_MODE.WIRELESS },
{ "CRD_Listen", "Coordinator Listen Mode", types.LISTEN_MODE.WIRELESS },
{ "PocketEnabled", "Pocket Connectivity", true },
{ "PocketTest", "Pocket Testing Features", true },
{ "TrustedRange", "Trusted Range", 0 }, { "TrustedRange", "Trusted Range", 0 },
{ "AuthKey", "Facility Auth Key" , "" }, { "AuthKey", "Facility Auth Key" , "" },
{ "PocketTest", "Pocket Testing Features", true },
{ "LogMode", "Log Mode", log.MODE.APPEND }, { "LogMode", "Log Mode", log.MODE.APPEND },
{ "LogPath", "Log Path", "/log.txt" }, { "LogPath", "Log Path", "/log.txt" },
{ "LogDebug", "Log Debug Messages", false }, { "LogDebug", "Log Debug Messages", false },

View File

@ -27,16 +27,16 @@ function databus.tx_versions(sv_v, comms_v)
databus.ps.publish("comms_version", comms_v) databus.ps.publish("comms_version", comms_v)
end end
-- transmit hardware status for the core comms modem connection state -- transmit hardware status for the wireless comms modem connection state
---@param has_modem boolean ---@param has_modem boolean
function databus.tx_hw_c_modem(has_modem) function databus.tx_hw_wl_modem(has_modem)
databus.ps.publish("has_c_modem", has_modem) databus.ps.publish("has_wl_modem", has_modem)
end end
-- transmit hardware status for the pocket modem connection state -- transmit hardware status for the wired comms modem connection state
---@param has_modem boolean ---@param has_modem boolean
function databus.tx_hw_p_modem(has_modem) function databus.tx_hw_wd_modem(has_modem)
databus.ps.publish("has_p_modem", has_modem) databus.ps.publish("has_wd_modem", has_modem)
end end
-- transmit PLC firmware version and session connection state -- transmit PLC firmware version and session connection state

View File

@ -11,65 +11,95 @@ local databus = require("supervisor.databus")
local pcie_bus = {} local pcie_bus = {}
local bus = { local bus = {
c_wired = false, ---@type string|false wired comms modem wired_modem = false, ---@type string|false wired comms modem name
c_nic = nil, ---@type nic core nic wl_nic = nil, ---@type nic|nil wireless nic
p_nic = nil ---@type nic|nil pocket nic wd_nic = nil ---@type nic|nil wired nic
} }
-- network cards -- network cards
---@class _svr_pcie_nic ---@class _svr_pcie_nic
---@field core nic the core comms NIC ---@field wl nic|nil the wireless comms NIC
---@field pocket nic the pocket NIC ---@field wd nic|nil the wired comms NIC
pcie_bus.nic = { pcie_bus.nic = {
-- close all channels then open a specified one on all nics -- close all channels and then open the configured channels on the appropriate nic(s)
---@param channel integer ---@param config svr_config
reset_open = function (channel) reset_open = function (config)
bus.c_nic.closeAll() if bus.wl_nic then
bus.c_nic.open(channel) bus.wl_nic.closeAll()
if bus.p_nic then if config.PLC_Listen % 2 == 0 then bus.wl_nic.open(config.PLC_Channel) end
bus.p_nic.closeAll() if config.RTU_Listen % 2 == 0 then bus.wl_nic.open(config.RTU_Channel) end
bus.p_nic.open(channel) if config.CRD_Listen % 2 == 0 then bus.wl_nic.open(config.CRD_Channel) end
if config.PocketEnabled then bus.wl_nic.open(config.PKT_Channel) end
end end
if bus.wd_nic then
bus.wd_nic.closeAll()
if config.PLC_Listen > 0 then bus.wd_nic.open(config.PLC_Channel) end
if config.RTU_Listen > 0 then bus.wd_nic.open(config.RTU_Channel) end
if config.CRD_Listen > 0 then bus.wd_nic.open(config.CRD_Channel) end
end end
end,
-- get the requested nic by interface
---@param iface string
---@return nic|nil
get = function(iface)
local dev = ppm.get_device(iface)
if dev then
if bus.wl_nic and bus.wl_nic.is_modem(dev) then return bus.wl_nic end
if bus.wd_nic and bus.wd_nic.is_modem(dev) then return bus.wd_nic end
end
return nil
end,
-- cards by interface
---@type { string: nic }
cards = {}
} }
-- initialize peripherals -- initialize peripherals
---@param config svr_config ---@param config svr_config
---@param println function ---@param println function
---@return boolean success
function pcie_bus.init(config, println) function pcie_bus.init(config, println)
-- setup networking peripheral(s) -- setup networking peripheral(s)
local core_modem, core_iface = ppm.get_wireless_modem()
if type(config.WiredModem) == "string" then if type(config.WiredModem) == "string" then
bus.c_wired = config.WiredModem bus.wired_modem = config.WiredModem
core_modem = ppm.get_wired_modem(config.WiredModem)
local wired_modem = ppm.get_wired_modem(bus.wired_modem)
if not (wired_modem and bus.wired_modem) then
println("startup> wired comms modem not found")
log.fatal("no wired comms modem on startup")
return false
end end
if not (core_modem and core_iface) then bus.wd_nic = network.nic(bus.wired_modem, wired_modem)
println("startup> core comms modem not found") pcie_bus.nic.cards[bus.wired_modem] = bus.wd_nic
log.fatal("no core comms modem on startup")
return
end end
bus.c_nic = network.nic(core_iface, core_modem) if config.WirelessModem then
local wireless_modem, wireless_iface = ppm.get_wireless_modem()
if config.WirelessModem and config.WiredModem then if not (wireless_modem and wireless_iface) then
local pocket_modem, pocket_iface = ppm.get_wireless_modem() println("startup> wireless comms modem not found")
log.fatal("no wireless comms modem on startup")
if not (pocket_modem and pocket_iface) then return false
println("startup> pocket wireless modem not found")
log.fatal("no pocket wireless modem on startup")
return
end end
bus.p_nic = network.nic(pocket_iface, pocket_modem) bus.wl_nic = network.nic(wireless_iface, wireless_modem)
pcie_bus.nic.cards[wireless_iface] = bus.wl_nic
end end
pcie_bus.nic.core = bus.c_nic pcie_bus.nic.wl = bus.wl_nic
pcie_bus.nic.pocket = bus.p_nic or bus.c_nic pcie_bus.nic.wd = bus.wd_nic
databus.tx_hw_c_modem(true) databus.tx_hw_wl_modem(true)
databus.tx_hw_p_modem(config.WirelessModem) databus.tx_hw_wd_modem(config.WirelessModem)
return true
end end
-- handle the connecting of a device -- handle the connecting of a device
@ -81,33 +111,27 @@ function pcie_bus.connect(iface, type, device, println)
if type == "modem" then if type == "modem" then
---@cast device Modem ---@cast device Modem
if device.isWireless() then if device.isWireless() then
if not (bus.c_wired or bus.c_nic.is_connected()) then if bus.wl_nic and not bus.wl_nic.is_connected() then
-- reconnected comms modem -- reconnected wireless comms modem
bus.c_nic.connect(device) bus.wl_nic.connect(device)
pcie_bus.nic.cards[iface] = bus.wl_nic
println("core comms modem reconnected") println("wireless comms modem reconnected")
log.info("core comms modem reconnected") log.info("wireless comms modem reconnected")
databus.tx_hw_c_modem(true) databus.tx_hw_wl_modem(true)
elseif bus.p_nic and not bus.p_nic.is_connected() then
-- reconnected pocket modem
bus.p_nic.connect(device)
println("pocket modem reconnected")
log.info("pocket modem reconnected")
databus.tx_hw_p_modem(true)
else else
log.info("unused wireless modem reconnected") log.info("unused wireless modem reconnected")
end end
elseif iface == bus.c_wired then elseif bus.wd_nic and (iface == bus.wired_modem) then
-- reconnected wired comms modem -- reconnected wired comms modem
bus.c_nic.connect(device) bus.wd_nic.connect(device)
pcie_bus.nic.cards[iface] = bus.wd_nic
println("core comms modem reconnected") println("wired comms modem reconnected")
log.info("core comms modem reconnected") log.info("wired comms modem reconnected")
databus.tx_hw_c_modem(true) databus.tx_hw_wl_modem(true)
else else
log.info("wired modem reconnected") log.info("wired modem reconnected")
end end
@ -115,45 +139,39 @@ function pcie_bus.connect(iface, type, device, println)
end end
-- handle the removal of a device -- handle the removal of a device
---@param iface string
---@param type string ---@param type string
---@param device table ---@param device table
---@param println function ---@param println function
function pcie_bus.remove(type, device, println) function pcie_bus.remove(iface, type, device, println)
if type == "modem" then if type == "modem" then
pcie_bus.nic.cards[iface] = nil
---@cast device Modem ---@cast device Modem
if bus.c_nic.is_modem(device) then if bus.wl_nic and bus.wl_nic.is_modem(device) then
bus.c_nic.disconnect() bus.wl_nic.disconnect()
println("core comms modem disconnected") println("wireless comms modem disconnected")
log.warning("core comms modem disconnected") log.warning("wireless comms modem disconnected")
local other_modem = ppm.get_wireless_modem()
if other_modem and not bus.c_wired then
log.info("found another wireless modem, using it for comms")
bus.c_nic.connect(other_modem)
else
databus.tx_hw_c_modem(false)
end
elseif bus.p_nic and bus.p_nic.is_modem(device) then
bus.p_nic.disconnect()
println("pocket modem disconnected")
log.warning("pocket modem disconnected")
local other_modem = ppm.get_wireless_modem() local other_modem = ppm.get_wireless_modem()
if other_modem then if other_modem then
log.info("found another wireless modem, using it for pocket comms") log.info("found another wireless modem, using it for comms")
bus.p_nic.connect(other_modem) bus.wl_nic.connect(other_modem)
else else
databus.tx_hw_p_modem(false) databus.tx_hw_wl_modem(false)
end end
elseif bus.wd_nic and bus.wd_nic.is_modem(device) then
bus.wd_nic.disconnect()
println("wired modem disconnected")
log.warning("wired modem disconnected")
databus.tx_hw_wd_modem(false)
else else
log.warning("non-comms modem disconnected") log.warning("non-comms modem disconnected")
end end
end end
end end
-- check if a dedicated pocket nic is in use
function pcie_bus.has_pocket_nic() return bus.p_nic ~= nil end
return pcie_bus return pcie_bus

View File

@ -81,9 +81,7 @@ local function _sv_handle_outq(session)
if msg ~= nil then if msg ~= nil then
if msg.qtype == mqueue.TYPE.PACKET then if msg.qtype == mqueue.TYPE.PACKET then
-- handle a packet to be sent -- handle a packet to be sent
if session.r_chan == self.config.PKT_Channel then session.nic.transmit(session.r_chan, self.config.SVR_Channel, msg.message)
pcie.nic.pocket.transmit(session.r_chan, self.config.SVR_Channel, msg.message)
else pcie.nic.core.transmit(session.r_chan, self.config.SVR_Channel, msg.message) end
elseif msg.qtype == mqueue.TYPE.COMMAND then elseif msg.qtype == mqueue.TYPE.COMMAND then
-- handle instruction/notification -- handle instruction/notification
elseif msg.qtype == mqueue.TYPE.DATA then elseif msg.qtype == mqueue.TYPE.DATA then
@ -155,9 +153,7 @@ local function _shutdown(session)
while session.out_queue.ready() do while session.out_queue.ready() do
local msg = session.out_queue.pop() local msg = session.out_queue.pop()
if msg ~= nil and msg.qtype == mqueue.TYPE.PACKET then if msg ~= nil and msg.qtype == mqueue.TYPE.PACKET then
if session.r_chan == self.config.PKT_Channel then session.nic.transmit(session.r_chan, self.config.SVR_Channel, msg.message)
pcie.nic.pocket.transmit(session.r_chan, self.config.SVR_Channel, msg.message)
else pcie.nic.core.transmit(session.r_chan, self.config.SVR_Channel, msg.message) end
end end
end end
@ -463,12 +459,13 @@ end
-- establish a new PLC session -- establish a new PLC session
---@nodiscard ---@nodiscard
---@param nic nic interface to use for this session
---@param source_addr integer PLC computer ID ---@param source_addr integer PLC computer ID
---@param i_seq_num integer initial (most recent) sequence number ---@param i_seq_num integer initial (most recent) sequence number
---@param for_reactor integer unit ID ---@param for_reactor integer unit ID
---@param version string PLC version ---@param version string PLC version
---@return integer|false session_id ---@return integer|false session_id
function svsessions.establish_plc_session(source_addr, i_seq_num, for_reactor, version) function svsessions.establish_plc_session(nic, source_addr, i_seq_num, for_reactor, version)
if svsessions.get_reactor_session(for_reactor) == nil and for_reactor >= 1 and for_reactor <= self.config.UnitCount then if svsessions.get_reactor_session(for_reactor) == nil and for_reactor >= 1 and for_reactor <= self.config.UnitCount then
---@class plc_session_struct ---@class plc_session_struct
local plc_s = { local plc_s = {
@ -476,6 +473,7 @@ function svsessions.establish_plc_session(source_addr, i_seq_num, for_reactor, v
open = true, open = true,
reactor = for_reactor, reactor = for_reactor,
version = version, version = version,
nic = nic,
r_chan = self.config.PLC_Channel, r_chan = self.config.PLC_Channel,
s_addr = source_addr, s_addr = source_addr,
in_queue = mqueue.new(), in_queue = mqueue.new(),
@ -513,17 +511,19 @@ end
-- establish a new RTU gateway session -- establish a new RTU gateway session
---@nodiscard ---@nodiscard
---@param nic nic interface to use for this session
---@param source_addr integer RTU gateway computer ID ---@param source_addr integer RTU gateway computer ID
---@param i_seq_num integer initial (most recent) sequence number ---@param i_seq_num integer initial (most recent) sequence number
---@param advertisement table RTU capability advertisement ---@param advertisement table RTU capability advertisement
---@param version string RTU gateway version ---@param version string RTU gateway version
---@return integer session_id ---@return integer session_id
function svsessions.establish_rtu_session(source_addr, i_seq_num, advertisement, version) function svsessions.establish_rtu_session(nic, source_addr, i_seq_num, advertisement, version)
---@class rtu_session_struct ---@class rtu_session_struct
local rtu_s = { local rtu_s = {
s_type = "rtu", s_type = "rtu",
open = true, open = true,
version = version, version = version,
nic = nic,
r_chan = self.config.RTU_Channel, r_chan = self.config.RTU_Channel,
s_addr = source_addr, s_addr = source_addr,
in_queue = mqueue.new(), in_queue = mqueue.new(),
@ -554,17 +554,19 @@ end
-- establish a new coordinator session -- establish a new coordinator session
---@nodiscard ---@nodiscard
---@param nic nic interface to use for this session
---@param source_addr integer coordinator computer ID ---@param source_addr integer coordinator computer ID
---@param i_seq_num integer initial (most recent) sequence number ---@param i_seq_num integer initial (most recent) sequence number
---@param version string coordinator version ---@param version string coordinator version
---@return integer|false session_id ---@return integer|false session_id
function svsessions.establish_crd_session(source_addr, i_seq_num, version) function svsessions.establish_crd_session(nic, source_addr, i_seq_num, version)
if svsessions.get_crd_session() == nil then if svsessions.get_crd_session() == nil then
---@class crd_session_struct ---@class crd_session_struct
local crd_s = { local crd_s = {
s_type = "crd", s_type = "crd",
open = true, open = true,
version = version, version = version,
nic = nic,
r_chan = self.config.CRD_Channel, r_chan = self.config.CRD_Channel,
s_addr = source_addr, s_addr = source_addr,
in_queue = mqueue.new(), in_queue = mqueue.new(),
@ -599,16 +601,18 @@ end
-- establish a new pocket diagnostics session -- establish a new pocket diagnostics session
---@nodiscard ---@nodiscard
---@param nic nic interface to use for this session
---@param source_addr integer pocket computer ID ---@param source_addr integer pocket computer ID
---@param i_seq_num integer initial (most recent) sequence number ---@param i_seq_num integer initial (most recent) sequence number
---@param version string pocket version ---@param version string pocket version
---@return integer|false session_id ---@return integer|false session_id
function svsessions.establish_pdg_session(source_addr, i_seq_num, version) function svsessions.establish_pdg_session(nic, source_addr, i_seq_num, version)
---@class pdg_session_struct ---@class pdg_session_struct
local pdg_s = { local pdg_s = {
s_type = "pkt", s_type = "pkt",
open = true, open = true,
version = version, version = version,
nic = nic,
r_chan = self.config.PKT_Channel, r_chan = self.config.PKT_Channel,
s_addr = source_addr, s_addr = source_addr,
in_queue = mqueue.new(), in_queue = mqueue.new(),

View File

@ -127,7 +127,7 @@ local function main()
end end
-- hardware bus initialization -- hardware bus initialization
pcie.init(config, println) if not pcie.init(config, println) then return end
-- start UI -- start UI
local fp_ok, message = renderer.try_start_ui(pcie.has_pocket_nic(), config.FrontPanelTheme, config.ColorMode) local fp_ok, message = renderer.try_start_ui(pcie.has_pocket_nic(), config.FrontPanelTheme, config.ColorMode)
@ -167,7 +167,7 @@ local function main()
if event == "peripheral_detach" then if event == "peripheral_detach" then
local type, device = ppm.handle_unmount(param1) local type, device = ppm.handle_unmount(param1)
if type ~= nil and device ~= nil then if type ~= nil and device ~= nil then
pcie.remove(type, device, println_ts) pcie.remove(param1, type, device, println_ts)
end end
elseif event == "peripheral" then elseif event == "peripheral" then
local type, device = ppm.mount(param1) local type, device = ppm.mount(param1)

View File

@ -137,16 +137,12 @@ function supervisor.comms(_version, fp_ok, facility)
comms.set_trusted_range(config.TrustedRange) comms.set_trusted_range(config.TrustedRange)
-- configure modem channels -- configure network channels
pcie.nic.reset_open(config.SVR_Channel) pcie.nic.reset_open(config)
-- pass system data and objects to svsessions -- pass system data and objects to svsessions
svsessions.init(fp_ok, config, facility) svsessions.init(fp_ok, config, facility)
-- get nic references
local c_nic = pcie.nic.core
local p_nic = pcie.nic.pocket
-- PRIVATE FUNCTIONS -- -- PRIVATE FUNCTIONS --
-- send an establish request response -- send an establish request response
@ -179,13 +175,8 @@ function supervisor.comms(_version, fp_ok, facility)
---@param distance integer ---@param distance integer
---@return modbus_frame|rplc_frame|mgmt_frame|crdn_frame|nil packet ---@return modbus_frame|rplc_frame|mgmt_frame|crdn_frame|nil packet
function public.parse_packet(side, sender, reply_to, message, distance) function public.parse_packet(side, sender, reply_to, message, distance)
local pkt = nil local pkt, nic = nil, pcie.nic.cards[side]
local s_pkt = c_nic.receive(side, sender, reply_to, message, distance) local s_pkt = nic.receive(side, sender, reply_to, message, distance)
if p_nic and not s_pkt then
-- try for it being from the pocket modem
s_pkt = p_nic.receive(side, sender, reply_to, message, distance)
end
if s_pkt then if s_pkt then
-- get as MODBUS TCP packet -- get as MODBUS TCP packet
@ -215,13 +206,16 @@ function supervisor.comms(_version, fp_ok, facility)
-- handle a packet -- handle a packet
---@param packet modbus_frame|rplc_frame|mgmt_frame|crdn_frame ---@param packet modbus_frame|rplc_frame|mgmt_frame|crdn_frame
function public.handle_packet(packet) function public.handle_packet(packet)
local nic = pcie.nic.get(packet.scada_frame.interface())
local l_chan = packet.scada_frame.local_channel() local l_chan = packet.scada_frame.local_channel()
local r_chan = packet.scada_frame.remote_channel() local r_chan = packet.scada_frame.remote_channel()
local src_addr = packet.scada_frame.src_addr() local src_addr = packet.scada_frame.src_addr()
local protocol = packet.scada_frame.protocol() local protocol = packet.scada_frame.protocol()
local i_seq_num = packet.scada_frame.seq_num() local i_seq_num = packet.scada_frame.seq_num()
if l_chan ~= config.SVR_Channel then if not nic then
log.error("received packet from unconfigured interface " .. packet.scada_frame.interface(), true)
elseif l_chan ~= config.SVR_Channel then
log.debug("received packet on unconfigured channel " .. l_chan, true) log.debug("received packet on unconfigured channel " .. l_chan, true)
elseif r_chan == config.PLC_Channel then elseif r_chan == config.PLC_Channel then
-- look for an associated session -- look for an associated session
@ -258,7 +252,7 @@ function supervisor.comms(_version, fp_ok, facility)
log.info(util.c("dropping PLC establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")")) log.info(util.c("dropping PLC establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")"))
end end
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
elseif dev_type == DEVICE_TYPE.PLC then elseif dev_type == DEVICE_TYPE.PLC then
-- PLC linking request -- PLC linking request
if packet.length == 4 and type(packet.data[4]) == "number" then if packet.length == 4 and type(packet.data[4]) == "number" then
@ -271,10 +265,10 @@ function supervisor.comms(_version, fp_ok, facility)
log.warning(util.c("PLC_ESTABLISH: denied assignment ", reactor_id, " outside of configured unit count ", config.UnitCount)) log.warning(util.c("PLC_ESTABLISH: denied assignment ", reactor_id, " outside of configured unit count ", config.UnitCount))
end end
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
else else
-- try to establish the session -- try to establish the session
local plc_id = svsessions.establish_plc_session(src_addr, i_seq_num, reactor_id, firmware_v) local plc_id = svsessions.establish_plc_session(nic, src_addr, i_seq_num, reactor_id, firmware_v)
if plc_id == false then if plc_id == false then
-- reactor already has a PLC assigned -- reactor already has a PLC assigned
@ -282,25 +276,25 @@ function supervisor.comms(_version, fp_ok, facility)
log.warning(util.c("PLC_ESTABLISH: assignment collision with reactor ", reactor_id)) log.warning(util.c("PLC_ESTABLISH: assignment collision with reactor ", reactor_id))
end end
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.COLLISION) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.COLLISION)
else else
-- got an ID; assigned to a reactor successfully -- got an ID; assigned to a reactor successfully
println(util.c("PLC (", firmware_v, ") [@", src_addr, "] \xbb reactor ", reactor_id, " connected")) println(util.c("PLC (", firmware_v, ") [@", src_addr, "] \xbb reactor ", reactor_id, " connected"))
log.info(util.c("PLC_ESTABLISH: PLC (", firmware_v, ") [@", src_addr, "] reactor unit ", reactor_id, " PLC connected with session ID ", plc_id)) log.info(util.c("PLC_ESTABLISH: PLC (", firmware_v, ") [@", src_addr, "] reactor unit ", reactor_id, " PLC connected with session ID ", plc_id))
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.ALLOW) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.ALLOW)
end end
end end
else else
log.debug("PLC_ESTABLISH: packet length mismatch/bad parameter type") log.debug("PLC_ESTABLISH: packet length mismatch/bad parameter type")
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
end end
else else
log.debug(util.c("illegal establish packet for device ", dev_type, " on PLC channel")) log.debug(util.c("illegal establish packet for device ", dev_type, " on PLC channel"))
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
end end
else else
log.debug("invalid establish packet (on PLC channel)") log.debug("invalid establish packet (on PLC channel)")
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
end end
else else
-- any other packet should be session related, discard it -- any other packet should be session related, discard it
@ -344,27 +338,27 @@ function supervisor.comms(_version, fp_ok, facility)
log.info(util.c("dropping RTU establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")")) log.info(util.c("dropping RTU establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")"))
end end
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
elseif dev_type == DEVICE_TYPE.RTU then elseif dev_type == DEVICE_TYPE.RTU then
if packet.length == 4 then if packet.length == 4 then
-- this is an RTU advertisement for a new session -- this is an RTU advertisement for a new session
local rtu_advert = packet.data[4] local rtu_advert = packet.data[4]
local s_id = svsessions.establish_rtu_session(src_addr, i_seq_num, rtu_advert, firmware_v) local s_id = svsessions.establish_rtu_session(nic, src_addr, i_seq_num, rtu_advert, firmware_v)
println(util.c("RTU (", firmware_v, ") [@", src_addr, "] \xbb connected")) println(util.c("RTU (", firmware_v, ") [@", src_addr, "] \xbb connected"))
log.info(util.c("RTU_ESTABLISH: RTU (",firmware_v, ") [@", src_addr, "] connected with session ID ", s_id)) log.info(util.c("RTU_ESTABLISH: RTU (",firmware_v, ") [@", src_addr, "] connected with session ID ", s_id))
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.ALLOW) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.ALLOW)
else else
log.debug("RTU_ESTABLISH: packet length mismatch") log.debug("RTU_ESTABLISH: packet length mismatch")
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
end end
else else
log.debug(util.c("illegal establish packet for device ", dev_type, " on RTU channel")) log.debug(util.c("illegal establish packet for device ", dev_type, " on RTU channel"))
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
end end
else else
log.debug("invalid establish packet (on RTU channel)") log.debug("invalid establish packet (on RTU channel)")
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
end end
else else
-- any other packet should be session related, discard it -- any other packet should be session related, discard it
@ -398,30 +392,30 @@ function supervisor.comms(_version, fp_ok, facility)
log.info(util.c("dropping coordinator establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")")) log.info(util.c("dropping coordinator establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")"))
end end
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
elseif dev_type == DEVICE_TYPE.CRD then elseif dev_type == DEVICE_TYPE.CRD then
-- this is an attempt to establish a new coordinator session -- this is an attempt to establish a new coordinator session
local s_id = svsessions.establish_crd_session(src_addr, i_seq_num, firmware_v) local s_id = svsessions.establish_crd_session(nic, src_addr, i_seq_num, firmware_v)
if s_id ~= false then if s_id ~= false then
println(util.c("CRD (", firmware_v, ") [@", src_addr, "] \xbb connected")) println(util.c("CRD (", firmware_v, ") [@", src_addr, "] \xbb connected"))
log.info(util.c("CRD_ESTABLISH: coordinator (", firmware_v, ") [@", src_addr, "] connected with session ID ", s_id)) log.info(util.c("CRD_ESTABLISH: coordinator (", firmware_v, ") [@", src_addr, "] connected with session ID ", s_id))
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.ALLOW, { config.UnitCount, facility.get_cooling_conf() }) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.ALLOW, { config.UnitCount, facility.get_cooling_conf() })
else else
if last_ack ~= ESTABLISH_ACK.COLLISION then if last_ack ~= ESTABLISH_ACK.COLLISION then
log.info("CRD_ESTABLISH: denied new coordinator [@" .. src_addr .. "] due to already being connected to another coordinator") log.info("CRD_ESTABLISH: denied new coordinator [@" .. src_addr .. "] due to already being connected to another coordinator")
end end
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.COLLISION) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.COLLISION)
end end
else else
log.debug(util.c("illegal establish packet for device ", dev_type, " on coordinator channel")) log.debug(util.c("illegal establish packet for device ", dev_type, " on coordinator channel"))
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
end end
else else
log.debug("CRD_ESTABLISH: establish packet length mismatch") log.debug("CRD_ESTABLISH: establish packet length mismatch")
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
end end
else else
-- any other packet should be session related, discard it -- any other packet should be session related, discard it
@ -465,22 +459,22 @@ function supervisor.comms(_version, fp_ok, facility)
log.info(util.c("dropping PDG establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")")) log.info(util.c("dropping PDG establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")"))
end end
_send_establish(p_nic or c_nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
elseif dev_type == DEVICE_TYPE.PKT then elseif dev_type == DEVICE_TYPE.PKT then
-- this is an attempt to establish a new pocket diagnostic session -- this is an attempt to establish a new pocket diagnostic session
local s_id = svsessions.establish_pdg_session(src_addr, i_seq_num, firmware_v) local s_id = svsessions.establish_pdg_session(nic, src_addr, i_seq_num, firmware_v)
println(util.c("PKT (", firmware_v, ") [@", src_addr, "] \xbb connected")) println(util.c("PKT (", firmware_v, ") [@", src_addr, "] \xbb connected"))
log.info(util.c("PDG_ESTABLISH: pocket (", firmware_v, ") [@", src_addr, "] connected with session ID ", s_id)) log.info(util.c("PDG_ESTABLISH: pocket (", firmware_v, ") [@", src_addr, "] connected with session ID ", s_id))
_send_establish(p_nic or c_nic, packet.scada_frame, ESTABLISH_ACK.ALLOW) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.ALLOW)
else else
log.debug(util.c("illegal establish packet for device ", dev_type, " on pocket channel")) log.debug(util.c("illegal establish packet for device ", dev_type, " on pocket channel"))
_send_establish(p_nic or c_nic, packet.scada_frame, ESTABLISH_ACK.DENY) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
end end
else else
log.debug("PDG_ESTABLISH: establish packet length mismatch") log.debug("PDG_ESTABLISH: establish packet length mismatch")
_send_establish(p_nic or c_nic, packet.scada_frame, ESTABLISH_ACK.DENY) _send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
end end
else else
-- any other packet should be session related, discard it -- any other packet should be session related, discard it