Skip to content
This repository has been archived by the owner on Sep 1, 2022. It is now read-only.

Commit

Permalink
Remove confirmed link-layer support. Fix #364 and possibly #138.
Browse files Browse the repository at this point in the history
  • Loading branch information
emgre committed Apr 21, 2020
1 parent ca6d120 commit 9a67e65
Show file tree
Hide file tree
Showing 13 changed files with 5 additions and 720 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ if(DNP3_TLS)
find_package(OpenSSL REQUIRED)
endif()

if(DNP3_TESTS)
if(DNP3_TESTS OR DNP3_FUZZING)
include(./deps/catch.cmake)
endif()

Expand Down
12 changes: 0 additions & 12 deletions cpp/lib/include/opendnp3/link/LinkConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,13 @@ struct LinkConfig
LinkConfig() = delete;

LinkConfig(bool isMaster,
bool useConfirms,
uint32_t numRetry,
uint16_t localAddr,
uint16_t remoteAddr,
TimeDuration timeout,
TimeDuration keepAliveTimeout)
:

IsMaster(isMaster),
UseConfirms(useConfirms),
NumRetry(numRetry),
LocalAddr(localAddr),
RemoteAddr(remoteAddr),
Timeout(timeout),
Expand All @@ -56,8 +52,6 @@ struct LinkConfig
:

IsMaster(isMaster),
UseConfirms(useConfirms),
NumRetry(0),
LocalAddr(isMaster ? 1 : 1024),
RemoteAddr(isMaster ? 1024 : 1),
Timeout(TimeDuration::Seconds(1)),
Expand All @@ -73,12 +67,6 @@ struct LinkConfig
/// The master/outstation bit set on all messages
bool IsMaster;

/// If true, the link layer will send data requesting confirmation
bool UseConfirms;

/// The number of retry attempts the link will attempt after the initial try
uint32_t NumRetry;

/// dnp3 address of the local device
uint16_t LocalAddr;

Expand Down
42 changes: 1 addition & 41 deletions cpp/lib/src/link/LinkContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,9 @@ LinkContext::LinkContext(const Logger& logger,
config(config),
pSegments(nullptr),
txMode(LinkTransmitMode::Idle),
numRetryRemaining(0),
executor(executor),
nextReadFCB(false),
nextWriteFCB(false),
isOnline(false),
isRemoteReset(false),
keepAliveTimeout(false),
lastMessageTimestamp(executor->get_time()),
pPriState(&PLLS_Idle::Instance()),
Expand Down Expand Up @@ -85,7 +82,6 @@ bool LinkContext::OnLowerLayerDown()

isOnline = false;
keepAliveTimeout = false;
isRemoteReset = false;
pSegments = nullptr;
txMode = LinkTransmitMode::Idle;
pendingPriTx.clear();
Expand Down Expand Up @@ -149,17 +145,6 @@ bool LinkContext::OnTxReady()
return true;
}

ser4cpp::rseq_t LinkContext::FormatPrimaryBufferWithConfirmed(const Addresses& addr,
const ser4cpp::rseq_t& tpdu,
bool FCB)
{
auto dest = this->priTxBuffer.as_wseq();
auto output
= LinkFrame::FormatConfirmedUserData(dest, config.IsMaster, FCB, addr.destination, addr.source, tpdu, &logger);
FORMAT_HEX_BLOCK(logger, flags::LINK_TX_HEX, output, 10, 18);
return output;
}

ser4cpp::rseq_t LinkContext::FormatPrimaryBufferWithUnconfirmed(const Addresses& addr, const ser4cpp::rseq_t& tpdu)
{
auto buffer = this->priTxBuffer.as_wseq();
Expand Down Expand Up @@ -206,14 +191,6 @@ void LinkContext::QueueLinkStatus(uint16_t destination)
this->QueueTransmit(buffer, false);
}

void LinkContext::QueueResetLinks(uint16_t destination)
{
auto dest = priTxBuffer.as_wseq();
auto buffer = LinkFrame::FormatResetLinkStates(dest, config.IsMaster, destination, this->config.LocalAddr, &logger);
FORMAT_HEX_BLOCK(logger, flags::LINK_TX_HEX, buffer, 10, 18);
this->QueueTransmit(buffer, true);
}

void LinkContext::QueueRequestLinkStatus(uint16_t destination)
{
auto dest = priTxBuffer.as_wseq();
Expand All @@ -223,22 +200,6 @@ void LinkContext::QueueRequestLinkStatus(uint16_t destination)
this->QueueTransmit(buffer, true);
}

void LinkContext::ResetRetry()
{
this->numRetryRemaining = config.NumRetry;
}

bool LinkContext::Retry()
{
if (numRetryRemaining > 0)
{
--numRetryRemaining;
return true;
}

return false;
}

