/************************************************************************************** Copyright (c) Hilscher Gesellschaft fuer Systemautomation mbH. All Rights Reserved. *************************************************************************************** $Id: Cip_ConnectionPath.c 98860 2021-03-08 10:41:03Z KMichel $: Description: This file contains all functions that are related to the encapsulation inactivity timer state machine. **************************************************************************************/ #define __CIP_CONNECTION_PATH_C /*######################################################################################*/ /* ___ _ _ */ /* |_ _|_ __ ___| |_ _ __| | ___ ___ */ /* | || '_ \ / __| | | | |/ _` |/ _ \/ __| */ /* | || | | | (__| | |_| | (_| | __/\__ \ */ /* |___|_| |_|\___|_|\__,_|\__,_|\___||___/ */ /*######################################################################################*/ #include "Cip_ConnectionPath.h" #include "EipObject_Includes.h" #if defined(EIP_UNIT_TESTS_ACTIVATED) /*######################################################################################*/ /* _____ _ ____ _ */ /* |_ _|__ ___| |_ | _ \ __ _| |_ __ _ */ /* | |/ _ \/ __| __| | | | |/ _` | __/ _` | */ /* | | __/\__ \ |_ | |_| | (_| | || (_| | */ /* |_|\___||___/\__| |____/ \__,_|\__\__,_| */ /*######################################################################################*/ /* More information about the test data can be found in the file ConnectionPath_TestData.xls in folder "Doc" */ /* Valid connection paths */ static uint8_t abValidConnPaths_00[] = {0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04, 0x24, 0x01, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03}; static uint8_t abValidConnPaths_01[] = {0x20, 0x04, 0x24, 0x66, 0x2C, 0x64, 0x2C, 0x65, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abValidConnPaths_02[] = {0x20, 0x04, 0x24, 0x66, 0x2C, 0x64, 0x2C, 0x65, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abValidConnPaths_03[] = {0x20, 0x04, 0x24, 0x66, 0x24, 0x64, 0x24, 0x65, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abValidConnPaths_04[] = {0x20, 0x04, 0x24, 0x66, 0x24, 0x64, 0x24, 0x65, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abValidConnPaths_05[] = {0x20, 0x04, 0x2C, 0x01, 0x20, 0x04, 0x2C, 0x64, 0x20, 0x04, 0x2C, 0x65}; static uint8_t abValidConnPaths_06[] = {0x20, 0x04, 0x24, 0x01, 0x30, 0x03, 0x30, 0x03, 0x30, 0x03}; static uint8_t abValidConnPaths_07[] = {0x20, 0x04, 0x24, 0x01, 0x30, 0x03, 0x24, 0x64, 0x30, 0x03, 0x24, 0x65, 0x30, 0x03}; static uint8_t abValidConnPaths_08[] = {0x20, 0x04, 0x24, 0x01, 0x30, 0x03, 0x24, 0x64, 0x30, 0x03, 0x24, 0x65, 0x30, 0x03}; static uint8_t abValidConnPaths_09[] = {0x20, 0x04, 0x24, 0x66, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abValidConnPaths_10[] = {0x20, 0x04, 0x24, 0x66, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abValidConnPaths_11[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abValidConnPaths_12[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abValidConnPaths_13[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x30, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abValidConnPaths_14[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x30, 0x03, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abValidConnPaths_15[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x24, 0x64, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abValidConnPaths_16[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x24, 0x64, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abValidConnPaths_17[] = {0x43, 0x64, 0x43, 0x64, 0x20, 0x04, 0x24, 0x64}; static uint8_t abValidConnPaths_18[] = {0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, 0x20, 0x04, 0x24, 0x64}; static uint8_t abValidConnPaths_19[] = {0x20, 0x04, 0x24, 0x66, 0x2C, 0x64, 0x2C, 0x65, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abValidConnPaths_20[] = {0x20, 0x04, 0x24, 0x66, 0x24, 0x64, 0x24, 0x65, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abValidConnPaths_21[] = {0x20, 0x04, 0x24, 0x66, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abValidConnPaths_22[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abValidConnPaths_23[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x30, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abValidConnPaths_24[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x24, 0x64, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; /* Array of valid connection paths */ static uint8_t* apbValidConnPaths[] = { abValidConnPaths_00, abValidConnPaths_01, abValidConnPaths_02, abValidConnPaths_03, abValidConnPaths_04, abValidConnPaths_05, abValidConnPaths_06, abValidConnPaths_07, abValidConnPaths_08, abValidConnPaths_09, abValidConnPaths_10, abValidConnPaths_11, abValidConnPaths_12, abValidConnPaths_13, abValidConnPaths_14, abValidConnPaths_15, abValidConnPaths_16, abValidConnPaths_17, abValidConnPaths_18, abValidConnPaths_19, abValidConnPaths_20, abValidConnPaths_21, abValidConnPaths_22, abValidConnPaths_23, abValidConnPaths_24 }; /* Array of valid connection paths lengths (word size) */ static uint32_t aulValidConnPathsLen[] = { sizeof( abValidConnPaths_00) / 2, sizeof( abValidConnPaths_01) / 2, sizeof( abValidConnPaths_02) / 2, sizeof( abValidConnPaths_03) / 2, sizeof( abValidConnPaths_04) / 2, sizeof( abValidConnPaths_05) / 2, sizeof( abValidConnPaths_06) / 2, sizeof( abValidConnPaths_07) / 2, sizeof( abValidConnPaths_08) / 2, sizeof( abValidConnPaths_09) / 2, sizeof( abValidConnPaths_10) / 2, sizeof( abValidConnPaths_11) / 2, sizeof( abValidConnPaths_12) / 2, sizeof( abValidConnPaths_13) / 2, sizeof( abValidConnPaths_14) / 2, sizeof( abValidConnPaths_15) / 2, sizeof( abValidConnPaths_16) / 2, sizeof( abValidConnPaths_17) / 2, sizeof( abValidConnPaths_18) / 2, sizeof( abValidConnPaths_19) / 2, sizeof( abValidConnPaths_20) / 2, sizeof( abValidConnPaths_21) / 2, sizeof( abValidConnPaths_22) / 2, sizeof( abValidConnPaths_23) / 2, sizeof( abValidConnPaths_24) / 2}; /* Invalid connection paths (see ConnectionPath_TestData.xls in folder "Doc") */ /* Idle: */ static uint8_t abInvalidConnPaths_00[] = {0x24, 0x01}; static uint8_t abInvalidConnPaths_01[] = {0x2C, 0x64}; static uint8_t abInvalidConnPaths_02[] = {0x30, 0x03}; static uint8_t abInvalidConnPaths_03[] = {0x80, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_04[] = {0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; /* Electronic Key: */ static uint8_t abInvalidConnPaths_05[] = {0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_06[] = {0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x64}; static uint8_t abInvalidConnPaths_07[] = {0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x64}; static uint8_t abInvalidConnPaths_08[] = {0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x03}; static uint8_t abInvalidConnPaths_09[] = {0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_10[] = {0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; /* NETWORK: */ static uint8_t abInvalidConnPaths_11[] = {0x43, 0x64, 0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_12[] = {0x43, 0x64, 0x24, 0x64}; static uint8_t abInvalidConnPaths_13[] = {0x43, 0x64, 0x2C, 0x64}; static uint8_t abInvalidConnPaths_14[] = {0x43, 0x64, 0x30, 0x03}; static uint8_t abInvalidConnPaths_15[] = {0x43, 0x64, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_16[] = {0x43, 0x64, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; /* App_Path1 - Class: */ static uint8_t abInvalidConnPaths_17[] = {0x20, 0x04, 0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_18[] = {0x20, 0x04, 0x43, 0x64}; static uint8_t abInvalidConnPaths_19[] = {0x20, 0x04, 0x20, 0x04}; static uint8_t abInvalidConnPaths_20[] = {0x20, 0x04, 0x30, 0x03}; static uint8_t abInvalidConnPaths_21[] = {0x20, 0x04, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_22[] = {0x20, 0x04, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; /* App_Path1 - Instance: */ static uint8_t abInvalidConnPaths_23[] = {0x20, 0x04, 0x24, 0x66, 0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_24[] = {0x20, 0x04, 0x24, 0x66, 0x43, 0x64}; /* App_Path1 - Attribute: */ static uint8_t abInvalidConnPaths_25[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_26[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x43, 0x64}; /* App_Path2 - Class: */ static uint8_t abInvalidConnPaths_27[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_28[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x43, 0x64}; static uint8_t abInvalidConnPaths_29[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x20, 0x04}; static uint8_t abInvalidConnPaths_30[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x30, 0x03}; static uint8_t abInvalidConnPaths_31[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_32[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; /* App_Path2 - Instance: */ static uint8_t abInvalidConnPaths_33[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_34[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x43, 0x64}; /* App_Path2 - Attribute: */ static uint8_t abInvalidConnPaths_35[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_36[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x43, 0x64}; /* App_Path3 - Class: */ static uint8_t abInvalidConnPaths_37[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_38[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x43, 0x64}; static uint8_t abInvalidConnPaths_39[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x20, 0x04}; static uint8_t abInvalidConnPaths_40[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x30, 0x03}; static uint8_t abInvalidConnPaths_41[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_42[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; /* App_Path3 - Instance: */ static uint8_t abInvalidConnPaths_43[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_44[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x43, 0x64}; static uint8_t abInvalidConnPaths_45[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x20, 0x04}; static uint8_t abInvalidConnPaths_46[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x24, 0x65}; static uint8_t abInvalidConnPaths_47[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x2C, 0x65}; /* App_Path3 - Attribute: */ static uint8_t abInvalidConnPaths_48[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_49[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x43, 0x64}; static uint8_t abInvalidConnPaths_50[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x20, 0x04}; static uint8_t abInvalidConnPaths_51[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x24, 0x65}; static uint8_t abInvalidConnPaths_52[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x2C, 0x65}; static uint8_t abInvalidConnPaths_53[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x30, 0x03}; /* Configuration: */ static uint8_t abInvalidConnPaths_54[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_55[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64}; static uint8_t abInvalidConnPaths_56[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04}; static uint8_t abInvalidConnPaths_57[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x24, 0x65}; static uint8_t abInvalidConnPaths_58[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x65}; static uint8_t abInvalidConnPaths_59[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x30, 0x03}; static uint8_t abInvalidConnPaths_60[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00}; /* Safety: */ static uint8_t abInvalidConnPaths_61[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_62[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64}; static uint8_t abInvalidConnPaths_63[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04}; static uint8_t abInvalidConnPaths_64[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00, 0x24, 0x65}; static uint8_t abInvalidConnPaths_65[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x65}; static uint8_t abInvalidConnPaths_66[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00, 0x30, 0x03}; static uint8_t abInvalidConnPaths_67[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00}; static uint8_t abInvalidConnPaths_68[] = {0x20, 0x04, 0x24, 0x66, 0x30, 0x03, 0x20, 0x04, 0x24, 0x64, 0x30, 0x03, 0x20, 0x04, 0x24, 0x65, 0x30, 0x03, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00}; /* Array of invalid connection paths */ static uint8_t* apbInvalidConnPaths[] = { abInvalidConnPaths_00, abInvalidConnPaths_01, abInvalidConnPaths_02, abInvalidConnPaths_03, abInvalidConnPaths_04, abInvalidConnPaths_05, abInvalidConnPaths_06, abInvalidConnPaths_07, abInvalidConnPaths_08, abInvalidConnPaths_09, abInvalidConnPaths_10, abInvalidConnPaths_11, abInvalidConnPaths_12, abInvalidConnPaths_13, abInvalidConnPaths_14, abInvalidConnPaths_15, abInvalidConnPaths_16, abInvalidConnPaths_17, abInvalidConnPaths_18, abInvalidConnPaths_19, abInvalidConnPaths_20, abInvalidConnPaths_21, abInvalidConnPaths_22, abInvalidConnPaths_23, abInvalidConnPaths_24, abInvalidConnPaths_25, abInvalidConnPaths_26, abInvalidConnPaths_27, abInvalidConnPaths_28, abInvalidConnPaths_29, abInvalidConnPaths_30, abInvalidConnPaths_31, abInvalidConnPaths_32, abInvalidConnPaths_33, abInvalidConnPaths_34, abInvalidConnPaths_35, abInvalidConnPaths_36, abInvalidConnPaths_37, abInvalidConnPaths_38, abInvalidConnPaths_39, abInvalidConnPaths_40, abInvalidConnPaths_41, abInvalidConnPaths_42, abInvalidConnPaths_43, abInvalidConnPaths_44, abInvalidConnPaths_45, abInvalidConnPaths_46, abInvalidConnPaths_47, abInvalidConnPaths_48, abInvalidConnPaths_49, abInvalidConnPaths_50, abInvalidConnPaths_51, abInvalidConnPaths_52, abInvalidConnPaths_53, abInvalidConnPaths_54, abInvalidConnPaths_55, abInvalidConnPaths_56, abInvalidConnPaths_57, abInvalidConnPaths_58, abInvalidConnPaths_59, abInvalidConnPaths_60, abInvalidConnPaths_61, abInvalidConnPaths_62, abInvalidConnPaths_63, abInvalidConnPaths_64, abInvalidConnPaths_65, abInvalidConnPaths_66, abInvalidConnPaths_67, abInvalidConnPaths_68 }; /* Array of invalid connection paths lengths (word size) */ static uint32_t aulInvalidConnPathsLen[] = { sizeof( abInvalidConnPaths_00) / 2, sizeof( abInvalidConnPaths_01) / 2, sizeof( abInvalidConnPaths_02) / 2, sizeof( abInvalidConnPaths_03) / 2, sizeof( abInvalidConnPaths_04) / 2, sizeof( abInvalidConnPaths_05) / 2, sizeof( abInvalidConnPaths_06) / 2, sizeof( abInvalidConnPaths_07) / 2, sizeof( abInvalidConnPaths_08) / 2, sizeof( abInvalidConnPaths_09) / 2, sizeof( abInvalidConnPaths_10) / 2, sizeof( abInvalidConnPaths_11) / 2, sizeof( abInvalidConnPaths_12) / 2, sizeof( abInvalidConnPaths_13) / 2, sizeof( abInvalidConnPaths_14) / 2, sizeof( abInvalidConnPaths_15) / 2, sizeof( abInvalidConnPaths_16) / 2, sizeof( abInvalidConnPaths_17) / 2, sizeof( abInvalidConnPaths_18) / 2, sizeof( abInvalidConnPaths_19) / 2, sizeof( abInvalidConnPaths_20) / 2, sizeof( abInvalidConnPaths_21) / 2, sizeof( abInvalidConnPaths_22) / 2, sizeof( abInvalidConnPaths_23) / 2, sizeof( abInvalidConnPaths_24) / 2, sizeof( abInvalidConnPaths_25) / 2, sizeof( abInvalidConnPaths_26) / 2, sizeof( abInvalidConnPaths_27) / 2, sizeof( abInvalidConnPaths_28) / 2, sizeof( abInvalidConnPaths_29) / 2, sizeof( abInvalidConnPaths_30) / 2, sizeof( abInvalidConnPaths_31) / 2, sizeof( abInvalidConnPaths_32) / 2, sizeof( abInvalidConnPaths_33) / 2, sizeof( abInvalidConnPaths_34) / 2, sizeof( abInvalidConnPaths_35) / 2, sizeof( abInvalidConnPaths_36) / 2, sizeof( abInvalidConnPaths_37) / 2, sizeof( abInvalidConnPaths_38) / 2, sizeof( abInvalidConnPaths_39) / 2, sizeof( abInvalidConnPaths_40) / 2, sizeof( abInvalidConnPaths_41) / 2, sizeof( abInvalidConnPaths_42) / 2, sizeof( abInvalidConnPaths_43) / 2, sizeof( abInvalidConnPaths_44) / 2, sizeof( abInvalidConnPaths_45) / 2, sizeof( abInvalidConnPaths_46) / 2, sizeof( abInvalidConnPaths_47) / 2, sizeof( abInvalidConnPaths_48) / 2, sizeof( abInvalidConnPaths_49) / 2, sizeof( abInvalidConnPaths_50) / 2, sizeof( abInvalidConnPaths_51) / 2, sizeof( abInvalidConnPaths_52) / 2, sizeof( abInvalidConnPaths_53) / 2, sizeof( abInvalidConnPaths_54) / 2, sizeof( abInvalidConnPaths_55) / 2, sizeof( abInvalidConnPaths_56) / 2, sizeof( abInvalidConnPaths_57) / 2, sizeof( abInvalidConnPaths_58) / 2, sizeof( abInvalidConnPaths_59) / 2, sizeof( abInvalidConnPaths_60) / 2, sizeof( abInvalidConnPaths_61) / 2, sizeof( abInvalidConnPaths_62) / 2, sizeof( abInvalidConnPaths_63) / 2, sizeof( abInvalidConnPaths_64) / 2, sizeof( abInvalidConnPaths_65) / 2, sizeof( abInvalidConnPaths_66) / 2, sizeof( abInvalidConnPaths_67) / 2, sizeof( abInvalidConnPaths_68) / 2 }; #endif /*#####################################################################################*/ /* ____ _ _ _ _____ _ _ */ /* / ___|| |_ __ _| |_(_) ___ | ___| _ _ __ ___| |_(_) ___ _ __ ___ */ /* \___ \| __/ _` | __| |/ __| | |_ | | | | '_ \ / __| __| |/ _ \| '_ \/ __| */ /* ___) | || (_| | |_| | (__ | _|| |_| | | | | (__| |_| | (_) | | | \__ \ */ /* |____/ \__\__,_|\__|_|\___| |_| \__,_|_| |_|\___|\__|_|\___/|_| |_|___/ */ /*#####################################################################################*/ /*************************************************************/ /* @brief: Puts a class segment into the connection path * * @param [in,out] ptConnPath - Pointer to connection path resources * @param [in] ulClass - Class segment value * * @return TLR_S_OK on success, otherwise an error code. */ static uint32_t CIP_ConnectionPath_Put_ClassSegment( CIP_CONNECTION_PATH_RSC_T* ptConnPath, uint32_t ulClass ); /*************************************************************/ /* @brief: Puts an instance segment into the connection path * * @param [in,out] ptConnPath - Pointer to connection path resources * @param [in] ulInstance - Instance segment value * * @return TLR_S_OK on success, otherwise an error code. */ static uint32_t CIP_ConnectionPath_Put_InstanceSegment( CIP_CONNECTION_PATH_RSC_T* ptConnPath, uint32_t ulInstance ); /*************************************************************/ /* @brief: Puts a connection point segment into the connection path * * @param [in,out] ptConnPath - Pointer to connection path resources * @param [in] ulConnPoint - Connection point segment value * * @return TLR_S_OK on success, otherwise an error code. */ static uint32_t CIP_ConnectionPath_Put_ConnectionPointSegment( CIP_CONNECTION_PATH_RSC_T* ptConnPath, uint32_t ulConnPoint ); /*************************************************************/ /* @brief: Puts an attribute segment into the connection path * * @param [in,out] ptConnPath - Pointer to connection path resources * @param [in] ulAttribute - Attribute segment value * * @return TLR_S_OK on success, otherwise an error code. */ static uint32_t CIP_ConnectionPath_Put_AttributeSegment( CIP_CONNECTION_PATH_RSC_T* ptConnPath, uint32_t ulAttribute ); /*************************************************************/ /* @brief: Puts an Electronic Key segment into the connection path * * @param [in,out] ptConnPath - Pointer to connection path resources * @param [in] ptElectronicKey - Pointer to Electronic Key data * * @return TLR_S_OK on success, otherwise an error code. */ static uint32_t CIP_ConnectionPath_Put_ElectronicKeySegment( CIP_CONNECTION_PATH_RSC_T* ptConnPath, EIP_CIP_EKEY_PACKED_T* ptElectronicKey ); /*************************************************************/ /* @brief: Puts a Network segment into the connection path * * @param [in,out] ptConnPath - Pointer to connection path resources * @param [in] eNetworkSegmentType - Network segment type * @param [in] ulByteSizeOfNetworkSegment - Byte size of network segment * @param [in] pbNetworkSegmentData - Pointer to Network segment data * * @return TLR_S_OK on success, otherwise an error code. */ static uint32_t CIP_ConnectionPath_Put_NetworkSegment( CIP_CONNECTION_PATH_RSC_T* ptConnPath, CIP_CONNECTION_PATH_NETWORK_SEGMENT_TYPE_E eNetworkSegmentType, uint32_t ulByteSizeOfNetworkSegment, uint8_t* pbNetworkSegmentData ); /*************************************************************/ /* @brief: Puts a Data segment into the connection path * * @param [in,out] ptConnPath - Pointer to connection path resources * @param [in] ulByteSizeOfDataSegment - Byte size of data segment * @param [in] pbDataSegmentData - Pointer to Data segment data * * @return TLR_S_OK on success, otherwise an error code. */ static uint32_t CIP_ConnectionPath_Put_DataSegment( CIP_CONNECTION_PATH_RSC_T* ptConnPath, uint32_t ulByteSizeOfDataSegment, uint8_t* pbDataSegmentData ); #if defined(EIP_UNIT_TESTS_ACTIVATED) /*######################################################################################*/ /* _____ _ _____ _ _ */ /* |_ _|__ ___| |_ | ___| _ _ __ ___| |_(_) ___ _ __ ___ */ /* | |/ _ \/ __| __| | |_ | | | | '_ \ / __| __| |/ _ \| '_ \/ __| */ /* | | __/\__ \ |_ | _|| |_| | | | | (__| |_| | (_) | | | \__ \ */ /* |_|\___||___/\__| |_| \__,_|_| |_|\___|\__|_|\___/|_| |_|___/ */ /*######################################################################################*/ uint32_t Cip_ConnectionPath_StartUnitTest() { uint32_t ulResult = 0; uint32_t ulTestDataIdx = 0; CIP_CONNECTION_PATH_RSC_T tConnPath; memset( &tConnPath, 0, sizeof(tConnPath) ); /* Test all valid connection paths */ for( ulTestDataIdx = 0; ulTestDataIdx < sizeof(apbValidConnPaths)/sizeof(apbValidConnPaths[0]); ulTestDataIdx++ ) { CIP_ConnectionPath_Init( &tConnPath ); ulResult = Cip_ConnectionPath_Parse( &tConnPath, aulValidConnPathsLen[ulTestDataIdx], apbValidConnPaths[ulTestDataIdx] ); if( TLR_S_OK != ulResult ) /* We expect a success here */ { break; } } /* Test all invalid connection paths */ for( ulTestDataIdx = 0; ulTestDataIdx < sizeof(apbInvalidConnPaths)/sizeof(apbInvalidConnPaths[0]); ulTestDataIdx++ ) { CIP_ConnectionPath_Init( &tConnPath ); ulResult = Cip_ConnectionPath_Parse( &tConnPath, aulInvalidConnPathsLen[ulTestDataIdx], apbInvalidConnPaths[ulTestDataIdx] ); if( TLR_S_OK == ulResult ) /* We expect an error here */ { ulResult = TLR_E_FAIL; break; } else { ulResult = TLR_S_OK; } } return ulResult; } #endif /*######################################################################################*/ /* _____ _ _ */ /* | ___| _ _ __ ___| |_(_) ___ _ __ ___ */ /* | |_ | | | | '_ \ / __| __| |/ _ \| '_ \/ __| */ /* | _|| |_| | | | | (__| |_| | (_) | | | \__ \ */ /* |_| \__,_|_| |_|\___|\__|_|\___/|_| |_|___/ */ /*######################################################################################*/ void CIP_ConnectionPath_Init( CIP_CONNECTION_PATH_RSC_T* ptConnPath ) { CIP_ConnectionPath_DeInitResources( ptConnPath ); ptConnPath->eState = CIP_CONNECTION_PATH_STATE_IDLE; ptConnPath->eSubState = CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_UNUSED; ptConnPath->eStatus = CIP_CONNECTION_PATH_STATUS_INVALID; ptConnPath->fElectronicKeyIsAvailable = false; memset( &ptConnPath->tElectronicKey, 0, sizeof(ptConnPath->tElectronicKey) ); ptConnPath->fProdInhibitTimeMsAvailable = false; ptConnPath->bProdInhibitTimeMs = 0; memset( &ptConnPath->atAppPaths[0], 0, sizeof(ptConnPath->atAppPaths) ); ptConnPath->bNumOfAvailAppPaths = 0; ptConnPath->tConfigData.ulDataSize = 0; ptConnPath->fSafetySegmentAvailable = false; } void CIP_ConnectionPath_DeInitResources( CIP_CONNECTION_PATH_RSC_T* ptConnPath ) { if( NULL != ptConnPath->tConfigData.pbData ) { free( ptConnPath->tConfigData.pbData ); ptConnPath->tConfigData.pbData = NULL; ptConnPath->tConfigData.ulDataSize = 0; ptConnPath->tConfigData.ulType = CIP_CONNECTION_PATH_CONFIG_DATA_TYPE_NON; } } /***************************************************************************************/ uint32_t Cip_ConnectionPath_Parse( CIP_CONNECTION_PATH_RSC_T* ptConnPath, uint32_t ulConnPathWordLength, uint8_t* pbConnPath) { uint32_t ulResult = EIP_GSR_SUCCESS; int32_t uPathWordSize = (int32_t)ulConnPathWordLength; int32_t uSegWordSize = 0; while( (uPathWordSize > 0) && (ulResult == EIP_GSR_SUCCESS) ) { switch( *pbConnPath & EIP_SEG_MASK) { case EIP_SEG_LOGICAL: { switch( *pbConnPath & EIP_SEG_LOG_TYP_MASK ) { /*************************************************/ /* CLASS SEGMENT */ /*************************************************/ case EIP_SEG_LOG_TYP_CLASS: { if( ((*pbConnPath) & EIP_SEG_LOG_FORMAT_MASK) == EIP_SEG_LOG_FORMAT_UINT8 ) { ulResult = CIP_ConnectionPath_Put_ClassSegment( ptConnPath, (uint32_t)(*(pbConnPath + 1)) ); uSegWordSize = 1; } else if( ((*pbConnPath) & EIP_SEG_LOG_FORMAT_MASK) == EIP_SEG_LOG_FORMAT_UINT16 ) { ulResult = CIP_ConnectionPath_Put_ClassSegment( ptConnPath, (uint32_t)(((PACKED_UINT16_T*) (pbConnPath + 2))->usData) ); uSegWordSize = 2; } else { ulResult = EIP_ESR_BAD_SEGMENT; } } break; /*************************************************/ /* INSTANCE SEGMENT */ /*************************************************/ case EIP_SEG_LOG_TYP_INSTANCE: { if( ((*pbConnPath) & EIP_SEG_LOG_FORMAT_MASK) == EIP_SEG_LOG_FORMAT_UINT8 ) { ulResult = CIP_ConnectionPath_Put_InstanceSegment( ptConnPath, (uint32_t)(*(pbConnPath + 1)) ); uSegWordSize = 1; } else if( ((*pbConnPath) & EIP_SEG_LOG_FORMAT_MASK) == EIP_SEG_LOG_FORMAT_UINT16 ) { ulResult = CIP_ConnectionPath_Put_InstanceSegment( ptConnPath, (uint32_t)(((PACKED_UINT16_T*) (pbConnPath + 2))->usData) ); uSegWordSize = 2; } else if( ((*pbConnPath) & EIP_SEG_LOG_FORMAT_MASK) == EIP_SEG_LOG_FORMAT_UINT32 ) { ulResult = CIP_ConnectionPath_Put_InstanceSegment( ptConnPath, ((PACKED_UINT32_T*) (pbConnPath + 2))->ulData ); uSegWordSize = 3; } else { ulResult = EIP_ESR_BAD_SEGMENT; } } break; /*************************************************/ /* CONNECTION POINT SEGMENT */ /*************************************************/ case EIP_SEG_LOG_TYP_CONNPOINT: { if( ((*pbConnPath) & EIP_SEG_LOG_FORMAT_MASK) == EIP_SEG_LOG_FORMAT_UINT8 ) { ulResult = CIP_ConnectionPath_Put_ConnectionPointSegment( ptConnPath, (uint32_t)(*(pbConnPath + 1)) ); uSegWordSize = 1; } else if( ((*pbConnPath) & EIP_SEG_LOG_FORMAT_MASK) == EIP_SEG_LOG_FORMAT_UINT16 ) { ulResult = CIP_ConnectionPath_Put_ConnectionPointSegment( ptConnPath, (uint32_t)( ((PACKED_UINT16_T*) (pbConnPath + 2))->usData) ); uSegWordSize = 2; } else if( ((*pbConnPath) & EIP_SEG_LOG_FORMAT_MASK) == EIP_SEG_LOG_FORMAT_UINT32 ) { ulResult = CIP_ConnectionPath_Put_ConnectionPointSegment( ptConnPath, ((PACKED_UINT32_T*) (pbConnPath + 2))->ulData ); uSegWordSize = 3; } else { ulResult = EIP_ESR_BAD_SEGMENT; } } break; /*************************************************/ /* ATTRIBUTE SEGMENT */ /*************************************************/ case EIP_SEG_LOG_TYP_ATTRIBUTE: { if( ((*pbConnPath) & EIP_SEG_LOG_FORMAT_MASK) == EIP_SEG_LOG_FORMAT_UINT8 ) { ulResult = CIP_ConnectionPath_Put_AttributeSegment( ptConnPath, (uint32_t)(*(pbConnPath + 1)) ); uSegWordSize = 1; } else if( ((*pbConnPath) & EIP_SEG_LOG_FORMAT_MASK) == EIP_SEG_LOG_FORMAT_UINT16 ) { ulResult = CIP_ConnectionPath_Put_AttributeSegment( ptConnPath, (uint32_t)( ((PACKED_UINT16_T*) (pbConnPath + 2))->usData) ); uSegWordSize = 2; } else { ulResult = EIP_ESR_BAD_SEGMENT; } } break; /*************************************************/ /* ELECTRONIC KEY SEGMENT */ /*************************************************/ case EIP_SEG_LOG_TYP_SPECIAL: { if( (*(pbConnPath + 1)) != 4 ) /* Check for key format == 4 (see CIP Volume 1 Adition 3.20 Table C-1.4 ) */ { ulResult = EIP_ESR_BAD_SEGMENT; } else { ulResult = CIP_ConnectionPath_Put_ElectronicKeySegment( ptConnPath, (EIP_CIP_EKEY_PACKED_T*) (pbConnPath + 2) ); uSegWordSize = 5; /* 5 words = 10 bytes = 1 byte segment type, 1 byte key format 8 bytes key data */ } } break; default: { /* Unknown segment */ ulResult = EIP_ESR_BAD_SEGMENT; } break; } } break; /*************************************************/ /* CONFIGURATION DATA SEGMENT */ /*************************************************/ case EIP_SEG_DATA: { if( (*pbConnPath & EIP_SEG_DATA_TYPE_MSK) == EIP_SEG_DATA_TYPE_SIMPLE ) { ulResult = CIP_ConnectionPath_Put_DataSegment( ptConnPath, *(pbConnPath + 1) << 1, /* the simple data segment size is provided as word size. So we must double this value. */ (pbConnPath + 2) ); uSegWordSize = (INT16)(*(pbConnPath + 1) + 1); } else if( (*pbConnPath & EIP_SEG_DATA_TYPE_MSK) == EIP_SEG_DATA_TYPE_ASCII ) { ulResult = CIP_ConnectionPath_Put_DataSegment( ptConnPath, *(pbConnPath + 1), /* the ASCII data segment size is provided as byte size. */ (pbConnPath + 2) ); uSegWordSize = (*(pbConnPath + 1) + 1) >> 1; /* Calculate word size of data and take an optional pad byte into account. */ } else { ulResult = EIP_ESR_BAD_SEGMENT; } } break; /*************************************************/ /* NETWORK SEGMENT */ /*************************************************/ case EIP_SEG_NETWORK: { switch( *pbConnPath ) { case EIP_SEG_NETWORK | EIP_SEG_NET_SCHEDULE: { ulResult = CIP_ConnectionPath_Put_NetworkSegment( ptConnPath, CIP_CONNECTION_PATH_NETWORK_SEGMENT_TYPE_SCHEDULE, 1, pbConnPath + 1 ); uSegWordSize = 1; } break; case EIP_SEG_NETWORK | EIP_SEG_NET_PROD_INHIBIT_TIME: { ulResult = CIP_ConnectionPath_Put_NetworkSegment( ptConnPath, CIP_CONNECTION_PATH_NETWORK_SEGMENT_TYPE_PROD_INHIBIT_TIME, 1, pbConnPath + 1 ); uSegWordSize = 1; } break; case EIP_SEG_NETWORK | EIP_SEG_NET_SAFETY: { ulResult = CIP_ConnectionPath_Put_NetworkSegment( ptConnPath, CIP_CONNECTION_PATH_NETWORK_SEGMENT_TYPE_SAFETY, *(pbConnPath + 1) << 1, pbConnPath + 2 ); uSegWordSize = (*(pbConnPath + 1)) + 1; } break; case EIP_SEG_NETWORK | EIP_SEG_NET_FIXED: { ulResult = CIP_ConnectionPath_Put_NetworkSegment( ptConnPath, CIP_CONNECTION_PATH_NETWORK_SEGMENT_TYPE_FIXED, 1, pbConnPath + 1 ); uSegWordSize = 1; } break; case EIP_SEG_NETWORK | EIP_SEG_NET_EXTENDED: { ulResult = CIP_ConnectionPath_Put_NetworkSegment( ptConnPath, CIP_CONNECTION_PATH_NETWORK_SEGMENT_TYPE_EXTENDED, *(pbConnPath + 1) << 1, pbConnPath + 2 ); uSegWordSize = (*(pbConnPath + 1)) + 1; } break; default: { ulResult = EIP_ESR_BAD_SEGMENT; } break; } } break; default: { /* Unknown segment */ ulResult = EIP_ESR_BAD_SEGMENT; } break; } pbConnPath += uSegWordSize << 1; /* set connection path pointer to next segment */ uPathWordSize -= uSegWordSize; /* decrease path length by previously parsed segment */ } if( (ulResult == EIP_GSR_SUCCESS) && (uPathWordSize < 0) ) { ulResult = EIP_GSR_PARTIAL_DATA; } return ulResult; } /***************************************************************************************/ static uint32_t CIP_ConnectionPath_Put_ClassSegment( CIP_CONNECTION_PATH_RSC_T* ptConnPath, uint32_t ulClass ) { uint32_t ulResult = EIP_GSR_SUCCESS; switch( ptConnPath->eState ) { case CIP_CONNECTION_PATH_STATE_IDLE: case CIP_CONNECTION_PATH_STATE_ELECTRONIC_KEY: case CIP_CONNECTION_PATH_STATE_NETWORK: { ptConnPath->atAppPaths[CIP_CONNECTION_PATH_APPL_PATH_1].ulClass = ulClass; ptConnPath->atAppPaths[CIP_CONNECTION_PATH_APPL_PATH_1].bValidFlags |= CIP_CONNECTION_PATH_APP_PATH_VALID_FLAG_CLASS; ptConnPath->eState = CIP_CONNECTION_PATH_STATE_APP_PATH_1; ptConnPath->eSubState = CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_CLASS; ptConnPath->eStatus = CIP_CONNECTION_PATH_STATUS_INVALID; ptConnPath->bNumOfAvailAppPaths = 1; } break; case CIP_CONNECTION_PATH_STATE_APP_PATH_1: case CIP_CONNECTION_PATH_STATE_APP_PATH_2: { CIP_CONNECTION_PATH_APPL_PATH_E eAppPathIdx; if( ptConnPath->eState == CIP_CONNECTION_PATH_STATE_APP_PATH_1 ) eAppPathIdx = CIP_CONNECTION_PATH_APPL_PATH_1; else eAppPathIdx = CIP_CONNECTION_PATH_APPL_PATH_2; switch( ptConnPath->eSubState ) { case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_CLASS: { ulResult = EIP_ESR_BAD_SEGMENT; } break; case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_INSTANCE: { ptConnPath->atAppPaths[eAppPathIdx + 1].ulClass = ulClass; ptConnPath->atAppPaths[eAppPathIdx + 1].bValidFlags |= CIP_CONNECTION_PATH_APP_PATH_VALID_FLAG_CLASS; ptConnPath->eState += (CIP_CONNECTION_PATH_STATE_E)1; /* Transition to next application path state (CIP_CONNECTION_PATH_STATE_APP_PATH_[2 or 3]) */ ptConnPath->eSubState = CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_CLASS; ptConnPath->eStatus = CIP_CONNECTION_PATH_STATUS_INVALID; ptConnPath->bNumOfAvailAppPaths += 1; } break; case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_ATTRIBUTE: { ptConnPath->atAppPaths[eAppPathIdx + 1].ulClass = ulClass; ptConnPath->atAppPaths[eAppPathIdx + 1].bValidFlags |= CIP_CONNECTION_PATH_APP_PATH_VALID_FLAG_CLASS; ptConnPath->eState += (CIP_CONNECTION_PATH_STATE_E)1; /* Transition to next application path state (CIP_CONNECTION_PATH_STATE_APP_PATH_[2 or 3]) */ ptConnPath->eSubState = CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_CLASS; ptConnPath->eStatus = CIP_CONNECTION_PATH_STATUS_INVALID; ptConnPath->bNumOfAvailAppPaths += 1; } break; case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_UNUSED: default: { ulResult = EIP_GSR_FAILURE; } break; } } break; case CIP_CONNECTION_PATH_STATE_APP_PATH_3: { switch( ptConnPath->eSubState ) { case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_CLASS: case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_INSTANCE: case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_ATTRIBUTE: case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_UNUSED: default: { ulResult = EIP_ESR_BAD_SEGMENT; } break; } } break; case CIP_CONNECTION_PATH_STATE_CONFIGURATION: case CIP_CONNECTION_PATH_STATE_SAFETY: default: { ulResult = EIP_ESR_BAD_SEGMENT; } break; } return ulResult; } /***************************************************************************************/ static uint32_t CIP_ConnectionPath_Put_InstanceSegment( CIP_CONNECTION_PATH_RSC_T* ptConnPath, uint32_t ulInstance ) { uint32_t ulResult = EIP_GSR_SUCCESS; switch( ptConnPath->eState ) { case CIP_CONNECTION_PATH_STATE_IDLE: case CIP_CONNECTION_PATH_STATE_ELECTRONIC_KEY: case CIP_CONNECTION_PATH_STATE_NETWORK: { ulResult = EIP_ESR_BAD_SEGMENT; } break; case CIP_CONNECTION_PATH_STATE_APP_PATH_1: case CIP_CONNECTION_PATH_STATE_APP_PATH_2: { uint8_t eAppPathIdx; if( ptConnPath->eState == CIP_CONNECTION_PATH_STATE_APP_PATH_1 ) eAppPathIdx = 0; else eAppPathIdx = 1; switch( ptConnPath->eSubState ) { case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_CLASS: { ptConnPath->atAppPaths[eAppPathIdx].ulInstance = ulInstance; ptConnPath->atAppPaths[eAppPathIdx].bValidFlags |= CIP_CONNECTION_PATH_APP_PATH_VALID_FLAG_INSTANCE; ptConnPath->eSubState = CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_INSTANCE; ptConnPath->eStatus = CIP_CONNECTION_PATH_STATUS_VALID; /* When the Connection Path parameter finds a Configuration or I/O path consisting of an instance of the Assembly object (Class Code 4) without an attribute, the Data attribute (Attribute 3) is assumed. (CIP Volume 1 Edition 3.20 Chapter 3-5.4.1.10.2 Assumed Assembly Object Attribute) */ /* We assume attribute number 3 in case of the assembly class is used. */ if( ptConnPath->atAppPaths[eAppPathIdx].ulClass == EIP_AS_CLASS_NUMBER ) { ptConnPath->atAppPaths[eAppPathIdx].ulAttribute = 3; ptConnPath->atAppPaths[eAppPathIdx].bValidFlags |= CIP_CONNECTION_PATH_APP_PATH_VALID_FLAG_ATTRIBUTE; } } break; case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_INSTANCE: { ptConnPath->atAppPaths[eAppPathIdx + 1].ulClass = ptConnPath->atAppPaths[eAppPathIdx].ulClass; ptConnPath->atAppPaths[eAppPathIdx + 1].bValidFlags |= CIP_CONNECTION_PATH_APP_PATH_VALID_FLAG_CLASS; ptConnPath->atAppPaths[eAppPathIdx + 1].ulInstance = ulInstance; ptConnPath->atAppPaths[eAppPathIdx + 1].bValidFlags |= CIP_CONNECTION_PATH_APP_PATH_VALID_FLAG_INSTANCE; ptConnPath->eState += (CIP_CONNECTION_PATH_STATE_E)1; /* Transition to next application path state (CIP_CONNECTION_PATH_STATE_APP_PATH_[2 or 3]) */ ptConnPath->eSubState = CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_INSTANCE; ptConnPath->eStatus = CIP_CONNECTION_PATH_STATUS_VALID; ptConnPath->bNumOfAvailAppPaths += 1; /* When the Connection Path parameter finds a Configuration or I/O path consisting of an instance of the Assembly object (Class Code 4) without an attribute, the Data attribute (Attribute 3) is assumed. (CIP Volume 1 Edition 3.20 Chapter 3-5.4.1.10.2 Assumed Assembly Object Attribute) */ /* We assume attribute number 3 in case of the assembly class is used. */ if( ptConnPath->atAppPaths[eAppPathIdx + 1].ulClass == EIP_AS_CLASS_NUMBER ) { ptConnPath->atAppPaths[eAppPathIdx + 1].ulAttribute = 3; ptConnPath->atAppPaths[eAppPathIdx + 1].bValidFlags |= CIP_CONNECTION_PATH_APP_PATH_VALID_FLAG_ATTRIBUTE; } } break; case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_ATTRIBUTE: { ptConnPath->atAppPaths[eAppPathIdx + 1].ulClass = ptConnPath->atAppPaths[eAppPathIdx].ulClass; ptConnPath->atAppPaths[eAppPathIdx + 1].bValidFlags |= CIP_CONNECTION_PATH_APP_PATH_VALID_FLAG_CLASS; ptConnPath->atAppPaths[eAppPathIdx + 1].ulInstance = ulInstance; ptConnPath->atAppPaths[eAppPathIdx + 1].bValidFlags |= CIP_CONNECTION_PATH_APP_PATH_VALID_FLAG_INSTANCE; ptConnPath->eState += (CIP_CONNECTION_PATH_STATE_E)1; /* Transition to next application path state (CIP_CONNECTION_PATH_STATE_APP_PATH_[2 or 3]) */ ptConnPath->eSubState = CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_INSTANCE; ptConnPath->eStatus = CIP_CONNECTION_PATH_STATUS_VALID; ptConnPath->bNumOfAvailAppPaths += 1; } break; case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_UNUSED: default: { ulResult = EIP_GSR_FAILURE; } break; } } break; case CIP_CONNECTION_PATH_STATE_APP_PATH_3: { switch( ptConnPath->eSubState ) { case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_CLASS: { ptConnPath->atAppPaths[CIP_CONNECTION_PATH_APPL_PATH_3].ulInstance = ulInstance; ptConnPath->atAppPaths[CIP_CONNECTION_PATH_APPL_PATH_3].bValidFlags |= CIP_CONNECTION_PATH_APP_PATH_VALID_FLAG_INSTANCE; ptConnPath->eSubState = CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_INSTANCE; ptConnPath->eStatus = CIP_CONNECTION_PATH_STATUS_VALID; /* When the Connection Path parameter finds a Configuration or I/O path consisting of an instance of the Assembly object (Class Code 4) without an attribute, the Data attribute (Attribute 3) is assumed. (CIP Volume 1 Edition 3.20 Chapter 3-5.4.1.10.2 Assumed Assembly Object Attribute) */ /* We assume attribute number 3 in case of the assembly class is used. */ if( ptConnPath->atAppPaths[CIP_CONNECTION_PATH_APPL_PATH_3].ulClass == EIP_AS_CLASS_NUMBER ) { ptConnPath->atAppPaths[CIP_CONNECTION_PATH_APPL_PATH_3].ulAttribute = 3; ptConnPath->atAppPaths[CIP_CONNECTION_PATH_APPL_PATH_3].bValidFlags |= CIP_CONNECTION_PATH_APP_PATH_VALID_FLAG_ATTRIBUTE; } } break; case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_INSTANCE: case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_ATTRIBUTE: case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_UNUSED: default: { ulResult = EIP_ESR_BAD_SEGMENT; } break; } } break; case CIP_CONNECTION_PATH_STATE_CONFIGURATION: case CIP_CONNECTION_PATH_STATE_SAFETY: default: { ulResult = EIP_ESR_BAD_SEGMENT; } break; } return ulResult; } /***************************************************************************************/ static uint32_t CIP_ConnectionPath_Put_ConnectionPointSegment( CIP_CONNECTION_PATH_RSC_T* ptConnPath, uint32_t ulConnPoint ) { return CIP_ConnectionPath_Put_InstanceSegment( ptConnPath, ulConnPoint ); } /***************************************************************************************/ static uint32_t CIP_ConnectionPath_Put_AttributeSegment( CIP_CONNECTION_PATH_RSC_T* ptConnPath, uint32_t ulAttribute ) { uint32_t ulResult = EIP_GSR_SUCCESS; switch( ptConnPath->eState ) { case CIP_CONNECTION_PATH_STATE_IDLE: case CIP_CONNECTION_PATH_STATE_ELECTRONIC_KEY: case CIP_CONNECTION_PATH_STATE_NETWORK: { ulResult = EIP_ESR_BAD_SEGMENT; } break; case CIP_CONNECTION_PATH_STATE_APP_PATH_1: case CIP_CONNECTION_PATH_STATE_APP_PATH_2: { uint8_t eAppPathIdx; if( ptConnPath->eState == CIP_CONNECTION_PATH_STATE_APP_PATH_1 ) eAppPathIdx = 0; else eAppPathIdx = 1; switch( ptConnPath->eSubState ) { case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_CLASS: { ulResult = EIP_ESR_BAD_SEGMENT; } break; case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_INSTANCE: { ptConnPath->atAppPaths[eAppPathIdx].ulAttribute = ulAttribute; ptConnPath->atAppPaths[eAppPathIdx].bValidFlags |= CIP_CONNECTION_PATH_APP_PATH_VALID_FLAG_ATTRIBUTE; ptConnPath->eSubState = CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_ATTRIBUTE; ptConnPath->eStatus = CIP_CONNECTION_PATH_STATUS_VALID; } break; case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_ATTRIBUTE: { ptConnPath->atAppPaths[eAppPathIdx + 1].ulClass = ptConnPath->atAppPaths[eAppPathIdx].ulClass; ptConnPath->atAppPaths[eAppPathIdx + 1].bValidFlags |= CIP_CONNECTION_PATH_APP_PATH_VALID_FLAG_CLASS; ptConnPath->atAppPaths[eAppPathIdx + 1].ulInstance = ptConnPath->atAppPaths[eAppPathIdx].ulInstance; ptConnPath->atAppPaths[eAppPathIdx + 1].bValidFlags |= CIP_CONNECTION_PATH_APP_PATH_VALID_FLAG_INSTANCE; ptConnPath->atAppPaths[eAppPathIdx + 1].ulAttribute = ulAttribute; ptConnPath->atAppPaths[eAppPathIdx + 1].bValidFlags |= CIP_CONNECTION_PATH_APP_PATH_VALID_FLAG_ATTRIBUTE; ptConnPath->eState += (CIP_CONNECTION_PATH_STATE_E)1; /* Transition to next application path state (CIP_CONNECTION_PATH_STATE_APP_PATH_[2 or 3]) */ ptConnPath->eSubState = CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_ATTRIBUTE; ptConnPath->eStatus = CIP_CONNECTION_PATH_STATUS_VALID; ptConnPath->bNumOfAvailAppPaths += 1; } break; case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_UNUSED: default: { ulResult = EIP_GSR_FAILURE; } break; } } break; case CIP_CONNECTION_PATH_STATE_APP_PATH_3: { switch( ptConnPath->eSubState ) { case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_CLASS: { ulResult = EIP_ESR_BAD_SEGMENT; } break; case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_INSTANCE: { ptConnPath->atAppPaths[CIP_CONNECTION_PATH_APPL_PATH_3].ulAttribute = ulAttribute; ptConnPath->atAppPaths[CIP_CONNECTION_PATH_APPL_PATH_3].bValidFlags |= CIP_CONNECTION_PATH_APP_PATH_VALID_FLAG_ATTRIBUTE; ptConnPath->eSubState = CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_ATTRIBUTE; ptConnPath->eStatus = CIP_CONNECTION_PATH_STATUS_VALID; } break; case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_ATTRIBUTE: case CIP_CONNECTION_PATH_APP_PATH_SUBSTATE_UNUSED: default: { ulResult = EIP_ESR_BAD_SEGMENT; } break; } } break; case CIP_CONNECTION_PATH_STATE_CONFIGURATION: case CIP_CONNECTION_PATH_STATE_SAFETY: default: { ulResult = EIP_ESR_BAD_SEGMENT; } break; } return ulResult; } /***************************************************************************************/ static uint32_t CIP_ConnectionPath_Put_ElectronicKeySegment( CIP_CONNECTION_PATH_RSC_T* ptConnPath, EIP_CIP_EKEY_PACKED_T* ptElectronicKey ) { uint32_t ulResult = EIP_GSR_SUCCESS; switch( ptConnPath->eState ) { case CIP_CONNECTION_PATH_STATE_IDLE: { ptConnPath->tElectronicKey.ulVendorId = ptElectronicKey->usVendorId; ptConnPath->tElectronicKey.ulProductType = ptElectronicKey->usProductType; ptConnPath->tElectronicKey.ulProductCode = ptElectronicKey->usProductCode; ptConnPath->tElectronicKey.ulMajorRevision = ptElectronicKey->bMajorRevision & EIP_KEY_MAJORREV_MASK; ptConnPath->tElectronicKey.ulMinorRevision = ptElectronicKey->bMinorRevision; if( (ptElectronicKey->bMajorRevision & EIP_KEY_COMPATIBILITY_BIT_MASK) != 0 ) { ptConnPath->tElectronicKey.fCompatibility = true; } else { ptConnPath->tElectronicKey.fCompatibility = false; } ptConnPath->fElectronicKeyIsAvailable = true; ptConnPath->eState = CIP_CONNECTION_PATH_STATE_ELECTRONIC_KEY; } break; case CIP_CONNECTION_PATH_STATE_ELECTRONIC_KEY: case CIP_CONNECTION_PATH_STATE_NETWORK: case CIP_CONNECTION_PATH_STATE_APP_PATH_1: case CIP_CONNECTION_PATH_STATE_APP_PATH_2: case CIP_CONNECTION_PATH_STATE_APP_PATH_3: case CIP_CONNECTION_PATH_STATE_CONFIGURATION: case CIP_CONNECTION_PATH_STATE_SAFETY: default: { ulResult = EIP_ESR_BAD_SEGMENT; } break; } return ulResult; } /***************************************************************************************/ static uint32_t CIP_ConnectionPath_Put_NetworkSegment( CIP_CONNECTION_PATH_RSC_T* ptConnPath, CIP_CONNECTION_PATH_NETWORK_SEGMENT_TYPE_E eNetworkSegmentType, uint32_t ulByteSizeOfNetworkSegment, uint8_t* pbNetworkSegmentData ) { uint32_t ulResult = EIP_GSR_SUCCESS; switch( eNetworkSegmentType ) { case CIP_CONNECTION_PATH_NETWORK_SEGMENT_TYPE_SCHEDULE: case CIP_CONNECTION_PATH_NETWORK_SEGMENT_TYPE_FIXED: case CIP_CONNECTION_PATH_NETWORK_SEGMENT_TYPE_EXTENDED: { /* We do not support these network segments at all. */ ulResult = EIP_ESR_BAD_SEGMENT; } break; case CIP_CONNECTION_PATH_NETWORK_SEGMENT_TYPE_PROD_INHIBIT_TIME: { if( (ptConnPath->eState == CIP_CONNECTION_PATH_STATE_IDLE) || (ptConnPath->eState == CIP_CONNECTION_PATH_STATE_ELECTRONIC_KEY) || (ptConnPath->eState == CIP_CONNECTION_PATH_STATE_NETWORK)) { /* We currently support only the production inhibit time in milliseconds, which is provided as 1 byte. */ if( 1 == ulByteSizeOfNetworkSegment ) { ptConnPath->bProdInhibitTimeMs = *pbNetworkSegmentData; ptConnPath->fProdInhibitTimeMsAvailable = true; ptConnPath->eState = CIP_CONNECTION_PATH_STATE_NETWORK; } else { ulResult = EIP_ESR_BAD_SEGMENT; } } else { ulResult = EIP_ESR_BAD_SEGMENT; } } break; case CIP_CONNECTION_PATH_NETWORK_SEGMENT_TYPE_SAFETY: { if( (CIP_CONNECTION_PATH_STATUS_VALID == ptConnPath->eStatus) /* We have a valid connection application path, so configuration data is allowed at this point */ && (ptConnPath->eState != CIP_CONNECTION_PATH_STATE_SAFETY)) { ptConnPath->fSafetySegmentAvailable = true; ptConnPath->eState = CIP_CONNECTION_PATH_STATE_SAFETY; } else { ulResult = EIP_ESR_BAD_SEGMENT; } } break; default: break; } return ulResult; } /***************************************************************************************/ static uint32_t CIP_ConnectionPath_Put_DataSegment( CIP_CONNECTION_PATH_RSC_T* ptConnPath, uint32_t ulByteSizeOfDataSegment, uint8_t* pbDataSegmentData ) { uint32_t ulResult = EIP_GSR_SUCCESS; if( (CIP_CONNECTION_PATH_STATUS_VALID == ptConnPath->eStatus) /* We have a valid connection application path, so configuration data is allowed at this point */ && (ptConnPath->eState != CIP_CONNECTION_PATH_STATE_CONFIGURATION) && (ptConnPath->eState != CIP_CONNECTION_PATH_STATE_SAFETY)) { ptConnPath->tConfigData.ulType = CIP_CONNECTION_PATH_CONFIG_DATA_TYPE_DATA; ptConnPath->tConfigData.ulDataSize = ulByteSizeOfDataSegment; if( 0 != ulByteSizeOfDataSegment ) { /* Allocate memory for safety data and copy the safety data into that memory. */ ptConnPath->tConfigData.pbData = malloc(ulByteSizeOfDataSegment); if( NULL != ptConnPath->tConfigData.pbData ) { memcpy( ptConnPath->tConfigData.pbData, pbDataSegmentData, ulByteSizeOfDataSegment ); } else { ulResult = EIP_ESR_NO_BUFFER; } } ptConnPath->eState = CIP_CONNECTION_PATH_STATE_CONFIGURATION; } else { ulResult = EIP_ESR_BAD_SEGMENT; } return ulResult; } /***************************************************************************************/