|
|
@@ -29,14 +29,11 @@
|
|
|
#include "cipepath.h"
|
|
|
#include "stdlib.h"
|
|
|
|
|
|
-/* global public variables */
|
|
|
-EipUint8 g_message_data_reply_buffer[OPENER_MESSAGE_DATA_REPLY_BUFFER]; /**< Reply buffer */
|
|
|
-
|
|
|
/* private functions*/
|
|
|
-int EncodeEPath(CipEpath *epath,
|
|
|
- EipUint8 **message);
|
|
|
+void EncodeEPath(CipEpath *epath,
|
|
|
+ ENIPMessage *message);
|
|
|
|
|
|
-void CipStackInit(const EipUint16 unique_connection_id) {
|
|
|
+EipStatus CipStackInit(const EipUint16 unique_connection_id) {
|
|
|
/* The message router is the first CIP object be initialized!!! */
|
|
|
EipStatus eip_status = CipMessageRouterInit();
|
|
|
OPENER_ASSERT(kEipStatusOk == eip_status);
|
|
|
@@ -60,8 +57,7 @@ void CipStackInit(const EipUint16 unique_connection_id) {
|
|
|
eip_status = ApplicationInitialization();
|
|
|
OPENER_ASSERT(kEipStatusOk == eip_status);
|
|
|
|
|
|
- /* Shut up compiler warning with traces disabled */
|
|
|
- (void) eip_status;
|
|
|
+ return eip_status;
|
|
|
}
|
|
|
|
|
|
void ShutdownCipStack(void) {
|
|
|
@@ -128,7 +124,7 @@ EipStatus NotifyClass(const CipClass *RESTRICT const cip_class,
|
|
|
|
|
|
/* handle error replies*/
|
|
|
message_router_response->size_of_additional_status = 0; /* fill in the rest of the reply with not much of anything*/
|
|
|
- message_router_response->data_length = 0;
|
|
|
+ InitializeENIPMessage(&message_router_response->message);
|
|
|
message_router_response->reply_service = (0x80
|
|
|
| message_router_request->service); /* except the reply code is an echo of the command + the reply flag */
|
|
|
|
|
|
@@ -229,7 +225,7 @@ CipClass *CreateCipClass(const CipUdint class_code,
|
|
|
and contains a pointer to a metaclass
|
|
|
CIP never explicitly addresses a metaclass*/
|
|
|
|
|
|
- CipClass *const cip_class = (CipClass *) CipCalloc(1, sizeof(CipClass) ); /* create the class object*/
|
|
|
+ CipClass * const cip_class = (CipClass *) CipCalloc(1, sizeof(CipClass) ); /* create the class object*/
|
|
|
CipClass *const meta_class = (CipClass *) CipCalloc(1, sizeof(CipClass) ); /* create the metaclass object*/
|
|
|
|
|
|
/* initialize the class-specific fields of the Class struct*/
|
|
|
@@ -271,8 +267,9 @@ CipClass *CreateCipClass(const CipUdint class_code,
|
|
|
meta_class->services = (CipServiceStruct *) CipCalloc(
|
|
|
meta_class->number_of_services, sizeof(CipServiceStruct) );
|
|
|
|
|
|
- cip_class->services = (CipServiceStruct *) CipCalloc(cip_class->number_of_services,
|
|
|
- sizeof(CipServiceStruct) );
|
|
|
+ cip_class->services = (CipServiceStruct *) CipCalloc(
|
|
|
+ cip_class->number_of_services,
|
|
|
+ sizeof(CipServiceStruct) );
|
|
|
|
|
|
if (number_of_instances > 0) {
|
|
|
AddCipInstances(cip_class, number_of_instances); /*TODO handle return value and clean up if necessary*/
|
|
|
@@ -286,46 +283,53 @@ CipClass *CreateCipClass(const CipUdint class_code,
|
|
|
AllocateAttributeMasks(cip_class); /* Allocation of bitmasks for Instance Attributes */
|
|
|
|
|
|
if (NULL == initializer) {
|
|
|
- InsertAttribute( (CipInstance *) cip_class, 1, kCipUint,
|
|
|
+ InsertAttribute( (CipInstance *) cip_class, 1, kCipUint, EncodeCipUint,
|
|
|
(void *) &cip_class->revision, kGetableSingleAndAll ); /* revision */
|
|
|
- InsertAttribute( (CipInstance *) cip_class, 2, kCipUint,
|
|
|
+ InsertAttribute( (CipInstance *) cip_class, 2, kCipUint, EncodeCipUint,
|
|
|
(void *) &cip_class->number_of_instances,
|
|
|
- kGetableSingleAndAll ); /* largest instance number */
|
|
|
- InsertAttribute( (CipInstance *) cip_class, 3, kCipUint,
|
|
|
+ kGetableSingleAndAll ); /* #2 Max instance no. */
|
|
|
+ InsertAttribute( (CipInstance *) cip_class, 3, kCipUint, EncodeCipUint,
|
|
|
(void *) &cip_class->number_of_instances,
|
|
|
kGetableSingleAndAll ); /* number of instances currently existing*/
|
|
|
- InsertAttribute( (CipInstance *) cip_class, 4, kCipUint,
|
|
|
- (void *) &kCipUintZero, kGetableAll ); /* optional attribute list - default = 0 */
|
|
|
- InsertAttribute( (CipInstance *) cip_class, 5, kCipUint,
|
|
|
+ InsertAttribute( (CipInstance *) cip_class, 4, kCipUint, EncodeCipUint,
|
|
|
+ (void *) &kCipUintZero, kGetableAllDummy ); /* optional attribute list - default = 0 */
|
|
|
+ InsertAttribute( (CipInstance *) cip_class, 5, kCipUint, EncodeCipUint,
|
|
|
(void *) &kCipUintZero, kNotSetOrGetable ); /* optional service list - default = 0 */
|
|
|
- InsertAttribute( (CipInstance *) cip_class, 6, kCipUint,
|
|
|
+ InsertAttribute( (CipInstance *) cip_class, 6, kCipUint, EncodeCipUint,
|
|
|
(void *) &meta_class->highest_attribute_number,
|
|
|
kGetableSingle ); /* max class attribute number*/
|
|
|
- InsertAttribute( (CipInstance *) cip_class, 7, kCipUint,
|
|
|
+ InsertAttribute( (CipInstance *) cip_class, 7, kCipUint, EncodeCipUint,
|
|
|
(void *) &cip_class->highest_attribute_number,
|
|
|
kGetableSingle ); /* max instance attribute number*/
|
|
|
+ if (number_of_class_services > 0) {
|
|
|
+ if (number_of_class_services > 1) { /*only if the mask has values add the get_attribute_all service */
|
|
|
+ InsertService(meta_class,
|
|
|
+ kGetAttributeAll,
|
|
|
+ &GetAttributeAll,
|
|
|
+ "GetAttributeAll"); /* bind instance services to the metaclass*/
|
|
|
+ }
|
|
|
+ InsertService(meta_class,
|
|
|
+ kGetAttributeSingle,
|
|
|
+ &GetAttributeSingle,
|
|
|
+ "GetAttributeSingle");
|
|
|
+ }
|
|
|
} else {
|
|
|
initializer(cip_class);
|
|
|
}
|
|
|
|
|
|
/* create the standard class services*/
|
|
|
- if (number_of_class_services > 0) {
|
|
|
- if (number_of_class_services > 1) { /*only if the mask has values add the get_attribute_all service */
|
|
|
- InsertService(meta_class, kGetAttributeAll, &GetAttributeAll,
|
|
|
- "GetAttributeAll"); /* bind instance services to the metaclass*/
|
|
|
- }
|
|
|
- InsertService(meta_class, kGetAttributeSingle, &GetAttributeSingle,
|
|
|
- "GetAttributeSingle");
|
|
|
- }
|
|
|
return cip_class;
|
|
|
}
|
|
|
|
|
|
void InsertAttribute(CipInstance *const instance,
|
|
|
const EipUint16 attribute_number,
|
|
|
const EipUint8 cip_type,
|
|
|
+ CipAttributeEncodeInMessage encode_function,
|
|
|
void *const data,
|
|
|
const EipByte cip_flags) {
|
|
|
|
|
|
+ OPENER_ASSERT(NULL != data); /* Its not allowed to push a NULL pointer, as this marks an unused attribute struct */
|
|
|
+
|
|
|
CipAttributeStruct *attribute = instance->attributes;
|
|
|
CipClass *cip_class = instance->cip_class;
|
|
|
|
|
|
@@ -335,6 +339,7 @@ void InsertAttribute(CipInstance *const instance,
|
|
|
if (attribute->data == NULL) { /* found non set attribute */
|
|
|
attribute->attribute_number = attribute_number;
|
|
|
attribute->type = cip_type;
|
|
|
+ attribute->encode = encode_function;
|
|
|
attribute->attribute_flags = cip_flags;
|
|
|
attribute->data = data;
|
|
|
|
|
|
@@ -346,7 +351,8 @@ void InsertAttribute(CipInstance *const instance,
|
|
|
(cip_flags & kGetableSingle) ?
|
|
|
1 << (attribute_number) % 8 : 0;
|
|
|
cip_class->get_all_bit_mask[index] |=
|
|
|
- (cip_flags & kGetableAll) ? 1 << (attribute_number) % 8 : 0;
|
|
|
+ (cip_flags & (kGetableAll | kGetableAllDummy) ) ? 1 <<
|
|
|
+ (attribute_number) % 8 : 0;
|
|
|
cip_class->set_bit_mask[index] |=
|
|
|
( (cip_flags & kSetable) ? 1 : 0 ) << ( (attribute_number) % 8 );
|
|
|
|
|
|
@@ -356,7 +362,9 @@ void InsertAttribute(CipInstance *const instance,
|
|
|
}
|
|
|
OPENER_TRACE_ERR(
|
|
|
"Tried to insert too many attributes into class: %" PRIu32 " '%s', instance %" PRIu32 "\n",
|
|
|
- cip_class->class_code, cip_class->class_name, instance->instance_number);
|
|
|
+ cip_class->class_code,
|
|
|
+ cip_class->class_name,
|
|
|
+ instance->instance_number);
|
|
|
OPENER_ASSERT(false);
|
|
|
/* trying to insert too many attributes*/
|
|
|
}
|
|
|
@@ -392,20 +400,20 @@ void InsertGetSetCallback
|
|
|
(
|
|
|
CipClass *const cip_class,
|
|
|
CipGetSetCallback callback_function,
|
|
|
- CIPAttributeFlag callbacks_to_install
|
|
|
+ CIPAttributeFlag callbacks_to_install
|
|
|
) {
|
|
|
- if (0 != (kPreGetFunc & callbacks_to_install)) {
|
|
|
+ if (0 != (kPreGetFunc & callbacks_to_install) ) {
|
|
|
cip_class->PreGetCallback = callback_function;
|
|
|
}
|
|
|
- if (0 != (kPostGetFunc & callbacks_to_install)) {
|
|
|
+ if (0 != (kPostGetFunc & callbacks_to_install) ) {
|
|
|
cip_class->PostGetCallback = callback_function;
|
|
|
}
|
|
|
- if (0 != (kPreSetFunc & callbacks_to_install)) {
|
|
|
+ if (0 != (kPreSetFunc & callbacks_to_install) ) {
|
|
|
cip_class->PreSetCallback = callback_function;
|
|
|
}
|
|
|
/* The PostSetCallback is used for both, the after set action and the storage
|
|
|
* of non volatile data. Therefore check for both flags set. */
|
|
|
- if (0 != ((kPostSetFunc | kNvDataFunc) & callbacks_to_install)) {
|
|
|
+ if (0 != ( (kPostSetFunc | kNvDataFunc) & callbacks_to_install ) ) {
|
|
|
cip_class->PostSetCallback = callback_function;
|
|
|
}
|
|
|
}
|
|
|
@@ -427,6 +435,16 @@ CipAttributeStruct *GetCipAttribute(const CipInstance *const instance,
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+void GenerateGetAttributeSingleHeader(
|
|
|
+ const CipMessageRouterRequest *const message_router_request,
|
|
|
+ CipMessageRouterResponse *const message_router_response) {
|
|
|
+ InitializeENIPMessage(&message_router_response->message);
|
|
|
+ message_router_response->reply_service =
|
|
|
+ (0x80 | message_router_request->service);
|
|
|
+ message_router_response->general_status = kCipErrorAttributeNotSupported;
|
|
|
+ message_router_response->size_of_additional_status = 0;
|
|
|
+}
|
|
|
+
|
|
|
/* TODO this needs to check for buffer overflow*/
|
|
|
EipStatus GetAttributeSingle(CipInstance *RESTRICT const instance,
|
|
|
CipMessageRouterRequest *const message_router_request,
|
|
|
@@ -437,47 +455,40 @@ EipStatus GetAttributeSingle(CipInstance *RESTRICT const instance,
|
|
|
|
|
|
CipAttributeStruct *attribute = GetCipAttribute(instance,
|
|
|
message_router_request->request_path.attribute_number);
|
|
|
- EipByte *message = message_router_response->data;
|
|
|
|
|
|
- message_router_response->data_length = 0;
|
|
|
- message_router_response->reply_service = (0x80
|
|
|
- | message_router_request->service);
|
|
|
- message_router_response->general_status = kCipErrorAttributeNotSupported;
|
|
|
- message_router_response->size_of_additional_status = 0;
|
|
|
+ GenerateGetAttributeSingleHeader(message_router_request,
|
|
|
+ message_router_response);
|
|
|
|
|
|
EipUint16 attribute_number =
|
|
|
message_router_request->request_path.attribute_number;
|
|
|
|
|
|
if ( (NULL != attribute) && (NULL != attribute->data) ) {
|
|
|
- uint8_t get_bit_mask = 0;
|
|
|
- if (kGetAttributeAll == message_router_request->service) {
|
|
|
- get_bit_mask =
|
|
|
- (instance->cip_class->get_all_bit_mask[CalculateIndex(
|
|
|
- attribute_number)]);
|
|
|
- message_router_response->general_status = kCipErrorSuccess;
|
|
|
- } else {
|
|
|
- get_bit_mask =
|
|
|
- (instance->cip_class->get_single_bit_mask[CalculateIndex(
|
|
|
- attribute_number)]);
|
|
|
- }
|
|
|
+ uint8_t get_bit_mask =
|
|
|
+ (instance->cip_class->get_single_bit_mask[CalculateIndex(
|
|
|
+ attribute_number)
|
|
|
+ ]);
|
|
|
if (0 != (get_bit_mask & (1 << (attribute_number % 8) ) ) ) {
|
|
|
OPENER_TRACE_INFO("getAttribute %d\n",
|
|
|
message_router_request->request_path.attribute_number); /* create a reply message containing the data*/
|
|
|
|
|
|
/* Call the PreGetCallback if enabled for this attribute and the class provides one. */
|
|
|
- if (attribute->attribute_flags & kPreGetFunc && NULL != instance->cip_class->PreGetCallback) {
|
|
|
- instance->cip_class->PreGetCallback(instance, attribute, message_router_request->service);
|
|
|
+ if ( (attribute->attribute_flags & kPreGetFunc) &&
|
|
|
+ NULL != instance->cip_class->PreGetCallback ) {
|
|
|
+ instance->cip_class->PreGetCallback(instance,
|
|
|
+ attribute,
|
|
|
+ message_router_request->service);
|
|
|
}
|
|
|
|
|
|
OPENER_ASSERT(NULL != attribute);
|
|
|
- message_router_response->data_length = EncodeData(attribute->type,
|
|
|
- attribute->data,
|
|
|
- &message);
|
|
|
+ attribute->encode(attribute->data, &message_router_response->message);
|
|
|
message_router_response->general_status = kCipErrorSuccess;
|
|
|
|
|
|
/* Call the PostGetCallback if enabled for this attribute and the class provides one. */
|
|
|
- if (attribute->attribute_flags & kPostGetFunc && NULL != instance->cip_class->PostGetCallback) {
|
|
|
- instance->cip_class->PostGetCallback(instance, attribute, message_router_request->service);
|
|
|
+ if ( (attribute->attribute_flags & kPostGetFunc) &&
|
|
|
+ NULL != instance->cip_class->PostGetCallback ) {
|
|
|
+ instance->cip_class->PostGetCallback(instance,
|
|
|
+ attribute,
|
|
|
+ message_router_request->service);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -485,170 +496,180 @@ EipStatus GetAttributeSingle(CipInstance *RESTRICT const instance,
|
|
|
return kEipStatusOkSend;
|
|
|
}
|
|
|
|
|
|
-int EncodeData(const EipUint8 cip_type,
|
|
|
- const void *const cip_data,
|
|
|
- EipUint8 **cip_message) {
|
|
|
- int counter = 0;
|
|
|
+void EncodeCipBool(const CipBool *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ AddSintToMessage(*(EipUint8 *) (data), outgoing_message);
|
|
|
+}
|
|
|
|
|
|
- switch (cip_type)
|
|
|
- /* check the data type of attribute */
|
|
|
- {
|
|
|
- case (kCipBool):
|
|
|
- case (kCipSint):
|
|
|
- case (kCipUsint):
|
|
|
- case (kCipByte):
|
|
|
- counter = AddSintToMessage(*(EipUint8 *) (cip_data), cip_message);
|
|
|
- break;
|
|
|
+void EncodeCipByte(const CipByte *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ AddSintToMessage(*(EipUint8 *) (data), outgoing_message);
|
|
|
+}
|
|
|
|
|
|
- case (kCipInt):
|
|
|
- case (kCipUint):
|
|
|
- case (kCipWord):
|
|
|
- counter = AddIntToMessage(*(EipUint16 *) (cip_data), cip_message);
|
|
|
- break;
|
|
|
+void EncodeCipWord(const CipWord *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ AddIntToMessage(*(EipUint16 *) (data), outgoing_message);
|
|
|
+}
|
|
|
|
|
|
- case (kCipDint):
|
|
|
- case (kCipUdint):
|
|
|
- case (kCipDword):
|
|
|
- case (kCipReal):
|
|
|
- counter = AddDintToMessage(*(EipUint32 *) (cip_data), cip_message);
|
|
|
- break;
|
|
|
+void EncodeCipDword(const CipDword *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ AddDintToMessage(*(EipUint32 *) (data), outgoing_message);
|
|
|
+}
|
|
|
|
|
|
-#ifdef OPENER_SUPPORT_64BIT_DATATYPES
|
|
|
- case (kCipLint):
|
|
|
- case (kCipUlint):
|
|
|
- case (kCipLword):
|
|
|
- case (kCipLreal):
|
|
|
- counter = AddLintToMessage(*(EipUint64 *) (cip_data), cip_message);
|
|
|
- break;
|
|
|
-#endif
|
|
|
+void EncodeCipLword(const CipLword *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ AddLintToMessage(*(EipUint64 *) (data), outgoing_message);
|
|
|
+}
|
|
|
|
|
|
- case (kCipStime):
|
|
|
- case (kCipDate):
|
|
|
- case (kCipTimeOfDay):
|
|
|
- case (kCipDateAndTime):
|
|
|
- break;
|
|
|
- case (kCipString): {
|
|
|
- CipString *const string = (CipString *) cip_data;
|
|
|
+void EncodeCipUsint(const CipUsint *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ AddSintToMessage(*(EipUint8 *) (data), outgoing_message);
|
|
|
+}
|
|
|
|
|
|
- AddIntToMessage(*(EipUint16 *) &(string->length), cip_message);
|
|
|
- memcpy(*cip_message, string->string, string->length);
|
|
|
- *cip_message += string->length;
|
|
|
+void EncodeCipUint(const CipUint *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ AddIntToMessage(*(EipUint16 *) (data), outgoing_message);
|
|
|
+}
|
|
|
|
|
|
- counter = string->length + 2; /* we have a two byte length field */
|
|
|
- if (counter & 0x01) {
|
|
|
- /* we have an odd byte count */
|
|
|
- **cip_message = 0;
|
|
|
- ++(*cip_message);
|
|
|
- counter++;
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- case (kCipString2):
|
|
|
- case (kCipFtime):
|
|
|
- case (kCipLtime):
|
|
|
- case (kCipItime):
|
|
|
- case (kCipStringN):
|
|
|
- break;
|
|
|
+void EncodeCipUdint(const CipUdint *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ AddDintToMessage(*(EipUint32 *) (data), outgoing_message);
|
|
|
+}
|
|
|
|
|
|
- case (kCipShortString): {
|
|
|
- CipShortString *const short_string = (CipShortString *) cip_data;
|
|
|
+void EncodeCipUlint(const CipUlint *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ AddLintToMessage(*(EipUint64 *) (data), outgoing_message);
|
|
|
+}
|
|
|
|
|
|
- **cip_message = short_string->length;
|
|
|
- ++(*cip_message);
|
|
|
+void EncodeCipSint(const CipSint *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ AddSintToMessage(*(EipUint8 *) (data), outgoing_message);
|
|
|
+}
|
|
|
|
|
|
- memcpy(*cip_message, short_string->string, short_string->length);
|
|
|
- *cip_message += short_string->length;
|
|
|
+void EncodeCipInt(const CipInt *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ AddIntToMessage(*(EipUint16 *) (data), outgoing_message);
|
|
|
+}
|
|
|
|
|
|
- counter = short_string->length + 1;
|
|
|
- break;
|
|
|
- }
|
|
|
+void EncodeCipDint(const CipDint *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ AddDintToMessage(*(EipUint32 *) (data), outgoing_message);
|
|
|
+}
|
|
|
|
|
|
- case (kCipTime):
|
|
|
- break;
|
|
|
+void EncodeCipLint(const CipLint *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ AddLintToMessage(*(EipUint64 *) (data), outgoing_message);
|
|
|
+}
|
|
|
|
|
|
- case (kCipEpath):
|
|
|
- counter = EncodeEPath( (CipEpath *) cip_data, cip_message );
|
|
|
- break;
|
|
|
+void EncodeCipReal(const CipReal *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ AddDintToMessage(*(EipUint32 *) (data), outgoing_message);
|
|
|
+}
|
|
|
|
|
|
- case (kCipEngUnit):
|
|
|
- break;
|
|
|
+void EncodeCipLreal(const CipLreal *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ AddLintToMessage(*(EipUint64 *) (data), outgoing_message);
|
|
|
+}
|
|
|
|
|
|
- case (kCipUsintUsint): {
|
|
|
- CipRevision *revision = (CipRevision *) cip_data;
|
|
|
+void EncodeCipShortString(const CipShortString *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ CipShortString *const short_string = (CipShortString *) data;
|
|
|
|
|
|
- **cip_message = revision->major_revision;
|
|
|
- ++(*cip_message);
|
|
|
- **cip_message = revision->minor_revision;
|
|
|
- ++(*cip_message);
|
|
|
- counter = 2;
|
|
|
- break;
|
|
|
- }
|
|
|
+ AddSintToMessage(short_string->length, outgoing_message);
|
|
|
|
|
|
- case (kCipUdintUdintUdintUdintUdintString): {
|
|
|
- /* TCP/IP attribute 5 */
|
|
|
- CipTcpIpInterfaceConfiguration *
|
|
|
- tcp_ip_network_interface_configuration =
|
|
|
- (CipTcpIpInterfaceConfiguration *) cip_data;
|
|
|
- counter += AddDintToMessage(
|
|
|
- ntohl(tcp_ip_network_interface_configuration->ip_address),
|
|
|
- cip_message);
|
|
|
- counter += AddDintToMessage(
|
|
|
- ntohl(tcp_ip_network_interface_configuration->network_mask),
|
|
|
- cip_message);
|
|
|
- counter += AddDintToMessage(
|
|
|
- ntohl(tcp_ip_network_interface_configuration->gateway),
|
|
|
- cip_message);
|
|
|
- counter += AddDintToMessage(
|
|
|
- ntohl(tcp_ip_network_interface_configuration->name_server),
|
|
|
- cip_message);
|
|
|
- counter += AddDintToMessage(
|
|
|
- ntohl(tcp_ip_network_interface_configuration->name_server_2),
|
|
|
- cip_message);
|
|
|
- counter += EncodeData(kCipString,
|
|
|
- &(tcp_ip_network_interface_configuration->
|
|
|
- domain_name),
|
|
|
- cip_message);
|
|
|
- break;
|
|
|
- }
|
|
|
+ memcpy(outgoing_message->current_message_position,
|
|
|
+ short_string->string,
|
|
|
+ short_string->length);
|
|
|
+ outgoing_message->current_message_position += short_string->length;
|
|
|
+ outgoing_message->used_message_length += short_string->length;
|
|
|
+}
|
|
|
|
|
|
- case (kCip6Usint): {
|
|
|
- EipUint8 *p = (EipUint8 *) cip_data;
|
|
|
- memcpy(*cip_message, p, 6);
|
|
|
- counter = 6;
|
|
|
- break;
|
|
|
- }
|
|
|
+void EncodeCipString(const CipString *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ CipString *const string = (CipString *) data;
|
|
|
|
|
|
- case (kCipMemberList):
|
|
|
- break;
|
|
|
+ AddIntToMessage(*(EipUint16 *) &(string->length), outgoing_message);
|
|
|
+ if(0 != string->length) {
|
|
|
+ memcpy(outgoing_message->current_message_position,
|
|
|
+ string->string,
|
|
|
+ string->length);
|
|
|
+ outgoing_message->current_message_position += string->length;
|
|
|
+ outgoing_message->used_message_length += string->length;
|
|
|
|
|
|
- case (kCipByteArray): {
|
|
|
- OPENER_TRACE_INFO(" -> get attribute byte array\r\n");
|
|
|
- CipByteArray *cip_byte_array = (CipByteArray *) cip_data;
|
|
|
- memcpy(*cip_message, cip_byte_array->data, cip_byte_array->length);
|
|
|
- *cip_message += cip_byte_array->length;
|
|
|
- counter = cip_byte_array->length;
|
|
|
+ if (outgoing_message->used_message_length & 0x01) {
|
|
|
+ /* we have an odd byte count */
|
|
|
+ AddSintToMessage(0, outgoing_message);
|
|
|
}
|
|
|
- break;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- case (kInternalUint6): /* TODO for port class attribute 9, hopefully we can find a better way to do this*/
|
|
|
- {
|
|
|
- EipUint16 *internal_unit16_6 = (EipUint16 *) cip_data;
|
|
|
-
|
|
|
- AddIntToMessage(internal_unit16_6[0], cip_message);
|
|
|
- AddIntToMessage(internal_unit16_6[1], cip_message);
|
|
|
- AddIntToMessage(internal_unit16_6[2], cip_message);
|
|
|
- AddIntToMessage(internal_unit16_6[3], cip_message);
|
|
|
- AddIntToMessage(internal_unit16_6[4], cip_message);
|
|
|
- AddIntToMessage(internal_unit16_6[5], cip_message);
|
|
|
- counter = 12;
|
|
|
- break;
|
|
|
- }
|
|
|
- default:
|
|
|
- break;
|
|
|
+void EncodeCipString2(const CipString2 *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ OPENER_ASSERT(false); /* Not implemented yet */
|
|
|
+}
|
|
|
|
|
|
+void EncodeCipStringN(const CipStringN *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ OPENER_ASSERT(false); /* Not implemented yet */
|
|
|
+}
|
|
|
+
|
|
|
+static void CipStringIHeaderEncoding(const CipStringIStruct *const string,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ EncodeCipUsint(&(string->language_char_1), outgoing_message);
|
|
|
+ EncodeCipUsint(&(string->language_char_2), outgoing_message);
|
|
|
+ EncodeCipUsint(&(string->language_char_3), outgoing_message);
|
|
|
+ EncodeCipUsint(&(string->char_string_struct), outgoing_message);
|
|
|
+ EncodeCipUint(&(string->character_set), outgoing_message);
|
|
|
+}
|
|
|
+
|
|
|
+void EncodeCipStringI(const CipStringI *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ const CipStringI *const string_i = data;
|
|
|
+ EncodeCipUsint(&(string_i->number_of_strings), outgoing_message);
|
|
|
+ for (size_t i = 0; i < string_i->number_of_strings; ++i) {
|
|
|
+ CipStringIHeaderEncoding( (string_i->array_of_string_i_structs) + i,
|
|
|
+ outgoing_message );
|
|
|
+ switch(string_i->array_of_string_i_structs[i].char_string_struct) {
|
|
|
+ case kCipString: EncodeCipString(
|
|
|
+ string_i->array_of_string_i_structs[i].string,
|
|
|
+ outgoing_message); break;
|
|
|
+ case kCipString2: EncodeCipString2(
|
|
|
+ string_i->array_of_string_i_structs[i].string,
|
|
|
+ outgoing_message); break;
|
|
|
+ case kCipStringN: EncodeCipStringN(
|
|
|
+ string_i->array_of_string_i_structs[i].string,
|
|
|
+ outgoing_message); break;
|
|
|
+ case kCipShortString: EncodeCipShortString(
|
|
|
+ string_i->array_of_string_i_structs[i].string,
|
|
|
+ outgoing_message); break;
|
|
|
+ default: OPENER_ASSERT(false); break;
|
|
|
+ }
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- return counter;
|
|
|
+void EncodeCipByteArray(const CipByteArray *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ OPENER_TRACE_INFO(" -> get attribute byte array\r\n");
|
|
|
+ CipByteArray *cip_byte_array = (CipByteArray *) data;
|
|
|
+ memcpy(outgoing_message->current_message_position,
|
|
|
+ cip_byte_array->data,
|
|
|
+ cip_byte_array->length);
|
|
|
+ outgoing_message->current_message_position += cip_byte_array->length;
|
|
|
+ outgoing_message->used_message_length += cip_byte_array->length;
|
|
|
+}
|
|
|
+
|
|
|
+void EncodeCipEPath(const CipEpath *const data,
|
|
|
+ ENIPMessage *const outgoing_message) {
|
|
|
+ EncodeEPath( (CipEpath *) data, outgoing_message );
|
|
|
+}
|
|
|
+
|
|
|
+void EncodeCipEthernetLinkPhyisicalAddress(const void *const data,
|
|
|
+ ENIPMessage *const outgoing_message)
|
|
|
+{
|
|
|
+ EipUint8 *p = (EipUint8 *) data;
|
|
|
+ memcpy(outgoing_message->current_message_position, p, 6);
|
|
|
+ outgoing_message->current_message_position += 6;
|
|
|
+ outgoing_message->used_message_length += 6;
|
|
|
}
|
|
|
|
|
|
int DecodeData(const EipUint8 cip_data_type,
|
|
|
@@ -746,106 +767,84 @@ EipStatus GetAttributeAll(CipInstance *instance,
|
|
|
const struct sockaddr *originator_address,
|
|
|
const int encapsulation_session) {
|
|
|
|
|
|
- EipUint8 *reply = message_router_response->data; /* pointer into the reply */
|
|
|
+ InitializeENIPMessage(&message_router_response->message);
|
|
|
CipAttributeStruct *attribute = instance->attributes; /* pointer to list of attributes*/
|
|
|
- CipServiceStruct *service = GetCipService(instance, kGetAttributeSingle); /* pointer to list of services*/
|
|
|
|
|
|
- if(NULL == service) {
|
|
|
- /* GetAttributeAll service not found */
|
|
|
- /* Return kEipStatusOk if cannot find GET_ATTRIBUTE_SINGLE service*/
|
|
|
- return kEipStatusOk;
|
|
|
- }
|
|
|
+ //Missing header
|
|
|
|
|
|
if (0 == instance->cip_class->number_of_attributes) {
|
|
|
- message_router_response->data_length = 0; /*there are no attributes to be sent back*/
|
|
|
+ /*there are no attributes to be sent back*/
|
|
|
message_router_response->reply_service =
|
|
|
(0x80 | message_router_request->service);
|
|
|
message_router_response->general_status = kCipErrorServiceNotSupported;
|
|
|
message_router_response->size_of_additional_status = 0;
|
|
|
} else {
|
|
|
+ GenerateGetAttributeSingleHeader(message_router_request,
|
|
|
+ message_router_response);
|
|
|
+ message_router_response->general_status = kCipErrorSuccess;
|
|
|
for (size_t j = 0; j < instance->cip_class->number_of_attributes; j++) {
|
|
|
/* for each instance attribute of this class */
|
|
|
- int attribute_number = attribute->attribute_number;
|
|
|
+ EipUint16 attribute_number = attribute->attribute_number;
|
|
|
if ( (instance->cip_class->get_all_bit_mask[CalculateIndex(
|
|
|
attribute_number)]) &
|
|
|
(1 << (attribute_number % 8) ) ) {
|
|
|
- /* only return attributes that are flagged as being part of GetAttributeALl */
|
|
|
+ /* only return attributes that are flagged as being part of GetAttributeAll */
|
|
|
message_router_request->request_path.attribute_number =
|
|
|
attribute_number;
|
|
|
- if (kEipStatusOkSend !=
|
|
|
- service->service_function(instance, message_router_request,
|
|
|
- message_router_response,
|
|
|
- originator_address,
|
|
|
- encapsulation_session) ) {
|
|
|
- message_router_response->data = reply;
|
|
|
- return kEipStatusError;
|
|
|
- }
|
|
|
- message_router_response->data += message_router_response->data_length;
|
|
|
+
|
|
|
+ attribute->encode(attribute->data, &message_router_response->message);
|
|
|
}
|
|
|
attribute++;
|
|
|
}
|
|
|
- message_router_response->data_length = message_router_response->data -
|
|
|
- reply;
|
|
|
- message_router_response->data = reply;
|
|
|
}
|
|
|
return kEipStatusOkSend;
|
|
|
}
|
|
|
|
|
|
-int EncodeEPath(CipEpath *epath,
|
|
|
- EipUint8 **message) {
|
|
|
+void EncodeEPath(CipEpath *epath,
|
|
|
+ ENIPMessage *message) {
|
|
|
unsigned int length = epath->path_size;
|
|
|
+ size_t start_length = message->used_message_length;
|
|
|
AddIntToMessage(epath->path_size, message);
|
|
|
|
|
|
if (epath->class_id < 256) {
|
|
|
- **message = 0x20; /*8Bit Class Id */
|
|
|
- ++(*message);
|
|
|
- **message = (EipUint8) epath->class_id;
|
|
|
- ++(*message);
|
|
|
+ AddSintToMessage(0x20, message); /* 8 Bit Class Id */
|
|
|
+ AddSintToMessage( (EipUint8) epath->class_id, message );
|
|
|
length -= 1;
|
|
|
} else {
|
|
|
- **message = 0x21; /*16Bit Class Id */
|
|
|
- ++(*message);
|
|
|
- **message = 0; /*pad byte */
|
|
|
- ++(*message);
|
|
|
+ AddSintToMessage(0x21, message); /*16Bit Class Id */
|
|
|
+ AddSintToMessage(0, message); /*pad byte */
|
|
|
AddIntToMessage(epath->class_id, message);
|
|
|
length -= 2;
|
|
|
}
|
|
|
|
|
|
if (0 < length) {
|
|
|
if (epath->instance_number < 256) {
|
|
|
- **message = 0x24; /*8Bit Instance Id */
|
|
|
- ++(*message);
|
|
|
- **message = (EipUint8) epath->instance_number;
|
|
|
- ++(*message);
|
|
|
+ AddSintToMessage(0x24, message); /*8Bit Instance Id */
|
|
|
+ AddSintToMessage(epath->instance_number, message);
|
|
|
length -= 1;
|
|
|
} else {
|
|
|
- **message = 0x25; /*16Bit Instance Id */
|
|
|
- ++(*message);
|
|
|
- **message = 0; /*padd byte */
|
|
|
- ++(*message);
|
|
|
+ AddSintToMessage(0x25, message); /*16Bit Instance Id */
|
|
|
+ AddSintToMessage(0, message); /*pad byte */
|
|
|
AddIntToMessage(epath->instance_number, message);
|
|
|
length -= 2;
|
|
|
}
|
|
|
|
|
|
if (0 < length) {
|
|
|
if (epath->attribute_number < 256) {
|
|
|
- **message = 0x30; /*8Bit Attribute Id */
|
|
|
- ++(*message);
|
|
|
- **message = (EipUint8) epath->attribute_number;
|
|
|
- ++(*message);
|
|
|
+ AddSintToMessage(0x30, message); /*8Bit Attribute Id */
|
|
|
+ AddSintToMessage(epath->attribute_number, message);
|
|
|
length -= 1;
|
|
|
} else {
|
|
|
- **message = 0x31; /*16Bit Attribute Id */
|
|
|
- ++(*message);
|
|
|
- **message = 0; /*pad byte */
|
|
|
- ++(*message);
|
|
|
+ AddSintToMessage(0x31, message); /*16Bit Attribute Id */
|
|
|
+ AddSintToMessage(0, message); /*pad byte */
|
|
|
AddIntToMessage(epath->attribute_number, message);
|
|
|
length -= 2;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return 2 + epath->path_size * 2; /* path size is in 16 bit chunks according to the specification */
|
|
|
+ OPENER_ASSERT(
|
|
|
+ 2 + epath->path_size * 2 == message->used_message_length - start_length); /* path size is in 16 bit chunks according to the specification */
|
|
|
}
|
|
|
|
|
|
int DecodePaddedEPath(CipEpath *epath,
|
|
|
@@ -943,138 +942,3 @@ size_t CalculateIndex(EipUint16 attribute_number) {
|
|
|
size_t index = attribute_number / 8;
|
|
|
return index;
|
|
|
}
|
|
|
-
|
|
|
-size_t GetSizeOfAttribute(const CipAttributeStruct *const attribute_struct) {
|
|
|
- size_t data_type_size = 0;
|
|
|
- switch (attribute_struct->type) {
|
|
|
- case (kCipBool):
|
|
|
- data_type_size = sizeof(CipBool);
|
|
|
- break;
|
|
|
- case (kCipSint):
|
|
|
- data_type_size = sizeof(CipSint);
|
|
|
- break;
|
|
|
- case (kCipInt):
|
|
|
- data_type_size = sizeof(CipInt);
|
|
|
- break;
|
|
|
- case (kCipDint):
|
|
|
- data_type_size = sizeof(CipDint);
|
|
|
- break;
|
|
|
- case (kCipUsint):
|
|
|
- data_type_size = sizeof(CipUsint);
|
|
|
- break;
|
|
|
- case (kCipUint):
|
|
|
- data_type_size = sizeof(CipUint);
|
|
|
- break;
|
|
|
- case (kCipUdint):
|
|
|
- data_type_size = sizeof(CipUdint);
|
|
|
- break;
|
|
|
- case (kCipReal):
|
|
|
- data_type_size = sizeof(CipReal);
|
|
|
- break;
|
|
|
-#ifdef OPENER_SUPPORT_64BIT_DATATYPES
|
|
|
- case (kCipLreal):
|
|
|
- data_type_size = sizeof(CipLreal);
|
|
|
- break;
|
|
|
- case (kCipUlint):
|
|
|
- data_type_size = sizeof(CipUlint);
|
|
|
- break;
|
|
|
- case (kCipLint):
|
|
|
- data_type_size = sizeof(CipLint);
|
|
|
- break;
|
|
|
- case (kCipLword):
|
|
|
- data_type_size = sizeof(CipLword);
|
|
|
- break;
|
|
|
- case (kCipLtime):
|
|
|
- data_type_size = sizeof(CipLint);
|
|
|
- break;
|
|
|
-#endif /* OPENER_SUPPORT_64BIT_DATATYPES */
|
|
|
-
|
|
|
- case (kCipStime):
|
|
|
- data_type_size = sizeof(CipDint);
|
|
|
- break;
|
|
|
- case (kCipDate):
|
|
|
- data_type_size = sizeof(CipUint);
|
|
|
- break;
|
|
|
- case (kCipTimeOfDay):
|
|
|
- data_type_size = sizeof(CipUdint);
|
|
|
- break;
|
|
|
- case (kCipDateAndTime):
|
|
|
- data_type_size = sizeof(CipUdint) + sizeof(CipUint);
|
|
|
- break;
|
|
|
- case (kCipString): {
|
|
|
- CipString *data = (CipString *) attribute_struct->data;
|
|
|
- data_type_size = sizeof(CipUint) + (data->length) * sizeof(CipOctet);
|
|
|
- }
|
|
|
- break;
|
|
|
- case (kCipByte):
|
|
|
- data_type_size = sizeof(CipByte);
|
|
|
- break;
|
|
|
- case (kCipWord):
|
|
|
- data_type_size = sizeof(CipWord);
|
|
|
- break;
|
|
|
- case (kCipDword):
|
|
|
- data_type_size = sizeof(CipDword);
|
|
|
- break;
|
|
|
- case (kCipString2): {
|
|
|
- CipString *data = (CipString *) attribute_struct->data;
|
|
|
- data_type_size = sizeof(CipUint) + 2 * (data->length) * sizeof(CipOctet);
|
|
|
- }
|
|
|
- break;
|
|
|
- case (kCipFtime):
|
|
|
- data_type_size = sizeof(CipDint);
|
|
|
- break;
|
|
|
- case (kCipItime):
|
|
|
- data_type_size = sizeof(CipInt);
|
|
|
- break;
|
|
|
- case (kCipStringN): {
|
|
|
- CipStringN *data = (CipStringN *) attribute_struct->data;
|
|
|
- data_type_size = sizeof(CipUint) + sizeof(CipUint)
|
|
|
- + (size_t) (data->length) * (size_t) (data->size);
|
|
|
- }
|
|
|
- break;
|
|
|
- case (kCipShortString): {
|
|
|
- CipShortString *data = (CipShortString *) attribute_struct->data;
|
|
|
- data_type_size = sizeof(CipUsint) + (data->length) * sizeof(CipOctet);
|
|
|
- }
|
|
|
- break;
|
|
|
- case (kCipTime):
|
|
|
- data_type_size = sizeof(CipDint);
|
|
|
- break;
|
|
|
- case (kCipEpath): {
|
|
|
- CipEpath *data = (CipEpath *) attribute_struct->data;
|
|
|
- data_type_size = 2 * (data->path_size);
|
|
|
- }
|
|
|
- break;
|
|
|
- case (kCipEngUnit):
|
|
|
- data_type_size = sizeof(CipUint);
|
|
|
- break;
|
|
|
- case (kCipUsintUsint):
|
|
|
- data_type_size = 2 * sizeof(CipUsint);
|
|
|
- break;
|
|
|
- case (kCipUdintUdintUdintUdintUdintString): {
|
|
|
- CipTcpIpInterfaceConfiguration *data =
|
|
|
- (CipTcpIpInterfaceConfiguration *) attribute_struct->data;
|
|
|
- data_type_size = 5 * sizeof(CipUdint) + sizeof(CipUint)
|
|
|
- + (data->domain_name.length) * sizeof(EipByte);
|
|
|
- }
|
|
|
- break;
|
|
|
- case (kCip6Usint):
|
|
|
- data_type_size = 6 * sizeof(CipUsint);
|
|
|
- break;
|
|
|
- case (kCipMemberList):
|
|
|
- data_type_size = 0;
|
|
|
- break;
|
|
|
- case (kCipByteArray): {
|
|
|
- CipByteArray *data = (CipByteArray *) attribute_struct->data;
|
|
|
- data_type_size = sizeof(CipUint) + (data->length) * sizeof(CipOctet);
|
|
|
- }
|
|
|
- break;
|
|
|
- case (kInternalUint6):
|
|
|
- data_type_size = 6 * sizeof(CipUint);
|
|
|
- break;
|
|
|
- default:
|
|
|
- data_type_size = 0;
|
|
|
- break;
|
|
|
- }
|
|
|
- return data_type_size;
|
|
|
-}
|