/* * mms_server_common.c * * Copyright 2013-2016 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 . * * See COPYING file for the complete license text. */ #include "libiec61850_platform_includes.h" #include "mms_server_internal.h" /* write_out function required for ASN.1 encoding */ int mmsServer_write_out(const void *buffer, size_t size, void *app_key) { ByteBuffer* writeBuffer = (ByteBuffer*) app_key; return ByteBuffer_append(writeBuffer, (uint8_t*) buffer, size); } MmsPdu_t* mmsServer_createConfirmedResponse(uint32_t invokeId) { MmsPdu_t* mmsPdu = (MmsPdu_t*) GLOBAL_CALLOC(1, sizeof(MmsPdu_t)); mmsPdu->present = MmsPdu_PR_confirmedResponsePdu; asn_long2INTEGER(&(mmsPdu->choice.confirmedResponsePdu.invokeID), invokeId); return mmsPdu; } static void mapErrorTypeToErrorClass(MmsError errorType, uint8_t* tag, uint8_t* value) { switch (errorType) { case MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED: *tag = 0x87; /* access */ *value = 1; break; case MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT: *tag = 0x87; /* access */ *value = 2; break; case MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED: *tag = 0x87; /* access */ *value = 3; break; case MMS_ERROR_SERVICE_OTHER: *tag = 0x84; /* service */ *value = 0; break; case MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT: *tag = 0x84; /* service */ *value = 5; break; case MMS_ERROR_DEFINITION_OTHER: *tag = 0x82; /* definition */ *value = 0; break; case MMS_ERROR_DEFINITION_OBJECT_UNDEFINED: *tag = 0x82; /* definition */ *value = 1; break; case MMS_ERROR_DEFINITION_TYPE_UNSUPPORTED: *tag = 0x82; /* definition */ *value = 3; break; case MMS_ERROR_DEFINITION_OBJECT_EXISTS: *tag = 0x82; /* definition */ *value = 5; break; case MMS_ERROR_FILE_OTHER: *tag = 0x8b; /* file */ *value = 0; break; case MMS_ERROR_FILE_FILE_NON_EXISTENT: *tag = 0x8b; /* file */ *value = 7; break; case MMS_ERROR_RESOURCE_OTHER: *tag = 0x83; /* resource */ *value = 0; break; case MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE: *tag = 0x83; /* resource */ *value = 4; break; default: if (DEBUG_MMS_SERVER) printf("MMS_SERVER: unknown errorType!\n"); *tag = 0x8c; /* others */ *value = 0; break; } } void mmsServer_createServiceErrorPduWithServiceSpecificInfo(uint32_t invokeId, ByteBuffer* response, MmsError errorType, uint8_t* serviceSpecificInfo, int serviceSpecficInfoLength) { /* determine encoded size */ uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId) + 2; uint32_t specificInfoSize = 0; if (serviceSpecificInfo != NULL) specificInfoSize = 1 + BerEncoder_determineLengthSize(serviceSpecficInfoLength) + serviceSpecficInfoLength; uint32_t serviceErrorContentSize = 5 /* errorClass */ + specificInfoSize; uint32_t serviceErrorSize = 1 + BerEncoder_determineLengthSize(serviceErrorContentSize) + serviceErrorContentSize; uint32_t confirmedErrorContentSize = serviceErrorSize + invokeIdSize; /* encode */ uint8_t* buffer = response->buffer; int bufPos = response->size; bufPos = BerEncoder_encodeTL(0xa2, confirmedErrorContentSize, buffer, bufPos); bufPos = BerEncoder_encodeTL(0x80, invokeIdSize - 2, buffer, bufPos); /* invokeID */ bufPos = BerEncoder_encodeUInt32((uint32_t) invokeId, buffer, bufPos); bufPos = BerEncoder_encodeTL(0xa2, serviceErrorContentSize, buffer, bufPos); /* serviceError */ bufPos = BerEncoder_encodeTL(0xa0, 3, buffer, bufPos); /* serviceError */ uint8_t errorCodeTag; uint8_t errorCodeValue; mapErrorTypeToErrorClass(errorType, &errorCodeTag, &errorCodeValue); buffer[bufPos++] = errorCodeTag; buffer[bufPos++] = 1; buffer[bufPos++] = errorCodeValue; if (serviceSpecificInfo != NULL) bufPos = BerEncoder_encodeOctetString(0xa3, serviceSpecificInfo, serviceSpecficInfoLength, buffer, bufPos); response->size = bufPos; } void /* Confirmed service error (ServiceError) */ mmsServer_createServiceErrorPdu(uint32_t invokeId, ByteBuffer* response, MmsError errorType) { mmsServer_createServiceErrorPduWithServiceSpecificInfo(invokeId, response, errorType, NULL, 0); } int mmsServer_isIndexAccess(AlternateAccess_t* alternateAccess) { if (alternateAccess->list.array[0]->present == AlternateAccess__Member_PR_unnamed) { if ((alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present == AlternateAccessSelection__selectAccess_PR_index) || (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present == AlternateAccessSelection__selectAccess_PR_indexRange)) { return 1; } else return 0; } else return 0; } int mmsServer_getLowIndex(AlternateAccess_t* alternateAccess) { if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present == AlternateAccessSelection__selectAccess_PR_index) { long index; asn_INTEGER2long( &alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index, &index); return (int) index; } if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present == AlternateAccessSelection__selectAccess_PR_indexRange) { long index; asn_INTEGER2long( &alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex, &index); return (int) index; } return -1; } int mmsServer_getNumberOfElements(AlternateAccess_t* alternateAccess) { if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present == AlternateAccessSelection__selectAccess_PR_indexRange) { long number; asn_INTEGER2long( &alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements, &number); return (int) number; } return 0; } MmsNamedVariableList mmsServer_getNamedVariableListWithName(LinkedList namedVariableLists, const char* variableListName) { MmsNamedVariableList variableList = NULL; LinkedList element = LinkedList_getNext(namedVariableLists); while (element != NULL) { MmsNamedVariableList varList = (MmsNamedVariableList) element->data; if (strcmp(MmsNamedVariableList_getName(varList), variableListName) == 0) { variableList = varList; break; } element = LinkedList_getNext(element); } return variableList; } void mmsServer_deleteVariableList(LinkedList namedVariableLists, char* variableListName) { LinkedList previousElement = namedVariableLists; LinkedList element = LinkedList_getNext(namedVariableLists); while (element != NULL ) { MmsNamedVariableList varList = (MmsNamedVariableList) element->data; if (strcmp(MmsNamedVariableList_getName(varList), variableListName) == 0) { previousElement->next = element->next; GLOBAL_FREEMEM(element); MmsNamedVariableList_destroy(varList); break; } previousElement = element; element = LinkedList_getNext(element); } }