| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620 |
- /*******************************************************************************
- * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved.
- *
- ******************************************************************************/
- #include <string.h>
- #include <stdio.h>
- #include "cipcommon.h"
- #include "opener_user_conf.h"
- #include "opener_api.h"
- #include "cipidentity.h"
- #include "ciptcpipinterface.h"
- #include "cipethernetlink.h"
- #include "cipconnectionmanager.h"
- #include "endianconv.h"
- #include "encap.h"
- #include "ciperror.h"
- #include "cipassembly.h"
- #include "cipmessagerouter.h"
- #if defined(OPENER_IS_DLR_DEVICE) && 0 != OPENER_IS_DLR_DEVICE
- #include "cipdlr.h"
- #endif
- #include "cipqos.h"
- #include "cpf.h"
- #include "trace.h"
- #include "appcontype.h"
- #include "cipepath.h"
- #include "stdlib.h"
- #include "ciptypes.h"
- #include "cipstring.h"
- #if defined(CIP_FILE_OBJECT) && 0 != CIP_FILE_OBJECT
- #include "OpENerFileObject/cipfile.h"
- #endif
- #if defined(CIP_SECURITY_OBJECTS) && 0 != CIP_SECURITY_OBJECTS
- #include "SecurityObjects/CipSecurityObject/cipsecurity.h"
- #include "SecurityObjects/EtherNetIPSecurityObject/ethernetipsecurity.h"
- #include "SecurityObjects/CertificateManagementObject/certificatemanagement.h"
- #endif
- /* private functions*/
- 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);
- eip_status = CipIdentityInit();
- OPENER_ASSERT(kEipStatusOk == eip_status);
- eip_status = CipTcpIpInterfaceInit();
- OPENER_ASSERT(kEipStatusOk == eip_status);
- eip_status = CipEthernetLinkInit();
- OPENER_ASSERT(kEipStatusOk == eip_status);
- eip_status = ConnectionManagerInit(unique_connection_id);
- OPENER_ASSERT(kEipStatusOk == eip_status);
- eip_status = CipAssemblyInitialize();
- OPENER_ASSERT(kEipStatusOk == eip_status);
- #if defined(OPENER_IS_DLR_DEVICE) && 0 != OPENER_IS_DLR_DEVICE
- eip_status = CipDlrInit();
- OPENER_ASSERT(kEipStatusOk == eip_status);
- #endif
- eip_status = CipQoSInit();
- OPENER_ASSERT(kEipStatusOk == eip_status);
- #if defined(CIP_FILE_OBJECT) && 0 != CIP_FILE_OBJECT
- eip_status = CipFileInit();
- OPENER_ASSERT(kEipStatusOk == eip_status);
- #endif
- #if defined(CIP_SECURITY_OBJECTS) && 0 != CIP_SECURITY_OBJECTS
- eip_status = CipSecurityInit();
- OPENER_ASSERT(kEipStatusOk == eip_status);
- eip_status = EIPSecurityInit();
- OPENER_ASSERT(kEipStatusOk == eip_status);
- eip_status = CertificateManagementObjectInit();
- OPENER_ASSERT(kEipStatusOk == eip_status);
- #endif
- /* the application has to be initialized at last */
- eip_status = ApplicationInitialization();
- OPENER_ASSERT(kEipStatusOk == eip_status);
- return eip_status;
- }
- void ShutdownCipStack(void) {
- /* First close all connections */
- CloseAllConnections();
- /* Than free the sockets of currently active encapsulation sessions */
- EncapsulationShutDown();
- /*clean the data needed for the assembly object's attribute 3*/
- ShutdownAssemblies();
- ShutdownTcpIpInterface();
- /*no clear all the instances and classes */
- DeleteAllClasses();
- }
- EipStatus NotifyClass(const CipClass *RESTRICT const cip_class,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response,
- const struct sockaddr *originator_address,
- const CipSessionHandle encapsulation_session) {
- /* find the instance: if instNr==0, the class is addressed, else find the instance */
- CipInstanceNum instance_number =
- message_router_request->request_path.instance_number; /* get the instance number */
- CipInstance *instance = GetCipInstance(cip_class, instance_number); /* look up the instance (note that if inst==0 this will be the class itself) */
- if(instance) /* if instance is found */
- {
- OPENER_TRACE_INFO("notify: found instance %d%s\n",
- instance_number,
- instance_number == 0 ? " (class object)" : "");
- CipServiceStruct *service = instance->cip_class->services; /* get pointer to array of services */
- if(NULL != service) /* if services are defined */
- {
- for(size_t i = 0; i < instance->cip_class->number_of_services; i++) /* seach the services list */
- {
- if(message_router_request->service == service->service_number) /* if match is found */
- {
- /* call the service, and return what it returns */
- OPENER_TRACE_INFO("notify: calling %s service\n", service->name);
- OPENER_ASSERT(NULL != service->service_function);
- return service->service_function(instance,
- message_router_request,
- message_router_response,
- originator_address,
- encapsulation_session);
- } else {
- service++;
- }
- }
- } OPENER_TRACE_WARN(
- "notify: service 0x%x not supported\n", message_router_request->service);
- message_router_response->general_status = kCipErrorServiceNotSupported; /* if no services or service not found, return an error reply*/
- } else {
- OPENER_TRACE_WARN("notify: instance number %d unknown\n", instance_number);
- /* if instance not found, return an error reply */
- message_router_response->general_status = kCipErrorPathDestinationUnknown;
- /* according to the test tool this is the correct error flag instead of CIP_ERROR_OBJECT_DOES_NOT_EXIST */
- }
- /* handle error replies*/
- message_router_response->size_of_additional_status = 0; /* fill in the rest of the reply with not much of anything*/
- 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 */
- return kEipStatusOkSend;
- }
- CipUint GetMaxInstanceNumber(CipClass *RESTRICT const cip_class) {
- CipUint max_instance = 0;
- CipInstance *instance = cip_class->instances;
- while (NULL != instance) { /* loop trough all instances of class */
- if(instance->instance_number > max_instance) {
- max_instance = instance->instance_number;
- }
- instance = instance->next;
- }
- return max_instance;
- }
- CipInstance *AddCipInstances(CipClass *RESTRICT const cip_class,
- const CipInstanceNum number_of_instances) {
- CipInstance **next_instance = NULL;
- CipInstance *first_instance = NULL; /* Initialize to error result */
- CipInstanceNum instance_number = 1; /* the first instance is number 1 */
- int new_instances = 0;
- OPENER_TRACE_INFO("adding %d instances to class %s\n",
- number_of_instances,
- cip_class->class_name);
- /* Allocate and initialize all needed instances one by one. */
- for(new_instances = 0; new_instances < number_of_instances; new_instances++) {
- /* Find next free instance number */
- CipBool found_free_number = false;
- while (!found_free_number) {
- next_instance = &cip_class->instances; /* set pointer to head of existing instances chain */
- found_free_number = true; /* anticipate instance_number is not in use*/
- /* loop through existing instances */
- while (*next_instance) /* as long as what next_instance points to is not zero */
- {
- /* check if instance number in use */
- if(instance_number == (*next_instance)->instance_number) {
- found_free_number = false; /* instance number exists already */
- break;
- }
- next_instance = &(*next_instance)->next; /* get next instance in instances chain*/
- }
- if(!found_free_number) {
- instance_number++; /* try next instance_number and loop again through existing instances */
- }
- }
- CipInstance *current_instance =
- (CipInstance *) CipCalloc( 1, sizeof(CipInstance) );
- OPENER_ASSERT(NULL != current_instance); /* fail if run out of memory */
- if(NULL == current_instance) {
- break;
- }
- if(NULL == first_instance) {
- first_instance = current_instance; /* remember the first allocated instance */
- }
- current_instance->instance_number = instance_number; /* assign the next sequential instance number */
- current_instance->cip_class = cip_class; /* point each instance to its class */
- if(cip_class->number_of_attributes) /* if the class calls for instance attributes */
- { /* then allocate storage for the attribute array */
- current_instance->attributes = (CipAttributeStruct *) CipCalloc(
- cip_class->number_of_attributes,
- sizeof(CipAttributeStruct) );
- OPENER_ASSERT(NULL != current_instance->attributes);/* fail if run out of memory */
- if(NULL == current_instance->attributes) {
- break;
- }
- }
- *next_instance = current_instance; /* link the previous pointer to this new node */
- next_instance = ¤t_instance->next; /* update pp to point to the next link of the current node */
- cip_class->number_of_instances += 1; /* update the total number of instances recorded by the class */
- instance_number++; /* update to the number of the next node*/
- }
- cip_class->max_instance = GetMaxInstanceNumber(cip_class); /* update largest instance number (class Attribute 2) */
- if(new_instances != number_of_instances) {
- /* TODO: Free again all attributes and instances allocated so far in this call. */
- OPENER_TRACE_ERR(
- "ERROR: Allocated only %d instances of requested %d for class %s\n",
- new_instances,
- number_of_instances,
- cip_class->class_name);
- first_instance = NULL; /* failed to allocate all instances / attributes */
- }
- return first_instance;
- }
- CipInstance *AddCipInstance(CipClass *RESTRICT const cip_class,
- const CipInstanceNum instance_id) {
- CipInstance *instance = GetCipInstance(cip_class, instance_id);
- if(NULL == instance) { /*we have no instance with given id*/
- instance = AddCipInstances(cip_class, 1);
- instance->instance_number = instance_id;
- }
- cip_class->max_instance = GetMaxInstanceNumber(cip_class); /* update largest instance number (class Attribute 2) */
- return instance;
- }
- CipClass *CreateCipClass(const CipUdint class_code,
- const int number_of_class_attributes,
- const EipUint32 highest_class_attribute_number,
- const int number_of_class_services,
- const int number_of_instance_attributes,
- const EipUint32 highest_instance_attribute_number,
- const int number_of_instance_services,
- const CipInstanceNum number_of_instances,
- const char *const name,
- const EipUint16 revision,
- InitializeCipClass initializer) {
- OPENER_TRACE_INFO("creating class '%s' with code: 0x%" PRIX32 "\n", name,
- class_code);
- OPENER_ASSERT( NULL == GetCipClass(class_code) ); /* check if an class with the ClassID already exists */
- /* should never try to redefine a class*/
- /* a metaClass is a class that holds the class attributes and services
- CIP can talk to an instance, therefore an instance has a pointer to its class
- CIP can talk to a class, therefore a class struct is a subclass of the instance struct,
- 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 meta_class = (CipClass *) CipCalloc( 1, sizeof(CipClass) ); /* create the metaclass object*/
- /* initialize the class-specific fields of the Class struct*/
- cip_class->class_code = class_code; /* the class remembers the class ID */
- cip_class->revision = revision; /* the class remembers the class ID */
- cip_class->max_instance = 0; /* the largest instance number of a created object in this class */
- cip_class->number_of_instances = 0; /* the number of instances initially zero (more created below) */
- cip_class->instances = 0;
- cip_class->number_of_attributes = number_of_instance_attributes; /* the class remembers the number of instances of that class */
- cip_class->highest_attribute_number = highest_instance_attribute_number; /* indicate which attributes are included in instance getAttributeAll */
- cip_class->number_of_services = number_of_instance_services; /* the class manages the behavior of the instances */
- cip_class->services = 0;
- /* Allocate and initialize the class name string. */
- OPENER_ASSERT(NULL != name);
- const size_t name_len = strlen(name); /* Length does not include termination byte. */
- OPENER_ASSERT(0 < name_len); /* Cannot be an empty string. */
- cip_class->class_name = CipCalloc(name_len + 1, 1); /* Allocate length plus termination byte. */
- OPENER_ASSERT(NULL != cip_class->class_name);
- /*
- * memcpy is used here, instead of a strcpy variant, to avoid Visual Studio
- * depreciation warnings arising from strcpy use, and the recommended
- * alternatives, e.g. strcpy_s, are not available on all systems. In this
- * case the size of the source string is already known, so memcpy() is
- * suitable.
- */
- memcpy(cip_class->class_name, name, name_len + 1);
- /* initialize the class-specific fields of the metaClass struct */
- meta_class->class_code = 0xffffffff; /* set metaclass ID (this should never be referenced) */
- meta_class->number_of_instances = 1; /* the class object is the only instance of the metaclass */
- meta_class->instances = (CipInstance *) cip_class;
- meta_class->number_of_attributes = number_of_class_attributes + 7; /* the metaclass remembers how many class attributes exist*/
- meta_class->highest_attribute_number = highest_class_attribute_number; /* indicate which attributes are included in class getAttributeAll*/
- meta_class->number_of_services = number_of_class_services; /* the metaclass manages the behavior of the class itself */
- meta_class->class_name = (char *) CipCalloc(1, strlen(name) + 6); /* fabricate the name "meta<classname>"*/
- snprintf(meta_class->class_name, strlen(name) + 6, "meta-%s", name);
- /* initialize the instance-specific fields of the Class struct*/
- cip_class->class_instance.instance_number = 0; /* the class object is instance zero of the class it describes (weird, but that's the spec)*/
- cip_class->class_instance.attributes = 0; /* this will later point to the class attibutes*/
- cip_class->class_instance.cip_class = meta_class; /* the class's class is the metaclass (like SmallTalk)*/
- cip_class->class_instance.next = 0; /* the next link will always be zero, since there is only one instance of any particular class object */
- meta_class->class_instance.instance_number = 0xffff; /*the metaclass object does not really have a valid instance number*/
- meta_class->class_instance.attributes = NULL;/* the metaclass has no attributes*/
- meta_class->class_instance.cip_class = NULL; /* the metaclass has no class*/
- meta_class->class_instance.next = NULL; /* the next link will always be zero, since there is only one instance of any particular metaclass object*/
- /* further initialization of the class object*/
- cip_class->class_instance.attributes = (CipAttributeStruct *) CipCalloc(
- meta_class->number_of_attributes,
- sizeof(CipAttributeStruct) );
- /* TODO -- check that we didn't run out of memory?*/
- meta_class->services = (CipServiceStruct *) CipCalloc(
- meta_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*/
- }
- if(RegisterCipClass(cip_class) == kEipStatusError) {/* no memory to register class in Message Router */
- return 0; /*TODO handle return value and clean up if necessary*/
- }
- AllocateAttributeMasks(meta_class); /* Allocation of bitmasks for Class Attributes */
- AllocateAttributeMasks(cip_class); /* Allocation of bitmasks for Instance Attributes */
- if(NULL == initializer) {
- InsertAttribute( (CipInstance *) cip_class, 1, kCipUint, EncodeCipUint,
- NULL, (void *) &cip_class->revision,
- kGetableSingleAndAll ); /* revision */
- InsertAttribute( (CipInstance *) cip_class, 2, kCipUint, EncodeCipUint,
- NULL, (void *) &cip_class->max_instance,
- kGetableSingleAndAll ); /* #2 Max instance no. */
- InsertAttribute( (CipInstance *) cip_class, 3, kCipUint, EncodeCipUint,
- NULL, (void *) &cip_class->number_of_instances,
- kGetableSingleAndAll ); /* number of instances currently existing*/
- InsertAttribute( (CipInstance *) cip_class, 4, kCipUint, EncodeCipUint,
- NULL, (void *) &kCipUintZero, kGetableAllDummy ); /* optional attribute list - default = 0 */
- InsertAttribute( (CipInstance *) cip_class, 5, kCipUint, EncodeCipUint,
- NULL, (void *) &kCipUintZero, kNotSetOrGetable ); /* optional service list - default = 0 */
- InsertAttribute( (CipInstance *) cip_class, 6, kCipUint, EncodeCipUint,
- NULL, (void *) &meta_class->highest_attribute_number,
- kGetableSingle ); /* max class attribute number*/
- InsertAttribute( (CipInstance *) cip_class, 7, kCipUint, EncodeCipUint,
- NULL, (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*/
- return cip_class;
- }
- void InsertAttribute(CipInstance *const instance,
- const EipUint16 attribute_number,
- const EipUint8 cip_type,
- CipAttributeEncodeInMessage encode_function,
- CipAttributeDecodeFromMessage decode_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;
- OPENER_ASSERT(NULL != attribute);
- /* adding a attribute to a class that was not declared to have any attributes is not allowed */
- for(int i = 0; i < instance->cip_class->number_of_attributes; i++) {
- if(attribute->data == NULL) { /* found non set attribute */
- attribute->attribute_number = attribute_number;
- attribute->type = cip_type;
- attribute->encode = encode_function;
- attribute->decode = decode_function;
- attribute->attribute_flags = cip_flags;
- attribute->data = data;
- OPENER_ASSERT(attribute_number <= cip_class->highest_attribute_number);
- size_t index = CalculateIndex(attribute_number);
- cip_class->get_single_bit_mask[index] |=
- (cip_flags & kGetableSingle) ? 1 << (attribute_number) % 8 : 0;
- cip_class->get_all_bit_mask[index] |=
- ( cip_flags & (kGetableAll | kGetableAllDummy) ) ? 1 <<
- (attribute_number) % 8 : 0;
- cip_class->set_bit_mask[index] |= ( (cip_flags & kSetable) ? 1 : 0 ) <<
- ( (attribute_number) % 8 );
- return;
- }
- attribute++;
- } 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);
- OPENER_ASSERT(false);
- /* trying to insert too many attributes*/
- }
- void InsertService(const CipClass *const cip_class,
- const EipUint8 service_number,
- const CipServiceFunction service_function,
- char *const service_name) {
- CipServiceStruct *service = cip_class->services; /* get a pointer to the service array*/
- OPENER_TRACE_INFO("%s, number of services:%d, service number:%d\n",
- cip_class->class_name, cip_class->number_of_services,
- service_number);
- OPENER_ASSERT(service != NULL);
- /* adding a service to a class that was not declared to have services is not allowed*/
- for(int i = 0; i < cip_class->number_of_services; i++) /* Iterate over all service slots attached to the class */
- {
- if(service->service_number == service_number ||
- service->service_function == NULL) /* found undefined service slot*/
- {
- service->service_number = service_number; /* fill in service number*/
- service->service_function = service_function; /* fill in function address*/
- service->name = service_name;
- return;
- }
- ++service;
- }
- OPENER_ASSERT(false);
- /* adding more services than were declared is a no-no*/
- }
- void InsertGetSetCallback(CipClass *const cip_class,
- CipGetSetCallback callback_function,
- CIPAttributeFlag callbacks_to_install) {
- if( 0 != (kPreGetFunc & callbacks_to_install) ) {
- cip_class->PreGetCallback = callback_function;
- }
- if( 0 != (kPostGetFunc & callbacks_to_install) ) {
- cip_class->PostGetCallback = callback_function;
- }
- 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 ) ) {
- cip_class->PostSetCallback = callback_function;
- }
- }
- CipAttributeStruct *GetCipAttribute(const CipInstance *const instance,
- const EipUint16 attribute_number) {
- CipAttributeStruct *attribute = instance->attributes; /* init pointer to array of attributes*/
- for(int i = 0; i < instance->cip_class->number_of_attributes; i++) {
- if(attribute_number == attribute->attribute_number) {
- return attribute;
- } else {
- ++attribute;
- }
- }
- OPENER_TRACE_WARN("attribute %d not defined\n", attribute_number);
- 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,
- CipMessageRouterResponse *const message_router_response,
- const struct sockaddr *originator_address,
- const CipSessionHandle encapsulation_session) {
- /* Suppress unused parameter compiler warning. */
- (void) originator_address;
- (void) encapsulation_session;
- /* Mask for filtering get-ability */
- CipAttributeStruct *attribute = GetCipAttribute(instance,
- message_router_request->request_path.attribute_number);
- 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 =
- (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);
- }
- OPENER_ASSERT(NULL != attribute);
- 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);
- }
- }
- }
- return kEipStatusOkSend;
- }
- void EncodeCipBool(const void *const data,
- ENIPMessage *const outgoing_message) {
- AddSintToMessage(*(EipUint8 *) (data), outgoing_message);
- }
- void EncodeCipByte(const void *const data,
- ENIPMessage *const outgoing_message) {
- AddSintToMessage(*(EipUint8 *) (data), outgoing_message);
- }
- void EncodeCipWord(const void *const data,
- ENIPMessage *const outgoing_message) {
- AddIntToMessage(*(EipUint16 *) (data), outgoing_message);
- }
- void EncodeCipDword(const void *const data,
- ENIPMessage *const outgoing_message) {
- AddDintToMessage(*(EipUint32 *) (data), outgoing_message);
- }
- void EncodeCipLword(const void *const data,
- ENIPMessage *const outgoing_message) {
- AddLintToMessage(*(EipUint64 *) (data), outgoing_message);
- }
- void EncodeCipUsint(const void *const data,
- ENIPMessage *const outgoing_message) {
- AddSintToMessage(*(EipUint8 *) (data), outgoing_message);
- }
- void EncodeCipUint(const void *const data,
- ENIPMessage *const outgoing_message) {
- AddIntToMessage(*(EipUint16 *) (data), outgoing_message);
- }
- void EncodeCipUdint(const void *const data,
- ENIPMessage *const outgoing_message) {
- AddDintToMessage(*(EipUint32 *) (data), outgoing_message);
- }
- void EncodeCipUlint(const void *const data,
- ENIPMessage *const outgoing_message) {
- AddLintToMessage(*(EipUint64 *) (data), outgoing_message);
- }
- void EncodeCipSint(const void *const data,
- ENIPMessage *const outgoing_message) {
- AddSintToMessage(*(EipUint8 *) (data), outgoing_message);
- }
- void EncodeCipInt(const void *const data,
- ENIPMessage *const outgoing_message) {
- AddIntToMessage(*(EipUint16 *) (data), outgoing_message);
- }
- void EncodeCipDint(const void *const data,
- ENIPMessage *const outgoing_message) {
- AddDintToMessage(*(EipUint32 *) (data), outgoing_message);
- }
- void EncodeCipLint(const void *const data,
- ENIPMessage *const outgoing_message) {
- AddLintToMessage(*(EipUint64 *) (data), outgoing_message);
- }
- void EncodeCipReal(const void *const data,
- ENIPMessage *const outgoing_message) {
- AddDintToMessage(*(EipUint32 *) (data), outgoing_message);
- }
- void EncodeCipLreal(const void *const data,
- ENIPMessage *const outgoing_message) {
- AddLintToMessage(*(EipUint64 *) (data), outgoing_message);
- }
- void EncodeCipShortString(const void *const data,
- ENIPMessage *const outgoing_message) {
- CipShortString *const short_string = (CipShortString *) data;
- AddSintToMessage(short_string->length, outgoing_message);
- 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;
- }
- void EncodeCipString(const void *const data,
- ENIPMessage *const outgoing_message) {
- CipString *const string = (CipString *) data;
- 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;
- if(outgoing_message->used_message_length & 0x01) {
- /* we have an odd byte count */
- AddSintToMessage(0, outgoing_message);
- }
- }
- }
- void EncodeCipString2(const void *const data,
- ENIPMessage *const outgoing_message) {
- /* Suppress unused parameter compiler warning. */
- (void)data;
- (void)outgoing_message;
- OPENER_ASSERT(false); /* Not implemented yet */
- }
- void EncodeCipStringN(const void *const data,
- ENIPMessage *const outgoing_message) {
- /* Suppress unused parameter compiler warning. */
- (void)data;
- (void)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 void *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;
- }
- }
- }
- void EncodeCipByteArray(const void *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 void *const data,
- ENIPMessage *const outgoing_message) {
- AddIntToMessage( ( (CipEpath *)data )->path_size, 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;
- }
- void GenerateSetAttributeSingleHeader(
- 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;
- }
- EipStatus SetAttributeSingle(CipInstance *RESTRICT const instance,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response,
- const struct sockaddr *originator_address,
- const CipSessionHandle encapsulation_session) {
- /* Suppress unused parameter compiler warning. */
- (void)originator_address;
- (void)encapsulation_session;
- CipAttributeStruct *attribute = GetCipAttribute(instance,
- message_router_request->request_path.attribute_number);
- GenerateSetAttributeSingleHeader(message_router_request,
- message_router_response);
- EipUint16 attribute_number =
- message_router_request->request_path.attribute_number;
- /* Mask for filtering set-ability */
- if( (NULL != attribute) && (NULL != attribute->data) ) {
- if( (attribute->attribute_flags == kGetableAllDummy) ||
- (attribute->attribute_flags == kNotSetOrGetable) ||
- (attribute->attribute_flags == kGetableAll) ) {
- OPENER_TRACE_WARN("SetAttributeSingle: Attribute %d not supported!\n\r",
- attribute_number);
- } else {
- uint8_t set_bit_mask =
- (instance->cip_class->set_bit_mask[CalculateIndex(attribute_number)]);
- if( 0 != ( set_bit_mask & ( 1 << (attribute_number % 8) ) ) ) {
- OPENER_TRACE_INFO("setAttribute %d\n", attribute_number);
- /* Call the PreSetCallback if enabled for this attribute and the class provides one. */
- if( (attribute->attribute_flags & kPreSetFunc) &&
- NULL != instance->cip_class->PreSetCallback ) {
- instance->cip_class->PreSetCallback(instance,
- attribute,
- message_router_request->service);
- }
- OPENER_ASSERT(NULL != attribute);
- attribute->decode(attribute->data,
- message_router_request,
- message_router_response); //writes data to attribute, sets resonse status
- /* Call the PostSetCallback if enabled for this attribute and the class provides one. */
- if( ( attribute->attribute_flags & (kPostSetFunc | kNvDataFunc) ) &&
- NULL != instance->cip_class->PostSetCallback ) {
- instance->cip_class->PostSetCallback(instance,
- attribute,
- message_router_request->service);
- }
- } else {
- message_router_response->general_status = kCipErrorAttributeNotSetable;
- OPENER_TRACE_WARN("SetAttributeSingle: Attribute %d not setable!\n\r",
- attribute_number);
- }
- }
- }
- return kEipStatusOkSend;
- }
- int DecodeCipBool(CipBool *const data,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- *data = GetBoolFromMessage(&message_router_request->data);
- message_router_response->general_status = kCipErrorSuccess;
- return 1;
- }
- int DecodeCipByte(CipByte *const data,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- *data = GetByteFromMessage(&message_router_request->data);
- message_router_response->general_status = kCipErrorSuccess;
- return 1;
- }
- int DecodeCipByteArray(CipByteArray *const data,
- const CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response)
- {
- int number_of_decoded_bytes = -1;
- OPENER_TRACE_INFO(" -> set attribute byte array\r\n");
- CipByteArray *cip_byte_array = data;
- if(message_router_request->request_data_size < data->length) {
- OPENER_TRACE_INFO(
- "DecodeCipByteArray: not enough data received.\n");
- message_router_response->general_status = kCipErrorNotEnoughData;
- return number_of_decoded_bytes;
- }
- if(message_router_request->request_data_size > data->length) {
- OPENER_TRACE_INFO(
- "DecodeCipByteArray: too much data received.\n");
- message_router_response->general_status = kCipErrorTooMuchData;
- return number_of_decoded_bytes;
- }
- // data-length is correct
- memcpy(cip_byte_array->data,
- message_router_request->data,
- cip_byte_array->length);
- number_of_decoded_bytes = cip_byte_array->length;
- message_router_response->general_status = kCipErrorSuccess;
- return number_of_decoded_bytes;
- }
- int DecodeCipWord(CipWord *const data,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- *data = GetWordFromMessage(&message_router_request->data);
- message_router_response->general_status = kCipErrorSuccess;
- return 2;
- }
- int DecodeCipDword(CipDword *const data,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- *data = GetDintFromMessage(&message_router_request->data);
- message_router_response->general_status = kCipErrorSuccess;
- return 4;
- }
- int DecodeCipLword(CipLword *const data,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- *data = GetLintFromMessage(&message_router_request->data);
- message_router_response->general_status = kCipErrorSuccess;
- return 4;
- }
- int DecodeCipUsint(CipUsint *const data,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- *data = GetUsintFromMessage(&message_router_request->data);
- message_router_response->general_status = kCipErrorSuccess;
- return 1;
- }
- int DecodeCipUint(CipUint *const data,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- *data = GetUintFromMessage(&message_router_request->data);
- message_router_response->general_status = kCipErrorSuccess;
- return 2;
- }
- int DecodeCipUdint(CipUdint *const data,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- *data = GetUdintFromMessage(&message_router_request->data);
- message_router_response->general_status = kCipErrorSuccess;
- return 4;
- }
- int DecodeCipUlint(CipUlint *const data,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- *data = GetLintFromMessage(&message_router_request->data);
- message_router_response->general_status = kCipErrorSuccess;
- return 8;
- }
- int DecodeCipSint(CipSint *const data,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- *data = GetSintFromMessage(&message_router_request->data);
- message_router_response->general_status = kCipErrorSuccess;
- return 1;
- }
- int DecodeCipInt(CipInt *const data,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- *data = GetIntFromMessage(&message_router_request->data);
- message_router_response->general_status = kCipErrorSuccess;
- return 2;
- }
- int DecodeCipDint(CipDint *const data,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- *data = GetDintFromMessage(&message_router_request->data);
- message_router_response->general_status = kCipErrorSuccess;
- return 4;
- }
- int DecodeCipLint(CipLint *const data,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- *data = GetLintFromMessage(&message_router_request->data);
- message_router_response->general_status = kCipErrorSuccess;
- return 8;
- }
- int DecodeCipReal(CipReal *const data,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- *data = GetDintFromMessage(&message_router_request->data);
- message_router_response->general_status = kCipErrorSuccess;
- return 4;
- }
- int DecodeCipLreal(CipLreal *const data,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- *data = GetLintFromMessage(&message_router_request->data);
- message_router_response->general_status = kCipErrorSuccess;
- return 8;
- }
- int DecodeCipString(CipString *const data,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- int number_of_decoded_bytes = -1;
- CipString *string = data;
- const CipUint length = GetUintFromMessage(&message_router_request->data);
- string = SetCipStringByData(string, length, message_router_request->data);
- const CipOctet **const buffer_address = &message_router_request->data;
- *buffer_address += string->length;
- number_of_decoded_bytes = string->length + 2; /* we have a two byte length field */
- if(number_of_decoded_bytes & 0x01) {
- /* we have an odd byte count */
- ++(*buffer_address);
- number_of_decoded_bytes++;
- }
- message_router_response->general_status = kCipErrorSuccess;
- return number_of_decoded_bytes;
- }
- int DecodeCipShortString(CipShortString *data,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response)
- {
- int number_of_decoded_bytes = -1;
- CipShortString *short_string = data;
- const CipUsint length = GetUsintFromMessage(&message_router_request->data);
- short_string = SetCipShortStringByData(short_string,
- length,
- message_router_request->data);
- const CipOctet **const buffer_address = &message_router_request->data;
- *buffer_address += short_string->length;
- number_of_decoded_bytes = short_string->length + 1; /* we have a one byte length field */
- message_router_response->general_status = kCipErrorSuccess;
- return number_of_decoded_bytes;
- }
- CipServiceStruct *GetCipService(const CipInstance *const instance,
- CipUsint service_number) {
- CipServiceStruct *service = instance->cip_class->services;
- for(size_t i = 0; i < instance->cip_class->number_of_services; i++) /* hunt for the GET_ATTRIBUTE_SINGLE service*/
- {
- if(service->service_number == service_number) {
- return service; /* found the service */
- }
- service++;
- }
- return NULL; /* didn't find the service */
- }
- EipStatus GetAttributeAll(CipInstance *instance,
- CipMessageRouterRequest *message_router_request,
- CipMessageRouterResponse *message_router_response,
- const struct sockaddr *originator_address,
- const CipSessionHandle encapsulation_session) {
- /* Suppress unused parameter compiler warning. */
- (void)originator_address;
- (void)encapsulation_session;
- InitializeENIPMessage(&message_router_response->message);
- CipAttributeStruct *attribute = instance->attributes; /* pointer to list of attributes*/
- //Missing header
- if(0 == instance->cip_class->number_of_attributes) {
- /*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 */
- 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 */
- message_router_request->request_path.attribute_number =
- attribute_number;
- attribute->encode(attribute->data, &message_router_response->message);
- }
- attribute++;
- }
- }
- return kEipStatusOkSend;
- }
- EipStatus GetAttributeList(CipInstance *instance,
- CipMessageRouterRequest *message_router_request,
- CipMessageRouterResponse *message_router_response,
- const struct sockaddr *originator_address,
- const CipSessionHandle encapsulation_session) {
- /* Suppress unused parameter compiler warning. */
- (void)originator_address;
- (void)encapsulation_session;
- InitializeENIPMessage(&message_router_response->message);
- message_router_response->reply_service =
- (0x80 | message_router_request->service);
- message_router_response->general_status = kCipErrorSuccess;
- message_router_response->size_of_additional_status = 0;
- CipUint attribute_count_request = GetUintFromMessage(
- &message_router_request->data);
- if(0 != attribute_count_request) {
- EipUint16 attribute_number = 0;
- CipAttributeStruct *attribute = NULL;
- CipOctet *attribute_count_responst_position =
- message_router_response->message.current_message_position;
- MoveMessageNOctets(sizeof(CipInt), &message_router_response->message); // move the message pointer to reserve memory
- for(size_t j = 0; j < attribute_count_request; j++) {
- attribute_number = GetUintFromMessage(&message_router_request->data);
- attribute = GetCipAttribute(instance, attribute_number);
- const int_fast64_t needed_message_space = NULL != attribute
- ? (int_fast64_t) GetCipDataTypeLength(attribute->type,
- attribute->data) : (int_fast64_t) (
- 2
- *
- sizeof(
- CipSint) );
- const int_fast64_t remaining_message_space =
- (int_fast64_t) PC_OPENER_ETHERNET_BUFFER_SIZE -
- (int_fast64_t) message_router_response->message.used_message_length -
- 33LL; //need 33 bytes extra space for the rest of the ENIP message
- if (needed_message_space > remaining_message_space) {
- message_router_response->message.used_message_length -= 2; // Correct count from Move above
- CipOctet *const save_current_position =
- message_router_response->message.current_message_position;
- message_router_response->message.current_message_position =
- attribute_count_responst_position;
- AddIntToMessage(attribute_count_request,
- &message_router_response
- ->message); // Add current amount of attributes
- message_router_response->message.current_message_position =
- save_current_position;
- // If there was not alreay an attribute list error, resturn partial
- // transfer
- if (message_router_response->general_status !=
- kCipErrorAttributeListError) {
- message_router_response->general_status = kCipErrorPartialTransfer;
- }
- return kEipStatusOkSend;
- }
- AddIntToMessage(attribute_number, &message_router_response->message); // Attribute-ID
- if(NULL != attribute) {
- uint8_t get_bit_mask =
- (instance->cip_class->get_single_bit_mask[CalculateIndex(
- attribute_number)]);
- if( 0 != ( get_bit_mask & ( 1 << (attribute_number % 8) ) ) ) { //check if attribute is gettable
- AddSintToMessage(kCipErrorSuccess, &message_router_response->message); // Attribute status
- AddSintToMessage(0, &message_router_response->message); // Reserved, shall be 0
- attribute->encode(attribute->data, &message_router_response->message); // write Attribute data to response
- } else {
- AddSintToMessage(kCipErrorAttributeNotGettable,
- &message_router_response->message); // Attribute status
- AddSintToMessage(0, &message_router_response->message); // Reserved, shall be 0
- message_router_response->general_status = kCipErrorAttributeListError;
- }
- } else {
- AddSintToMessage(kCipErrorAttributeNotSupported,
- &message_router_response->message); // status
- AddSintToMessage(0, &message_router_response->message); // Reserved, shall be 0
- message_router_response->general_status = kCipErrorAttributeListError;
- }
- }
- // If we are there, we returned all elements
- message_router_response->message.used_message_length -= 2; // Correct count from Move above
- CipOctet *const save_current_position =
- message_router_response->message.current_message_position;
- message_router_response->message.current_message_position =
- attribute_count_responst_position;
- AddIntToMessage(
- attribute_count_request,
- &message_router_response->message); // Add current amount of attributes
- message_router_response->message.current_message_position =
- save_current_position;
- } else {
- message_router_response->general_status = kCipErrorAttributeListError;
- }
- return kEipStatusOkSend;
- }
- EipStatus SetAttributeList(CipInstance *instance,
- CipMessageRouterRequest *message_router_request,
- CipMessageRouterResponse *message_router_response,
- const struct sockaddr *originator_address,
- const CipSessionHandle encapsulation_session) {
- /* Suppress unused parameter compiler warning. */
- (void)originator_address;
- (void)encapsulation_session;
- InitializeENIPMessage(&message_router_response->message);
- message_router_response->reply_service =
- (0x80 | message_router_request->service);
- message_router_response->general_status = kCipErrorSuccess;
- message_router_response->size_of_additional_status = 0;
- CipUint attribute_count_request = GetUintFromMessage(
- &message_router_request->data);
- if(0 != attribute_count_request) {
- EipUint16 attribute_number = 0;
- CipAttributeStruct *attribute = NULL;
- CipOctet *attribute_count_responst_position =
- message_router_response->message.current_message_position;
- MoveMessageNOctets(sizeof(CipInt), &message_router_response->message); // move the message pointer to reserve memory
- for(size_t j = 0; j < attribute_count_request; j++) {
- attribute_number = GetUintFromMessage(&message_router_request->data);
- attribute = GetCipAttribute(instance, attribute_number);
- const int_fast64_t needed_message_space = NULL != attribute
- ? (int_fast64_t) GetCipDataTypeLength(attribute->type,
- attribute->data) : (int_fast64_t) (
- 2
- *
- sizeof(
- CipSint) );
- const int_fast64_t remaining_message_space =
- (int_fast64_t) PC_OPENER_ETHERNET_BUFFER_SIZE -
- (int_fast64_t) message_router_response->message.used_message_length -
- 33LL; //need 33 bytes extra space for the rest of the ENIP message
- if (needed_message_space > remaining_message_space) {
- message_router_response->message.used_message_length -= 2; // Correct count from Move above
- CipOctet *const save_current_position =
- message_router_response->message.current_message_position;
- message_router_response->message.current_message_position =
- attribute_count_responst_position;
- AddIntToMessage(attribute_count_request,
- &message_router_response
- ->message); // Add current amount of attributes
- message_router_response->message.current_message_position =
- save_current_position;
- // If there was not alreay an attribute list error, resturn partial
- // transfer
- if (message_router_response->general_status !=
- kCipErrorAttributeListError) {
- message_router_response->general_status = kCipErrorPartialTransfer;
- }
- return kEipStatusOkSend;
- }
- AddIntToMessage(attribute_number, &message_router_response->message); // Attribute-ID
- if(NULL != attribute) {
- uint8_t set_bit_mask =
- (instance->cip_class->set_bit_mask[CalculateIndex(attribute_number)]);
- if( 0 != ( set_bit_mask & ( 1 << (attribute_number % 8) ) ) ) { //check if attribute is settable
- AddSintToMessage(kCipErrorSuccess, &message_router_response->message); // Attribute status
- AddSintToMessage(0, &message_router_response->message); // Reserved, shall be 0
- attribute->decode(attribute->data,
- message_router_request,
- message_router_response); // write data to attribute
- } else {
- AddSintToMessage(kCipErrorAttributeNotSetable,
- &message_router_response->message); // Attribute status
- AddSintToMessage(0, &message_router_response->message); // Reserved, shall be 0
- //move request message pointer
- size_t attribute_data_length = GetCipDataTypeLength(attribute->type,
- message_router_request->data);
- if(0 != attribute_data_length) {
- message_router_request->data += attribute_data_length;
- message_router_response->general_status =
- kCipErrorAttributeListError;
- } else {
- message_router_response->general_status = kCipErrorPartialTransfer;
- return kEipStatusOkSend;
- }
- }
- } else {
- AddSintToMessage(kCipErrorAttributeNotSupported,
- &message_router_response->message); // status
- AddSintToMessage(0, &message_router_response->message); // Reserved, shall be 0
- message_router_response->general_status = kCipErrorAttributeListError;
- }
- }
- // If we are there, we returned all elements
- message_router_response->message.used_message_length -=
- 2; // Correct count from Move above
- CipOctet *const save_current_position =
- message_router_response->message.current_message_position;
- message_router_response->message.current_message_position =
- attribute_count_responst_position;
- AddIntToMessage(
- attribute_count_request,
- &message_router_response->message); // Add current amount of attributes
- message_router_response->message.current_message_position =
- save_current_position;
- } else {
- message_router_response->general_status = kCipErrorAttributeListError;
- }
- return kEipStatusOkSend;
- }
- void EncodeEPath(const void *const data,
- ENIPMessage *const message) {
- const CipEpath *const epath = (CipEpath *)data;
- unsigned int length = epath->path_size;
- size_t start_length = message->used_message_length;
- if(epath->class_id < 256) {
- AddSintToMessage(0x20, message); /* 8 Bit Class Id */
- AddSintToMessage( (EipUint8) epath->class_id, message );
- length -= 1;
- } else {
- 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) {
- AddSintToMessage(0x24, message); /*8Bit Instance Id */
- AddSintToMessage( (EipUint8)epath->instance_number, message );
- length -= 1;
- } else {
- 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) {
- AddSintToMessage(0x30, message); /*8Bit Attribute Id */
- AddSintToMessage(epath->attribute_number, message);
- length -= 1;
- } else {
- AddSintToMessage(0x31, message); /*16Bit Attribute Id */
- AddSintToMessage(0, message); /*pad byte */
- AddIntToMessage(epath->attribute_number, message);
- length -= 2;
- }
- }
- }
- /* path size is in 16 bit chunks according to the specification */
- OPENER_ASSERT(
- epath->path_size * sizeof(CipWord) ==
- message->used_message_length - start_length);
- }
- int DecodePaddedEPath(CipEpath *epath,
- const EipUint8 **message) {
- unsigned int number_of_decoded_elements = 0;
- const EipUint8 *message_runner = *message;
- epath->path_size = *message_runner;
- message_runner++;
- /* copy path to structure, in version 0.1 only 8 bit for Class,Instance and Attribute, need to be replaced with function */
- epath->class_id = 0;
- epath->instance_number = 0;
- epath->attribute_number = 0;
- while(number_of_decoded_elements < epath->path_size) {
- if( kSegmentTypeReserved == ( (*message_runner) & kSegmentTypeReserved ) ) {
- /* If invalid/reserved segment type, segment type greater than 0xE0 */
- return kEipStatusError;
- }
- number_of_decoded_elements++; /*At least one element is decoded */
- switch(*message_runner) {
- case SEGMENT_TYPE_LOGICAL_SEGMENT + LOGICAL_SEGMENT_TYPE_CLASS_ID +
- LOGICAL_SEGMENT_FORMAT_EIGHT_BIT:
- epath->class_id = *(EipUint8 *) (message_runner + 1);
- message_runner += 2;
- break;
- case SEGMENT_TYPE_LOGICAL_SEGMENT + LOGICAL_SEGMENT_TYPE_CLASS_ID +
- LOGICAL_SEGMENT_FORMAT_SIXTEEN_BIT:
- message_runner += 2;
- epath->class_id = GetUintFromMessage( &(message_runner) );
- number_of_decoded_elements++;
- break;
- case SEGMENT_TYPE_LOGICAL_SEGMENT + LOGICAL_SEGMENT_TYPE_INSTANCE_ID +
- LOGICAL_SEGMENT_FORMAT_EIGHT_BIT:
- epath->instance_number = *(EipUint8 *) (message_runner + 1);
- message_runner += 2;
- break;
- case SEGMENT_TYPE_LOGICAL_SEGMENT + LOGICAL_SEGMENT_TYPE_INSTANCE_ID +
- LOGICAL_SEGMENT_FORMAT_SIXTEEN_BIT:
- message_runner += 2;
- epath->instance_number = GetUintFromMessage( &(message_runner) );
- number_of_decoded_elements++;
- break;
- case SEGMENT_TYPE_LOGICAL_SEGMENT + LOGICAL_SEGMENT_TYPE_ATTRIBUTE_ID +
- LOGICAL_SEGMENT_FORMAT_EIGHT_BIT:
- epath->attribute_number = *(EipUint8 *) (message_runner + 1);
- message_runner += 2;
- break;
- case SEGMENT_TYPE_LOGICAL_SEGMENT + LOGICAL_SEGMENT_TYPE_ATTRIBUTE_ID +
- LOGICAL_SEGMENT_FORMAT_SIXTEEN_BIT:
- message_runner += 2;
- epath->attribute_number = GetUintFromMessage( &(message_runner) );
- number_of_decoded_elements++;
- break;
- case SEGMENT_TYPE_LOGICAL_SEGMENT + LOGICAL_SEGMENT_TYPE_MEMBER_ID +
- LOGICAL_SEGMENT_FORMAT_EIGHT_BIT:
- message_runner += 2;
- break;
- case SEGMENT_TYPE_LOGICAL_SEGMENT + LOGICAL_SEGMENT_TYPE_MEMBER_ID +
- LOGICAL_SEGMENT_FORMAT_SIXTEEN_BIT:
- message_runner += 2;
- number_of_decoded_elements++;
- break;
- default:
- OPENER_TRACE_ERR("wrong path requested\n");
- return kEipStatusError;
- }
- }
- *message = message_runner;
- return number_of_decoded_elements * 2 + 1; /* number_of_decoded_elements times 2 as every encoding uses 2 bytes */
- }
- EipStatus CipCreateService(CipInstance *RESTRICT const instance,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response,
- const struct sockaddr *originator_address,
- const CipSessionHandle encapsulation_session) {
- /* Suppress unused parameter compiler warning. */
- (void)originator_address;
- (void)encapsulation_session;
- InitializeENIPMessage(&message_router_response->message);
- message_router_response->reply_service =
- (0x80 | message_router_request->service);
- message_router_response->general_status = kCipErrorSuccess;
- message_router_response->size_of_additional_status = 0;
- CipClass *class = GetCipClass(message_router_request->request_path.class_id);
- EipStatus internal_state = kEipStatusOk;
- /* Call the PreCreateCallback if the class provides one. */
- if( NULL != class->PreCreateCallback) {
- internal_state = class->PreCreateCallback(instance,
- message_router_request,
- message_router_response);
- }
- if (kEipStatusOk == internal_state) {
- CipInstance *new_instance = AddCipInstances(class, 1); /* add 1 instance to class*/
- OPENER_ASSERT(NULL != new_instance); /* fail if run out of memory */
- /* Call the PostCreateCallback if the class provides one. */
- if (NULL != class->PostCreateCallback) {
- class->PostCreateCallback(new_instance,
- message_router_request,
- message_router_response);
- }
- OPENER_TRACE_INFO("Instance number %d created\n",
- new_instance->instance_number);
- }
- return kEipStatusOkSend;
- }
- EipStatus CipDeleteService(CipInstance *RESTRICT const instance,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response,
- const struct sockaddr *originator_address,
- const CipSessionHandle encapsulation_session) {
- /* Suppress unused parameter compiler warning. */
- (void)originator_address;
- (void)encapsulation_session;
- message_router_response->general_status = kCipErrorInstanceNotDeletable;
- message_router_response->size_of_additional_status = 0;
- InitializeENIPMessage(&message_router_response->message);
- message_router_response->reply_service =
- (0x80 | message_router_request->service);
- EipStatus internal_state = kEipStatusOk;
- CipClass *const class = instance->cip_class;
- /* Call the PreDeleteCallback if the class provides one. */
- if (NULL != class->PreDeleteCallback) {
- internal_state = class->PreDeleteCallback(instance, message_router_request,
- message_router_response);
- }
- if (kEipStatusOk == internal_state) {
- CipInstance *instances = class->instances;
- // update pointers in instance list
- instances = class->instances; /* pointer to first instance */
- if (instances->instance_number ==
- instance->instance_number) { // if instance to delete is head
- class->instances = instances->next;
- } else {
- while (NULL != instances->next) // as long as pointer in not NULL
- {
- CipInstance *next_instance = instances->next;
- if (next_instance->instance_number == instance->instance_number) {
- instances->next = next_instance->next;
- break;
- }
- instances = instances->next;
- }
- }
- /* Call the PostDeleteCallback if the class provides one. */
- if (NULL != class->PostDeleteCallback) {
- class->PostDeleteCallback(instance, message_router_request,
- message_router_response);
- }
- CipFree(instance); // delete instance
- class->number_of_instances--; /* update the total number of instances
- recorded by the class - Attr. 3 */
- class->max_instance = GetMaxInstanceNumber(class); /* update largest instance number (class Attribute 2) */
- message_router_response->general_status = kCipErrorSuccess;
- }
- return kEipStatusOk;
- }
- EipStatus CipResetService(CipInstance *RESTRICT const instance,
- CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response,
- const struct sockaddr *originator_address,
- const CipSessionHandle encapsulation_session) {
- /* Suppress unused parameter compiler warning. */
- (void)originator_address;
- (void)encapsulation_session;
- message_router_response->general_status = kCipErrorSuccess;
- message_router_response->size_of_additional_status = 0;
- InitializeENIPMessage(&message_router_response->message);
- message_router_response->reply_service =
- (0x80 | message_router_request->service);
- EipStatus internal_state = kEipStatusOk;
- CipClass *const class = instance->cip_class;
- /* Call the PreResetCallback if the class provides one. */
- if (NULL != class->PreResetCallback) {
- internal_state = class->PreResetCallback(instance, message_router_request,
- message_router_response);
- }
- if (kEipStatusError != internal_state) {
- /* Call the PostResetCallback if the class provides one. */
- if (NULL != class->PostResetCallback) {
- class->PostResetCallback(instance, message_router_request,
- message_router_response);
- }
- }
- return internal_state;
- }
- void AllocateAttributeMasks(CipClass *target_class) {
- size_t size = 1 + CalculateIndex(target_class->highest_attribute_number);
- OPENER_TRACE_INFO(
- ">>> Allocate memory for %s %zu bytes times 3 for masks\n",
- target_class->class_name, size);
- target_class->get_single_bit_mask = CipCalloc( size, sizeof(uint8_t) );
- target_class->set_bit_mask = CipCalloc( size, sizeof(uint8_t) );
- target_class->get_all_bit_mask = CipCalloc( size, sizeof(uint8_t) );
- }
- size_t CalculateIndex(EipUint16 attribute_number) {
- size_t index = attribute_number / 8;
- return index;
- }
|