You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libiec61850/src/mms/iso_mms/server/mms_association_service.c

266 lines
8.2 KiB
C

/*
* mms_association_service.c
*
* Copyright 2013, 2014 Michael Zillgith
*
* This file is part of libIEC61850.
*
* libIEC61850 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libIEC61850 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libIEC61850. If not, see <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/
#include "libiec61850_platform_includes.h"
#include "mms_server_internal.h"
/**********************************************************************************************
* MMS Server Capabilities
*********************************************************************************************/
#define MMS_SERVICE_STATUS 0x80
#define MMS_SERVICE_GET_NAME_LIST 0x40
#define MMS_SERVICE_IDENTIFY 0x20
#define MMS_SERVICE_RENAME 0x10
#define MMS_SERVICE_READ 0x08
#define MMS_SERVICE_WRITE 0x04
#define MMS_SERVICE_GET_VARIABLE_ACCESS_ATTRIBUTES 0x02
#define MMS_SERVICE_DEFINE_NAMED_VARIABLE 0x01
#define MMS_SERVICE_DEFINE_SCATTERED_ACCESS 0x80
#define MMS_SERVICE_GET_SCATTERED_ACCESS_ATTRIBUTES 0x40
#define MMS_SERVICE_DELETE_VARIABLE_ACCESS 0x20
#define MMS_SERVICE_DEFINE_NAMED_VARIABLE_LIST 0x10
#define MMS_SERVICE_GET_NAMED_VARIABLE_LIST_ATTRIBUTES 0x08
#define MMS_SERVICE_DELETE_NAMED_VARIABLE_LIST 0x04
#define MMS_SERVICE_DEFINE_NAMED_TYPE 0x02
#define MMS_SERVICE_GET_NAMED_TYPE_ATTRIBUTES 0x01
#define MMS_SERVICE_READ_JOURNAL 0x40
#define MMS_SERVICE_FILE_OPEN 0x80
#define MMS_SERVICE_FILE_READ 0x40
#define MMS_SERVICE_FILE_CLOSE 0x20
#define MMS_SERVICE_FILE_RENAME 0x01
#define MMS_SERVICE_FILE_DELETE 0x08
#define MMS_SERVICE_FILE_DIRECTORY 0x04
#define MMS_SERVICE_UNSOLICITED_STATUS 0x02
#define MMS_SERVICE_INFORMATION_REPORT 0x01
#define MMS_SERVICE_CONCLUDE 0x10
#define MMS_SERVICE_CANCEL 0x08
//TODO make dependent on stack configuration!
/* servicesSupported MMS bitstring */
static uint8_t servicesSupported[] =
{
0x00
#if (MMS_STATUS_SERVICE == 1)
| MMS_SERVICE_STATUS
#endif
| MMS_SERVICE_GET_NAME_LIST
#if (MMS_IDENTIFY_SERVICE == 1)
| MMS_SERVICE_IDENTIFY
#endif
| MMS_SERVICE_READ
| MMS_SERVICE_WRITE
| MMS_SERVICE_GET_VARIABLE_ACCESS_ATTRIBUTES
,
0x00
| MMS_SERVICE_DEFINE_NAMED_VARIABLE_LIST
| MMS_SERVICE_DELETE_NAMED_VARIABLE_LIST
| MMS_SERVICE_GET_NAMED_VARIABLE_LIST_ATTRIBUTES
,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00
#if (MMS_JOURNAL_SERVICE == 1)
| MMS_SERVICE_READ_JOURNAL
#endif
,
0x00
#if (MMS_FILE_SERVICE == 1)
| MMS_SERVICE_FILE_OPEN
| MMS_SERVICE_FILE_READ
| MMS_SERVICE_FILE_CLOSE
| MMS_SERVICE_FILE_RENAME
| MMS_SERVICE_FILE_DELETE
| MMS_SERVICE_FILE_DIRECTORY
#endif
| MMS_SERVICE_INFORMATION_REPORT
,
0x00
| MMS_SERVICE_CONCLUDE
| MMS_SERVICE_CANCEL
};
/* negotiated parameter CBB */
static uint8_t parameterCBB[] =
{
0xf1,
0x00
};
/**********************************************************************************************
* MMS Initiate Service
*********************************************************************************************/
static int
encodeInitResponseDetail(uint8_t* buffer, int bufPos, bool encode)
{
int initResponseDetailSize = 14 + 5 + 3;
if (encode == false)
return initResponseDetailSize + 2;
bufPos = BerEncoder_encodeTL(0xa4, initResponseDetailSize, buffer, bufPos);
bufPos = BerEncoder_encodeUInt32WithTL(0x80, 1, buffer, bufPos); /* negotiated protocol version */
bufPos = BerEncoder_encodeBitString(0x81, 11, parameterCBB, buffer, bufPos);
bufPos = BerEncoder_encodeBitString(0x82, 85, servicesSupported, buffer, bufPos);
return bufPos;
}
static int
createInitiateResponse(MmsServerConnection self, ByteBuffer* writeBuffer)
{
uint8_t* buffer = writeBuffer->buffer;
int bufPos = 0;
int initiateResponseLength = 0;
initiateResponseLength += 2 + BerEncoder_UInt32determineEncodedSize(self->maxPduSize);
initiateResponseLength += 2 + BerEncoder_UInt32determineEncodedSize(self->maxServOutstandingCalling);
initiateResponseLength += 2 + BerEncoder_UInt32determineEncodedSize(self->maxServOutstandingCalled);
initiateResponseLength += 2 + BerEncoder_UInt32determineEncodedSize(self->dataStructureNestingLevel);
initiateResponseLength += encodeInitResponseDetail(NULL, 0, false);
/* Initiate response pdu */
bufPos = BerEncoder_encodeTL(0xa9, initiateResponseLength, buffer, bufPos);
bufPos = BerEncoder_encodeUInt32WithTL(0x80, self->maxPduSize, buffer, bufPos);
bufPos = BerEncoder_encodeUInt32WithTL(0x81, self->maxServOutstandingCalling, buffer, bufPos);
bufPos = BerEncoder_encodeUInt32WithTL(0x82, self->maxServOutstandingCalled, buffer, bufPos);
bufPos = BerEncoder_encodeUInt32WithTL(0x83, self->dataStructureNestingLevel, buffer, bufPos);
bufPos = encodeInitResponseDetail(buffer, bufPos, true);
writeBuffer->size = bufPos;
return bufPos;
}
static bool
parseInitiateRequestPdu(MmsServerConnection self, uint8_t* buffer, int bufPos, int maxBufPos)
{
self->maxPduSize = CONFIG_MMS_MAXIMUM_PDU_SIZE;
self->dataStructureNestingLevel =
DEFAULT_DATA_STRUCTURE_NESTING_LEVEL;
self->maxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
self->maxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
while (bufPos < maxBufPos) {
uint8_t tag = buffer[bufPos++];
int length;
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
if (bufPos < 0) {
// TODO write initiate error PDU!
return false;
}
switch (tag) {
case 0x80: /* local-detail-calling */
self->maxPduSize = BerDecoder_decodeUint32(buffer, length, bufPos);
if (self->maxPduSize > CONFIG_MMS_MAXIMUM_PDU_SIZE)
self->maxPduSize = CONFIG_MMS_MAXIMUM_PDU_SIZE;
break;
case 0x81: /* proposed-max-serv-outstanding-calling */
self->maxServOutstandingCalling = BerDecoder_decodeUint32(buffer, length, bufPos);
if (self->maxServOutstandingCalling > DEFAULT_MAX_SERV_OUTSTANDING_CALLING)
self->maxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
break;
case 0x82: /* proposed-max-serv-outstanding-called */
self->maxServOutstandingCalled = BerDecoder_decodeUint32(buffer, length, bufPos);
if (self->maxServOutstandingCalled > DEFAULT_MAX_SERV_OUTSTANDING_CALLED)
self->maxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
break;
case 0x83: /* proposed-data-structure-nesting-level */
self->dataStructureNestingLevel = BerDecoder_decodeUint32(buffer, length, bufPos);
break;
case 0xa4: /* mms-init-request-detail */
/* we ignore this */
break;
default:
break; /* Ignore unknown tags */
}
bufPos += length;
}
return true;
}
void
mmsServer_handleInitiateRequest (
MmsServerConnection self,
uint8_t* buffer, int bufPos, int maxBufPos,
ByteBuffer* response)
{
if (parseInitiateRequestPdu(self, buffer, bufPos, maxBufPos))
createInitiateResponse(self, response);
else {
//TODO send initiate error PDU
}
}
/**********************************************************************************************
* MMS Conclude Service
*********************************************************************************************/
void
mmsServer_writeConcludeResponsePdu(ByteBuffer* response)
{
ByteBuffer_appendByte(response, 0x8c);
ByteBuffer_appendByte(response, 0x00);
}