void LinkContext::PushDataUp(const Message& message)
{
upper->OnReceive(message);
Expand All @@ -262,8 +223,7 @@ void LinkContext::TryStartTransmission()

if (this->pSegments)
{
this->pPriState = (this->config.UseConfirms) ? &pPriState->TrySendConfirmed(*this, *pSegments)
: &pPriState->TrySendUnconfirmed(*this, *pSegments);
this->pPriState = &pPriState->TrySendUnconfirmed(*this, *pSegments);
}
}

Expand Down
15 changes: 0 additions & 15 deletions cpp/lib/src/link/LinkContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,10 @@ class LinkContext
{
nextReadFCB = true;
}
void ResetWriteFCB()
{
nextWriteFCB = true;
}
void ToggleReadFCB()
{
nextReadFCB = !nextReadFCB;
}
void ToggleWriteFCB()
{
nextWriteFCB = !nextWriteFCB;
}

// --- helpers for dealing with layer state transitations ---
bool OnLowerLayerUp();
Expand All @@ -89,20 +81,16 @@ class LinkContext

// --- helpers for formatting user data messages ---
ser4cpp::rseq_t FormatPrimaryBufferWithUnconfirmed(const Addresses& addr, const ser4cpp::rseq_t& tpdu);
ser4cpp::rseq_t FormatPrimaryBufferWithConfirmed(const Addresses& addr, const ser4cpp::rseq_t& tpdu, bool FCB);

// --- Helpers for queueing frames ---
void QueueAck(uint16_t destination);
void QueueLinkStatus(uint16_t destination);
void QueueResetLinks(uint16_t destination);
void QueueRequestLinkStatus(uint16_t destination);

void QueueTransmit(const ser4cpp::rseq_t& buffer, bool primary);

// --- public members ----

void ResetRetry();
bool Retry();
void PushDataUp(const Message& message);
void CompleteSendOperation();
void TryStartTransmission();
Expand All @@ -127,16 +115,13 @@ class LinkContext
const LinkLayerConfig config;
ITransportSegment* pSegments;
LinkTransmitMode txMode;
uint32_t numRetryRemaining;

const std::shared_ptr<exe4cpp::IExecutor> executor;

exe4cpp::Timer rspTimeoutTimer;
exe4cpp::Timer keepAliveTimer;
bool nextReadFCB;
bool nextWriteFCB;
bool isOnline;
bool isRemoteReset;
bool keepAliveTimeout;
Timestamp lastMessageTimestamp;
StackStatistics::Link statistics;
Expand Down
150 changes: 0 additions & 150 deletions cpp/lib/src/link/PriLinkLayerStates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,6 @@ PriStateBase& PriStateBase::OnTimeout(LinkContext& ctx)
return *this;
}

PriStateBase& PriStateBase::TrySendConfirmed(LinkContext& /*ctx*/, ITransportSegment& /*unused*/)
{
return *this;
}

PriStateBase& PriStateBase::TrySendUnconfirmed(LinkContext& /*ctx*/, ITransportSegment& /*unused*/)
{
return *this;
Expand All @@ -100,22 +95,6 @@ PriStateBase& PLLS_Idle::TrySendUnconfirmed(LinkContext& ctx, ITransportSegment&
return PLLS_SendUnconfirmedTransmitWait::Instance();
}

PriStateBase& PLLS_Idle::TrySendConfirmed(LinkContext& ctx, ITransportSegment& segments)
{
if (ctx.isRemoteReset)
{
ctx.ResetRetry();
auto buffer
= ctx.FormatPrimaryBufferWithConfirmed(segments.GetAddresses(), segments.GetSegment(), ctx.nextWriteFCB);
ctx.QueueTransmit(buffer, true);
return PLLS_ConfUserDataTransmitWait::Instance();
}

ctx.ResetRetry();
ctx.QueueResetLinks(segments.GetAddresses().destination);
return PLLS_LinkResetTransmitWait::Instance();
}

PriStateBase& PLLS_Idle::TrySendRequestLinkStatus(LinkContext& ctx)
{
ctx.keepAliveTimeout = false;
Expand Down Expand Up @@ -145,32 +124,6 @@ PriStateBase& PLLS_SendUnconfirmedTransmitWait::OnTxReady(LinkContext& ctx)
return PLLS_Idle::Instance();
}

/////////////////////////////////////////////////////////////////////////////
// Wait for the link layer to transmit the reset links
/////////////////////////////////////////////////////////////////////////////

PLLS_LinkResetTransmitWait PLLS_LinkResetTransmitWait::instance;

PriStateBase& PLLS_LinkResetTransmitWait::OnTxReady(LinkContext& ctx)
{
// now we're waiting for an ACK
ctx.StartResponseTimer();
return PLLS_ResetLinkWait::Instance();
}

/////////////////////////////////////////////////////////////////////////////
// Wait for the link layer to transmit confirmed user data
/////////////////////////////////////////////////////////////////////////////

PLLS_ConfUserDataTransmitWait PLLS_ConfUserDataTransmitWait::instance;

PriStateBase& PLLS_ConfUserDataTransmitWait::OnTxReady(LinkContext& ctx)
{
// now we're waiting on an ACK
ctx.StartResponseTimer();
return PLLS_ConfDataWait::Instance();
}

/////////////////////////////////////////////////////////////////////////////
// Wait for the link layer to transmit the request link status
/////////////////////////////////////////////////////////////////////////////
Expand All @@ -184,109 +137,6 @@ PriStateBase& PLLS_RequestLinkStatusTransmitWait::OnTxReady(LinkContext& ctx)
return PLLS_RequestLinkStatusWait::Instance();
}

