mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#488 HMAC acceleration and seq_num changes
This commit is contained in:
parent
2bc20ec312
commit
d2bc4f6bc0
@ -232,8 +232,7 @@ function coordinator.comms(version, nic, sv_watchdog)
|
|||||||
local self = {
|
local self = {
|
||||||
sv_linked = false,
|
sv_linked = false,
|
||||||
sv_addr = comms.BROADCAST,
|
sv_addr = comms.BROADCAST,
|
||||||
sv_seq_num = 0,
|
sv_seq_num = util.time_ms() * 10, -- unique per peer, restarting will not re-use seq nums due to message rate
|
||||||
sv_r_seq_num = nil,
|
|
||||||
sv_config_err = false,
|
sv_config_err = false,
|
||||||
last_est_ack = ESTABLISH_ACK.ALLOW,
|
last_est_ack = ESTABLISH_ACK.ALLOW,
|
||||||
last_api_est_acks = {},
|
last_api_est_acks = {},
|
||||||
@ -370,7 +369,6 @@ function coordinator.comms(version, nic, sv_watchdog)
|
|||||||
sv_watchdog.cancel()
|
sv_watchdog.cancel()
|
||||||
self.sv_addr = comms.BROADCAST
|
self.sv_addr = comms.BROADCAST
|
||||||
self.sv_linked = false
|
self.sv_linked = false
|
||||||
self.sv_r_seq_num = nil
|
|
||||||
iocontrol.fp_link_state(types.PANEL_LINK_STATE.DISCONNECTED)
|
iocontrol.fp_link_state(types.PANEL_LINK_STATE.DISCONNECTED)
|
||||||
_send_sv(PROTOCOL.SCADA_MGMT, MGMT_TYPE.CLOSE, {})
|
_send_sv(PROTOCOL.SCADA_MGMT, MGMT_TYPE.CLOSE, {})
|
||||||
end
|
end
|
||||||
@ -492,7 +490,7 @@ function coordinator.comms(version, nic, sv_watchdog)
|
|||||||
_send_api_establish_ack(packet.scada_frame, ESTABLISH_ACK.BAD_API_VERSION)
|
_send_api_establish_ack(packet.scada_frame, ESTABLISH_ACK.BAD_API_VERSION)
|
||||||
elseif dev_type == DEVICE_TYPE.PKT then
|
elseif dev_type == DEVICE_TYPE.PKT then
|
||||||
-- pocket linking request
|
-- pocket linking request
|
||||||
local id = apisessions.establish_session(src_addr, firmware_v)
|
local id = apisessions.establish_session(src_addr, packet.scada_frame.seq_num() + 1, firmware_v)
|
||||||
coordinator.log_comms(util.c("API_ESTABLISH: pocket (", firmware_v, ") [@", src_addr, "] connected with session ID ", id))
|
coordinator.log_comms(util.c("API_ESTABLISH: pocket (", firmware_v, ") [@", src_addr, "] connected with session ID ", id))
|
||||||
|
|
||||||
local conf = iocontrol.get_db().facility.conf
|
local conf = iocontrol.get_db().facility.conf
|
||||||
@ -514,16 +512,14 @@ function coordinator.comms(version, nic, sv_watchdog)
|
|||||||
end
|
end
|
||||||
elseif r_chan == config.SVR_Channel then
|
elseif r_chan == config.SVR_Channel then
|
||||||
-- check sequence number
|
-- check sequence number
|
||||||
if self.sv_r_seq_num == nil then
|
if self.sv_seq_num ~= packet.scada_frame.seq_num() then
|
||||||
self.sv_r_seq_num = packet.scada_frame.seq_num()
|
log.warning("sequence out-of-order: last = " .. self.sv_seq_num .. ", new = " .. packet.scada_frame.seq_num())
|
||||||
elseif self.sv_linked and ((self.sv_r_seq_num + 1) ~= packet.scada_frame.seq_num()) then
|
|
||||||
log.warning("sequence out-of-order: last = " .. self.sv_r_seq_num .. ", new = " .. packet.scada_frame.seq_num())
|
|
||||||
return false
|
return false
|
||||||
elseif self.sv_linked and src_addr ~= self.sv_addr then
|
elseif self.sv_linked and src_addr ~= self.sv_addr then
|
||||||
log.debug("received packet from unknown computer " .. src_addr .. " while linked; channel in use by another system?")
|
log.debug("received packet from unknown computer " .. src_addr .. " while linked; channel in use by another system?")
|
||||||
return false
|
return false
|
||||||
else
|
else
|
||||||
self.sv_r_seq_num = packet.scada_frame.seq_num()
|
self.sv_seq_num = packet.scada_frame.seq_num() + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- feed watchdog on valid sequence number
|
-- feed watchdog on valid sequence number
|
||||||
@ -675,7 +671,6 @@ function coordinator.comms(version, nic, sv_watchdog)
|
|||||||
sv_watchdog.cancel()
|
sv_watchdog.cancel()
|
||||||
self.sv_addr = comms.BROADCAST
|
self.sv_addr = comms.BROADCAST
|
||||||
self.sv_linked = false
|
self.sv_linked = false
|
||||||
self.sv_r_seq_num = nil
|
|
||||||
iocontrol.fp_link_state(types.PANEL_LINK_STATE.DISCONNECTED)
|
iocontrol.fp_link_state(types.PANEL_LINK_STATE.DISCONNECTED)
|
||||||
log.info("server connection closed by remote host")
|
log.info("server connection closed by remote host")
|
||||||
else
|
else
|
||||||
@ -706,7 +701,6 @@ function coordinator.comms(version, nic, sv_watchdog)
|
|||||||
|
|
||||||
self.sv_addr = src_addr
|
self.sv_addr = src_addr
|
||||||
self.sv_linked = true
|
self.sv_linked = true
|
||||||
self.sv_r_seq_num = nil
|
|
||||||
self.sv_config_err = false
|
self.sv_config_err = false
|
||||||
|
|
||||||
iocontrol.fp_link_state(types.PANEL_LINK_STATE.LINKED)
|
iocontrol.fp_link_state(types.PANEL_LINK_STATE.LINKED)
|
||||||
|
@ -89,10 +89,11 @@ end
|
|||||||
|
|
||||||
-- establish a new API session
|
-- establish a new API session
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param source_addr integer
|
---@param source_addr integer pocket computer ID
|
||||||
---@param version string
|
---@param i_seq_num integer initial sequence number to use next
|
||||||
|
---@param version string pocket version
|
||||||
---@return integer session_id
|
---@return integer session_id
|
||||||
function apisessions.establish_session(source_addr, version)
|
function apisessions.establish_session(source_addr, i_seq_num, version)
|
||||||
---@class pkt_session_struct
|
---@class pkt_session_struct
|
||||||
local pkt_s = {
|
local pkt_s = {
|
||||||
open = true,
|
open = true,
|
||||||
@ -105,7 +106,7 @@ function apisessions.establish_session(source_addr, version)
|
|||||||
|
|
||||||
local id = self.next_id
|
local id = self.next_id
|
||||||
|
|
||||||
pkt_s.instance = pocket.new_session(id, source_addr, pkt_s.in_queue, pkt_s.out_queue, self.config.API_Timeout)
|
pkt_s.instance = pocket.new_session(id, source_addr, i_seq_num, pkt_s.in_queue, pkt_s.out_queue, self.config.API_Timeout)
|
||||||
table.insert(self.sessions, pkt_s)
|
table.insert(self.sessions, pkt_s)
|
||||||
|
|
||||||
local mt = {
|
local mt = {
|
||||||
|
@ -32,16 +32,16 @@ local PERIODICS = {
|
|||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param id integer session ID
|
---@param id integer session ID
|
||||||
---@param s_addr integer device source address
|
---@param s_addr integer device source address
|
||||||
|
---@param i_seq_num integer initial sequence number
|
||||||
---@param in_queue mqueue in message queue
|
---@param in_queue mqueue in message queue
|
||||||
---@param out_queue mqueue out message queue
|
---@param out_queue mqueue out message queue
|
||||||
---@param timeout number communications timeout
|
---@param timeout number communications timeout
|
||||||
function pocket.new_session(id, s_addr, in_queue, out_queue, timeout)
|
function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
|
||||||
local log_header = "pkt_session(" .. id .. "): "
|
local log_header = "pkt_session(" .. id .. "): "
|
||||||
|
|
||||||
local self = {
|
local self = {
|
||||||
-- connection properties
|
-- connection properties
|
||||||
seq_num = 0,
|
seq_num = i_seq_num,
|
||||||
r_seq_num = nil,
|
|
||||||
connected = true,
|
connected = true,
|
||||||
conn_watchdog = util.new_watchdog(timeout),
|
conn_watchdog = util.new_watchdog(timeout),
|
||||||
last_rtt = 0,
|
last_rtt = 0,
|
||||||
@ -104,13 +104,11 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout)
|
|||||||
---@param pkt mgmt_frame|crdn_frame
|
---@param pkt mgmt_frame|crdn_frame
|
||||||
local function _handle_packet(pkt)
|
local function _handle_packet(pkt)
|
||||||
-- check sequence number
|
-- check sequence number
|
||||||
if self.r_seq_num == nil then
|
if self.seq_num ~= pkt.scada_frame.seq_num() then
|
||||||
self.r_seq_num = pkt.scada_frame.seq_num()
|
log.warning(log_header .. "sequence out-of-order: last = " .. self.seq_num .. ", new = " .. pkt.scada_frame.seq_num())
|
||||||
elseif (self.r_seq_num + 1) ~= pkt.scada_frame.seq_num() then
|
|
||||||
log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num())
|
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
self.r_seq_num = pkt.scada_frame.seq_num()
|
self.seq_num = pkt.scada_frame.seq_num() + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- feed watchdog
|
-- feed watchdog
|
||||||
|
@ -19,7 +19,7 @@ local renderer = require("coordinator.renderer")
|
|||||||
local sounder = require("coordinator.sounder")
|
local sounder = require("coordinator.sounder")
|
||||||
local threads = require("coordinator.threads")
|
local threads = require("coordinator.threads")
|
||||||
|
|
||||||
local COORDINATOR_VERSION = "v1.4.7"
|
local COORDINATOR_VERSION = "v1.5.0"
|
||||||
|
|
||||||
local CHUNK_LOAD_DELAY_S = 30.0
|
local CHUNK_LOAD_DELAY_S = 30.0
|
||||||
|
|
||||||
|
@ -370,15 +370,13 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
|
|||||||
sv = {
|
sv = {
|
||||||
linked = false,
|
linked = false,
|
||||||
addr = comms.BROADCAST,
|
addr = comms.BROADCAST,
|
||||||
seq_num = 0,
|
seq_num = util.time_ms() * 10, -- unique per peer, restarting will not re-use seq nums due to message rate
|
||||||
r_seq_num = nil, ---@type nil|integer
|
|
||||||
last_est_ack = ESTABLISH_ACK.ALLOW
|
last_est_ack = ESTABLISH_ACK.ALLOW
|
||||||
},
|
},
|
||||||
api = {
|
api = {
|
||||||
linked = false,
|
linked = false,
|
||||||
addr = comms.BROADCAST,
|
addr = comms.BROADCAST,
|
||||||
seq_num = 0,
|
seq_num = util.time_ms() * 10, -- unique per peer, restarting will not re-use seq nums due to message rate
|
||||||
r_seq_num = nil, ---@type nil|integer
|
|
||||||
last_est_ack = ESTABLISH_ACK.ALLOW
|
last_est_ack = ESTABLISH_ACK.ALLOW
|
||||||
},
|
},
|
||||||
establish_delay_counter = 0
|
establish_delay_counter = 0
|
||||||
@ -466,7 +464,6 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
|
|||||||
sv_watchdog.cancel()
|
sv_watchdog.cancel()
|
||||||
nav.unload_sv()
|
nav.unload_sv()
|
||||||
self.sv.linked = false
|
self.sv.linked = false
|
||||||
self.sv.r_seq_num = nil
|
|
||||||
self.sv.addr = comms.BROADCAST
|
self.sv.addr = comms.BROADCAST
|
||||||
_send_sv(MGMT_TYPE.CLOSE, {})
|
_send_sv(MGMT_TYPE.CLOSE, {})
|
||||||
end
|
end
|
||||||
@ -476,7 +473,6 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
|
|||||||
api_watchdog.cancel()
|
api_watchdog.cancel()
|
||||||
nav.unload_api()
|
nav.unload_api()
|
||||||
self.api.linked = false
|
self.api.linked = false
|
||||||
self.api.r_seq_num = nil
|
|
||||||
self.api.addr = comms.BROADCAST
|
self.api.addr = comms.BROADCAST
|
||||||
_send_crd(MGMT_TYPE.CLOSE, {})
|
_send_crd(MGMT_TYPE.CLOSE, {})
|
||||||
end
|
end
|
||||||
@ -603,17 +599,15 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
|
|||||||
log.debug("received packet on unconfigured channel " .. l_chan, true)
|
log.debug("received packet on unconfigured channel " .. l_chan, true)
|
||||||
elseif r_chan == config.CRD_Channel then
|
elseif r_chan == config.CRD_Channel then
|
||||||
-- check sequence number
|
-- check sequence number
|
||||||
if self.api.r_seq_num == nil then
|
if self.api.seq_num ~= packet.scada_frame.seq_num() then
|
||||||
self.api.r_seq_num = packet.scada_frame.seq_num()
|
log.warning("sequence out-of-order (API): last = " .. self.api.seq_num .. ", new = " .. packet.scada_frame.seq_num())
|
||||||
elseif self.connected and ((self.api.r_seq_num + 1) ~= packet.scada_frame.seq_num()) then
|
|
||||||
log.warning("sequence out-of-order (API): last = " .. self.api.r_seq_num .. ", new = " .. packet.scada_frame.seq_num())
|
|
||||||
return
|
return
|
||||||
elseif self.api.linked and (src_addr ~= self.api.addr) then
|
elseif self.api.linked and (src_addr ~= self.api.addr) then
|
||||||
log.debug("received packet from unknown computer " .. src_addr .. " while linked (API expected " .. self.api.addr ..
|
log.debug("received packet from unknown computer " .. src_addr .. " while linked (API expected " .. self.api.addr ..
|
||||||
"); channel in use by another system?")
|
"); channel in use by another system?")
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
self.api.r_seq_num = packet.scada_frame.seq_num()
|
self.api.seq_num = packet.scada_frame.seq_num() + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- feed watchdog on valid sequence number
|
-- feed watchdog on valid sequence number
|
||||||
@ -658,7 +652,6 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
|
|||||||
api_watchdog.cancel()
|
api_watchdog.cancel()
|
||||||
nav.unload_api()
|
nav.unload_api()
|
||||||
self.api.linked = false
|
self.api.linked = false
|
||||||
self.api.r_seq_num = nil
|
|
||||||
self.api.addr = comms.BROADCAST
|
self.api.addr = comms.BROADCAST
|
||||||
log.info("coordinator server connection closed by remote host")
|
log.info("coordinator server connection closed by remote host")
|
||||||
else _fail_type(packet) end
|
else _fail_type(packet) end
|
||||||
@ -723,17 +716,15 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
|
|||||||
end
|
end
|
||||||
elseif r_chan == config.SVR_Channel then
|
elseif r_chan == config.SVR_Channel then
|
||||||
-- check sequence number
|
-- check sequence number
|
||||||
if self.sv.r_seq_num == nil then
|
if self.sv.seq_num ~= packet.scada_frame.seq_num() then
|
||||||
self.sv.r_seq_num = packet.scada_frame.seq_num()
|
log.warning("sequence out-of-order (SVR): last = " .. self.sv.seq_num .. ", new = " .. packet.scada_frame.seq_num())
|
||||||
elseif self.connected and ((self.sv.r_seq_num + 1) ~= packet.scada_frame.seq_num()) then
|
|
||||||
log.warning("sequence out-of-order (SVR): last = " .. self.sv.r_seq_num .. ", new = " .. packet.scada_frame.seq_num())
|
|
||||||
return
|
return
|
||||||
elseif self.sv.linked and (src_addr ~= self.sv.addr) then
|
elseif self.sv.linked and (src_addr ~= self.sv.addr) then
|
||||||
log.debug("received packet from unknown computer " .. src_addr .. " while linked (SVR expected " .. self.sv.addr ..
|
log.debug("received packet from unknown computer " .. src_addr .. " while linked (SVR expected " .. self.sv.addr ..
|
||||||
"); channel in use by another system?")
|
"); channel in use by another system?")
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
self.sv.r_seq_num = packet.scada_frame.seq_num()
|
self.sv.seq_num = packet.scada_frame.seq_num() + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- feed watchdog on valid sequence number
|
-- feed watchdog on valid sequence number
|
||||||
@ -764,7 +755,6 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
|
|||||||
sv_watchdog.cancel()
|
sv_watchdog.cancel()
|
||||||
nav.unload_sv()
|
nav.unload_sv()
|
||||||
self.sv.linked = false
|
self.sv.linked = false
|
||||||
self.sv.r_seq_num = nil
|
|
||||||
self.sv.addr = comms.BROADCAST
|
self.sv.addr = comms.BROADCAST
|
||||||
log.info("supervisor server connection closed by remote host")
|
log.info("supervisor server connection closed by remote host")
|
||||||
elseif packet.type == MGMT_TYPE.DIAG_TONE_GET then
|
elseif packet.type == MGMT_TYPE.DIAG_TONE_GET then
|
||||||
|
@ -20,7 +20,7 @@ local pocket = require("pocket.pocket")
|
|||||||
local renderer = require("pocket.renderer")
|
local renderer = require("pocket.renderer")
|
||||||
local threads = require("pocket.threads")
|
local threads = require("pocket.threads")
|
||||||
|
|
||||||
local POCKET_VERSION = "v0.10.0-alpha"
|
local POCKET_VERSION = "v0.11.0-alpha"
|
||||||
|
|
||||||
local println = util.println
|
local println = util.println
|
||||||
local println_ts = util.println_ts
|
local println_ts = util.println_ts
|
||||||
|
@ -524,8 +524,7 @@ end
|
|||||||
function plc.comms(version, nic, reactor, rps, conn_watchdog)
|
function plc.comms(version, nic, reactor, rps, conn_watchdog)
|
||||||
local self = {
|
local self = {
|
||||||
sv_addr = comms.BROADCAST,
|
sv_addr = comms.BROADCAST,
|
||||||
seq_num = 0,
|
seq_num = util.time_ms() * 10, -- unique per peer, restarting will not re-use seq nums due to message rate
|
||||||
r_seq_num = nil,
|
|
||||||
scrammed = false,
|
scrammed = false,
|
||||||
linked = false,
|
linked = false,
|
||||||
last_est_ack = ESTABLISH_ACK.ALLOW,
|
last_est_ack = ESTABLISH_ACK.ALLOW,
|
||||||
@ -725,7 +724,6 @@ function plc.comms(version, nic, reactor, rps, conn_watchdog)
|
|||||||
function public.unlink()
|
function public.unlink()
|
||||||
self.sv_addr = comms.BROADCAST
|
self.sv_addr = comms.BROADCAST
|
||||||
self.linked = false
|
self.linked = false
|
||||||
self.r_seq_num = nil
|
|
||||||
self.status_cache = nil
|
self.status_cache = nil
|
||||||
databus.tx_link_state(types.PANEL_LINK_STATE.DISCONNECTED)
|
databus.tx_link_state(types.PANEL_LINK_STATE.DISCONNECTED)
|
||||||
end
|
end
|
||||||
@ -834,17 +832,15 @@ function plc.comms(version, nic, reactor, rps, conn_watchdog)
|
|||||||
-- handle packets now that we have prints setup
|
-- handle packets now that we have prints setup
|
||||||
if l_chan == config.PLC_Channel then
|
if l_chan == config.PLC_Channel then
|
||||||
-- check sequence number
|
-- check sequence number
|
||||||
if self.r_seq_num == nil then
|
if self.seq_num ~= packet.scada_frame.seq_num() then
|
||||||
self.r_seq_num = packet.scada_frame.seq_num()
|
log.warning("sequence out-of-order: last = " .. self.seq_num .. ", new = " .. packet.scada_frame.seq_num())
|
||||||
elseif self.linked and ((self.r_seq_num + 1) ~= packet.scada_frame.seq_num()) then
|
|
||||||
log.warning("sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. packet.scada_frame.seq_num())
|
|
||||||
return
|
return
|
||||||
elseif self.linked and (src_addr ~= self.sv_addr) then
|
elseif self.linked and (src_addr ~= self.sv_addr) then
|
||||||
log.debug("received packet from unknown computer " .. src_addr .. " while linked (expected " .. self.sv_addr ..
|
log.debug("received packet from unknown computer " .. src_addr .. " while linked (expected " .. self.sv_addr ..
|
||||||
"); channel in use by another system?")
|
"); channel in use by another system?")
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
self.r_seq_num = packet.scada_frame.seq_num()
|
self.seq_num = packet.scada_frame.seq_num() + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- feed the watchdog first so it doesn't uhh...eat our packets :)
|
-- feed the watchdog first so it doesn't uhh...eat our packets :)
|
||||||
@ -1030,10 +1026,9 @@ function plc.comms(version, nic, reactor, rps, conn_watchdog)
|
|||||||
println_ts("linked!")
|
println_ts("linked!")
|
||||||
log.info("supervisor establish request approved, linked to SV (CID#" .. src_addr .. ")")
|
log.info("supervisor establish request approved, linked to SV (CID#" .. src_addr .. ")")
|
||||||
|
|
||||||
-- link + reset remote sequence number and cache
|
-- link + reset cache
|
||||||
self.sv_addr = src_addr
|
self.sv_addr = src_addr
|
||||||
self.linked = true
|
self.linked = true
|
||||||
self.r_seq_num = nil
|
|
||||||
self.status_cache = nil
|
self.status_cache = nil
|
||||||
|
|
||||||
if plc_state.reactor_formed then _send_struct() end
|
if plc_state.reactor_formed then _send_struct() end
|
||||||
|
@ -18,7 +18,7 @@ local plc = require("reactor-plc.plc")
|
|||||||
local renderer = require("reactor-plc.renderer")
|
local renderer = require("reactor-plc.renderer")
|
||||||
local threads = require("reactor-plc.threads")
|
local threads = require("reactor-plc.threads")
|
||||||
|
|
||||||
local R_PLC_VERSION = "v1.7.11"
|
local R_PLC_VERSION = "v1.8.0"
|
||||||
|
|
||||||
local println = util.println
|
local println = util.println
|
||||||
local println_ts = util.println_ts
|
local println_ts = util.println_ts
|
||||||
|
13
rtu/rtu.lua
13
rtu/rtu.lua
@ -284,8 +284,7 @@ end
|
|||||||
function rtu.comms(version, nic, conn_watchdog)
|
function rtu.comms(version, nic, conn_watchdog)
|
||||||
local self = {
|
local self = {
|
||||||
sv_addr = comms.BROADCAST,
|
sv_addr = comms.BROADCAST,
|
||||||
seq_num = 0,
|
seq_num = util.time_ms() * 10, -- unique per peer, restarting will not re-use seq nums due to message rate
|
||||||
r_seq_num = nil,
|
|
||||||
txn_id = 0,
|
txn_id = 0,
|
||||||
last_est_ack = ESTABLISH_ACK.ALLOW
|
last_est_ack = ESTABLISH_ACK.ALLOW
|
||||||
}
|
}
|
||||||
@ -363,7 +362,6 @@ function rtu.comms(version, nic, conn_watchdog)
|
|||||||
function public.unlink(rtu_state)
|
function public.unlink(rtu_state)
|
||||||
rtu_state.linked = false
|
rtu_state.linked = false
|
||||||
self.sv_addr = comms.BROADCAST
|
self.sv_addr = comms.BROADCAST
|
||||||
self.r_seq_num = nil
|
|
||||||
databus.tx_link_state(types.PANEL_LINK_STATE.DISCONNECTED)
|
databus.tx_link_state(types.PANEL_LINK_STATE.DISCONNECTED)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -441,17 +439,15 @@ function rtu.comms(version, nic, conn_watchdog)
|
|||||||
|
|
||||||
if l_chan == config.RTU_Channel then
|
if l_chan == config.RTU_Channel then
|
||||||
-- check sequence number
|
-- check sequence number
|
||||||
if self.r_seq_num == nil then
|
if self.seq_num ~= packet.scada_frame.seq_num() then
|
||||||
self.r_seq_num = packet.scada_frame.seq_num()
|
log.warning("sequence out-of-order: last = " .. self.seq_num .. ", new = " .. packet.scada_frame.seq_num())
|
||||||
elseif rtu_state.linked and ((self.r_seq_num + 1) ~= packet.scada_frame.seq_num()) then
|
|
||||||
log.warning("sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. packet.scada_frame.seq_num())
|
|
||||||
return
|
return
|
||||||
elseif rtu_state.linked and (src_addr ~= self.sv_addr) then
|
elseif rtu_state.linked and (src_addr ~= self.sv_addr) then
|
||||||
log.debug("received packet from unknown computer " .. src_addr .. " while linked (expected " .. self.sv_addr ..
|
log.debug("received packet from unknown computer " .. src_addr .. " while linked (expected " .. self.sv_addr ..
|
||||||
"); channel in use by another system?")
|
"); channel in use by another system?")
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
self.r_seq_num = packet.scada_frame.seq_num()
|
self.seq_num = packet.scada_frame.seq_num() + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- feed watchdog on valid sequence number
|
-- feed watchdog on valid sequence number
|
||||||
@ -556,7 +552,6 @@ function rtu.comms(version, nic, conn_watchdog)
|
|||||||
-- establish allowed
|
-- establish allowed
|
||||||
rtu_state.linked = true
|
rtu_state.linked = true
|
||||||
self.sv_addr = packet.scada_frame.src_addr()
|
self.sv_addr = packet.scada_frame.src_addr()
|
||||||
self.r_seq_num = nil
|
|
||||||
println_ts("supervisor connection established")
|
println_ts("supervisor connection established")
|
||||||
log.info("supervisor connection established")
|
log.info("supervisor connection established")
|
||||||
else
|
else
|
||||||
|
@ -31,7 +31,7 @@ local sna_rtu = require("rtu.dev.sna_rtu")
|
|||||||
local sps_rtu = require("rtu.dev.sps_rtu")
|
local sps_rtu = require("rtu.dev.sps_rtu")
|
||||||
local turbinev_rtu = require("rtu.dev.turbinev_rtu")
|
local turbinev_rtu = require("rtu.dev.turbinev_rtu")
|
||||||
|
|
||||||
local RTU_VERSION = "v1.9.6"
|
local RTU_VERSION = "v1.10.0"
|
||||||
|
|
||||||
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
|
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
|
||||||
local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE
|
local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE
|
||||||
|
@ -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 = "2.5.2"
|
comms.version = "3.0.0"
|
||||||
comms.api_version = "0.0.3"
|
comms.api_version = "0.0.3"
|
||||||
|
|
||||||
---@enum PROTOCOL
|
---@enum PROTOCOL
|
||||||
@ -240,6 +240,8 @@ function comms.scada_packet()
|
|||||||
---@nodiscard
|
---@nodiscard
|
||||||
function public.modem_event() return self.modem_msg_in end
|
function public.modem_event() return self.modem_msg_in end
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
|
function public.raw_header() return { self.src_addr, self.dest_addr, self.seq_num, self.protocol } end
|
||||||
|
---@nodiscard
|
||||||
function public.raw_sendable() return self.raw end
|
function public.raw_sendable() return self.raw end
|
||||||
|
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
@ -278,7 +280,7 @@ function comms.authd_packet()
|
|||||||
src_addr = comms.BROADCAST,
|
src_addr = comms.BROADCAST,
|
||||||
dest_addr = comms.BROADCAST,
|
dest_addr = comms.BROADCAST,
|
||||||
mac = "",
|
mac = "",
|
||||||
payload = ""
|
payload = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
---@class authd_packet
|
---@class authd_packet
|
||||||
@ -286,14 +288,13 @@ function comms.authd_packet()
|
|||||||
|
|
||||||
-- make an authenticated SCADA packet
|
-- make an authenticated SCADA packet
|
||||||
---@param s_packet scada_packet scada packet to authenticate
|
---@param s_packet scada_packet scada packet to authenticate
|
||||||
---@param mac function message authentication function
|
---@param mac function message authentication hash function
|
||||||
function public.make(s_packet, mac)
|
function public.make(s_packet, mac)
|
||||||
self.valid = true
|
self.valid = true
|
||||||
self.src_addr = s_packet.src_addr()
|
self.src_addr = s_packet.src_addr()
|
||||||
self.dest_addr = s_packet.dest_addr()
|
self.dest_addr = s_packet.dest_addr()
|
||||||
self.payload = textutils.serialize(s_packet.raw_sendable(), { allow_repetitions = true, compact = true })
|
self.mac = mac(textutils.serialize(s_packet.raw_header(), { allow_repetitions = true, compact = true }))
|
||||||
self.mac = mac(self.payload)
|
self.raw = { self.src_addr, self.dest_addr, self.mac, s_packet.data() }
|
||||||
self.raw = { self.src_addr, self.dest_addr, self.mac, self.payload }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- parse in a modem message as an authenticated SCADA packet
|
-- parse in a modem message as an authenticated SCADA packet
|
||||||
@ -330,14 +331,14 @@ function comms.authd_packet()
|
|||||||
self.src_addr = nil
|
self.src_addr = nil
|
||||||
self.dest_addr = nil
|
self.dest_addr = nil
|
||||||
self.mac = ""
|
self.mac = ""
|
||||||
self.payload = ""
|
self.payload = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- check if this packet is destined for this device
|
-- check if this packet is destined for this device
|
||||||
local is_destination = (self.dest_addr == comms.BROADCAST) or (self.dest_addr == COMPUTER_ID)
|
local is_destination = (self.dest_addr == comms.BROADCAST) or (self.dest_addr == COMPUTER_ID)
|
||||||
|
|
||||||
self.valid = is_destination and type(self.src_addr) == "number" and type(self.dest_addr) == "number" and
|
self.valid = is_destination and type(self.src_addr) == "number" and type(self.dest_addr) == "number" and
|
||||||
type(self.mac) == "string" and type(self.payload) == "string"
|
type(self.mac) == "string" and type(self.payload) == "table"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ function network.nic(modem)
|
|||||||
modem.open(channel)
|
modem.open(channel)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- link all public functions except for transmit
|
-- link all public functions except for transmit, open, and close
|
||||||
for key, func in pairs(modem) do
|
for key, func in pairs(modem) do
|
||||||
if key ~= "transmit" and key ~= "open" and key ~= "close" and key ~= "closeAll" then public[key] = func end
|
if key ~= "transmit" and key ~= "open" and key ~= "close" and key ~= "closeAll" then public[key] = func end
|
||||||
end
|
end
|
||||||
@ -184,7 +184,7 @@ function network.nic(modem)
|
|||||||
---@cast tx_packet authd_packet
|
---@cast tx_packet authd_packet
|
||||||
tx_packet.make(packet, compute_hmac)
|
tx_packet.make(packet, compute_hmac)
|
||||||
|
|
||||||
-- log.debug("crypto.modem.transmit: data processing took " .. (util.time_ms() - start) .. "ms")
|
-- log.debug("network.modem.transmit: data processing took " .. (util.time_ms() - start) .. "ms")
|
||||||
end
|
end
|
||||||
|
|
||||||
modem.transmit(dest_channel, local_channel, tx_packet.raw_sendable())
|
modem.transmit(dest_channel, local_channel, tx_packet.raw_sendable())
|
||||||
@ -211,17 +211,18 @@ function network.nic(modem)
|
|||||||
a_packet.receive(side, sender, reply_to, message, distance)
|
a_packet.receive(side, sender, reply_to, message, distance)
|
||||||
|
|
||||||
if a_packet.is_valid() then
|
if a_packet.is_valid() then
|
||||||
-- local start = util.time_ms()
|
s_packet.receive(side, sender, reply_to, a_packet.data(), distance)
|
||||||
local packet_hmac = a_packet.mac()
|
|
||||||
local msg = a_packet.data()
|
|
||||||
local computed_hmac = compute_hmac(msg)
|
|
||||||
|
|
||||||
if packet_hmac == computed_hmac then
|
if s_packet.is_valid() then
|
||||||
-- log.debug("crypto.modem.receive: HMAC verified in " .. (util.time_ms() - start) .. "ms")
|
-- local start = util.time_ms()
|
||||||
s_packet.receive(side, sender, reply_to, textutils.unserialize(msg), distance)
|
local computed_hmac = compute_hmac(textutils.serialize(s_packet.raw_header(), { allow_repetitions = true, compact = true }))
|
||||||
|
|
||||||
|
if a_packet.mac() == computed_hmac then
|
||||||
|
-- log.debug("network.modem.receive: HMAC verified in " .. (util.time_ms() - start) .. "ms")
|
||||||
s_packet.stamp_authenticated()
|
s_packet.stamp_authenticated()
|
||||||
else
|
else
|
||||||
-- log.debug("crypto.modem.receive: HMAC failed verification in " .. (util.time_ms() - start) .. "ms")
|
-- log.debug("network.modem.receive: HMAC failed verification in " .. (util.time_ms() - start) .. "ms")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -43,12 +43,13 @@ local PERIODICS = {
|
|||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param id integer session ID
|
---@param id integer session ID
|
||||||
---@param s_addr integer device source address
|
---@param s_addr integer device source address
|
||||||
|
---@param i_seq_num integer initial sequence number
|
||||||
---@param in_queue mqueue in message queue
|
---@param in_queue mqueue in message queue
|
||||||
---@param out_queue mqueue out message queue
|
---@param out_queue mqueue out message queue
|
||||||
---@param timeout number communications timeout
|
---@param timeout number communications timeout
|
||||||
---@param facility facility facility data table
|
---@param facility facility facility data table
|
||||||
---@param fp_ok boolean if the front panel UI is running
|
---@param fp_ok boolean if the front panel UI is running
|
||||||
function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facility, fp_ok)
|
function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, facility, fp_ok)
|
||||||
-- print a log message to the terminal as long as the UI isn't running
|
-- print a log message to the terminal as long as the UI isn't running
|
||||||
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
|
||||||
|
|
||||||
@ -57,8 +58,7 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
|
|||||||
local self = {
|
local self = {
|
||||||
units = facility.get_units(),
|
units = facility.get_units(),
|
||||||
-- connection properties
|
-- connection properties
|
||||||
seq_num = 0,
|
seq_num = i_seq_num,
|
||||||
r_seq_num = nil,
|
|
||||||
connected = true,
|
connected = true,
|
||||||
conn_watchdog = util.new_watchdog(timeout),
|
conn_watchdog = util.new_watchdog(timeout),
|
||||||
establish_time = util.time_s(),
|
establish_time = util.time_s(),
|
||||||
@ -182,13 +182,11 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
|
|||||||
---@param pkt mgmt_frame|crdn_frame
|
---@param pkt mgmt_frame|crdn_frame
|
||||||
local function _handle_packet(pkt)
|
local function _handle_packet(pkt)
|
||||||
-- check sequence number
|
-- check sequence number
|
||||||
if self.r_seq_num == nil then
|
if self.seq_num ~= pkt.scada_frame.seq_num() then
|
||||||
self.r_seq_num = pkt.scada_frame.seq_num()
|
log.warning(log_header .. "sequence out-of-order: last = " .. self.seq_num .. ", new = " .. pkt.scada_frame.seq_num())
|
||||||
elseif (self.r_seq_num + 1) ~= pkt.scada_frame.seq_num() then
|
|
||||||
log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num())
|
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
self.r_seq_num = pkt.scada_frame.seq_num()
|
self.seq_num = pkt.scada_frame.seq_num() + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- feed watchdog
|
-- feed watchdog
|
||||||
|
@ -48,12 +48,13 @@ local PERIODICS = {
|
|||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param id integer session ID
|
---@param id integer session ID
|
||||||
---@param s_addr integer device source address
|
---@param s_addr integer device source address
|
||||||
|
---@param i_seq_num integer initial sequence number
|
||||||
---@param reactor_id integer reactor ID
|
---@param reactor_id integer reactor ID
|
||||||
---@param in_queue mqueue in message queue
|
---@param in_queue mqueue in message queue
|
||||||
---@param out_queue mqueue out message queue
|
---@param out_queue mqueue out message queue
|
||||||
---@param timeout number communications timeout
|
---@param timeout number communications timeout
|
||||||
---@param fp_ok boolean if the front panel UI is running
|
---@param fp_ok boolean if the front panel UI is running
|
||||||
function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, fp_ok)
|
function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue, timeout, fp_ok)
|
||||||
-- print a log message to the terminal as long as the UI isn't running
|
-- print a log message to the terminal as long as the UI isn't running
|
||||||
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
|
||||||
|
|
||||||
@ -66,8 +67,7 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f
|
|||||||
ramping_rate = false,
|
ramping_rate = false,
|
||||||
auto_lock = false,
|
auto_lock = false,
|
||||||
-- connection properties
|
-- connection properties
|
||||||
seq_num = 0,
|
seq_num = i_seq_num,
|
||||||
r_seq_num = nil,
|
|
||||||
connected = true,
|
connected = true,
|
||||||
received_struct = false,
|
received_struct = false,
|
||||||
received_status_cache = false,
|
received_status_cache = false,
|
||||||
@ -309,13 +309,11 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f
|
|||||||
---@param pkt mgmt_frame|rplc_frame
|
---@param pkt mgmt_frame|rplc_frame
|
||||||
local function _handle_packet(pkt)
|
local function _handle_packet(pkt)
|
||||||
-- check sequence number
|
-- check sequence number
|
||||||
if self.r_seq_num == nil then
|
if self.seq_num ~= pkt.scada_frame.seq_num() then
|
||||||
self.r_seq_num = pkt.scada_frame.seq_num()
|
log.warning(log_header .. "sequence out-of-order: last = " .. self.seq_num .. ", new = " .. pkt.scada_frame.seq_num())
|
||||||
elseif (self.r_seq_num + 1) ~= pkt.scada_frame.seq_num() then
|
|
||||||
log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num())
|
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
self.r_seq_num = pkt.scada_frame.seq_num()
|
self.seq_num = pkt.scada_frame.seq_num() + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- process packet
|
-- process packet
|
||||||
|
@ -30,12 +30,13 @@ local PERIODICS = {
|
|||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param id integer session ID
|
---@param id integer session ID
|
||||||
---@param s_addr integer device source address
|
---@param s_addr integer device source address
|
||||||
|
---@param i_seq_num integer initial sequence number
|
||||||
---@param in_queue mqueue in message queue
|
---@param in_queue mqueue in message queue
|
||||||
---@param out_queue mqueue out message queue
|
---@param out_queue mqueue out message queue
|
||||||
---@param timeout number communications timeout
|
---@param timeout number communications timeout
|
||||||
---@param facility facility facility data table
|
---@param facility facility facility data table
|
||||||
---@param fp_ok boolean if the front panel UI is running
|
---@param fp_ok boolean if the front panel UI is running
|
||||||
function pocket.new_session(id, s_addr, in_queue, out_queue, timeout, facility, fp_ok)
|
function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, facility, fp_ok)
|
||||||
-- print a log message to the terminal as long as the UI isn't running
|
-- print a log message to the terminal as long as the UI isn't running
|
||||||
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
|
||||||
|
|
||||||
@ -43,8 +44,7 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout, facility,
|
|||||||
|
|
||||||
local self = {
|
local self = {
|
||||||
-- connection properties
|
-- connection properties
|
||||||
seq_num = 0,
|
seq_num = i_seq_num,
|
||||||
r_seq_num = nil,
|
|
||||||
connected = true,
|
connected = true,
|
||||||
conn_watchdog = util.new_watchdog(timeout),
|
conn_watchdog = util.new_watchdog(timeout),
|
||||||
last_rtt = 0,
|
last_rtt = 0,
|
||||||
@ -93,13 +93,11 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout, facility,
|
|||||||
---@param pkt mgmt_frame
|
---@param pkt mgmt_frame
|
||||||
local function _handle_packet(pkt)
|
local function _handle_packet(pkt)
|
||||||
-- check sequence number
|
-- check sequence number
|
||||||
if self.r_seq_num == nil then
|
if self.seq_num ~= pkt.scada_frame.seq_num() then
|
||||||
self.r_seq_num = pkt.scada_frame.seq_num()
|
log.warning(log_header .. "sequence out-of-order: last = " .. self.seq_num .. ", new = " .. pkt.scada_frame.seq_num())
|
||||||
elseif (self.r_seq_num + 1) ~= pkt.scada_frame.seq_num() then
|
|
||||||
log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num())
|
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
self.r_seq_num = pkt.scada_frame.seq_num()
|
self.seq_num = pkt.scada_frame.seq_num() + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- feed watchdog
|
-- feed watchdog
|
||||||
|
@ -34,13 +34,14 @@ local PERIODICS = {
|
|||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param id integer session ID
|
---@param id integer session ID
|
||||||
---@param s_addr integer device source address
|
---@param s_addr integer device source address
|
||||||
|
---@param i_seq_num integer initial sequence number
|
||||||
---@param in_queue mqueue in message queue
|
---@param in_queue mqueue in message queue
|
||||||
---@param out_queue mqueue out message queue
|
---@param out_queue mqueue out message queue
|
||||||
---@param timeout number communications timeout
|
---@param timeout number communications timeout
|
||||||
---@param advertisement table RTU device advertisement
|
---@param advertisement table RTU device advertisement
|
||||||
---@param facility facility facility data table
|
---@param facility facility facility data table
|
||||||
---@param fp_ok boolean if the front panel UI is running
|
---@param fp_ok boolean if the front panel UI is running
|
||||||
function rtu.new_session(id, s_addr, in_queue, out_queue, timeout, advertisement, facility, fp_ok)
|
function rtu.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, advertisement, facility, fp_ok)
|
||||||
-- print a log message to the terminal as long as the UI isn't running
|
-- print a log message to the terminal as long as the UI isn't running
|
||||||
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
|
||||||
|
|
||||||
@ -51,8 +52,7 @@ function rtu.new_session(id, s_addr, in_queue, out_queue, timeout, advertisement
|
|||||||
advert = advertisement,
|
advert = advertisement,
|
||||||
fac_units = facility.get_units(),
|
fac_units = facility.get_units(),
|
||||||
-- connection properties
|
-- connection properties
|
||||||
seq_num = 0,
|
seq_num = i_seq_num,
|
||||||
r_seq_num = nil,
|
|
||||||
connected = true,
|
connected = true,
|
||||||
conn_watchdog = util.new_watchdog(timeout),
|
conn_watchdog = util.new_watchdog(timeout),
|
||||||
last_rtt = 0,
|
last_rtt = 0,
|
||||||
@ -240,13 +240,11 @@ function rtu.new_session(id, s_addr, in_queue, out_queue, timeout, advertisement
|
|||||||
---@param pkt modbus_frame|mgmt_frame
|
---@param pkt modbus_frame|mgmt_frame
|
||||||
local function _handle_packet(pkt)
|
local function _handle_packet(pkt)
|
||||||
-- check sequence number
|
-- check sequence number
|
||||||
if self.r_seq_num == nil then
|
if self.seq_num ~= pkt.scada_frame.seq_num() then
|
||||||
self.r_seq_num = pkt.scada_frame.seq_num()
|
log.warning(log_header .. "sequence out-of-order: last = " .. self.seq_num .. ", new = " .. pkt.scada_frame.seq_num())
|
||||||
elseif (self.r_seq_num + 1) ~= pkt.scada_frame.seq_num() then
|
|
||||||
log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num())
|
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
self.r_seq_num = pkt.scada_frame.seq_num()
|
self.seq_num = pkt.scada_frame.seq_num() + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- feed watchdog
|
-- feed watchdog
|
||||||
|
@ -273,11 +273,12 @@ end
|
|||||||
|
|
||||||
-- establish a new PLC session
|
-- establish a new PLC session
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param source_addr integer
|
---@param source_addr integer PLC computer ID
|
||||||
---@param for_reactor integer
|
---@param i_seq_num integer initial sequence number to use next
|
||||||
---@param version string
|
---@param for_reactor integer unit ID
|
||||||
|
---@param version string PLC version
|
||||||
---@return integer|false session_id
|
---@return integer|false session_id
|
||||||
function svsessions.establish_plc_session(source_addr, for_reactor, version)
|
function svsessions.establish_plc_session(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 = {
|
||||||
@ -294,7 +295,7 @@ function svsessions.establish_plc_session(source_addr, for_reactor, version)
|
|||||||
|
|
||||||
local id = self.next_ids.plc
|
local id = self.next_ids.plc
|
||||||
|
|
||||||
plc_s.instance = plc.new_session(id, source_addr, for_reactor, plc_s.in_queue, plc_s.out_queue, self.config.PLC_Timeout, self.fp_ok)
|
plc_s.instance = plc.new_session(id, source_addr, i_seq_num, for_reactor, plc_s.in_queue, plc_s.out_queue, self.config.PLC_Timeout, self.fp_ok)
|
||||||
table.insert(self.sessions.plc, plc_s)
|
table.insert(self.sessions.plc, plc_s)
|
||||||
|
|
||||||
local units = self.facility.get_units()
|
local units = self.facility.get_units()
|
||||||
@ -320,13 +321,14 @@ function svsessions.establish_plc_session(source_addr, for_reactor, version)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- establish a new RTU session
|
-- establish a new RTU gateway session
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param source_addr integer
|
---@param source_addr integer RTU gateway computer ID
|
||||||
---@param advertisement table
|
---@param i_seq_num integer initial sequence number to use next
|
||||||
---@param version string
|
---@param advertisement table RTU capability advertisement
|
||||||
|
---@param version string RTU gateway version
|
||||||
---@return integer session_id
|
---@return integer session_id
|
||||||
function svsessions.establish_rtu_session(source_addr, advertisement, version)
|
function svsessions.establish_rtu_session(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",
|
||||||
@ -341,7 +343,7 @@ function svsessions.establish_rtu_session(source_addr, advertisement, version)
|
|||||||
|
|
||||||
local id = self.next_ids.rtu
|
local id = self.next_ids.rtu
|
||||||
|
|
||||||
rtu_s.instance = rtu.new_session(id, source_addr, rtu_s.in_queue, rtu_s.out_queue, self.config.RTU_Timeout, advertisement, self.facility, self.fp_ok)
|
rtu_s.instance = rtu.new_session(id, source_addr, i_seq_num, rtu_s.in_queue, rtu_s.out_queue, self.config.RTU_Timeout, advertisement, self.facility, self.fp_ok)
|
||||||
table.insert(self.sessions.rtu, rtu_s)
|
table.insert(self.sessions.rtu, rtu_s)
|
||||||
|
|
||||||
local mt = {
|
local mt = {
|
||||||
@ -362,10 +364,11 @@ end
|
|||||||
|
|
||||||
-- establish a new coordinator session
|
-- establish a new coordinator session
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param source_addr integer
|
---@param source_addr integer coordinator computer ID
|
||||||
---@param version string
|
---@param i_seq_num integer initial sequence number to use next
|
||||||
|
---@param version string coordinator version
|
||||||
---@return integer|false session_id
|
---@return integer|false session_id
|
||||||
function svsessions.establish_crd_session(source_addr, version)
|
function svsessions.establish_crd_session(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 = {
|
||||||
@ -381,7 +384,7 @@ function svsessions.establish_crd_session(source_addr, version)
|
|||||||
|
|
||||||
local id = self.next_ids.crd
|
local id = self.next_ids.crd
|
||||||
|
|
||||||
crd_s.instance = coordinator.new_session(id, source_addr, crd_s.in_queue, crd_s.out_queue, self.config.CRD_Timeout, self.facility, self.fp_ok)
|
crd_s.instance = coordinator.new_session(id, source_addr, i_seq_num, crd_s.in_queue, crd_s.out_queue, self.config.CRD_Timeout, self.facility, self.fp_ok)
|
||||||
table.insert(self.sessions.crd, crd_s)
|
table.insert(self.sessions.crd, crd_s)
|
||||||
|
|
||||||
local mt = {
|
local mt = {
|
||||||
@ -406,10 +409,11 @@ end
|
|||||||
|
|
||||||
-- establish a new pocket diagnostics session
|
-- establish a new pocket diagnostics session
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param source_addr integer
|
---@param source_addr integer pocket computer ID
|
||||||
---@param version string
|
---@param i_seq_num integer initial sequence number to use next
|
||||||
|
---@param version string pocket version
|
||||||
---@return integer|false session_id
|
---@return integer|false session_id
|
||||||
function svsessions.establish_pdg_session(source_addr, version)
|
function svsessions.establish_pdg_session(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",
|
||||||
@ -424,7 +428,7 @@ function svsessions.establish_pdg_session(source_addr, version)
|
|||||||
|
|
||||||
local id = self.next_ids.pdg
|
local id = self.next_ids.pdg
|
||||||
|
|
||||||
pdg_s.instance = pocket.new_session(id, source_addr, pdg_s.in_queue, pdg_s.out_queue, self.config.PKT_Timeout, self.facility, self.fp_ok)
|
pdg_s.instance = pocket.new_session(id, source_addr, i_seq_num, pdg_s.in_queue, pdg_s.out_queue, self.config.PKT_Timeout, self.facility, self.fp_ok)
|
||||||
table.insert(self.sessions.pdg, pdg_s)
|
table.insert(self.sessions.pdg, pdg_s)
|
||||||
|
|
||||||
local mt = {
|
local mt = {
|
||||||
|
@ -21,7 +21,7 @@ local supervisor = require("supervisor.supervisor")
|
|||||||
|
|
||||||
local svsessions = require("supervisor.session.svsessions")
|
local svsessions = require("supervisor.session.svsessions")
|
||||||
|
|
||||||
local SUPERVISOR_VERSION = "v1.3.12"
|
local SUPERVISOR_VERSION = "v1.4.0"
|
||||||
|
|
||||||
local println = util.println
|
local println = util.println
|
||||||
local println_ts = util.println_ts
|
local println_ts = util.println_ts
|
||||||
@ -214,7 +214,7 @@ local function main()
|
|||||||
elseif event == "modem_message" then
|
elseif event == "modem_message" then
|
||||||
-- got a packet
|
-- got a packet
|
||||||
local packet = superv_comms.parse_packet(param1, param2, param3, param4, param5)
|
local packet = superv_comms.parse_packet(param1, param2, param3, param4, param5)
|
||||||
superv_comms.handle_packet(packet)
|
if packet then superv_comms.handle_packet(packet) end
|
||||||
elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll" or
|
elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll" or
|
||||||
event == "double_click" then
|
event == "double_click" then
|
||||||
-- handle a mouse event
|
-- handle a mouse event
|
||||||
|
@ -191,13 +191,13 @@ function supervisor.comms(_version, nic, fp_ok)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- handle a packet
|
-- handle a packet
|
||||||
---@param packet modbus_frame|rplc_frame|mgmt_frame|crdn_frame|nil
|
---@param packet modbus_frame|rplc_frame|mgmt_frame|crdn_frame
|
||||||
function public.handle_packet(packet)
|
function public.handle_packet(packet)
|
||||||
if packet ~= nil then
|
|
||||||
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() + 1
|
||||||
|
|
||||||
if l_chan ~= config.SVR_Channel then
|
if 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)
|
||||||
@ -241,7 +241,7 @@ function supervisor.comms(_version, nic, fp_ok)
|
|||||||
-- 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
|
||||||
local reactor_id = packet.data[4]
|
local reactor_id = packet.data[4]
|
||||||
local plc_id = svsessions.establish_plc_session(src_addr, reactor_id, firmware_v)
|
local plc_id = svsessions.establish_plc_session(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
|
||||||
@ -315,7 +315,7 @@ function supervisor.comms(_version, nic, fp_ok)
|
|||||||
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, rtu_advert, firmware_v)
|
local s_id = svsessions.establish_rtu_session(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))
|
||||||
@ -367,7 +367,7 @@ function supervisor.comms(_version, nic, fp_ok)
|
|||||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
_send_establish(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, firmware_v)
|
local s_id = svsessions.establish_crd_session(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"))
|
||||||
@ -434,7 +434,7 @@ function supervisor.comms(_version, nic, fp_ok)
|
|||||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
_send_establish(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, firmware_v)
|
local s_id = svsessions.establish_pdg_session(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))
|
||||||
@ -469,7 +469,6 @@ function supervisor.comms(_version, nic, fp_ok)
|
|||||||
log.debug("received packet for unknown channel " .. r_chan, true)
|
log.debug("received packet for unknown channel " .. r_chan, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
return public
|
return public
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user