diff --git a/src/mms/inc_private/mms_client_internal.h b/src/mms/inc_private/mms_client_internal.h
index 8eb23a4..bc52d6a 100644
--- a/src/mms/inc_private/mms_client_internal.h
+++ b/src/mms/inc_private/mms_client_internal.h
@@ -133,7 +133,7 @@ mmsClient_getInvokeId(ConfirmedResponsePdu_t* confirmedResponse);
int
mmsClient_write_out(void *buffer, size_t size, void *app_key);
-int
+void
mmsClient_createInitiateRequest(MmsConnection self, ByteBuffer* writeBuffer);
MmsPdu_t*
diff --git a/src/mms/iso_mms/client/mms_client_initiate.c b/src/mms/iso_mms/client/mms_client_initiate.c
index e8c7d7d..5cf93b4 100644
--- a/src/mms/iso_mms/client/mms_client_initiate.c
+++ b/src/mms/iso_mms/client/mms_client_initiate.c
@@ -1,28 +1,27 @@
/*
* mms_client_initiate.c
*
- * Copyright 2013, 2014 Michael Zillgith
+ * Copyright 2013-2017 Michael Zillgith
*
- * This file is part of libIEC61850.
+ * 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 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.
+ * 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 .
+ * You should have received a copy of the GNU General Public License
+ * along with libIEC61850. If not, see .
*
- * See COPYING file for the complete license text.
+ * See COPYING file for the complete license text.
*/
#include "libiec61850_platform_includes.h"
-#include
#include "mms_common.h"
#include "mms_common_internal.h"
#include "mms_indication.h"
@@ -33,63 +32,80 @@
#include "mms_client_internal.h"
+#include "ber_encoder.h"
+
/* servicesSupported = {GetNameList} - required by initiate request, other services are required by some servers to work properly */
static uint8_t servicesSupported[] = { 0xee, 0x1c, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x79, 0xef, 0x18 };
-static InitiateRequestPdu_t
-createInitiateRequestPdu(MmsConnection self)
-{
- InitiateRequestPdu_t request;
-
- request.localDetailCalling = (Integer32_t*) GLOBAL_CALLOC(1, sizeof(Integer32_t));
- *(request.localDetailCalling) = self->parameters.maxPduSize;
-
- request.proposedMaxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
- request.proposedMaxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
-
- request.proposedDataStructureNestingLevel = (Integer8_t*) GLOBAL_CALLOC(1, sizeof(Integer8_t));
- *(request.proposedDataStructureNestingLevel) = DEFAULT_DATA_STRUCTURE_NESTING_LEVEL;
-
- request.mmsInitRequestDetail.proposedParameterCBB.size = 2;
- request.mmsInitRequestDetail.proposedParameterCBB.bits_unused = 5;
- request.mmsInitRequestDetail.proposedParameterCBB.buf = (uint8_t*) GLOBAL_CALLOC(2, sizeof(uint8_t));
- request.mmsInitRequestDetail.proposedParameterCBB.buf[0] = 0xf1;
- request.mmsInitRequestDetail.proposedParameterCBB.buf[1] = 0x00;
-
- request.mmsInitRequestDetail.proposedVersionNumber = 1;
-
- request.mmsInitRequestDetail.servicesSupportedCalling.size = 11;
- request.mmsInitRequestDetail.servicesSupportedCalling.bits_unused = 3;
-
- request.mmsInitRequestDetail.servicesSupportedCalling.buf = servicesSupported;
-
- return request;
-}
-
-static void
-freeInitiateRequestPdu(InitiateRequestPdu_t request)
-{
- GLOBAL_FREEMEM(request.localDetailCalling);
- GLOBAL_FREEMEM(request.proposedDataStructureNestingLevel);
- GLOBAL_FREEMEM(request.mmsInitRequestDetail.proposedParameterCBB.buf);
-}
-
-int
+void
mmsClient_createInitiateRequest(MmsConnection self, ByteBuffer* message)
{
- MmsPdu_t* mmsPdu = (MmsPdu_t*) GLOBAL_CALLOC(1, sizeof(MmsPdu_t));
+ int maxServerOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
+ int maxServerOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
+ int dataStructureNestingLevel = DEFAULT_DATA_STRUCTURE_NESTING_LEVEL;
- mmsPdu->present = MmsPdu_PR_initiateRequestPdu;
+ uint32_t localDetailSize =
+ BerEncoder_UInt32determineEncodedSize(self->parameters.maxPduSize);
- mmsPdu->choice.initiateRequestPdu = createInitiateRequestPdu(self);
+ uint32_t proposedMaxServerOutstandingCallingSize =
+ BerEncoder_UInt32determineEncodedSize(maxServerOutstandingCalling);
- asn_enc_rval_t rval = der_encode(&asn_DEF_MmsPdu, mmsPdu,
- (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) message);
+ uint32_t proposedMaxServerOutstandingCalledSize =
+ BerEncoder_UInt32determineEncodedSize(maxServerOutstandingCalled);
- freeInitiateRequestPdu(mmsPdu->choice.initiateRequestPdu);
- GLOBAL_FREEMEM(mmsPdu);
+ uint32_t dataStructureNestingLevelSize =
+ BerEncoder_UInt32determineEncodedSize(dataStructureNestingLevel);
- return rval.encoded;
+ uint32_t initRequestDetailSize = 3 + 5 + 14;
+
+ uint32_t initiateRequestPduSize = 2 + localDetailSize +
+ 2 + proposedMaxServerOutstandingCallingSize +
+ 2 + proposedMaxServerOutstandingCalledSize +
+ 2 + dataStructureNestingLevelSize +
+ 2 + initRequestDetailSize;
+
+ /* encode message (InitiateRequestPdu) */
+
+ int bufPos = 0;
+ uint8_t* buffer = message->buffer;
+
+ bufPos = BerEncoder_encodeTL(0xa8, initiateRequestPduSize, buffer, bufPos);
+
+ /* localDetail */
+ bufPos = BerEncoder_encodeTL(0x80, localDetailSize, buffer, bufPos);
+ bufPos = BerEncoder_encodeUInt32(self->parameters.maxPduSize, buffer, bufPos);
+
+ /* proposedMaxServerOutstandingCalling */
+ bufPos = BerEncoder_encodeTL(0x81, proposedMaxServerOutstandingCallingSize, buffer, bufPos);
+ bufPos = BerEncoder_encodeUInt32(maxServerOutstandingCalling, buffer, bufPos);
+
+ /* proposedMaxServerOutstandingCalled */
+ bufPos = BerEncoder_encodeTL(0x82, proposedMaxServerOutstandingCalledSize, buffer, bufPos);
+ bufPos = BerEncoder_encodeUInt32(maxServerOutstandingCalled, buffer, bufPos);
+
+ /* proposedDataStructureNestingLevel */
+ bufPos = BerEncoder_encodeTL(0x83, dataStructureNestingLevelSize, buffer, bufPos);
+ bufPos = BerEncoder_encodeUInt32(dataStructureNestingLevel, buffer, bufPos);
+
+ /* initRequestDetail */
+ bufPos = BerEncoder_encodeTL(0xa4, initRequestDetailSize, buffer, bufPos);
+
+ /* proposedVersionNumber = 1 */
+ buffer[bufPos++] = 0x80;
+ buffer[bufPos++] = 0x01;
+ buffer[bufPos++] = 0x01;
+
+ /* proposedParameterCBC */
+ buffer[bufPos++] = 0x81;
+ buffer[bufPos++] = 0x03;
+ buffer[bufPos++] = 0x05; /* padding */
+ buffer[bufPos++] = 0xf1;
+ buffer[bufPos++] = 0x00;
+
+ /* servicesSupportedCalling */
+ bufPos = BerEncoder_encodeBitString(0x82, 85, servicesSupported, buffer, bufPos);
+
+ message->size = bufPos;
}
int
@@ -105,43 +121,112 @@ mmsClient_createConcludeRequest(MmsConnection self, ByteBuffer* message)
return -1;
}
+static bool
+parseInitResponseDetail(MmsConnection self, uint8_t* buffer, int bufPos, int maxBufPos)
+{
+ while (bufPos < maxBufPos) {
+ uint8_t tag = buffer[bufPos++];
+ int length;
+
+ bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
+
+ if (bufPos < 0)
+ return false;
+
+ switch (tag) {
+
+ case 0x80: /* negotiated protocol version */
+ break;
+
+ case 0x81: /* parameter CBB */
+ break;
+
+ case 0x82: /* services supported called */
+ {
+ int i;
+
+ for (i = 0; i < 11; i++)
+ self->parameters.servicesSupported[i] = buffer[bufPos + i];
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ bufPos += length;
+ }
+
+ return true;
+}
+
bool
mmsClient_parseInitiateResponse(MmsConnection self)
{
bool result = false;
- MmsPdu_t* mmsPdu = 0;
- asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu,
- (void**) &mmsPdu, ByteBuffer_getBuffer(self->lastResponse),
- ByteBuffer_getSize(self->lastResponse));
+ self->parameters.maxPduSize = CONFIG_MMS_MAXIMUM_PDU_SIZE;
+ self->parameters.dataStructureNestingLevel = DEFAULT_DATA_STRUCTURE_NESTING_LEVEL;
+ self->parameters.maxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
+ self->parameters.maxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
- if (rval.code != RC_OK) goto exit_function;
+ int bufPos = 0;
+ int maxBufPos = ByteBuffer_getSize(self->lastResponse);
+ uint8_t* buffer = ByteBuffer_getBuffer(self->lastResponse);
- if (mmsPdu->present == MmsPdu_PR_initiateResponsePdu) {
- InitiateResponsePdu_t* initiateResponse = &(mmsPdu->choice.initiateResponsePdu);
+ while (bufPos < maxBufPos) {
+ uint8_t tag = buffer[bufPos++];
+ int length;
- if (initiateResponse->localDetailCalled != NULL)
- self->parameters.maxPduSize = *(initiateResponse->localDetailCalled);
+ bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
- if (initiateResponse->negotiatedDataStructureNestingLevel != NULL)
- self->parameters.dataStructureNestingLevel = *(initiateResponse->negotiatedDataStructureNestingLevel);;
+ if (bufPos < 0) {
+ // TODO write initiate error PDU!
+ return false;
+ }
- self->parameters.maxServOutstandingCalled = initiateResponse->negotiatedMaxServOutstandingCalled;
+ switch (tag) {
+ case 0x80: /* local-detail-calling */
+ self->parameters.maxPduSize = BerDecoder_decodeUint32(buffer, length, bufPos);
- self->parameters.maxServOutstandingCalling = initiateResponse->negotiatedMaxServOutstandingCalling;
+ if (self->parameters.maxPduSize > CONFIG_MMS_MAXIMUM_PDU_SIZE)
+ self->parameters.maxPduSize = CONFIG_MMS_MAXIMUM_PDU_SIZE;
- int i;
+ break;
- for (i = 0; i < 11; i++)
- self->parameters.servicesSupported[i] = initiateResponse->mmsInitResponseDetail.servicesSupportedCalled.buf[i];
+ case 0x81: /* proposed-max-serv-outstanding-calling */
+ self->parameters.maxServOutstandingCalling = BerDecoder_decodeUint32(buffer, length, bufPos);
- result = true;
+ if (self->parameters.maxServOutstandingCalling > DEFAULT_MAX_SERV_OUTSTANDING_CALLING)
+ self->parameters.maxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
+
+ break;
+
+ case 0x82: /* proposed-max-serv-outstanding-called */
+ self->parameters.maxServOutstandingCalled = BerDecoder_decodeUint32(buffer, length, bufPos);
+
+ if (self->parameters.maxServOutstandingCalled > DEFAULT_MAX_SERV_OUTSTANDING_CALLED)
+ self->parameters.maxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
+
+ break;
+ case 0x83: /* proposed-data-structure-nesting-level */
+ self->parameters.dataStructureNestingLevel = BerDecoder_decodeUint32(buffer, length, bufPos);
+ break;
+
+ case 0xa4: /* mms-init-request-detail */
+ {
+ if (parseInitResponseDetail(self, buffer, bufPos, bufPos + length) == false)
+ return false;
+ }
+ break;
+
+ default:
+ break; /* Ignore unknown tags */
+ }
+
+ bufPos += length;
}
- else
- result = false;
- asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0);
-exit_function:
return result;
}