////////////////////////////////////////////////////////
// Class PLLS_ResetLinkWait
////////////////////////////////////////////////////////

PLLS_ResetLinkWait PLLS_ResetLinkWait::instance;

PriStateBase& PLLS_ResetLinkWait::OnAck(LinkContext& ctx, bool /*rxBuffFull*/)
{
ctx.isRemoteReset = true;
ctx.ResetWriteFCB();
ctx.CancelTimer();
auto buffer = ctx.FormatPrimaryBufferWithConfirmed(ctx.pSegments->GetAddresses(), ctx.pSegments->GetSegment(),
ctx.nextWriteFCB);
ctx.QueueTransmit(buffer, true);
ctx.listener->OnStateChange(LinkStatus::RESET);
return PLLS_ConfUserDataTransmitWait::Instance();
}

PriStateBase& PLLS_ResetLinkWait::OnTimeout(LinkContext& ctx)
{
if (ctx.Retry())
{
FORMAT_LOG_BLOCK(ctx.logger, flags::WARN, "Link reset timeout, retrying %i remaining", ctx.numRetryRemaining);
ctx.QueueResetLinks(ctx.config.RemoteAddr);
return PLLS_LinkResetTransmitWait::Instance();
}

SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "Link reset final timeout, no retries remain");
ctx.CompleteSendOperation();
return PLLS_Idle::Instance();
}

PriStateBase& PLLS_ResetLinkWait::Failure(LinkContext& ctx)
{
ctx.CancelTimer();
ctx.CompleteSendOperation();
return PLLS_Idle::Instance();
}

////////////////////////////////////////////////////////
// Class PLLS_ConfDataWait
////////////////////////////////////////////////////////

PLLS_ConfDataWait PLLS_ConfDataWait::instance;

PriStateBase& PLLS_ConfDataWait::OnAck(LinkContext& ctx, bool /*rxBuffFull*/)
{
ctx.ToggleWriteFCB();
ctx.CancelTimer();

if (ctx.pSegments->Advance())
{
auto buffer = ctx.FormatPrimaryBufferWithConfirmed(ctx.pSegments->GetAddresses(), ctx.pSegments->GetSegment(),
ctx.nextWriteFCB);
ctx.QueueTransmit(buffer, true);
return PLLS_ConfUserDataTransmitWait::Instance();
}
// we're done!

ctx.CompleteSendOperation();
return PLLS_Idle::Instance();
}

PriStateBase& PLLS_ConfDataWait::OnNack(LinkContext& ctx, bool rxBuffFull)
{
ctx.listener->OnStateChange(LinkStatus::UNRESET);

if (rxBuffFull)
{
return Failure(ctx);
}

ctx.ResetRetry();
ctx.CancelTimer();
ctx.QueueResetLinks(ctx.pSegments->GetAddresses().destination);
return PLLS_LinkResetTransmitWait::Instance();
}

PriStateBase& PLLS_ConfDataWait::Failure(LinkContext& ctx)
{
ctx.isRemoteReset = false;
ctx.CancelTimer();
ctx.CompleteSendOperation();
return PLLS_Idle::Instance();
}

PriStateBase& PLLS_ConfDataWait::OnTimeout(LinkContext& ctx)
{
if (ctx.Retry())
{
FORMAT_LOG_BLOCK(ctx.logger, flags::WARN, "confirmed data timeout, retrying %u remaining",
ctx.numRetryRemaining);
auto buffer = ctx.FormatPrimaryBufferWithConfirmed(ctx.pSegments->GetAddresses(), ctx.pSegments->GetSegment(),
ctx.nextWriteFCB);
ctx.QueueTransmit(buffer, true);
return PLLS_ConfUserDataTransmitWait::Instance();
}

SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "Confirmed data final timeout, no retries remain");
ctx.listener->OnStateChange(LinkStatus::UNRESET);
return Failure(ctx);
}

////////////////////////////////////////////////////////
// Class PLLS_RequestLinkStatusWait
////////////////////////////////////////////////////////
Expand Down

0 comments on commit 9a67e65

Please sign in to comment.