#488 HMAC acceleration and seq_num changes

This commit is contained in:
Mikayla 2024-06-29 02:27:55 +00:00
parent 2bc20ec312
commit d2bc4f6bc0
19 changed files with 355 additions and 385 deletions

View File

@ -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)

View File

@ -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 = {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 = {

View File

@ -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

View File

@ -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