#580 supervisor wired/wireless dual networking
This commit is contained in:
parent
4d6c388f37
commit
fc24f39991
@ -17,7 +17,7 @@ local max_distance = nil
|
|||||||
local comms = {}
|
local comms = {}
|
||||||
|
|
||||||
-- protocol/data versions (protocol/data independent changes tracked by util.lua version)
|
-- protocol/data versions (protocol/data independent changes tracked by util.lua version)
|
||||||
comms.version = "3.0.8"
|
comms.version = "3.0.9"
|
||||||
comms.api_version = "0.0.10"
|
comms.api_version = "0.0.10"
|
||||||
|
|
||||||
---@enum PROTOCOL
|
---@enum PROTOCOL
|
||||||
@ -49,13 +49,14 @@ local MGMT_TYPE = {
|
|||||||
ESTABLISH = 0, -- establish new connection
|
ESTABLISH = 0, -- establish new connection
|
||||||
KEEP_ALIVE = 1, -- keep alive packet w/ RTT
|
KEEP_ALIVE = 1, -- keep alive packet w/ RTT
|
||||||
CLOSE = 2, -- close a connection
|
CLOSE = 2, -- close a connection
|
||||||
RTU_ADVERT = 3, -- RTU capability advertisement
|
PROBE = 3,
|
||||||
RTU_DEV_REMOUNT = 4, -- RTU multiblock possbily changed (formed, unformed) due to PPM remount
|
RTU_ADVERT = 4, -- RTU capability advertisement
|
||||||
RTU_TONE_ALARM = 5, -- instruct RTUs to play specified alarm tones
|
RTU_DEV_REMOUNT = 5, -- RTU multiblock possbily changed (formed, unformed) due to PPM remount
|
||||||
DIAG_TONE_GET = 6, -- (API) diagnostic: get alarm tones
|
RTU_TONE_ALARM = 6, -- instruct RTUs to play specified alarm tones
|
||||||
DIAG_TONE_SET = 7, -- (API) diagnostic: set alarm tones
|
DIAG_TONE_GET = 7, -- (API) diagnostic: get alarm tones
|
||||||
DIAG_ALARM_SET = 8, -- (API) diagnostic: set alarm to simulate audio for
|
DIAG_TONE_SET = 8, -- (API) diagnostic: set alarm tones
|
||||||
INFO_LIST_CMP = 9 -- (API) info: list all computers on the network
|
DIAG_ALARM_SET = 9, -- (API) diagnostic: set alarm to simulate audio for
|
||||||
|
INFO_LIST_CMP = 10 -- (API) info: list all computers on the network
|
||||||
}
|
}
|
||||||
|
|
||||||
---@enum CRDN_TYPE
|
---@enum CRDN_TYPE
|
||||||
@ -89,6 +90,12 @@ local ESTABLISH_ACK = {
|
|||||||
---@enum DEVICE_TYPE device types for establish messages
|
---@enum DEVICE_TYPE device types for establish messages
|
||||||
local DEVICE_TYPE = { PLC = 0, RTU = 1, SVR = 2, CRD = 3, PKT = 4 }
|
local DEVICE_TYPE = { PLC = 0, RTU = 1, SVR = 2, CRD = 3, PKT = 4 }
|
||||||
|
|
||||||
|
---@enum PROBE_ACK
|
||||||
|
local PROBE_ACK = {
|
||||||
|
OPEN = 0,
|
||||||
|
CONFLICT = 1
|
||||||
|
}
|
||||||
|
|
||||||
---@enum PLC_AUTO_ACK
|
---@enum PLC_AUTO_ACK
|
||||||
local PLC_AUTO_ACK = {
|
local PLC_AUTO_ACK = {
|
||||||
FAIL = 0, -- failed to set burn rate/burn rate invalid
|
FAIL = 0, -- failed to set burn rate/burn rate invalid
|
||||||
@ -130,6 +137,8 @@ comms.CRDN_TYPE = CRDN_TYPE
|
|||||||
comms.ESTABLISH_ACK = ESTABLISH_ACK
|
comms.ESTABLISH_ACK = ESTABLISH_ACK
|
||||||
comms.DEVICE_TYPE = DEVICE_TYPE
|
comms.DEVICE_TYPE = DEVICE_TYPE
|
||||||
|
|
||||||
|
comms.PROBE_ACK = PROBE_ACK
|
||||||
|
|
||||||
comms.PLC_AUTO_ACK = PLC_AUTO_ACK
|
comms.PLC_AUTO_ACK = PLC_AUTO_ACK
|
||||||
|
|
||||||
comms.UNIT_COMMAND = UNIT_COMMAND
|
comms.UNIT_COMMAND = UNIT_COMMAND
|
||||||
|
|||||||
@ -82,7 +82,9 @@ end
|
|||||||
function network.nic(modem)
|
function network.nic(modem)
|
||||||
local self = {
|
local self = {
|
||||||
-- modem interface name
|
-- modem interface name
|
||||||
iface = ppm.get_iface(modem),
|
iface = "?",
|
||||||
|
-- phy name
|
||||||
|
name = "?",
|
||||||
-- used to quickly return out of tx/rx functions if there is nothing to do
|
-- used to quickly return out of tx/rx functions if there is nothing to do
|
||||||
connected = true,
|
connected = true,
|
||||||
-- used to avoid costly MAC calculations if not required
|
-- used to avoid costly MAC calculations if not required
|
||||||
@ -94,6 +96,10 @@ function network.nic(modem)
|
|||||||
---@class nic:Modem
|
---@class nic:Modem
|
||||||
local public = {}
|
local public = {}
|
||||||
|
|
||||||
|
-- get the phy name
|
||||||
|
---@nodiscard
|
||||||
|
function public.phy_name() return self.name end
|
||||||
|
|
||||||
-- check if this NIC has a connected modem
|
-- check if this NIC has a connected modem
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
function public.is_connected() return self.connected end
|
function public.is_connected() return self.connected end
|
||||||
@ -102,11 +108,14 @@ function network.nic(modem)
|
|||||||
---@param reconnected_modem Modem
|
---@param reconnected_modem Modem
|
||||||
function public.connect(reconnected_modem)
|
function public.connect(reconnected_modem)
|
||||||
modem = reconnected_modem
|
modem = reconnected_modem
|
||||||
|
|
||||||
|
self.iface = ppm.get_iface(modem)
|
||||||
|
self.name = util.c(util.trinary(modem.isWireless(), "WLAN_PHY", "ETH_PHY"), "{", self.iface, "}")
|
||||||
self.connected = true
|
self.connected = true
|
||||||
|
self.use_hash = c_eng.hmac and modem.isWireless()
|
||||||
|
|
||||||
|
-- open only previously opened channels
|
||||||
modem.closeAll()
|
modem.closeAll()
|
||||||
|
|
||||||
-- open previously opened channels
|
|
||||||
for _, channel in ipairs(self.channels) do
|
for _, channel in ipairs(self.channels) do
|
||||||
modem.open(channel)
|
modem.open(channel)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -18,7 +18,7 @@ local _bp = {
|
|||||||
|
|
||||||
wd_nic = nil, ---@type nic|nil wired nic
|
wd_nic = nil, ---@type nic|nil wired nic
|
||||||
wl_nic = nil, ---@type nic|nil wireless nic
|
wl_nic = nil, ---@type nic|nil wireless nic
|
||||||
nic_map = {}
|
nic_map = {} ---@type nic[] connected nics
|
||||||
}
|
}
|
||||||
|
|
||||||
backplane.nics = _bp.nic_map
|
backplane.nics = _bp.nic_map
|
||||||
|
|||||||
@ -13,6 +13,7 @@ local supervisor = {}
|
|||||||
local PROTOCOL = comms.PROTOCOL
|
local PROTOCOL = comms.PROTOCOL
|
||||||
local DEVICE_TYPE = comms.DEVICE_TYPE
|
local DEVICE_TYPE = comms.DEVICE_TYPE
|
||||||
local ESTABLISH_ACK = comms.ESTABLISH_ACK
|
local ESTABLISH_ACK = comms.ESTABLISH_ACK
|
||||||
|
local PROBE_ACK = comms.PROBE_ACK
|
||||||
local MGMT_TYPE = comms.MGMT_TYPE
|
local MGMT_TYPE = comms.MGMT_TYPE
|
||||||
|
|
||||||
---@type svr_config
|
---@type svr_config
|
||||||
@ -156,14 +157,11 @@ function supervisor.comms(_version, fp_ok, facility)
|
|||||||
local function println(message) if not fp_ok then util.println_ts(message) end end
|
local function println(message) if not fp_ok then util.println_ts(message) end end
|
||||||
|
|
||||||
local self = {
|
local self = {
|
||||||
last_est_acks = {}
|
last_est_acks = {} ---@type ESTABLISH_ACK[]
|
||||||
}
|
}
|
||||||
|
|
||||||
comms.set_trusted_range(config.TrustedRange)
|
comms.set_trusted_range(config.TrustedRange)
|
||||||
|
|
||||||
-- configure network channels
|
|
||||||
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)
|
||||||
|
|
||||||
@ -175,8 +173,7 @@ function supervisor.comms(_version, fp_ok, facility)
|
|||||||
---@param ack ESTABLISH_ACK
|
---@param ack ESTABLISH_ACK
|
||||||
---@param data? any optional data
|
---@param data? any optional data
|
||||||
local function _send_establish(nic, packet, ack, data)
|
local function _send_establish(nic, packet, ack, data)
|
||||||
local s_pkt = comms.scada_packet()
|
local s_pkt, m_pkt = comms.scada_packet(), comms.mgmt_packet()
|
||||||
local m_pkt = comms.mgmt_packet()
|
|
||||||
|
|
||||||
m_pkt.make(MGMT_TYPE.ESTABLISH, { ack, data })
|
m_pkt.make(MGMT_TYPE.ESTABLISH, { ack, data })
|
||||||
s_pkt.make(packet.src_addr(), packet.seq_num() + 1, PROTOCOL.SCADA_MGMT, m_pkt.raw_sendable())
|
s_pkt.make(packet.src_addr(), packet.seq_num() + 1, PROTOCOL.SCADA_MGMT, m_pkt.raw_sendable())
|
||||||
@ -185,6 +182,188 @@ function supervisor.comms(_version, fp_ok, facility)
|
|||||||
self.last_est_acks[packet.src_addr()] = ack
|
self.last_est_acks[packet.src_addr()] = ack
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- send a probe response
|
||||||
|
---@param nic nic
|
||||||
|
---@param packet scada_packet
|
||||||
|
---@param ack PROBE_ACK
|
||||||
|
local function _send_probe(nic, packet, ack)
|
||||||
|
local s_pkt, m_pkt = comms.scada_packet(), comms.mgmt_packet()
|
||||||
|
|
||||||
|
m_pkt.make(MGMT_TYPE.PROBE, { ack })
|
||||||
|
s_pkt.make(packet.src_addr(), packet.seq_num() + 1, PROTOCOL.SCADA_MGMT, m_pkt.raw_sendable())
|
||||||
|
|
||||||
|
nic.transmit(packet.remote_channel(), config.SVR_Channel, s_pkt)
|
||||||
|
end
|
||||||
|
|
||||||
|
--#region Establish Handlers
|
||||||
|
|
||||||
|
-- handle a PLC establish
|
||||||
|
---@param nic nic
|
||||||
|
---@param packet mgmt_frame
|
||||||
|
---@param src_addr integer
|
||||||
|
---@param i_seq_num integer
|
||||||
|
---@param last_ack ESTABLISH_ACK
|
||||||
|
local function _establish_plc(nic, packet, src_addr, i_seq_num, last_ack)
|
||||||
|
local comms_v = packet.data[1]
|
||||||
|
local firmware_v = packet.data[2]
|
||||||
|
local dev_type = packet.data[3]
|
||||||
|
|
||||||
|
if comms_v ~= comms.version then
|
||||||
|
if last_ack ~= ESTABLISH_ACK.BAD_VERSION then
|
||||||
|
log.info(util.c("dropping PLC establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")"))
|
||||||
|
end
|
||||||
|
|
||||||
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
||||||
|
elseif dev_type == DEVICE_TYPE.PLC then
|
||||||
|
-- PLC linking request
|
||||||
|
if packet.length == 4 and type(packet.data[4]) == "number" then
|
||||||
|
local reactor_id = packet.data[4]
|
||||||
|
|
||||||
|
-- check ID validity
|
||||||
|
if reactor_id < 1 or reactor_id > config.UnitCount then
|
||||||
|
-- reactor index out of range
|
||||||
|
if last_ack ~= ESTABLISH_ACK.DENY then
|
||||||
|
log.warning(util.c("PLC_ESTABLISH: denied assignment ", reactor_id, " outside of configured unit count ", config.UnitCount))
|
||||||
|
end
|
||||||
|
|
||||||
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||||
|
else
|
||||||
|
-- try to establish the session
|
||||||
|
local plc_id = svsessions.establish_plc_session(nic, src_addr, i_seq_num, reactor_id, firmware_v)
|
||||||
|
|
||||||
|
if plc_id == false then
|
||||||
|
-- reactor already has a PLC assigned
|
||||||
|
if last_ack ~= ESTABLISH_ACK.COLLISION then
|
||||||
|
log.warning(util.c("PLC_ESTABLISH: assignment collision with reactor ", reactor_id))
|
||||||
|
end
|
||||||
|
|
||||||
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.COLLISION)
|
||||||
|
else
|
||||||
|
-- got an ID; assigned to a reactor successfully
|
||||||
|
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, " on ", nic.phy_name()))
|
||||||
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.ALLOW)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.debug("PLC_ESTABLISH: packet length mismatch/bad parameter type")
|
||||||
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.debug(util.c("illegal establish packet for device ", dev_type, " on PLC channel"))
|
||||||
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- handle an RTU gateway establish
|
||||||
|
---@param nic nic
|
||||||
|
---@param packet mgmt_frame
|
||||||
|
---@param src_addr integer
|
||||||
|
---@param i_seq_num integer
|
||||||
|
---@param last_ack ESTABLISH_ACK
|
||||||
|
local function _establish_rtu_gw(nic, packet, src_addr, i_seq_num, last_ack)
|
||||||
|
local comms_v = packet.data[1]
|
||||||
|
local firmware_v = packet.data[2]
|
||||||
|
local dev_type = packet.data[3]
|
||||||
|
|
||||||
|
if comms_v ~= comms.version then
|
||||||
|
if last_ack ~= ESTABLISH_ACK.BAD_VERSION then
|
||||||
|
log.info(util.c("dropping RTU_GW establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")"))
|
||||||
|
end
|
||||||
|
|
||||||
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
||||||
|
elseif dev_type == DEVICE_TYPE.RTU then
|
||||||
|
if packet.length == 4 then
|
||||||
|
-- this is an RTU advertisement for a new session
|
||||||
|
local rtu_advert = packet.data[4]
|
||||||
|
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"))
|
||||||
|
log.info(util.c("RTU_GW_ESTABLISH: RTU_GW (",firmware_v, ") [@", src_addr, "] connected with session ID ", s_id, " on ", nic.phy_name()))
|
||||||
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.ALLOW)
|
||||||
|
else
|
||||||
|
log.debug("RTU_GW_ESTABLISH: packet length mismatch")
|
||||||
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.debug(util.c("illegal establish packet for device ", dev_type, " on RTU channel"))
|
||||||
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- handle a coordinator establish
|
||||||
|
---@param nic nic
|
||||||
|
---@param packet mgmt_frame
|
||||||
|
---@param src_addr integer
|
||||||
|
---@param i_seq_num integer
|
||||||
|
---@param last_ack ESTABLISH_ACK
|
||||||
|
local function _establish_crd(nic, packet, src_addr, i_seq_num, last_ack)
|
||||||
|
local comms_v = packet.data[1]
|
||||||
|
local firmware_v = packet.data[2]
|
||||||
|
local dev_type = packet.data[3]
|
||||||
|
|
||||||
|
if comms_v ~= comms.version then
|
||||||
|
if last_ack ~= ESTABLISH_ACK.BAD_VERSION then
|
||||||
|
log.info(util.c("dropping coordinator establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")"))
|
||||||
|
end
|
||||||
|
|
||||||
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
||||||
|
elseif dev_type == DEVICE_TYPE.CRD then
|
||||||
|
-- this is an attempt to establish a new coordinator session
|
||||||
|
local s_id = svsessions.establish_crd_session(nic, src_addr, i_seq_num, firmware_v)
|
||||||
|
|
||||||
|
if s_id ~= false then
|
||||||
|
println(util.c("CRD (", firmware_v, ") [@", src_addr, "] \xbb connected"))
|
||||||
|
log.info(util.c("CRD_ESTABLISH: CRD (", firmware_v, ") [@", src_addr, "] connected with session ID ", s_id, " on ", nic.phy_name()))
|
||||||
|
|
||||||
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.ALLOW, { config.UnitCount, facility.get_cooling_conf() })
|
||||||
|
else
|
||||||
|
if last_ack ~= ESTABLISH_ACK.COLLISION then
|
||||||
|
log.info("CRD_ESTABLISH: denied new coordinator [@" .. src_addr .. "] due to already being connected to another coordinator")
|
||||||
|
end
|
||||||
|
|
||||||
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.COLLISION)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.debug(util.c("illegal establish packet for device ", dev_type, " on CRD channel"))
|
||||||
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- handle a pocket debug establish
|
||||||
|
---@param nic nic
|
||||||
|
---@param packet mgmt_frame
|
||||||
|
---@param src_addr integer
|
||||||
|
---@param i_seq_num integer
|
||||||
|
---@param last_ack ESTABLISH_ACK
|
||||||
|
local function _establish_pdg(nic, packet, src_addr, i_seq_num, last_ack)
|
||||||
|
local comms_v = packet.data[1]
|
||||||
|
local firmware_v = packet.data[2]
|
||||||
|
local dev_type = packet.data[3]
|
||||||
|
|
||||||
|
if comms_v ~= comms.version then
|
||||||
|
if last_ack ~= ESTABLISH_ACK.BAD_VERSION then
|
||||||
|
log.info(util.c("dropping PKT establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")"))
|
||||||
|
end
|
||||||
|
|
||||||
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
||||||
|
elseif dev_type == DEVICE_TYPE.PKT then
|
||||||
|
-- this is an attempt to establish a new pocket diagnostic session
|
||||||
|
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"))
|
||||||
|
log.info(util.c("PDG_ESTABLISH: pocket (", firmware_v, ") [@", src_addr, "] connected with session ID ", s_id, " on ", nic.phy_name()))
|
||||||
|
|
||||||
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.ALLOW)
|
||||||
|
else
|
||||||
|
log.debug(util.c("illegal establish packet for device ", dev_type, " on PKT channel"))
|
||||||
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--#endregion
|
||||||
|
|
||||||
-- PUBLIC FUNCTIONS --
|
-- PUBLIC FUNCTIONS --
|
||||||
|
|
||||||
---@class superv_comms
|
---@class superv_comms
|
||||||
@ -240,89 +419,45 @@ function supervisor.comms(_version, fp_ok, facility)
|
|||||||
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 not nic then
|
if l_chan ~= config.SVR_Channel 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
|
||||||
local session = svsessions.find_plc_session(src_addr)
|
local session = svsessions.find_plc_session(src_addr)
|
||||||
|
|
||||||
if protocol == PROTOCOL.RPLC then
|
if session then
|
||||||
---@cast packet rplc_frame
|
if nic ~= session.nic then
|
||||||
-- reactor PLC packet
|
-- this is from the same device but on a different interface
|
||||||
if session ~= nil then
|
-- drop unless it is a connection probe
|
||||||
|
if (protocol == PROTOCOL.SCADA_MGMT) and (packet.type == MGMT_TYPE.PROBE) then
|
||||||
|
---@cast packet mgmt_frame
|
||||||
|
log.debug(util.c("PROBE_ACK: conflict with PLC @", src_addr, " on ", session.nic.phy_name(), " probed on ", nic.phy_name()))
|
||||||
|
_send_probe(nic, packet.scada_frame, PROBE_ACK.CONFLICT)
|
||||||
|
else
|
||||||
|
log.debug(util.c("unexpected packet for PLC @ ", src_addr, " received on ", nic.phy_name()))
|
||||||
|
end
|
||||||
|
else
|
||||||
-- pass the packet onto the session handler
|
-- pass the packet onto the session handler
|
||||||
session.in_queue.push_packet(packet)
|
session.in_queue.push_packet(packet)
|
||||||
else
|
|
||||||
-- any other packet should be session related, discard it
|
|
||||||
log.debug("discarding RPLC packet without a known session")
|
|
||||||
end
|
end
|
||||||
|
elseif protocol == PROTOCOL.RPLC then
|
||||||
|
-- reactor PLC packet should be session related, discard it
|
||||||
|
log.debug("discarding RPLC packet without a known session")
|
||||||
elseif protocol == PROTOCOL.SCADA_MGMT then
|
elseif protocol == PROTOCOL.SCADA_MGMT then
|
||||||
---@cast packet mgmt_frame
|
---@cast packet mgmt_frame
|
||||||
-- SCADA management packet
|
-- SCADA management packet
|
||||||
if session ~= nil then
|
if packet.type == MGMT_TYPE.ESTABLISH then
|
||||||
-- pass the packet onto the session handler
|
-- establish a new session: validate packet and continue
|
||||||
session.in_queue.push_packet(packet)
|
|
||||||
elseif packet.type == MGMT_TYPE.ESTABLISH then
|
|
||||||
-- establish a new session
|
|
||||||
local last_ack = self.last_est_acks[src_addr]
|
|
||||||
|
|
||||||
-- validate packet and continue
|
|
||||||
if packet.length >= 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then
|
if packet.length >= 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then
|
||||||
local comms_v = packet.data[1]
|
_establish_plc(nic, packet, src_addr, i_seq_num, self.last_est_acks[src_addr])
|
||||||
local firmware_v = packet.data[2]
|
|
||||||
local dev_type = packet.data[3]
|
|
||||||
|
|
||||||
if comms_v ~= comms.version then
|
|
||||||
if last_ack ~= ESTABLISH_ACK.BAD_VERSION then
|
|
||||||
log.info(util.c("dropping PLC establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")"))
|
|
||||||
end
|
|
||||||
|
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
|
||||||
elseif dev_type == DEVICE_TYPE.PLC then
|
|
||||||
-- PLC linking request
|
|
||||||
if packet.length == 4 and type(packet.data[4]) == "number" then
|
|
||||||
local reactor_id = packet.data[4]
|
|
||||||
|
|
||||||
-- check ID validity
|
|
||||||
if reactor_id < 1 or reactor_id > config.UnitCount then
|
|
||||||
-- reactor index out of range
|
|
||||||
if last_ack ~= ESTABLISH_ACK.DENY then
|
|
||||||
log.warning(util.c("PLC_ESTABLISH: denied assignment ", reactor_id, " outside of configured unit count ", config.UnitCount))
|
|
||||||
end
|
|
||||||
|
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
|
||||||
else
|
|
||||||
-- try to establish the session
|
|
||||||
local plc_id = svsessions.establish_plc_session(nic, src_addr, i_seq_num, reactor_id, firmware_v)
|
|
||||||
|
|
||||||
if plc_id == false then
|
|
||||||
-- reactor already has a PLC assigned
|
|
||||||
if last_ack ~= ESTABLISH_ACK.COLLISION then
|
|
||||||
log.warning(util.c("PLC_ESTABLISH: assignment collision with reactor ", reactor_id))
|
|
||||||
end
|
|
||||||
|
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.COLLISION)
|
|
||||||
else
|
|
||||||
-- got an ID; assigned to a reactor successfully
|
|
||||||
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))
|
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.ALLOW)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
log.debug("PLC_ESTABLISH: packet length mismatch/bad parameter type")
|
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
log.debug(util.c("illegal establish packet for device ", dev_type, " on PLC channel"))
|
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
log.debug("invalid establish packet (on PLC channel)")
|
log.debug("invalid establish packet (on PLC channel)")
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||||
end
|
end
|
||||||
|
elseif packet.type == MGMT_TYPE.PROBE then
|
||||||
|
-- connection probing
|
||||||
|
log.debug(util.c("PROBE_ACK: reporting open to PLC @", src_addr, " probed on ", nic.phy_name()))
|
||||||
|
_send_probe(nic, packet.scada_frame, PROBE_ACK.OPEN)
|
||||||
else
|
else
|
||||||
-- any other packet should be session related, discard it
|
-- any other packet should be session related, discard it
|
||||||
log.debug(util.c("discarding PLC SCADA_MGMT packet without a known session from computer ", src_addr))
|
log.debug(util.c("discarding PLC SCADA_MGMT packet without a known session from computer ", src_addr))
|
||||||
@ -334,62 +469,43 @@ function supervisor.comms(_version, fp_ok, facility)
|
|||||||
-- look for an associated session
|
-- look for an associated session
|
||||||
local session = svsessions.find_rtu_session(src_addr)
|
local session = svsessions.find_rtu_session(src_addr)
|
||||||
|
|
||||||
if protocol == PROTOCOL.MODBUS_TCP then
|
if session then
|
||||||
---@cast packet modbus_frame
|
if nic ~= session.nic then
|
||||||
-- MODBUS response
|
-- this is from the same device but on a different interface
|
||||||
if session ~= nil then
|
-- drop unless it is a connection probe
|
||||||
|
if (protocol == PROTOCOL.SCADA_MGMT) and (packet.type == MGMT_TYPE.PROBE) then
|
||||||
|
---@cast packet mgmt_frame
|
||||||
|
log.debug(util.c("PROBE_ACK: conflict with RTU_GW @", src_addr, " on ", session.nic.phy_name(), " probed on ", nic.phy_name()))
|
||||||
|
_send_probe(nic, packet.scada_frame, PROBE_ACK.CONFLICT)
|
||||||
|
else
|
||||||
|
log.debug(util.c("unexpected packet for RTU_GW @ ", src_addr, " received on ", nic.phy_name()))
|
||||||
|
end
|
||||||
|
else
|
||||||
-- pass the packet onto the session handler
|
-- pass the packet onto the session handler
|
||||||
session.in_queue.push_packet(packet)
|
session.in_queue.push_packet(packet)
|
||||||
else
|
|
||||||
-- any other packet should be session related, discard it
|
|
||||||
log.debug("discarding MODBUS_TCP packet without a known session")
|
|
||||||
end
|
end
|
||||||
|
elseif protocol == PROTOCOL.MODBUS_TCP then
|
||||||
|
---@cast packet modbus_frame
|
||||||
|
-- MODBUS response, should be session related, discard it
|
||||||
|
log.debug("discarding MODBUS_TCP packet without a known session")
|
||||||
elseif protocol == PROTOCOL.SCADA_MGMT then
|
elseif protocol == PROTOCOL.SCADA_MGMT then
|
||||||
---@cast packet mgmt_frame
|
---@cast packet mgmt_frame
|
||||||
-- SCADA management packet
|
-- SCADA management packet
|
||||||
if session ~= nil then
|
if packet.type == MGMT_TYPE.ESTABLISH then
|
||||||
-- pass the packet onto the session handler
|
-- establish a new session: validate packet and continue
|
||||||
session.in_queue.push_packet(packet)
|
|
||||||
elseif packet.type == MGMT_TYPE.ESTABLISH then
|
|
||||||
-- establish a new session
|
|
||||||
local last_ack = self.last_est_acks[src_addr]
|
|
||||||
|
|
||||||
-- validate packet and continue
|
|
||||||
if packet.length >= 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then
|
if packet.length >= 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then
|
||||||
local comms_v = packet.data[1]
|
_establish_rtu_gw(nic, packet, src_addr, i_seq_num, self.last_est_acks[src_addr])
|
||||||
local firmware_v = packet.data[2]
|
|
||||||
local dev_type = packet.data[3]
|
|
||||||
|
|
||||||
if comms_v ~= comms.version then
|
|
||||||
if last_ack ~= ESTABLISH_ACK.BAD_VERSION then
|
|
||||||
log.info(util.c("dropping RTU establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")"))
|
|
||||||
end
|
|
||||||
|
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
|
||||||
elseif dev_type == DEVICE_TYPE.RTU then
|
|
||||||
if packet.length == 4 then
|
|
||||||
-- this is an RTU advertisement for a new session
|
|
||||||
local rtu_advert = packet.data[4]
|
|
||||||
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"))
|
|
||||||
log.info(util.c("RTU_ESTABLISH: RTU (",firmware_v, ") [@", src_addr, "] connected with session ID ", s_id))
|
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.ALLOW)
|
|
||||||
else
|
|
||||||
log.debug("RTU_ESTABLISH: packet length mismatch")
|
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
log.debug(util.c("illegal establish packet for device ", dev_type, " on RTU channel"))
|
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
log.debug("invalid establish packet (on RTU channel)")
|
log.debug("invalid establish packet (on RTU channel)")
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||||
end
|
end
|
||||||
|
elseif packet.type == MGMT_TYPE.PROBE then
|
||||||
|
-- connection probing
|
||||||
|
log.debug(util.c("PROBE_ACK: reporting open to RTU_GW @", src_addr, " probed on ", nic.phy_name()))
|
||||||
|
_send_probe(nic, packet.scada_frame, PROBE_ACK.OPEN)
|
||||||
else
|
else
|
||||||
-- any other packet should be session related, discard it
|
-- any other packet should be session related, discard it
|
||||||
log.debug(util.c("discarding RTU SCADA_MGMT packet without a known session from computer ", src_addr))
|
log.debug(util.c("discarding RTU gateway SCADA_MGMT packet without a known session from computer ", src_addr))
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
log.debug(util.c("illegal packet type ", protocol, " on RTU channel"))
|
log.debug(util.c("illegal packet type ", protocol, " on RTU channel"))
|
||||||
@ -398,107 +514,61 @@ function supervisor.comms(_version, fp_ok, facility)
|
|||||||
-- look for an associated session
|
-- look for an associated session
|
||||||
local session = svsessions.find_crd_session(src_addr)
|
local session = svsessions.find_crd_session(src_addr)
|
||||||
|
|
||||||
if protocol == PROTOCOL.SCADA_MGMT then
|
if session then
|
||||||
|
if nic ~= session.nic then
|
||||||
|
-- this is from the same device but on a different interface
|
||||||
|
-- drop unless it is a connection probe
|
||||||
|
if (protocol == PROTOCOL.SCADA_MGMT) and (packet.type == MGMT_TYPE.PROBE) then
|
||||||
---@cast packet mgmt_frame
|
---@cast packet mgmt_frame
|
||||||
-- SCADA management packet
|
log.debug(util.c("PROBE_ACK: conflict with CRD @", src_addr, " on ", session.nic.phy_name(), " probed on ", nic.phy_name()))
|
||||||
if session ~= nil then
|
_send_probe(nic, packet.scada_frame, PROBE_ACK.CONFLICT)
|
||||||
|
else
|
||||||
|
log.debug(util.c("unexpected packet for CRD @ ", src_addr, " received on ", nic.phy_name()))
|
||||||
|
end
|
||||||
|
else
|
||||||
-- pass the packet onto the session handler
|
-- pass the packet onto the session handler
|
||||||
session.in_queue.push_packet(packet)
|
session.in_queue.push_packet(packet)
|
||||||
elseif packet.type == MGMT_TYPE.ESTABLISH then
|
end
|
||||||
-- establish a new session
|
elseif protocol == PROTOCOL.SCADA_MGMT then
|
||||||
local last_ack = self.last_est_acks[src_addr]
|
---@cast packet mgmt_frame
|
||||||
|
-- SCADA management packet
|
||||||
-- validate packet and continue
|
if packet.type == MGMT_TYPE.ESTABLISH then
|
||||||
|
-- establish a new session: validate packet and continue
|
||||||
if packet.length >= 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then
|
if packet.length >= 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then
|
||||||
local comms_v = packet.data[1]
|
_establish_crd(nic, packet, src_addr, i_seq_num, self.last_est_acks[src_addr])
|
||||||
local firmware_v = packet.data[2]
|
|
||||||
local dev_type = packet.data[3]
|
|
||||||
|
|
||||||
if comms_v ~= comms.version then
|
|
||||||
if last_ack ~= ESTABLISH_ACK.BAD_VERSION then
|
|
||||||
log.info(util.c("dropping coordinator establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")"))
|
|
||||||
end
|
|
||||||
|
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
|
||||||
elseif dev_type == DEVICE_TYPE.CRD then
|
|
||||||
-- this is an attempt to establish a new coordinator session
|
|
||||||
local s_id = svsessions.establish_crd_session(nic, src_addr, i_seq_num, firmware_v)
|
|
||||||
|
|
||||||
if s_id ~= false then
|
|
||||||
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))
|
|
||||||
|
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.ALLOW, { config.UnitCount, facility.get_cooling_conf() })
|
|
||||||
else
|
|
||||||
if last_ack ~= ESTABLISH_ACK.COLLISION then
|
|
||||||
log.info("CRD_ESTABLISH: denied new coordinator [@" .. src_addr .. "] due to already being connected to another coordinator")
|
|
||||||
end
|
|
||||||
|
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.COLLISION)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
log.debug(util.c("illegal establish packet for device ", dev_type, " on coordinator channel"))
|
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
log.debug("CRD_ESTABLISH: establish packet length mismatch")
|
log.debug("CRD_ESTABLISH: establish packet length mismatch")
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||||
end
|
end
|
||||||
|
elseif packet.type == MGMT_TYPE.PROBE then
|
||||||
|
-- connection probing
|
||||||
|
log.debug(util.c("PROBE_ACK: reporting open to CRD @", src_addr, " probed on ", nic.phy_name()))
|
||||||
|
_send_probe(nic, packet.scada_frame, PROBE_ACK.OPEN)
|
||||||
else
|
else
|
||||||
-- any other packet should be session related, discard it
|
-- any other packet should be session related, discard it
|
||||||
log.debug(util.c("discarding coordinator SCADA_MGMT packet without a known session from computer ", src_addr))
|
log.debug(util.c("discarding coordinator SCADA_MGMT packet without a known session from computer ", src_addr))
|
||||||
end
|
end
|
||||||
elseif protocol == PROTOCOL.SCADA_CRDN then
|
elseif protocol == PROTOCOL.SCADA_CRDN then
|
||||||
---@cast packet crdn_frame
|
---@cast packet crdn_frame
|
||||||
-- coordinator packet
|
-- coordinator packet, should be session related, discard it
|
||||||
if session ~= nil then
|
|
||||||
-- pass the packet onto the session handler
|
|
||||||
session.in_queue.push_packet(packet)
|
|
||||||
else
|
|
||||||
-- any other packet should be session related, discard it
|
|
||||||
log.debug(util.c("discarding coordinator SCADA_CRDN packet without a known session from computer ", src_addr))
|
log.debug(util.c("discarding coordinator SCADA_CRDN packet without a known session from computer ", src_addr))
|
||||||
end
|
|
||||||
else
|
else
|
||||||
log.debug(util.c("illegal packet type ", protocol, " on coordinator channel"))
|
log.debug(util.c("illegal packet type ", protocol, " on CRD channel"))
|
||||||
end
|
end
|
||||||
elseif r_chan == config.PKT_Channel then
|
elseif r_chan == config.PKT_Channel then
|
||||||
-- look for an associated session
|
-- look for an associated session
|
||||||
local session = svsessions.find_pdg_session(src_addr)
|
local session = svsessions.find_pdg_session(src_addr)
|
||||||
|
|
||||||
if protocol == PROTOCOL.SCADA_MGMT then
|
if session then
|
||||||
---@cast packet mgmt_frame
|
|
||||||
-- SCADA management packet
|
|
||||||
if session ~= nil then
|
|
||||||
-- pass the packet onto the session handler
|
-- pass the packet onto the session handler
|
||||||
session.in_queue.push_packet(packet)
|
session.in_queue.push_packet(packet)
|
||||||
elseif packet.type == MGMT_TYPE.ESTABLISH then
|
elseif protocol == PROTOCOL.SCADA_MGMT then
|
||||||
-- establish a new session
|
---@cast packet mgmt_frame
|
||||||
local last_ack = self.last_est_acks[src_addr]
|
-- SCADA management packet
|
||||||
|
if packet.type == MGMT_TYPE.ESTABLISH then
|
||||||
-- validate packet and continue
|
-- establish a new session: validate packet and continue
|
||||||
if packet.length >= 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then
|
if packet.length >= 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then
|
||||||
local comms_v = packet.data[1]
|
_establish_pdg(nic, packet, src_addr, i_seq_num, self.last_est_acks[src_addr])
|
||||||
local firmware_v = packet.data[2]
|
|
||||||
local dev_type = packet.data[3]
|
|
||||||
|
|
||||||
if comms_v ~= comms.version then
|
|
||||||
if last_ack ~= ESTABLISH_ACK.BAD_VERSION then
|
|
||||||
log.info(util.c("dropping PDG establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")"))
|
|
||||||
end
|
|
||||||
|
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
|
||||||
elseif dev_type == DEVICE_TYPE.PKT then
|
|
||||||
-- this is an attempt to establish a new pocket diagnostic session
|
|
||||||
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"))
|
|
||||||
log.info(util.c("PDG_ESTABLISH: pocket (", firmware_v, ") [@", src_addr, "] connected with session ID ", s_id))
|
|
||||||
|
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.ALLOW)
|
|
||||||
else
|
|
||||||
log.debug(util.c("illegal establish packet for device ", dev_type, " on pocket channel"))
|
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
log.debug("PDG_ESTABLISH: establish packet length mismatch")
|
log.debug("PDG_ESTABLISH: establish packet length mismatch")
|
||||||
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
_send_establish(nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||||
@ -509,14 +579,8 @@ function supervisor.comms(_version, fp_ok, facility)
|
|||||||
end
|
end
|
||||||
elseif protocol == PROTOCOL.SCADA_CRDN then
|
elseif protocol == PROTOCOL.SCADA_CRDN then
|
||||||
---@cast packet crdn_frame
|
---@cast packet crdn_frame
|
||||||
-- coordinator packet
|
-- coordinator packet, should be session related, discard it
|
||||||
if session ~= nil then
|
|
||||||
-- pass the packet onto the session handler
|
|
||||||
session.in_queue.push_packet(packet)
|
|
||||||
else
|
|
||||||
-- any other packet should be session related, discard it
|
|
||||||
log.debug(util.c("discarding pocket SCADA_CRDN packet without a known session from computer ", src_addr))
|
log.debug(util.c("discarding pocket SCADA_CRDN packet without a known session from computer ", src_addr))
|
||||||
end
|
|
||||||
else
|
else
|
||||||
log.debug(util.c("illegal packet type ", protocol, " on pocket channel"))
|
log.debug(util.c("illegal packet type ", protocol, " on pocket channel"))
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user