Exemple #1
0
bool LinkLayerReceiver::ValidateFunctionCode()
{
	//Now make sure that the function code is known and that the FCV is appropriate
	if(mHeader.IsPriToSec())
	{
		bool fcv_set = false;

		switch(mHeader.GetFuncEnum())
		{
			case(FC_PRI_CONFIRMED_USER_DATA):
			case(FC_PRI_TEST_LINK_STATES):
				fcv_set = true;
				break;
			case(FC_PRI_REQUEST_LINK_STATUS):
			case(FC_PRI_RESET_LINK_STATES):
			case(FC_PRI_UNCONFIRMED_USER_DATA):
				break;
			default:
			{
				ERROR_BLOCK(LEV_WARNING, "Unknown PriToSec FUNCTION: " << mHeader.GetFuncEnum(), DLERR_UNKNOWN_FUNC);
				return false;
			}
		}

		//now check the fcv
		if(fcv_set != mHeader.IsFcvDfcSet())
		{
			ERROR_BLOCK(LEV_WARNING, "Bad FCV for FUNCTION: " << mHeader.GetFuncEnum(), DLERR_UNEXPECTED_FCV);
			return false;
		}

		//if fcv isn't expected to be set, fcb can be either 1 or 0, doesn't matter
		
	}
	else // SecToPri - just validate the function codes and that FCB is 0
	{
		switch(mHeader.GetFuncEnum())
		{
			case(FC_SEC_ACK):
			case(FC_SEC_NACK):
			case(FC_SEC_LINK_STATUS):
			case(FC_SEC_NOT_SUPPORTED):
				break;
			default:
			{
				ERROR_BLOCK(LEV_ERROR, "Unknown SecToPri FUNCTION: " << mHeader.GetFuncEnum(), DLERR_UNKNOWN_FUNC);
				return false;
			}	
		}

		//now check the fcb, it should always be zero
		if(mHeader.IsFcbSet())
		{
			ERROR_BLOCK(LEV_ERROR, "FCB set for SecToPri FUNCTION: " << mHeader.GetFuncEnum(), DLERR_UNEXPECTED_FCB);
			return false;
		}
	}

	return true; //valid!
}
void Slave::HandleWriteIIN(HeaderReadIterator& arHdr)
{
	for (ObjectReadIterator obj = arHdr.BeginRead(); !obj.IsEnd(); ++obj) {
		switch (obj->Index()) {
		case IINI_DEVICE_RESTART: {
				bool value = Group80Var1::Inst()->Read(*obj, obj->Start(), obj->Index());
				if (!value) {
					mIIN.SetDeviceRestart(false);
				}
				else {
					mRspIIN.SetParameterError(true);
					ERROR_BLOCK(LEV_WARNING, "", SERR_INVALID_IIN_WRITE);
				}
				break;
			}

		case IINI_NEED_TIME:
			mpTimeTimer->Cancel();
			mpTimeTimer = NULL;
			mIIN.SetNeedTime(false);
			LOG_BLOCK(LEV_INFO, "Master forced clear time needed flag");
			break;

		default:
			mRspIIN.SetParameterError(true);
			ERROR_BLOCK(LEV_WARNING, "", SERR_INVALID_IIN_WRITE);
			break;
		}
	}
}
Exemple #3
0
bool TransportRx::ValidateHeader(bool aFir, bool aFin, int aSeq, size_t aPayloadSize)
{
	//get the transport byte and parse it

	if(aFir) {
		mSeq = aSeq; //always accept the sequence on FIR
		if(mNumBytesRead > 0) {
			/*  2004-03-29_DNP3_Doc_Library.pdf: 2-2 Page 64.
				When a secondary station receives a frame with the FIR bit set,
				all previously received unterminated frame sequences are discarded. */
			ERROR_BLOCK(LEV_WARNING, "FIR received mid-fragment, discarding: " << mNumBytesRead << "bytes", TLERR_NEW_FIR);
			mNumBytesRead = 0;
		}
	}
	else if(mNumBytesRead == 0) { //non-first packet with 0 prior bytes
		ERROR_BLOCK(LEV_WARNING, "non-FIR packet with 0 prior bytes", TLERR_MESSAGE_WITHOUT_FIR);
		return false;
	}

	if(!aFin && aPayloadSize != TL_MAX_TPDU_PAYLOAD) {
		//if it's not a FIN packet it should have a length of
		ERROR_BLOCK(LEV_WARNING, "Partial non-FIN frame, payload= " << aPayloadSize, TLERR_BAD_LENGTH);
		return false;
	}

	if(aSeq != mSeq) {
		ERROR_BLOCK(LEV_WARNING, "Ignoring bad sequence, got: " << aSeq << " expected: " << mSeq, TLERR_BAD_SEQUENCE);
		return false;
	}



	return true;
}
bool LinkLayerReceiver::ValidateBody()
{
	size_t len = mHeader.GetLength() - LS_MIN_LENGTH;
	if(LinkFrame::ValidateBodyCRC(mBuffer.ReadBuff() + LS_HEADER_SIZE, len)) return true;
	else {
		ERROR_BLOCK(LEV_ERROR, "CRC failure in body", DLERR_CRC);
		return false;
	}
}
Exemple #5
0
void TransportRx::HandleReceive(const boost::uint8_t* apData, size_t aNumBytes)
{
	switch(aNumBytes) {
	case(1):
		ERROR_BLOCK(LEV_WARNING, "Received tpdu with no payload", TLERR_NO_PAYLOAD);
		return;
	case(0):
		throw ArgumentException(LOCATION, "Zero length invalid");
	default:
		if(aNumBytes > TL_MAX_TPDU_LENGTH) {
			ostringstream oss;
			oss << "Illegal arg: " << aNumBytes << " exceeds max tpdu size of " << TL_MAX_TPDU_LENGTH;
			throw ArgumentException(LOCATION, oss.str());
		}
	}

	boost::uint8_t hdr = apData[0];
	LOG_BLOCK(LEV_INTERPRET, "<- " << TransportLayer::ToString(hdr));
	bool first = (hdr & TL_HDR_FIR) != 0;
	bool last = (hdr & TL_HDR_FIN) != 0;
	int seq = hdr & TL_HDR_SEQ;
	size_t payload_len = aNumBytes - 1;

	if(this->ValidateHeader(first, last, seq, payload_len)) {
		if(BufferRemaining() < payload_len) {
			ERROR_BLOCK(LEV_WARNING, "Exceeded the buffer size before a complete fragment was read", TLERR_BUFFER_FULL);
			mNumBytesRead = 0;
		}
		else { //passed all validation
			memcpy(mBuffer + mNumBytesRead, apData + 1, payload_len);
			mNumBytesRead += payload_len;
			mSeq = (mSeq + 1) % 64;

			if(last) {
				size_t tmp = mNumBytesRead;
				mNumBytesRead = 0;
				mpContext->ReceiveAPDU(mBuffer, tmp);
			}
		}
	}
}
Exemple #6
0
bool LinkLayerReceiver::ValidateHeader()
{
	//first thing to do is check the CRC
	if(!DNPCrc::IsCorrectCRC(mBuffer.ReadBuff(), LI_CRC)) {
		mCrcFailures.Increment();
		ERROR_BLOCK(LEV_ERROR, "CRC failure in header", DLERR_CRC);
		return false;
	}

	if(!mHeader.ValidLength()) {
		ERROR_BLOCK(LEV_ERROR, "LENGTH out of range [5,255]: " << static_cast<int>(mHeader.GetLength()), DLERR_INVALID_LENGTH);
		return false;
	}

	LOG_BLOCK(LEV_INTERPRET, "<~ " << mHeader.ToString());

	// some combinations of these header parameters are invalid
	// check for them here

	//Now make sure that the function code is known and that the FCV is appropriate
	if(!this->ValidateFunctionCode()) return false;

	boost::uint8_t user_data_length = mHeader.GetLength() - LS_MIN_LENGTH;
	mFrameSize = LinkFrame::CalcFrameSize(user_data_length);
	FuncCodes func = mHeader.GetFuncEnum();

	// make sure that the presence/absence of user data
	// matches the function code
	if(func == FC_PRI_CONFIRMED_USER_DATA || func == FC_PRI_UNCONFIRMED_USER_DATA) {
		if(user_data_length > 0) {
			//mFrameSize = LinkFrame::CalcFrameSize(user_data_length);
		} else {
			ERROR_BLOCK(LEV_ERROR, "User data packet received with zero payload. FUNCTION: " << func, DLERR_NO_DATA);
			return false;
		}
	} else {
		if(user_data_length > 0) {
			ERROR_BLOCK(LEV_ERROR, "Unexpected LENGTH in frame: " << static_cast<int>(user_data_length) << " with FUNCTION: " << func, DLERR_UNEXPECTED_DATA);
			return false;
		}

	}

	if(user_data_length > 0) {
		if(func == FC_PRI_CONFIRMED_USER_DATA || func == FC_PRI_UNCONFIRMED_USER_DATA) {

		} else {
			ERROR_BLOCK(LEV_ERROR, "Unexpected LENGTH in frame: " << static_cast<int>(user_data_length) << " with FUNCTION: " << func, DLERR_UNEXPECTED_DATA);
			return false;
		}
	} else {
		if(func == FC_PRI_CONFIRMED_USER_DATA || func == FC_PRI_UNCONFIRMED_USER_DATA) {
			ERROR_BLOCK(LEV_ERROR, "User data packet received with zero payload. FUNCTION: " << func, DLERR_NO_DATA);
			return false;
		}
	}

	return true;
}
void Slave::HandleVtoTransfer(const APDU& arRequest)
{
	for(HeaderReadIterator hdr = arRequest.BeginRead(); !hdr.IsEnd(); ++hdr) {
		switch(hdr->GetGroup()) {
			case 112:
				this->HandleWriteVto(hdr);
				break;
			default:
				mRspIIN.SetFuncNotSupported(true);
				ERROR_BLOCK(LEV_WARNING, "Object/Function mismatch", SERR_OBJ_FUNC_MISMATCH);
				break;
		}
	}
}
Exemple #8
0
bool LinkLayer::Validate(bool aIsMaster, boost::uint16_t aSrc, boost::uint16_t aDest)
{
	if(!mIsOnline)
		throw InvalidStateException(LOCATION, "LowerLayerDown");

	if(aIsMaster == mCONFIG.IsMaster) {
		ERROR_BLOCK(LEV_WARNING,
		            (aIsMaster ? "Master frame received for master" : "Slave frame received for slave"),
		            DLERR_MASTER_BIT_MATCH);
		return false;
	}

	if(aDest != mCONFIG.LocalAddr) {
		ERROR_BLOCK(LEV_WARNING, "Frame for unknown destintation", DLERR_UNKNOWN_DESTINATION);
		return false;
	}

	if(aSrc != mCONFIG.RemoteAddr) {
		ERROR_BLOCK(LEV_WARNING, "Frame from unknwon source", DLERR_UNKNOWN_SOURCE);
		return false;
	}

	return true;
}
void Slave::HandleOperate(const APDU& arRequest, SequenceInfo aSeqInfo)
{
	if (aSeqInfo == SI_PREV && mLastRequest == arRequest) {
		return;
	}

	mResponse.Set(FC_RESPONSE);

	for (HeaderReadIterator hdr = arRequest.BeginRead(); !hdr.IsEnd(); ++hdr) {

		ObjectReadIterator i = hdr.BeginRead();

		switch (MACRO_DNP_RADIX(hdr->GetGroup(), hdr->GetVariation())) {

		case (MACRO_DNP_RADIX(12, 1)):
			this->RespondToCommands<BinaryOutput>(Group12Var1::Inst(), i, boost::bind(&Slave::Operate<BinaryOutput>, this, _1, _2, false, hdr.info(), aSeqInfo, arRequest.GetControl().SEQ));
			break;

		case (MACRO_DNP_RADIX(41, 1)):
			this->RespondToCommands<Setpoint>(Group41Var1::Inst(), i, boost::bind(&Slave::Operate<Setpoint>, this, _1, _2, false, hdr.info(), aSeqInfo, arRequest.GetControl().SEQ));
			break;

		case (MACRO_DNP_RADIX(41, 2)):
			this->RespondToCommands<Setpoint>(Group41Var2::Inst(), i, boost::bind(&Slave::Operate<Setpoint>, this, _1, _2, false, hdr.info(), aSeqInfo, arRequest.GetControl().SEQ));
			break;

		case (MACRO_DNP_RADIX(41, 3)):
			this->RespondToCommands<Setpoint>(Group41Var3::Inst(), i, boost::bind(&Slave::Operate<Setpoint>, this, _1, _2, false, hdr.info(), aSeqInfo, arRequest.GetControl().SEQ));
			break;

		case (MACRO_DNP_RADIX(41, 4)):
			this->RespondToCommands<Setpoint>(Group41Var4::Inst(), i, boost::bind(&Slave::Operate<Setpoint>, this, _1, _2, false, hdr.info(), aSeqInfo, arRequest.GetControl().SEQ));
			break;

		default:
			mRspIIN.SetFuncNotSupported(true);
			ERROR_BLOCK(LEV_WARNING, "Object/Function mismatch", SERR_OBJ_FUNC_MISMATCH);
			break;
		}
	}
}
void ResponseLoader::ProcessSizeByVariation(HeaderReadIterator& arIter, int aGrp, int aVar)
{
	/*
	 * These objects only require matching on the aGrp field.
	 */
	switch (aGrp) {
		/* Virtual Terminal Objects */
	case (112): this->ReadVto(arIter, Group112Var0::Inst()); break;
	case (113): this->ReadVto(arIter, Group113Var0::Inst()); break;

	default:
		/*
		* If we reach this point, then we don't yet support this object type.
		*/
		ERROR_BLOCK(LEV_WARNING,
		            "Group: " << aGrp << " "
		            "Var: " << aVar << " "
		            "does not map to a data type", MERR_UNSUPPORTED_OBJECT_TYPE);
		break;
	}
}
void Slave::HandleWrite(const APDU& arRequest)
{
	for (HeaderReadIterator hdr = arRequest.BeginRead(); !hdr.IsEnd(); ++hdr) {
		switch (hdr->GetGroup()) {
		case 112:
			this->HandleWriteVto(hdr);
			continue;
		}

		switch (MACRO_DNP_RADIX(hdr->GetGroup(), hdr->GetVariation())) {
		case (MACRO_DNP_RADIX(80, 1)):
			this->HandleWriteIIN(hdr);
			break;
		case (MACRO_DNP_RADIX(50, 1)):
			this->HandleWriteTimeDate(hdr);
			break;
		default:
			mRspIIN.SetFuncNotSupported(true);
			ERROR_BLOCK(LEV_WARNING, "Object/Function mismatch", SERR_OBJ_FUNC_MISMATCH);
			break;
		}
	}
}