/************************************************************************/ /* SISCO SOFTWARE MODULE HEADER *****************************************/ /************************************************************************/ /* (c) Copyright Systems Integration Specialists Company, Inc., */ /* 1998-2005, All Rights Reserved. */ /* */ /* PROPRIETARY AND CONFIDENTIAL */ /* */ /* MODULE NAME : mvl_uca.c */ /* PRODUCT(S) : MMSEASE */ /* */ /* MODULE DESCRIPTION : */ /* Special read/write processing functions for UCA and */ /* IEC 61850 objects. */ /* */ /* NOTE: define MVL61850_CTL_DISABLE to avoid calling user functions */ /* (u_mvl61850_ctl_oper_*) if 61850 Controls not needed. */ /* */ /* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ /* */ /* MODIFICATION LOG : */ /* Date Who Rev Comments */ /* -------- --- ------ ------------------------------------------- */ /* 08/05/29 LW 58 加入支持3层目录模型的服务器代码(加入代码后注释包括//lw) /* 03/07/07 JRB 57 Add mvlu_get_leaf_val_int_any. */ /* 11/21/06 JRB 56 Send LastApplError if write of Oper, etc fails.*/ /* 10/30/06 JRB 55 Use new mvl_vmd_* object handling functions. */ /* mvlu_find_base_va: add args. */ /* u_mvl_get_va_aa: add args. */ /* u_gnl_ind_*: add net_info arg to */ /* elim use of global var "_mvl_curr_net_info". */ /* u_mvl_get_va_aa: do not set va->usr_ind_ctrl */ /* (done by calling functions). */ /* 10/26/06 JRB 54 Del unused local vars. */ /* 09/27/06 MDE 53 Added MMSOP_RDWR_USR_HANDLED for IOS */ /* 09/13/06 JRB 52 mvlu_find_comp_type: allow non-dynamic types.*/ /* 08/09/06 JRB 51 Del u_mvl_get_nvl, u_mvl_free_nvl functions */ /* (not needed with new improved Foundry). */ /* Use "mvl_var_create/destroy" so all variables*/ /* created/destroyed in one place. */ /* 07/24/06 JRB 50 Chg some common ERR logs to FLOW. */ /* 03/27/06 JRB 49 Add more mvlu_get_leaf_* functions. */ /* 07/29/05 MDE 48 Fixed static data use for write handling */ /* 07/11/05 JRB 47 Call user fcts (u_mvl61850_ctl_oper_*) if */ /* !defined (MVL61850_CTL_DISABLE). */ /* 01/19/05 JRB 46 u_gnl_ind_* return (-1) on error. */ /* 12/09/04 JRB 45 init_prim_info_recursive: fix ARR_END handling.*/ /* init_prim_info_arr: simplify & ret ST_VOID. */ /* Add mvlu_find_comp_type, mvlu_get_leaf_val*. */ /* Chg trim_branch_name to global mvlu_trim_.. */ /* & simplify it using strrchr. */ /* 09/20/04 JRB 44 startElWrites: if writing "Oper" or "Cancel" */ /* struct, check SBO state. */ /* mvlu_wr_prim_done call mvlu_sbo_ctrl_free. */ /* 06/29/04 JRB 43 Del global var mvluUseStaticData, instead use*/ /* use_static_data flag in MVL_VAR_ASSOC for Read.*/ /* NEVER use static data for Write. */ /* startElReads, etc: add prim_info arg. */ /* Del elmntOffset, use prim_info->prim_offset. */ /* 11/24/03 JRB 42 getGnlVarNames: fix prefix len by using */ /* MAX_IDENT_LEN, chk overflow BEFORE writing, */ /* & add logging & asserts. */ /* 09/18/03 JRB 41 Allow alt acc on array of "nested" structures*/ /* Add some debug logging & extra comments. */ /* 05/02/03 JRB 40 switch(rt->el_tag): Use default for most cases*/ /* 04/04/03 JRB 39 Fix integrity/GI scan code so multiple */ /* concurrent scans don't corrupt one another. */ /* 12/20/02 JRB 38 Moved mvlu_set_leaf_param to mvluleaf.c */ /* 12/12/02 JRB 37 Use usr_resp_fun ptr to call scan done funcs.*/ /* 12/09/02 MDE 36 Made mvlu_find_uca_var global */ /* 11/27/02 MDE 35 Addded leaf indication handlers */ /* Addded mvlu_find_rt_leaf */ /* Addded mvlu_set_leaf_param */ /* 11/29/01 MDE 34 Added GOOSE function pointer */ /* 11/14/01 EJV 33 Added support for new MMS type UtcTime: */ /* 11/13/01 MDE 32 Added GOOSE scan support */ /* 05/21/01 MDE 31 Cleaned up memory allocation for SMEM */ /* 10/25/00 JRB 30 Del u_mvl & u_gnl funct ptrs. Call directly. */ /* Del mvlu_install (no longer needed). */ /* 08/18/00 JRB 29 Don't clear va_to_free. Need value later. */ /* mvlu_free_nvl free va->va_to_free only if */ /* it was allocated by mvlu_get_nvl. */ /* 08/18/00 RKR 28 Added rt fields to MVLU_ typedefs */ /* 07/13/00 JRB 27 Cleanup ms_comp_na.. chg for MVL_XNAME. */ /* 07/13/00 JRB 26 Use new ms_comp_name_find to get comp names. */ /* 07/13/00 JRB 25 Move these functs to mvl_type.c: */ /* mvlu_add_rt_type, mvlu_free_rt_type. */ /* 06/21/00 MDE 24 Now copy base VA user_info to new VA */ /* 05/15/00 MDE 23 Now filder out too-long variable names */ /* 04/14/00 JRB 22 Lint cleanup. */ /* 04/05/00 RKR 21 Made MVL_XNAME a compile time option */ /* 04/03/00 RKR 20 Added the xName to UCA Rd and Wr Ind funs */ /* 03/30/00 RKR 19 Passed the expanded UCA var name to ind fun */ /* 01/21/00 MDE 18 Now use MEM_SMEM for dynamic memory */ /* 12/20/99 MDE 17 Fix getArrAARtType to return SUCCESS/FAIL */ /* 11/03/99 JRB 16 Fix GetNameList if CA name = base var name. */ /* 09/30/99 EJV 15 Added slog macro to mvlu_rd_prim_done */ /* 09/13/99 MDE 14 Added SD_CONST modifiers */ /* 09/07/99 MDE 13 Revised and enhanced the UCA report system */ /* 06/04/99 MDE 12 Now allow arrays as base VA type, other */ /* minor changes to VA processing */ /* 06/04/99 MDE 11 Fixed memory leak for nested array alt acc */ /* 04/07/99 MDE 10 Logging improvements (fixed wrong AA log too)*/ /* 03/09/99 JRB 12 Fix illegal free of gnlNameBuf. */ /* 02/22/99 JRB 11 BUG FIX: Always start with clean "arrCtrl". */ /* 01/08/99 JRB 10 Use new "bsearch" object model. Don't use */ /* "_UCA_" prefix on va and nvl names. */ /* 12/11/98 MDE 09 Removed scope references from VA */ /* 11/17/98 MDE 08 Made mvlu_get_va_aa alloc space for name */ /* 11/16/98 MDE 07 Renamed internal functions (prefix '_') */ /* 09/21/98 MDE 06 Uninitialized ptr fix, Minor lint cleanup */ /* 08/11/98 MDE 05 Added UCA variable array support */ /* 07/13/98 MDE 04 Mixed scope NVL fixes, data alignment fix */ /* 06/29/98 MDE 03 Added report function pointers */ /* 06/15/98 MDE 02 Changes to allow compile under C++ */ /* 01/02/98 MDE 01 New */ /************************************************************************/ #include "glbtypes.h" #include "sysincs.h" #include "glbsem.h" #include "mmsdefs.h" #include "mms_pvar.h" #include "mms_vvar.h" #include "mvl_uca.h" #include "mvl_log.h" #if defined(MVL_UCA) /* This entire module is only valid for UCA. */ /************************************************************************/ /* For debug version, use a static pointer to avoid duplication of */ /* __FILE__ strings. */ #ifdef DEBUG_SISCO SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__; #endif /* PRIM_INFO struct: extra info about primitive. */ typedef struct { ST_UINT prim_num; /* index to data */ ST_UINT prim_offset; /* mem offset from start of var */ ST_UINT prim_offset_base; /* mem offset from start of "base" var */ } PRIM_INFO; /* extra info about primitive */ /************************************************************************/ static ST_VOID mvluDefGetVaDataBufFun (ST_INT service, MVL_VAR_ASSOC *va, ST_INT size); static ST_VOID mvluDefFreeVaDataBufFun (ST_INT service, MVL_VAR_ASSOC *va); /************************************************************************/ /* Read/Write leaf indication override handlers */ ST_VOID (*u_mvlu_leaf_rd_ind_fun)(MVLU_RD_VA_CTRL *mvluRdVaCtrl); ST_VOID (*u_mvlu_leaf_wr_ind_fun)(MVLU_WR_VA_CTRL *mvluWrVaCtrl); /************************************************************************/ /* STATIC VARIABLES, LOCAL DEFINES */ /* GNL Variables */ static ST_CHAR *gnlNameBuf; static ST_CHAR *currGnlNamePos; #define _OBJ_NAME_CLONE_NAME_SIZE (65) #define _OBJ_NAME_CLONE_SIZE (sizeof(OBJECT_NAME)+(2 * _OBJ_NAME_CLONE_NAME_SIZE)) /************************************************************************/ /* STATIC FUNCTIONS */ static ST_RET mvlu_find_struct_comp (ST_CHAR *compName, RUNTIME_TYPE **rtIo, ST_INT *numRtIo); static ST_VOID mvlu_handle_alt_acc (OBJECT_NAME *obj, ALT_ACCESS *alt_acc, MVL_ARR_CTRL *arrCtrl); static ST_RET getArrAARtType (MVL_ARR_CTRL *arrCtrl, RUNTIME_TYPE **pRt, ST_INT *pNumRt); static ST_VOID cloneArrAA (ALT_ACC_EL *arrAa, ALT_ACCESS *dest); static ST_VOID mvlu_find_base_va (MVL_VMD_CTRL *vmd_ctrl, OBJECT_NAME *obj, MVL_NET_INFO *net_info, MVL_VAR_ASSOC **vaOut); ST_VOID getGnlVarNames (MVL_VAR_ASSOC *va, ST_CHAR *caPtr, ST_CHAR **dest, ST_INT maxNames, ST_INT *numNames, ST_BOOLEAN *moreFollowsOut); static ST_VOID mvlu_clone_objname (ST_CHAR *dest, OBJECT_NAME *src); static ST_VOID startArrRds (MVL_IND_PEND *indCtrl, MVLAS_READ_CTRL *rdCtrl, MVLAS_RD_VA_CTRL *rdVaCtrl, RUNTIME_TYPE *rt, PRIM_INFO *prim_info); static ST_VOID startElReads (MVL_IND_PEND *indCtrl, MVLAS_READ_CTRL *rdCtrl, MVLAS_RD_VA_CTRL *rdVaCtrl, RUNTIME_TYPE *rt, ST_INT rt_num, PRIM_INFO *prim_info); static ST_VOID startArrWrs (MVL_IND_PEND *indCtrl, MVLAS_WRITE_CTRL *wrCtrl, MVLAS_WR_VA_CTRL *wrVaCtrl, RUNTIME_TYPE *rt, PRIM_INFO *prim_info); static ST_VOID startElWrites (MVL_IND_PEND *indCtrl, MVLAS_WRITE_CTRL *wrCtrl, MVLAS_WR_VA_CTRL *wrVaCtrl, RUNTIME_TYPE *rt, ST_INT rt_num, PRIM_INFO *prim_info); static ST_INT countPrimEl (MVL_VAR_ASSOC *va, RUNTIME_TYPE *rt, ST_INT rt_num); ST_RET init_prim_info_recursive (PRIM_INFO *prim_info, RUNTIME_TYPE *rt_first, ST_INT rt_num, ST_UINT first_offset_base); /************************************************************************/ /* init_prim_info_arr */ /* Updates prim_info->prim_num. */ /* Must never find match within an array, because impossible to specify */ /* IEC/UCA flattened name for array element, so just ignore returns */ /* from init_prim_info_recursive, and finish loop anyway. */ /* Errors will be detected when this function returns. */ /************************************************************************/ ST_VOID init_prim_info_arr (PRIM_INFO *prim_info, RUNTIME_TYPE *rt_first, ST_UINT first_offset_base) /* mem offset from start of "base" var*/ /* for "first" prim of this var */ { ST_RTINT rt_num; ST_RTINT num_arr_elements; /* num of elements in array */ ST_RTINT j; assert (rt_first->el_tag == RT_ARR_START); /* confirm this. */ rt_num = rt_first->u.arr.num_rt_blks; /* num RUNTIME_TYPE to define one element of array*/ num_arr_elements = rt_first->u.arr.num_elmnts; assert (num_arr_elements > 0); /* Call "init_prim_info_recursive" once for each array element. */ for (j = 0; j < num_arr_elements; ++j) { init_prim_info_recursive (prim_info, rt_first+1, rt_num, first_offset_base); } return; } /************************************************************************/ /* init_prim_info_recursive */ /* Updates prim_info->prim_num. */ /* NOTE: when called recursively by init_prim_info_arr, this will */ /* often fail. That is to be expected. */ /* RETURNS: SD_FAILURE if NOT found yet. */ /* SD_SUCCESS if found. */ /************************************************************************/ ST_RET init_prim_info_recursive (PRIM_INFO *prim_info, RUNTIME_TYPE *rt_first, ST_INT rt_num, ST_UINT first_offset_base) /* mem offset from start of "base" var*/ /* for "first" prim of this var */ { RUNTIME_TYPE *rt_type; ST_INT j; ST_RET retcode = SD_FAILURE; for (j = 0, rt_type = rt_first; j < rt_num; j++, rt_type++) { /* NOTE: Usually el_size=0 for non-primitives (RT_STR_START/END, */ /* RT_ARR_START/END) but sometimes el_size!=0 for padding. */ prim_info->prim_offset_base += rt_type->el_size; switch (rt_type->el_tag) { case RT_STR_START: case RT_STR_END: case RT_ARR_END: break; /* do nothing */ case RT_ARR_START: init_prim_info_arr (prim_info, rt_type, first_offset_base); /* CRITICAL: Index to just before RT_ARR_END. Don't skip over it*/ /* or its rt_type->el_size will not be added to prim_offset_base.*/ rt_type += rt_type->u.arr.num_rt_blks; j += rt_type->u.arr.num_rt_blks; break; default: /* Primitive */ prim_info->prim_num++; break; } /* end "switch" */ if (prim_info->prim_offset_base == first_offset_base) { retcode = SD_SUCCESS; /* this is only way SD_SUCCESS returned */ break; /* break out of main loop & return */ } if (prim_info->prim_offset_base > first_offset_base) { /* Will NEVER find it. This is a SERIOUS error. */ /* NOTE: this error may occur more than once if it occurs in recursive call.*/ /* Don't log error here. Log in init_prim_info if this funct fails.*/ break; /* stop trying */ } } return (retcode); /* SD_FAILURE if NOT found, SD_SUCCESS if found */ } /************************************************************************/ /* init_prim_info */ /* Initializes prim_info struct. This is the main function. It calls */ /* init_prim_info_recursive & init_prim_info_arr recursively. */ /* NOTE: prim_info->prim_offset set = 0, never changed by this function.*/ /************************************************************************/ ST_RET init_prim_info (MVL_VAR_ASSOC *va, PRIM_INFO *prim_info) { ST_RET retcode = SD_SUCCESS; MVL_TYPE_CTRL *type_ctrl; /* Set initial values in prim_info. If this is top level var, * these values will be used. */ prim_info->prim_num = 0; prim_info->prim_offset_base = 0; prim_info->prim_offset = 0; /* NOTE: never changed by this function */ /* If NOT top level var, must call init_prim_info_recursive to fix * prim_info->prim_num. */ if (va->offset_from_base) { type_ctrl = mvl_type_ctrl_find (va->base_va->type_id); retcode = init_prim_info_recursive (prim_info, type_ctrl->rt, type_ctrl->num_rt, va->offset_from_base); if (retcode != SD_SUCCESS) MVL_LOG_ERR3 ("No component in variable '%s' at offset=%d. Nearest is at offset=%d", va->base_va->name, va->offset_from_base, prim_info->prim_offset_base); } assert (prim_info->prim_offset == 0); /* verify this was NOT changed */ return (retcode); } /************************************************************************/ /************************************************************************/ /* MANUFACTURED VARIABLE RESOLUTION FUNCTIONS */ /************************************************************************/ /* u_mvl_get_va_aa */ /************************************************************************/ /* This function is called from MVL when it is unable to find a */ /* configured MMS server variable for a READ, WRITE, or GET VARIABLE */ /* ACCESS ATTRIBUTES indication. */ MVL_VAR_ASSOC *u_mvl_get_va_aa (MVL_VMD_CTRL *vmd_ctrl, ST_INT service, OBJECT_NAME *obj, MVL_NET_INFO *netInfo, ST_BOOLEAN alt_access_pres, ALT_ACCESS *alt_acc, ST_BOOLEAN *alt_access_done_out) { ST_CHAR *name; MVL_VAR_ASSOC *va; MVL_VAR_ASSOC *baseVa; ST_RET rc; OBJECT_NAME *objClone; ST_CHAR objNameBuf[_OBJ_NAME_CLONE_SIZE]; RUNTIME_TYPE *baseRt; ST_INT numBaseRt; RUNTIME_TYPE *ucaRt; ST_INT numUcaRt; ST_CHAR *subStart; ST_INT subTypeId; MVL_ARR_CTRL arrCtrl; /* Make a working copy of the variable name (mvlu_handle_alt_acc may change it) */ objClone = (OBJECT_NAME *) objNameBuf; mvlu_clone_objname (objNameBuf, obj); /* We will handle any alternate access here, by creating the UCA from */ /* variable name. */ memset (&arrCtrl, 0, sizeof (MVL_ARR_CTRL)); /* start with clean "arrCtrl"*/ if (alt_access_pres) { mvlu_handle_alt_acc (objClone, alt_acc, &arrCtrl); *alt_access_done_out = SD_TRUE; } /* We need to find the base type for this variable */ mvlu_find_base_va (vmd_ctrl, objClone, netInfo, &baseVa); if (baseVa == NULL) { MVL_LOG_NERR1 ("Could not resolve UCA variable '%s'", objClone->obj_name.vmd_spec); return (NULL); } /* Now resolve this variable's type given it's name and the base */ /* type. */ rc = mvl_get_runtime (baseVa->type_id, &baseRt, &numBaseRt); if (rc != SD_SUCCESS) { MVL_LOG_NERR1 ("Could not get RT type for type id %d", baseVa->type_id); return (NULL); } ucaRt = baseRt; numUcaRt = numBaseRt; /* Check to see if this is for base var... name has no embedded '$' */ /* If is a derived variable we need to create from the variable name */ /* 'path' and runtime type. */ name = objClone->obj_name.vmd_spec; /* We know this is a union ... */ subStart = strstr (name,"$"); /* Skip the outer (base) name */ if (subStart) { /* This is a derived variable, and we have the base UCA variable */ /* Using the base runtime table and the variable name, we can get the */ /* subset type for this variable */ ++subStart; //lw:以下代码作了修改,主要为兼容3层目录服务器//////////////////// if ((baseVa->flags == MVL_VAR_FLAG_UCA) != 0) { rc = mvlu_find_uca_var (&ucaRt, &numUcaRt, subStart); } else if ((baseVa->flags & 0x02) != 0) { subStart = strstr(subStart, "$"); if (subStart) { ++subStart; rc = mvlu_find_uca_var (&ucaRt, &numUcaRt, subStart); } } //////////////////////////////////////////////////////////////////// if (rc != SD_SUCCESS) { MVL_LOG_NERR1 ("Error - could not find subcomponent '%s'", subStart); return (NULL); } } /* If this is an alternate access on an array, we need to copy the */ /* RT type so we can modify the number of elements and total size */ if (arrCtrl.arrAltAccPres == SD_TRUE) { rc = getArrAARtType (&arrCtrl, &ucaRt, &numUcaRt); if (rc != SD_SUCCESS) { M_FREE (MSMEM_MVLU_AA, arrCtrl.alt_acc.aa); return (NULL); } } /* OK, now we have the sub-runtime type, go ahead and create a temp */ /* RT type and variable association. */ rc = mvlu_add_rt_type (ucaRt, numUcaRt, &subTypeId); if (rc != SD_SUCCESS) { MVL_LOG_NERR0 ("Error - could not add temp RT type"); return (NULL); } /* Create the variable association for this variable */ /* CRITICAL: Must use "mvl_var_create", not "mvl_var_add" because */ /* this var must not be added to list (i.e. it will not be sent in */ /* GetNameList responses). */ va = mvl_var_create (objClone, subTypeId, NULL, /* data (set later by mvluDefGet..) */ NULL, /* (MVL_VAR_PROC *) not needed */ SD_TRUE); /* copy var name */ /* Set special "va" elements not set by mvl_var_create. */ va->base_va = baseVa; va->user_info = baseVa->user_info; va->offset_from_base = ucaRt->mvluTypeInfo.offSet; /* If the user elected to use offset, data or proc initialization, */ /* take care of it here. */ #if defined(MVLU_USE_REF) va->ref = ucaRt->mvluTypeInfo.ref; #endif /* Copy the array AA information */ memcpy (&va->arrCtrl, &arrCtrl, sizeof (MVL_ARR_CTRL)); va->arrCtrl.curr_index = arrCtrl.low_index; /* Get the data buffer */ /* This function sets "va->data". */ mvluDefGetVaDataBufFun (service, va, ucaRt->offset_to_last); /* Good work, we are done here. */ return (va); } /************************************************************************/ /* getArrAARtType */ /************************************************************************/ static ST_RET getArrAARtType (MVL_ARR_CTRL *arrCtrl, RUNTIME_TYPE **pRt, ST_INT *pNumRt) { ST_INT numRt; ST_INT i, j; RUNTIME_TYPE *rt; RUNTIME_TYPE *endRt; RUNTIME_TYPE *newRt; ALT_ACCESS *alt_acc; ALT_ACC_EL *alt_acc_el; /* ptr to current entry in alt acc array */ ST_INT nest_level = 0; rt = *pRt; numRt = *pNumRt; /* Check to see if further nesting with this AA selection ... */ if (arrCtrl->nested == SD_FALSE) { /* If just one element, need to lose the outer array */ if (arrCtrl->num_elmnts == 1) { numRt -= 2; ++rt; } } else /* Further nesting is requested, let's do it! */ { /* We only support a single drill down AA */ if (arrCtrl->num_elmnts > 1) { MVL_LOG_NERR0 ("AA resolution problem - multiple elements and nested"); return (SD_FAILURE); } numRt -= 2; ++rt; /* OK, we now need to find the type of the component ... */ alt_acc = &arrCtrl->alt_acc; /* Only support AA_COMP and AA_COMP_NEST for now. */ /* If AA_COMP_NEST is used, this is recursive process. */ for (j=0; j < alt_acc->num_aa; j++) { alt_acc_el = &alt_acc->aa[j]; if (alt_acc_el->sel_type == AA_COMP || alt_acc_el->sel_type == AA_COMP_NEST) { if (alt_acc_el->sel_type == AA_COMP_NEST) nest_level++; /* find this component name within the current RUNTIME_TYPE array*/ for (i = 0; i < numRt; ++i, ++rt) { if (!strcmp (alt_acc_el->u.component, ms_comp_name_find (rt))) break; } if (i >= numRt) { MVL_LOG_NERR1 ("AA resolution problem - could not find component '%s'", alt_acc_el->u.component); return (SD_FAILURE); } if (rt->el_tag == RT_STR_START) numRt = rt->u.str.num_rt_blks+2; else if (rt->el_tag == RT_ARR_START) numRt = rt->u.arr.num_rt_blks+2; else numRt = 1; } else if (alt_acc_el->sel_type == AA_END_NEST) nest_level--; else { MVL_LOG_NERR0 ("AA resolution problem - complex nested AA on array"); return (SD_FAILURE); } } /* end "for" loop */ if (nest_level != 0) { MVL_LOG_NERR0 ("AA resolution problem - invalid nesting"); return (SD_FAILURE); } } /* OK, now copy the runtime type elements into a new one so we can fool */ /* with it. */ newRt = (RUNTIME_TYPE *) M_MALLOC (MSMEM_DYN_RT, numRt * sizeof (RUNTIME_TYPE)); memcpy (newRt, rt, numRt * sizeof (RUNTIME_TYPE)); /* Adjust the total size of the type, using scaling */ if (arrCtrl->num_elmnts > 1) { newRt->offset_to_last = rt[1].offset_to_last * arrCtrl->num_elmnts; /* Now set the number of elements as desired */ newRt->u.arr.num_elmnts = arrCtrl->num_elmnts; endRt = newRt + (newRt->u.arr.num_rt_blks + 1); endRt->u.arr.num_elmnts = arrCtrl->num_elmnts; /* We don't want end of array padding */ endRt->el_size = 0; } *pRt = newRt; *pNumRt = numRt; return (SD_SUCCESS); } /************************************************************************/ /* mvlu_handle_alt_acc */ /************************************************************************/ /* Here we deal with an alternate access. We will simply add the */ /* sub-name components to the base name to create a fully qualified UCA */ /* sub-var name */ /* Of course, this only handles the most simple form of alternate */ /* access correctly ... */ static ST_VOID mvlu_handle_alt_acc (OBJECT_NAME *obj, ALT_ACCESS *alt_acc, MVL_ARR_CTRL *arrCtrl) { ST_INT i; ST_CHAR *name; ST_BOOLEAN done; name = obj->obj_name.vmd_spec; /* We know this is a union ... */ arrCtrl->nested = SD_FALSE; done = SD_FALSE; for (i = 0; i < alt_acc->num_aa && !done; ++i) { switch (alt_acc->aa[i].sel_type) { case AA_COMP : case AA_COMP_NEST : strcat (name, "$"); strcat (name, alt_acc->aa[i].u.component); break; case AA_INDEX_NEST : arrCtrl->nested = SD_TRUE; cloneArrAA (&alt_acc->aa[i], &arrCtrl->alt_acc); /* Lets fall through into common code ... */ case AA_INDEX : arrCtrl->arrAltAccPres = SD_TRUE; arrCtrl->low_index = (ST_RTINT) alt_acc->aa[i].u.index; arrCtrl->num_elmnts = 1; done = SD_TRUE; break; case AA_INDEX_RANGE_NEST : arrCtrl->nested = SD_TRUE; cloneArrAA (&alt_acc->aa[i], &arrCtrl->alt_acc); /* Lets fall through into common code ... */ case AA_INDEX_RANGE : arrCtrl->arrAltAccPres = SD_TRUE; arrCtrl->low_index = (ST_RTINT) alt_acc->aa[i].u.ir.low_index; arrCtrl->num_elmnts = (ST_RTINT) alt_acc->aa[i].u.ir.num_elmnts; done = SD_TRUE; break; case AA_ALL: case AA_ALL_NEST : arrCtrl->nested = SD_TRUE; cloneArrAA (&alt_acc->aa[i], &arrCtrl->alt_acc); arrCtrl->arrAltAccPres = SD_TRUE; arrCtrl->low_index = 0; arrCtrl->num_elmnts = 0; /* 'all' flag */ done = SD_TRUE; break; case AA_END_NEST : done = SD_TRUE; break; default: MVL_LOG_NERR1 ("Error: Invalid alt access sel_type", alt_acc->aa[i].sel_type); break; } } } /************************************************************************/ /* cloneArrAA */ /************************************************************************/ static ST_VOID cloneArrAA (ALT_ACC_EL *arrAa, ALT_ACCESS *dest) { ST_INT elCount; ST_INT nestLevel; ALT_ACC_EL *aaEl; /* First let's count how many we need */ nestLevel = 0; elCount = 0; aaEl = arrAa + 1; while (SD_TRUE) { if (nestLevel == 0 && aaEl->sel_type == AA_END_NEST) break; ++elCount; if (aaEl->sel_type == AA_COMP_NEST || aaEl->sel_type == AA_INDEX_NEST || aaEl->sel_type == AA_INDEX_RANGE_NEST || aaEl->sel_type == AA_ALL_NEST) { ++nestLevel; } if (aaEl->sel_type == AA_END_NEST) { --nestLevel; } ++aaEl; } /* OK, now just calloc and copy the nested alternate access */ if (elCount) { dest->num_aa = elCount; dest->aa = (ALT_ACC_EL *) M_MALLOC (MSMEM_MVLU_AA, elCount * sizeof (ALT_ACC_EL)); memcpy (dest->aa, arrAa+1, elCount * sizeof (ALT_ACC_EL)); } else { MVL_LOG_NERR0 ("Nested AA construction problem"); } } /************************************************************************/ /* mvlu_find_base_va */ /************************************************************************/ /* This function takes a MMS variable name and determines the type ID */ /* for the base type for the variable. This is done here by */ /* extracting the name root then looking for a configured variable */ /* of that name. */ static ST_VOID mvlu_find_base_va (MVL_VMD_CTRL *vmd_ctrl, OBJECT_NAME *obj, MVL_NET_INFO *net_info, MVL_VAR_ASSOC **vaOut) { MVL_VAR_ASSOC *va; ST_CHAR *p; ST_CHAR *name; ST_CHAR temp[128]; OBJECT_NAME *objClone; ST_CHAR objNameBuf[_OBJ_NAME_CLONE_SIZE]; objClone = (OBJECT_NAME *) objNameBuf; mvlu_clone_objname (objNameBuf, obj); name = objClone->obj_name.vmd_spec; /* We know this is a union ... */ strcpy(temp, name); /* See if this variable name has embedded '$', and if so wack it so */ /* that we have the base name to work with. */ p = strstr (name,"$"); if (p) *p = 0; va = mvl_vmd_find_var (vmd_ctrl, objClone, net_info); if (va) { if ((va->flags & MVL_VAR_FLAG_UCA) == 0) va = NULL; /* Found va but not UCA variable, so don't return it. */ *vaOut = va; return; } //lw:以下代码为兼容3层服务器所增加//////////////////////////////// strcpy(name, temp); p++; p = strstr(p, "$"); if (p) *p = 0; va = mvl_vmd_find_var(vmd_ctrl, objClone, net_info); if (va && (va->flags & 0x02) == 0) { va = NULL; } *vaOut = va; /////////////////////////////////////////////////////////////////// } /************************************************************************/ /* mvlu_find_uca_var */ /************************************************************************/ /* This function searches a runtime type for the given UCA variable */ /* name. It does this by breaking the UCA name into its components */ /* and then finding the name in the current level of the runtime type. */ ST_RET mvlu_find_uca_var (RUNTIME_TYPE **rtIo, ST_INT *numRtIo, ST_CHAR *varName) { ST_CHAR nameBuf[MAX_IDENT_LEN+1]; ST_CHAR *nameToFind; ST_CHAR *compEnd; ST_BOOLEAN nameDone; ST_RET ret; /* Note that varName does not have the base name prefix */ strcpy (nameBuf, varName); nameToFind = nameBuf; nameDone = SD_FALSE; while (nameDone == SD_FALSE) { /* Isolate the component name for this level, removing subcomp names */ compEnd = strstr (nameToFind, "$"); if (compEnd != NULL) *compEnd = 0; else /* This is the last nest level */ nameDone = SD_TRUE; /* Find the component name in the current runtime type nest level */ ret = mvlu_find_struct_comp (nameToFind, rtIo, numRtIo); if (ret == SD_FAILURE) { /* Many things can cause this so just use FLOW Logging. */ MVLU_LOG_FLOW2 ("Could not find name component %s from name %s", nameToFind, varName); return (SD_FAILURE); } /* OK, we now have found the component in the runtime type, and our */ /* runtime pointer and numRt reflect the sub-runtime type. */ /* next component. */ /* Prepare to find the next level component name */ nameToFind = compEnd+1; } return (SD_SUCCESS); } /************************************************************************/ /* mvlu_find_struct_comp */ /************************************************************************/ /* This function searches a structure runtime type for the given */ /* component name at the outer level. */ static ST_RET mvlu_find_struct_comp (ST_CHAR *compName, RUNTIME_TYPE **rtIo, ST_INT *numRtIo) { RUNTIME_TYPE *rt; RUNTIME_TYPE *endRt; ST_BOOLEAN foundRt; foundRt = SD_FALSE; rt = *rtIo; endRt = rt + *numRtIo; if (rt->el_tag != RT_STR_START) { MVL_LOG_NERR0 ("Find struct comp: First RT is not structure start"); return (SD_FAILURE); } ++rt; /* Skip the structure start */ while (rt < endRt) { if (!strcmp (compName, ms_comp_name_find (rt))) { *rtIo = rt; foundRt = SD_TRUE; } switch (rt->el_tag) { case RT_STR_START : if (foundRt == SD_TRUE) { *numRtIo = rt->u.str.num_rt_blks+2; return (SD_SUCCESS); } rt += rt->u.str.num_rt_blks+2; /* Skip the structure contents */ break; case RT_ARR_START : if (foundRt == SD_TRUE) { *numRtIo = rt->u.arr.num_rt_blks+2; return (SD_SUCCESS); } rt += rt->u.arr.num_rt_blks+1; /* Skip the array contents */ break; case RT_STR_END : case RT_ARR_END : ++rt; break; default: if (foundRt == SD_TRUE) { *numRtIo = 1; return (SD_SUCCESS); } ++rt; break; } } return (SD_FAILURE); } /************************************************************************/ /* u_mvl_free_va */ /************************************************************************/ /* MVL calls this function when it is through with it. We will free */ /* the data buffer, and then the VA (unless it was a base VA). */ ST_VOID u_mvl_free_va (ST_INT service, MVL_VAR_ASSOC *va, MVL_NET_INFO *netInfo) { RUNTIME_TYPE *ucaRt; ST_INT numUcaRt; ST_RET rc; /* We always 'allocate' the data buffer */ mvluDefFreeVaDataBufFun(service, va); /* If this was not a 'base' VA, free the derived type */ if ( (va->flags & MVL_VAR_FLAG_UCA) == 0) { /* See if we allocated the runtime type ... */ if (va->arrCtrl.arrAltAccPres == SD_TRUE) { rc = mvl_get_runtime (va->type_id, &ucaRt, &numUcaRt); if (rc == SD_SUCCESS) M_FREE (MSMEM_DYN_RT, ucaRt); else { MVL_LOG_NERR0 ("Error: internal error"); } if (va->arrCtrl.nested == SD_TRUE) M_FREE (MSMEM_MVLU_AA, va->arrCtrl.alt_acc.aa); } mvlu_free_rt_type (va->type_id); mvl_var_destroy (va); } } /************************************************************************/ /************************************************************************/ /* MANUFACTURED VARIABLE_LIST RESOLUTION FUNCTIONS */ /************************************************************************/ /* u_mvl_get_nvl, u_mvl_free_nvl functions deleted (no longer needed). */ /* They were only needed because Foundry could not find the variables */ /* for the NVL to set "vl->entries". But new improved Foundry */ /* generates code like the following (only done once at startup, */ /* so it is much more efficient): */ /* * varObjName.obj_name.vmd_spec = "DI$Name"; * varObjName.object_tag = DOM_SPEC; * varObjName.domain_id = mvl_vmd.dom_tbl[6]->name; * vl->entries [0] = u_mvl_get_va_aa (MMSOP_INFO_RPT, &varObjName, NULL, SD_FALSE, NULL, NULL); */ /************************************************************************/ /************************************************************************/ /* GET NAMELIST HELPER FUNCTIONS */ /* These functions are necessary because MVL does not know about our */ /* manufactured variables and variable lists. We will fill in part of */ /* the namelist response data structure. */ /************************************************************************/ /************************************************************************/ /* u_gnl_ind_vars */ /************************************************************************/ ST_INT u_gnl_ind_vars (MVL_NET_INFO *net_info, NAMELIST_REQ_INFO *req_info, ST_CHAR **ptr, ST_BOOLEAN *moreFollowsOut, ST_INT maxNames) { ST_INT i; ST_INT numRespNames; ST_CHAR caBuf[100]; ST_CHAR *caPtr; ST_CHAR *p; ST_INT numVa; ST_INT v; MVL_VAR_ASSOC **va; MVL_AA_OBJ_CTRL *aa; MVL_DOM_CTRL *domCtrl; gnlNameBuf = (ST_CHAR *) M_CALLOC (MSMEM_MVLU_GNL, 1, maxNames * (MAX_IDENT_LEN +1)); /* Start by finding the VA that we should start with */ /* Get the variable associations in the selected scope */ numVa = 0; if (req_info->objscope == VMD_SPEC) { numVa = mvl_vmd.num_var_assoc; va = mvl_vmd.var_assoc_tbl; } else if (req_info->objscope == DOM_SPEC) { domCtrl = mvl_vmd_find_dom (&mvl_vmd, req_info->dname); if (domCtrl) { numVa = domCtrl->num_var_assoc; va = domCtrl->var_assoc_tbl; } else { MVL_LOG_NERR1 ("GetNameList variables: Domain '%s' not found", req_info->dname); *moreFollowsOut = SD_FALSE; return (-1); /* error. This triggers error response */ } } else /* AA_SPEC */ { aa = (MVL_AA_OBJ_CTRL *) net_info->aa_objs; if (aa) { numVa = aa->num_var_assoc; va = aa->var_assoc_tbl; } else { *moreFollowsOut = SD_FALSE; return (-1); /* error. This triggers error response */ } } /* Take care of the 'continue after' business as necessary. Note that */ /* we will only look at the base name. */ i = 0; if (req_info->cont_after_pres) { caPtr = req_info->continue_after; strcpy (caBuf, req_info->continue_after); p = strstr (caBuf,"$"); if (p) *p = 0; while (i < numVa) { p = va[i]->name; v = strcmp (caBuf, p); if (v == 0) /* Exact match */ break; if (v < 0) /* CA is less than real VA name */ { if (i > 0) /* Start with the previous VA */ --i; break; } ++i; /* We have not found our place yet ... */ } } else caPtr = NULL; *moreFollowsOut = SD_FALSE; currGnlNamePos = gnlNameBuf; /* OK, va[i] is where we start putting together our names */ for (numRespNames = 0; numRespNames < maxNames && i < numVa; ++i) { ST_INT j; ST_INT numRespNamesStart = numRespNames; /* save count modified by fct*/ getGnlVarNames (va[i], caPtr, &ptr[numRespNames], maxNames, &numRespNames, moreFollowsOut); MVLU_LOG_DEBUG0 ("Names returned from getGnlVarNames"); for (j = numRespNamesStart; jflags & MVL_VAR_FLAG_UCA) == 0) { ++(*numNames); dest[0] = va->name; return; } memset (namePrefix, 0, sizeof(namePrefix)); strcpy (namePrefix[0], va->name); /* First we need to find the starting 'sortedNum', based on the CA name */ nameCount = *numNames; startSortedNum = 1; if (caPtr != NULL) { baseIndexOffset = 0; /* CA name could be base name, or derived name. */ if (strcmp (caPtr, va->name) == 0) { /* CA name equals base name. Start with next name AFTER base. */ startSortedNum = 1; } else if ((subStart = strstr (caPtr,"$")) == NULL) /* Skip the base name*/ { MVL_LOG_ERR1 ("Problem finding sub-type in '%s'", caPtr); return; } else { rc = mvl_get_runtime (va->type_id, &ucaRt, &numUcaRt); ++subStart; rc = mvlu_find_uca_var (&ucaRt, &numUcaRt, subStart); if (rc == SD_SUCCESS) startSortedNum = ucaRt->mvluTypeInfo.sortedNum + 1; } } else /* No continue after, we need to include the base name */ { dest[0] = va->name; ++nameCount; baseIndexOffset = 1; --maxNames; } maxRetNames = maxNames - *numNames; maxSortedNum = startSortedNum + maxRetNames - 1; /* OK, now we start doing the real thing. Derive names for this */ /* type, put them into the dest array. */ /* We will save those elements with 'sortedNum' between */ /* 'startSortedNum' and 'maxSortedNum' */ compress = SD_FALSE; rc = mvl_get_runtime (va->type_id, &ucaRt, &numUcaRt); /* This code assumes all UCA vars are structs, so first tag must be RT_STR_START*/ /* DEBUG: change this to "assert"? */ if (ucaRt->el_tag != RT_STR_START) MVL_LOG_ERR1 ("IEC/UCA type (type_id=%d) is not a struct. Cannot derive variable names for GetNameList response.", va->type_id); nestLevel = 0; for (i = 0; i < numUcaRt; ++i, ++ucaRt) { sortedNum = ucaRt->mvluTypeInfo.sortedNum; comp_name = ms_comp_name_find (ucaRt); if (strlen (comp_name) && sortedNum >= startSortedNum && sortedNum <= maxSortedNum) { /* Chk len is legal BEFORE writing (need room for 2 strings + '$'.*/ if (strlen (namePrefix[nestLevel]) + strlen (comp_name) + 1 <= MAX_IDENT_LEN) { sprintf (nameBuf, "%s$%s", namePrefix[nestLevel], comp_name); strLen = strlen (nameBuf); assert (strLen <= MAX_IDENT_LEN); /* if this fails, len chk in "if" is wrong*/ dest[sortedNum-startSortedNum+baseIndexOffset] = currGnlNamePos; strcpy (currGnlNamePos, nameBuf); currGnlNamePos += strLen +1; ++nameCount; } else { MVL_LOG_NERR2 ("Derived variable name '%s$%s' too long to access", namePrefix[nestLevel], comp_name); compress = SD_TRUE; } } if (ucaRt->el_tag == RT_STR_START) { comp_name = ms_comp_name_find (ucaRt); if (strlen (comp_name)) { ++nestLevel; assert (nestLevel < MAX_NEST_LEVEL); assert (nestLevel > 0); strcpy (namePrefix[nestLevel], namePrefix[nestLevel-1]); strcat (namePrefix[nestLevel], "$"); strcat (namePrefix[nestLevel], comp_name); } } else if (ucaRt->el_tag == RT_STR_END) --nestLevel; else if (ucaRt->el_tag == RT_ARR_START) { /* Skip the array elements */ /* There is no way to create UCA names for objects inside an */ /* array, so skip over the array. */ i += (ucaRt->u.arr.num_rt_blks + 1); ucaRt += (ucaRt->u.arr.num_rt_blks + 1); } if (sortedNum > maxSortedNum) *moreFollowsOut = SD_TRUE; } /* DEBUG: at this point loop, 'nestLevel' should equal (-1). This may */ /* sound strange, but nestLevel NOT incremented on first RT_STR_START,*/ /* so last RT_STR_END makes it -1. Add assert here? */ /* If we had to skip one or more names, we need to eliminate the */ /* holes in the name pointer table. */ if (compress == SD_TRUE) { get = 0; put = 0; numNewNames = nameCount - *numNames; while (put < numNewNames) { if (dest[get] != NULL) dest[put++] = dest[get]; ++get; } } *numNames = nameCount; } /************************************************************************/ /* u_gnl_done */ /************************************************************************/ /* This function is called after MVL has send the MMS response to a */ /* GET_NAME_LIST indication. We will clean up memory resources. */ ST_VOID u_gnl_done (ST_INT16 mms_class, NAMELIST_RESP_INFO *resp_info) { if (mms_class == MMS_CLASS_VAR) M_FREE (MSMEM_MVLU_GNL, gnlNameBuf); } /************************************************************************/ /************************************************************************/ /* u_gnl_ind_nvls */ /************************************************************************/ ST_INT u_gnl_ind_nvls (MVL_NET_INFO *net_info, NAMELIST_REQ_INFO *req_info, ST_CHAR **ptr, ST_BOOLEAN *moreFollowsOut, ST_INT maxNames) { ST_INT v; ST_INT i; ST_INT num_obj; MVL_AA_OBJ_CTRL *aa; MVL_NVLIST_CTRL **vl; MVL_DOM_CTRL *domCtrl; ST_INT startIndex; ST_INT numObjLeft; ST_INT numRetNames; ST_CHAR *name; /* First get the number of objects and pointer to the object table */ num_obj = 0; if (req_info->objscope == VMD_SPEC) { num_obj = mvl_vmd.num_nvlist; vl = mvl_vmd.nvlist_tbl; } else if (req_info->objscope == DOM_SPEC) { domCtrl = mvl_vmd_find_dom (&mvl_vmd, req_info->dname); if (domCtrl) { num_obj = domCtrl->num_nvlist; vl = domCtrl->nvlist_tbl; } else { MVL_LOG_NERR1 ("GetNameList NVL: Domain '%s' not found", req_info->dname); *moreFollowsOut = SD_FALSE; return (-1); /* error. This triggers error response */ } } else /* AA_SPEC */ { aa = (MVL_AA_OBJ_CTRL *) net_info->aa_objs; if (aa) { num_obj = aa->num_nvlist; vl = aa->nvlist_tbl; } else { *moreFollowsOut = SD_FALSE; return (-1); /* error. This triggers error response */ } } if (num_obj) { /* Take care of the 'continue after' business if necessary */ startIndex = 0; if (req_info->cont_after_pres) { while (startIndex < num_obj) { name = vl[startIndex]->name; v = strcmp (req_info->continue_after, name); if (v == 0) { ++startIndex; /* Index to the next one */ break; } if (v < 0) break; ++startIndex; /* We have not found our place yet ... */ } } numObjLeft = num_obj-startIndex; numRetNames = min(numObjLeft, maxNames); if (numRetNames < numObjLeft) *moreFollowsOut = SD_TRUE; /* Now make the list for the response */ for (i = 0; i < numRetNames; ++i, ++ptr) *ptr = vl[startIndex+i]->name; return (numRetNames); } return (0); } /************************************************************************/ /************************************************************************/ /* mvlu_clone_objname */ /************************************************************************/ /* This function 'clones' a MMS OBJECT_NAME structure, which means that */ /* it must allocate the various storage elements as required. Note */ /* that the name storage allocation is 65, to give calling routines */ /* room to work. */ static ST_VOID mvlu_clone_objname (ST_CHAR *dest, OBJECT_NAME *src) { OBJECT_NAME *objClone; objClone = (OBJECT_NAME *) dest; memset (dest, 0, _OBJ_NAME_CLONE_SIZE); objClone->object_tag = src->object_tag; objClone->obj_name.vmd_spec = (ST_CHAR *) (objClone + 1); strcpy (objClone->obj_name.vmd_spec, src->obj_name.vmd_spec); if (src->object_tag == DOM_SPEC) { objClone->domain_id = objClone->obj_name.vmd_spec + _OBJ_NAME_CLONE_NAME_SIZE; strcpy (objClone->domain_id, src->domain_id); } } /************************************************************************/ /************************************************************************/ /* MVLU READ/WRITE HANDLERS */ /************************************************************************/ static ST_VOID mvluDefAsyncWrIndFun (struct mvlu_wr_va_ctrl *mvluWrVaCtrl); static ST_VOID mvluDefAsyncRdIndFun (struct mvlu_rd_va_ctrl *mvluRdVaCtrl); /* Function pointers for non-UCA variable handling */ ST_VOID(*mvluAsyncRdIndFun)(struct mvlu_rd_va_ctrl *mvluRdVaCtrl) = mvluDefAsyncRdIndFun; ST_VOID(*mvluAsyncWrIndFun)(struct mvlu_wr_va_ctrl *mvluWrVaCtrl) = mvluDefAsyncWrIndFun; /************************************************************************/ /************************************************************************/ /************************************************************************/ /* mvl_read_ind */ /************************************************************************/ ST_VOID u_mvl_read_ind (MVL_IND_PEND *indCtrl) { MVLAS_READ_CTRL *rdCtrl; MVLAS_RD_VA_CTRL *rdVaCtrl; MVL_VAR_ASSOC *va; MVLU_RD_VA_CTRL *mvluRdVaCtrl; ST_INT i; ST_INT numVar; RUNTIME_TYPE *rt; ST_INT numRt; PRIM_INFO prim_info; rdCtrl = &indCtrl->u.rd; numVar = rdCtrl->numVar; /* First we will go through each variable being read and count the */ /* primitive elelemts. */ rdVaCtrl = rdCtrl->vaCtrlTbl; for (i = 0; i < numVar; ++i, ++rdVaCtrl) { va = rdVaCtrl->va; if (va) /* VA was resolved, we can deal with it */ { mvl_get_runtime (va->type_id, &rt, &numRt); rdVaCtrl->acc_rslt_tag = ACC_RSLT_SUCCESS; rdVaCtrl->numPrimDataDone = 0; if (va->base_va != NULL) /* UCA variable handling ... */ { rdVaCtrl->numPrimData = countPrimEl (va, rt, numRt); } else rdVaCtrl->numPrimData = 1; } else rdVaCtrl->numPrimData = 1; } /* Now we will go through each var being read and invoke the rdInd */ /* function for it. */ rdVaCtrl = rdCtrl->vaCtrlTbl; for (i = 0; i < numVar; ++i, ++rdVaCtrl) { va = rdVaCtrl->va; if (va) /* VA was resolved, we can deal with it */ { /* The VA's data pointer is valid, as is the type ID. */ /* We want to call the handlers for all primitive level functions */ /* for this data type */ if (va->base_va != NULL) /* UCA variable handling ... */ { mvl_get_runtime (va->type_id, &rt, &numRt); /* Initialize prim_info struct. */ if (init_prim_info (va, &prim_info)) { /* Failed. Can't process this var. Skip to next var in list*/ MVL_LOG_ERR1 ("init_prim_info failed for 'Read' of variable '%s'", va->name); rdVaCtrl->acc_rslt_tag = ACC_RSLT_FAILURE; continue; /* skip to next variable */ } #if defined (IEC_61850_SERVER_OPC_CLIENT) /* OPC Client code runs in a separate thread and writes data to * the static data buffer (i.e. va->base_va->data). Need this * semaphore to protect access to the static data buffer. * CRITICAL: OPC Client must use the same semaphore. */ S_LOCK_COMMON_RESOURCES (); #endif startElReads (indCtrl, rdCtrl, rdVaCtrl, rt, numRt, &prim_info); #if defined (IEC_61850_SERVER_OPC_CLIENT) S_UNLOCK_COMMON_RESOURCES (); #endif } else /* Non-UCA variable handling ... */ { mvluRdVaCtrl = (MVLU_RD_VA_CTRL *) M_CALLOC (MSMEM_MVLU_VA_CTRL, 1, sizeof (MVLU_RD_VA_CTRL)); mvluRdVaCtrl->primData = (ST_CHAR *) va->data; mvluRdVaCtrl->indCtrl = indCtrl; mvluRdVaCtrl->rdVaCtrl = rdVaCtrl; (*mvluAsyncRdIndFun)(mvluRdVaCtrl); } } else /* VA not found, let it be done */ { mvluRdVaCtrl = (MVLU_RD_VA_CTRL *) M_CALLOC (MSMEM_MVLU_VA_CTRL, 1, sizeof (MVLU_RD_VA_CTRL)); mvluRdVaCtrl->indCtrl = indCtrl; mvluRdVaCtrl->rdVaCtrl = rdVaCtrl; mvlu_rd_prim_done (mvluRdVaCtrl, SD_SUCCESS); } } } /************************************************************************/ /* mvlu_trim_branch_name */ /* Find last '$' in name and replace it with NULL. */ /************************************************************************/ ST_VOID mvlu_trim_branch_name (ST_CHAR *branch_name) { ST_CHAR *ptr; if ((ptr = strrchr (branch_name, '$')) != NULL) /* find last '$'*/ *ptr = 0; /* replace '$' with NULL */ return; } /************************************************************************/ /* startElReads */ /************************************************************************/ static ST_VOID startElReads (MVL_IND_PEND *indCtrl, MVLAS_READ_CTRL *rdCtrl, MVLAS_RD_VA_CTRL *rdVaCtrl, RUNTIME_TYPE *rt, ST_INT rt_num, PRIM_INFO *prim_info) { ST_INT i; MVLU_RD_VA_CTRL *mvluRdVaCtrl; ST_RTINT rdIndFunIndex; ST_UCHAR el_tag; ST_RTINT el_size; ST_RTINT num_rt_blks; #if defined(MVL_XNAME) ST_CHAR element_name[MAX_IDENT_LEN+1]; ST_CHAR branch_name[MAX_IDENT_LEN+1]; MVL_VAR_ASSOC *va; ST_CHAR *comp_name; #endif #if defined(MVL_XNAME) va = rdVaCtrl->va; element_name[0]=0; strcpy (branch_name,va->name); /* if this is a substructure we need to trim back one level of the name */ /* because the first rt element will be the name of the component */ /* already part of the va->name */ if ((rt_num > 1) && (strstr (branch_name,"$"))) { mvlu_trim_branch_name (branch_name); } #endif for (i = 0; i < rt_num; ++i, ++rt) { #if defined(MVL_XNAME) if (rt_num > 1) { comp_name = ms_comp_name_find (rt); if (strlen (comp_name)) { if ((rt->el_tag == RT_STR_START)) { strcat (branch_name, "$"); strcat (branch_name, comp_name); strcpy (element_name, branch_name); } else { element_name[0]=0; strcat (element_name, branch_name); strcat (element_name, "$"); strcat (element_name, comp_name); } } if (rt->el_tag == RT_STR_END) { strcpy (element_name, branch_name); mvlu_trim_branch_name (branch_name); } } else { /* only one element in the RT table assume it's a primitive */ strcpy (element_name, branch_name); } #endif el_tag = rt->el_tag; num_rt_blks = rt->u.arr.num_rt_blks; el_size = rt->el_size; if (ms_is_rt_prim (rt) == SD_TRUE) { rdIndFunIndex = rt->mvluTypeInfo.rdIndFunIndex; if (u_mvlu_leaf_rd_ind_fun != NULL || (rdIndFunIndex >= 0 && rdIndFunIndex < mvluNumRdFunEntries)) { mvluRdVaCtrl = (MVLU_RD_VA_CTRL *) M_CALLOC (MSMEM_MVLU_VA_CTRL, 1, sizeof (MVLU_RD_VA_CTRL)); mvluRdVaCtrl->rt = rt; #if defined(MVL_XNAME) strcpy (mvluRdVaCtrl->xName, element_name); #endif mvluRdVaCtrl->primData = (ST_CHAR *) rdVaCtrl->va->data + prim_info->prim_offset; mvluRdVaCtrl->indCtrl = indCtrl; mvluRdVaCtrl->rdVaCtrl = rdVaCtrl; #if defined(MVLU_USE_REF) mvluRdVaCtrl->primRef = rt->mvluTypeInfo.ref; #endif mvluRdVaCtrl->prim_num = prim_info->prim_num; mvluRdVaCtrl->prim_offset_base = prim_info->prim_offset_base; if (u_mvlu_leaf_rd_ind_fun == NULL) (*mvluRdFunInfoTbl[rdIndFunIndex].fun_ptr)(mvluRdVaCtrl); else (*u_mvlu_leaf_rd_ind_fun)(mvluRdVaCtrl); } else rdVaCtrl->acc_rslt_tag = ACC_RSLT_FAILURE; prim_info->prim_num++; } if (el_tag == RT_ARR_START) { startArrRds (indCtrl, rdCtrl, rdVaCtrl, rt, prim_info); i += (num_rt_blks + 1); rt += (num_rt_blks + 1); } else { prim_info->prim_offset += el_size; prim_info->prim_offset_base += el_size; } } } /************************************************************************/ /* startArrRds */ /************************************************************************/ static ST_VOID startArrRds (MVL_IND_PEND *indCtrl, MVLAS_READ_CTRL *rdCtrl, MVLAS_RD_VA_CTRL *rdVaCtrl, RUNTIME_TYPE *rt, PRIM_INFO *prim_info) { ST_RTINT i; MVL_VAR_ASSOC *va; ST_INT numRt; ST_RTINT low_index; ST_RTINT num_elmnts; numRt = rt->u.arr.num_rt_blks+2; va = rdVaCtrl->va; if (va->arrCtrl.arrAltAccPres == SD_TRUE) { low_index = va->arrCtrl.low_index; num_elmnts = va->arrCtrl.num_elmnts; } else { low_index = 0; num_elmnts = rt->u.arr.num_elmnts; } /* Let's check to see if the client is selecting a sub-object ... */ prim_info->prim_offset += rt->el_size; prim_info->prim_offset_base += rt->el_size; for (i = 0; i < num_elmnts; ++i) { va->arrCtrl.curr_index = low_index + i; startElReads (indCtrl, rdCtrl, rdVaCtrl, rt+1, numRt-2, prim_info); } prim_info->prim_offset += (rt+numRt-1)->el_size; prim_info->prim_offset_base += (rt+numRt-1)->el_size; } /************************************************************************/ /* mvlu_rd_prim_done */ /************************************************************************/ /* The user calls this function acynchronously when the primitive data */ /* has been put in the 'primData' buffer. */ ST_VOID mvlu_rd_prim_done (MVLU_RD_VA_CTRL *mvluRdVaCtrl, ST_RET rc) { MVL_IND_PEND *indCtrl; MVLAS_READ_CTRL *rdCtrl; MVLAS_RD_VA_CTRL *rdVaCtrl; ST_INT i; rdVaCtrl = mvluRdVaCtrl->rdVaCtrl; if (rc != SD_SUCCESS) { /* DEBUG LIZ: added logging why read failed */ MVL_LOG_NERR2 ("Read failed for UCA variable '%s' rc=%d", rdVaCtrl->va->name, rc); rdVaCtrl->acc_rslt_tag = ACC_RSLT_FAILURE; } ++rdVaCtrl->numPrimDataDone; if (rdVaCtrl->numPrimDataDone == rdVaCtrl->numPrimData) { /* All primitives for "one" variable are complete. */ indCtrl = mvluRdVaCtrl->indCtrl; if (indCtrl->scan_va_done_fun) (*indCtrl->scan_va_done_fun)(indCtrl, rdVaCtrl->va); /* If all primitives for all variables are complete, respond now */ rdCtrl = &indCtrl->u.rd; rdVaCtrl = rdCtrl->vaCtrlTbl; for (i = 0; i < rdCtrl->numVar; ++i, ++rdVaCtrl) { if (rdVaCtrl->numPrimDataDone != rdVaCtrl->numPrimData) break; } if (i == rdCtrl->numVar) { if (indCtrl->op != MMSOP_READ) { /* Not normal read. Do special processing. */ if (indCtrl->usr_resp_fun) { /* If user set custom resp fun, call it. */ (*indCtrl->usr_resp_fun) (indCtrl); } } else mvlas_read_resp (indCtrl); } } M_FREE (MSMEM_MVLU_VA_CTRL, mvluRdVaCtrl); } /************************************************************************/ /* mvluDefAsyncRdIndFun */ /************************************************************************/ static ST_VOID mvluDefAsyncRdIndFun (struct mvlu_rd_va_ctrl *mvluRdVaCtrl) { mvlu_rd_prim_done (mvluRdVaCtrl, SD_SUCCESS); } /************************************************************************/ /************************************************************************/ /* mvlu_write_ind */ /************************************************************************/ ST_VOID u_mvl_write_ind (MVL_IND_PEND *indCtrl) { MVLAS_WRITE_CTRL *wrCtrl; MVLAS_WR_VA_CTRL *wrVaCtrl; MVL_VAR_ASSOC *va; MVLU_WR_VA_CTRL *mvluWrVaCtrl; ST_INT i; ST_INT numVar; RUNTIME_TYPE *rt; ST_INT numRt; PRIM_INFO prim_info; wrCtrl = &indCtrl->u.wr; numVar = wrCtrl->numVar; /* First we will go through each variable being written and count the */ /* primitive elelemts. */ wrVaCtrl = wrCtrl->vaCtrlTbl; for (i = 0; i < numVar; ++i, ++wrVaCtrl) { va = wrVaCtrl->va; if (va) /* VA was resolved, we can look it over */ { mvl_get_runtime (va->type_id, &rt, &numRt); wrVaCtrl->resp_tag = WR_RSLT_SUCCESS; wrVaCtrl->numPrimDataDone = 0; if (va->base_va != NULL) /* UCA variable handling ... */ wrVaCtrl->numPrimData = countPrimEl (va, rt, numRt); else wrVaCtrl->numPrimData = 1; } else wrVaCtrl->numPrimData = 1; } /* Now we will go through each var being written and invoke the wrInd */ /* function for it. */ wrVaCtrl = wrCtrl->vaCtrlTbl; for (i = 0; i < numVar; ++i, ++wrVaCtrl) { va = wrVaCtrl->va; if (va) /* VA was resolved, we can look it over */ { /* The VA's data pointer is valid, as is the type ID. */ /* We want to call the handlers for all primitive level functions */ /* for this data type */ if (va->base_va != NULL) /* UCA variable handling ... */ { mvl_get_runtime (va->type_id, &rt, &numRt); /* Initialize prim_info struct. */ if (init_prim_info (va, &prim_info)) { /* Failed. Can't process this var. Skip to next var in list*/ MVL_LOG_ERR1 ("init_prim_info failed for 'Write' of variable '%s'", va->name); wrVaCtrl->resp_tag = WR_RSLT_FAILURE; continue; /* skip to next variable */ } startElWrites (indCtrl, wrCtrl,wrVaCtrl, rt, numRt, &prim_info); } else /* Non-UCA variable handling ... */ { mvluWrVaCtrl = (MVLU_WR_VA_CTRL *) M_CALLOC (MSMEM_MVLU_VA_CTRL, 1, sizeof (MVLU_WR_VA_CTRL)); mvluWrVaCtrl->primData = (ST_CHAR *) va->data; mvluWrVaCtrl->indCtrl = indCtrl; mvluWrVaCtrl->wrVaCtrl = wrVaCtrl; (*mvluAsyncWrIndFun)(mvluWrVaCtrl); } } else { mvluWrVaCtrl = (MVLU_WR_VA_CTRL *) M_CALLOC (MSMEM_MVLU_VA_CTRL, 1, sizeof (MVLU_WR_VA_CTRL)); mvluWrVaCtrl->indCtrl = indCtrl; mvluWrVaCtrl->wrVaCtrl = wrVaCtrl; mvlu_wr_prim_done (mvluWrVaCtrl, SD_SUCCESS); } } } /************************************************************************/ /* startElWrites */ /************************************************************************/ static ST_VOID startElWrites (MVL_IND_PEND *indCtrl, MVLAS_WRITE_CTRL *wrCtrl, MVLAS_WR_VA_CTRL *wrVaCtrl, RUNTIME_TYPE *rt, ST_INT rt_num, PRIM_INFO *prim_info) { ST_INT i; MVLU_WR_VA_CTRL *mvluWrVaCtrl; ST_RTINT wrIndFunIndex; ST_UCHAR el_tag; ST_RTINT el_size; ST_RTINT num_rt_blks; #if defined(MVL_XNAME) ST_CHAR element_name[MAX_IDENT_LEN+1]; ST_CHAR branch_name[MAX_IDENT_LEN+1]; MVL_VAR_ASSOC *va; ST_CHAR *comp_name; #endif ST_CHAR sboName[MAX_SBO_NAME_SIZE+1]; #if !defined(MVL61850_CTL_DISABLE) ST_INT oper_nest_level = 0; MVL_NET_INFO *save_net_info = indCtrl->event->net_info; /* save to use after indCtrl free*/ MVL_VAR_ASSOC *base_var = wrVaCtrl->va->base_va; #endif #if defined(MVL_XNAME) va = wrVaCtrl->va; element_name[0]=0; strcpy (branch_name,va->name); /* if this is a substructure we need to trim back one level of the name */ /* because the first rt element will be the name of the component */ /* already part of the va->name */ if ((rt_num > 1) && (strstr (branch_name, "$"))) { mvlu_trim_branch_name (branch_name); } #endif for (i = 0; i < rt_num; ++i, ++rt) { #if defined(MVL_XNAME) if (rt_num > 1) /* is this a collection of elements? */ { comp_name = ms_comp_name_find (rt); if (strlen (comp_name)) { if ((rt->el_tag == RT_STR_START)) { strcat (branch_name, "$"); strcat (branch_name, comp_name); strcpy (element_name, branch_name); } else { element_name[0]=0; strcat (element_name, branch_name); strcat (element_name, "$"); strcat (element_name, comp_name); } } if (rt->el_tag == RT_STR_END) { strcpy (element_name, branch_name); mvlu_trim_branch_name (branch_name); } } else { /* only one element in the RT table assume it's a primitive */ strcpy (element_name, branch_name); } #endif el_tag = rt->el_tag; num_rt_blks = rt->u.arr.num_rt_blks; el_size = rt->el_size; /* Do some special stuff for IEC 61850 SBO controls. */ /* If this comp is start of struct & comp name is "Oper" or "Cancel",*/ /* check SBO state. */ if (rt->el_tag == RT_STR_START && (strcmp (ms_comp_name_find(rt), "Oper") == 0 || strcmp (ms_comp_name_find(rt), "Cancel") == 0)) { /* Check "Select" timeouts for ALL SBO controls. */ mvlu_sbo_chk_timers (); /* Chk SBO state. Save in wrVaCtrl->sboCtrl (NULL if "Select" not done).*/ mvl61850_sbo_create_sboname (wrVaCtrl->va, &wrVaCtrl->va_scope, sboName); wrVaCtrl->sboCtrl = mvlu_sbo_chk_state (sboName, indCtrl->event->net_info); } #if !defined(MVL61850_CTL_DISABLE) if (rt->el_tag == RT_STR_START) { /* only increment this if this is "Oper" or already inside "Oper". */ if (oper_nest_level>0) oper_nest_level++; else if (strcmp (ms_comp_name_find(rt), "Oper") == 0) { u_mvl61850_ctl_oper_begin (sboName); oper_nest_level++; } } if (rt->el_tag == RT_STR_END) { if (oper_nest_level>0) { if (--oper_nest_level==0) { /* All leaf functs have been called for "Oper" struct.*/ /* CRITICAL: use save_net_info because indCtrl may have been freed.*/ u_mvl61850_ctl_oper_end (save_net_info, sboName, base_var); } } } #endif /* !defined(MVL61850_CTL_DISABLE) */ if (ms_is_rt_prim (rt) == SD_TRUE) { wrIndFunIndex = rt->mvluTypeInfo.wrIndFunIndex; if (u_mvlu_leaf_wr_ind_fun != NULL || (wrIndFunIndex >= 0 && wrIndFunIndex < mvluNumWrFunEntries)) { mvluWrVaCtrl = (MVLU_WR_VA_CTRL *) M_CALLOC (MSMEM_MVLU_VA_CTRL, 1, sizeof (MVLU_WR_VA_CTRL)); #if defined(MVL_XNAME) strcpy (mvluWrVaCtrl->xName, element_name); #endif mvluWrVaCtrl->primData = (ST_CHAR *) wrVaCtrl->va->data + prim_info->prim_offset; mvluWrVaCtrl->indCtrl = indCtrl; mvluWrVaCtrl->wrVaCtrl = wrVaCtrl; mvluWrVaCtrl->rt = rt; #if defined(MVLU_USE_REF) mvluWrVaCtrl->primRef = rt->mvluTypeInfo.ref; #endif mvluWrVaCtrl->prim_num = prim_info->prim_num; mvluWrVaCtrl->prim_offset_base = prim_info->prim_offset_base; if (u_mvlu_leaf_wr_ind_fun == NULL) (*mvluWrFunInfoTbl[wrIndFunIndex].fun_ptr)(mvluWrVaCtrl); else (*u_mvlu_leaf_wr_ind_fun)(mvluWrVaCtrl); } else wrVaCtrl->resp_tag = WR_RSLT_FAILURE; prim_info->prim_num++; } if (el_tag == RT_ARR_START) { startArrWrs (indCtrl, wrCtrl, wrVaCtrl, rt, prim_info); i += (num_rt_blks + 1); rt += (num_rt_blks + 1); } else { prim_info->prim_offset += el_size; prim_info->prim_offset_base += el_size; } } } /************************************************************************/ /* startArrWrs */ /************************************************************************/ static ST_VOID startArrWrs (MVL_IND_PEND *indCtrl, MVLAS_WRITE_CTRL *wrCtrl, MVLAS_WR_VA_CTRL *wrVaCtrl, RUNTIME_TYPE *rt, PRIM_INFO *prim_info) { ST_RTINT i; MVL_VAR_ASSOC *va; ST_INT numRt; ST_RTINT low_index; ST_RTINT num_elmnts; numRt = rt->u.arr.num_rt_blks+2; va = wrVaCtrl->va; if (va->arrCtrl.arrAltAccPres == SD_TRUE) { low_index = va->arrCtrl.low_index; num_elmnts = va->arrCtrl.num_elmnts; } else { low_index = 0; num_elmnts = rt->u.arr.num_elmnts; } /* Let's check to see if the client is selecting a sub-object ... */ prim_info->prim_offset += rt->el_size; prim_info->prim_offset_base += rt->el_size; for (i = 0; i < num_elmnts; ++i) { va->arrCtrl.curr_index = low_index + i; startElWrites (indCtrl, wrCtrl, wrVaCtrl, rt+1, numRt-2, prim_info); } prim_info->prim_offset += (rt+numRt-1)->el_size; prim_info->prim_offset_base += (rt+numRt-1)->el_size; } /************************************************************************/ /* mvlu_wr_prim_done */ /************************************************************************/ /* The user calls this function acynchronously when the primitive data */ /* has been put in the 'primData' buffer. */ ST_VOID mvlu_wr_prim_done (MVLU_WR_VA_CTRL *mvluWrVaCtrl, ST_RET rc) { MVL_IND_PEND *indCtrl; MVLAS_WRITE_CTRL *wrCtrl; MVLAS_WR_VA_CTRL *wrVaCtrl; ST_INT i; wrVaCtrl = mvluWrVaCtrl->wrVaCtrl; if (rc != SD_SUCCESS) wrVaCtrl->resp_tag = WR_RSLT_FAILURE; ++wrVaCtrl->numPrimDataDone; if (wrVaCtrl->numPrimDataDone == wrVaCtrl->numPrimData) { indCtrl = mvluWrVaCtrl->indCtrl; wrCtrl = &indCtrl->u.wr; /* If all primitives for all variables are complete, respond now */ wrVaCtrl = wrCtrl->vaCtrlTbl; for (i = 0; i < wrCtrl->numVar; ++i, ++wrVaCtrl) { if (wrVaCtrl->numPrimDataDone != wrVaCtrl->numPrimData) break; else { /* Done writing this var. */ /* Do special cleanup for IEC 61850 SBO controls. */ /* If wrVaCtrl->sboCtrl != NULL, this var is SBO Oper or Cancel */ /* (see startElWrites), so do SBO cleanup. */ if (wrVaCtrl->sboCtrl) { mvlu_sbo_ctrl_free (wrVaCtrl->sboCtrl); wrVaCtrl->sboCtrl = NULL; /* reset this so free not done twice.*/ } #if !defined(MVL61850_CTL_DISABLE) /* If Write failed, and Var is IEC 61850 Oper, Cancel, or SBOw, */ /* must also send InformationReport containing LastApplError. */ if (wrVaCtrl->resp_tag == WR_RSLT_FAILURE && wrVaCtrl->va != NULL) /* var might not be found*/ { ST_CHAR *lastdollar = strrchr (wrVaCtrl->va->name, '$'); /* find last '$'*/ /* lastdollar should ALWAYS be valid*/ /* If var name ends in Oper, etc, call user funct to send LastApplError.*/ if (strcmp (lastdollar+1, "Oper") == 0 || strcmp (lastdollar+1, "Cancel") == 0 || strcmp (lastdollar+1, "SBOw") == 0) { /* Construct & send LastApplError info report.*/ ST_CHAR *ptr; /* ptr into CntrlObj string */ /* Fill in "LastApplError" structure. */ /* Construct CntrlObj from var->name. Other members (Error, */ /* AddCause, Origin, ctlNum) already set by leaf functions. */ strcpy (wrVaCtrl->LastApplError.CntrlObj, wrVaCtrl->va->name); ptr = strrchr (wrVaCtrl->LastApplError.CntrlObj, '$'); /* find last '$'*/ strcpy (ptr+1, "Oper"); /* replace last component name with "Oper"*/ mvl61850_ctl_lastapplerror_send (indCtrl->event->net_info, &wrVaCtrl->LastApplError); } } #endif /* !defined(MVL61850_CTL_DISABLE) */ } } if (i == wrCtrl->numVar) { mvlas_write_resp (indCtrl); } } M_FREE (MSMEM_MVLU_VA_CTRL, mvluWrVaCtrl); } /************************************************************************/ /* mvluDefAsyncWrIndFun */ /************************************************************************/ static ST_VOID mvluDefAsyncWrIndFun (struct mvlu_wr_va_ctrl *mvluWrVaCtrl) { mvlu_wr_prim_done (mvluWrVaCtrl, SD_SUCCESS); } /************************************************************************/ /************************************************************************/ /* countPrimEl */ /************************************************************************/ static ST_INT countPrimEl (MVL_VAR_ASSOC *va, RUNTIME_TYPE *rt, ST_INT rt_num) { ST_INT i; ST_INT num_elmnts; ST_INT numPrimData; ST_INT subElCount; numPrimData = 0; for (i = 0; i < rt_num; ++i, ++rt) { if (ms_is_rt_prim (rt) == SD_TRUE) ++numPrimData; if (rt->el_tag == RT_ARR_START) { subElCount = countPrimEl (va, rt+1, rt->u.arr.num_rt_blks); if (va->arrCtrl.arrAltAccPres == SD_FALSE) num_elmnts = rt->u.arr.num_elmnts; else num_elmnts = va->arrCtrl.num_elmnts; numPrimData += (subElCount * num_elmnts); i += (rt->u.arr.num_rt_blks + 1); rt += (rt->u.arr.num_rt_blks + 1); } } return (numPrimData); } /************************************************************************/ /* mvluDefGetVaDataBufFun */ /************************************************************************/ static ST_VOID mvluDefGetVaDataBufFun (ST_INT service, MVL_VAR_ASSOC *va, ST_INT size) { if (service == MMSOP_READ || service == MMSOP_WRITE || service == MMSOP_INFO_RPT || service == MMSOP_RDWR_USR_HANDLED) { /* If static data used, va->data points within base_va. */ if (!va->base_va->use_static_data) va->data = M_MALLOC (MSMEM_MVLU_VA_DATA, size); else va->data = (((ST_CHAR *) va->base_va->data) + va->offset_from_base); } else if (service == MMSOP_MVLU_RPT_VA) { } } /************************************************************************/ /* mvluDefFreeVaDataBufFun */ /************************************************************************/ static ST_VOID mvluDefFreeVaDataBufFun (ST_INT service, MVL_VAR_ASSOC *va) { if (service == MMSOP_READ || service == MMSOP_WRITE || service == MMSOP_INFO_RPT || service == MMSOP_RDWR_USR_HANDLED) { if (!va->base_va->use_static_data) M_FREE (MSMEM_MVLU_VA_DATA, va->data); } else if (service == MMSOP_MVLU_RPT_VA) { } } /************************************************************************/ /* mvlu_find_rt_leaf */ /************************************************************************/ RUNTIME_TYPE *mvlu_find_rt_leaf (ST_INT type_id, ST_CHAR *leafName) { RUNTIME_TYPE *rt; ST_INT numRt; ST_RET ret; ret = mvl_get_runtime (type_id, &rt, &numRt); if (ret != SD_SUCCESS) { MVL_LOG_NERR1 ("Could not get RT type for type id %d", type_id); return (NULL); } ret = mvlu_find_uca_var (&rt, &numRt, leafName); if (ret != SD_SUCCESS) { MVL_LOG_NERR1 ("Could not find leaf '%s'", leafName); return (NULL); } if (numRt != 1) { /* See if this is an array with a single primitive element */ if (rt->el_tag == RT_ARR_START && numRt == 3) return (rt+1); MVL_LOG_NERR1 ("'%s' is a branch, not a leaf", leafName); return (NULL); } return (rt); } /************************************************************************/ /* mvlu_find_comp_type */ /* Arguments: */ /* base_type_id type ID for top level variable */ /* flatname flattened component name with top level var */ /* name (Logical Node) stripped off. */ /* sub_rt_type Ptr to (RUNTIME_TYPE *) to be filled in. */ /* sub_rt_num Ptr to "count" to be filled in. */ /************************************************************************/ ST_RET mvlu_find_comp_type (ST_INT base_type_id, ST_CHAR *flatname, RUNTIME_TYPE **sub_rt_type, /* out */ ST_INT *sub_rt_num) /* out */ { MVL_TYPE_CTRL *base_type_ctrl; ST_RET ret; base_type_ctrl = mvl_type_ctrl_find (base_type_id); if (base_type_ctrl) { *sub_rt_type = base_type_ctrl->rt; *sub_rt_num = base_type_ctrl->num_rt; ret = mvlu_find_uca_var (sub_rt_type, sub_rt_num, flatname); } else ret = SD_FAILURE; /* NOTE: don't log error here. Caller may often pass invalid names. */ return (ret); } /************************************************************************/ /* mvlu_get_leaf_val_int8 */ /* Get leaf data value for type ST_INT8. */ /* Arguments: */ /* base_va base variable (i.e. logical node) */ /* flatname flattened leaf name (e.g. ST$Mod$stVal) */ /* data ptr to data written by this function */ /* RETURNS: SD_SUCCESS or SD_FAILURE */ /************************************************************************/ ST_RET mvlu_get_leaf_val_int8 (MVL_VAR_ASSOC *base_va, ST_CHAR *flatname, ST_INT8 *data) { RUNTIME_TYPE *comp_rt_type; /* first rt_type of component */ ST_INT comp_rt_num; /* num of rt_types in component */ ST_RET ret = SD_FAILURE; /* Find the attribute type. */ if (mvlu_find_comp_type (base_va->type_id, flatname, /* flattened name */ &comp_rt_type, /* ptr to val set by function */ &comp_rt_num) /* ptr to val set by function */ == SD_SUCCESS) { if (comp_rt_type->el_tag == RT_INTEGER && comp_rt_type->u.p.el_len == 1) { /* must be INT8 */ *data = *(ST_INT8 *)((ST_CHAR *) base_va->data + comp_rt_type->mvluTypeInfo.offSet); ret = SD_SUCCESS; } else MVL_LOG_ERR1 ("Invalid type for '%s' attribute. Cannot use it.", flatname); } else MVLU_LOG_FLOW2 ("Cannot find '%s' attribute in this variable '%s'", flatname, base_va->name); return (ret); } /************************************************************************/ /* mvlu_get_leaf_val_int32 */ /* Get leaf data value for type ST_INT32. */ /* Arguments: */ /* base_va base variable (i.e. logical node) */ /* flatname flattened leaf name (e.g. ST$Mod$stVal) */ /* data ptr to data written by this function */ /* RETURNS: SD_SUCCESS or SD_FAILURE */ /************************************************************************/ ST_RET mvlu_get_leaf_val_int32 (MVL_VAR_ASSOC *base_va, ST_CHAR *flatname, ST_INT32 *data) { RUNTIME_TYPE *comp_rt_type; /* first rt_type of component */ ST_INT comp_rt_num; /* num of rt_types in component */ ST_RET ret = SD_FAILURE; /* Find the attribute type. */ if (mvlu_find_comp_type (base_va->type_id, flatname, /* flattened name */ &comp_rt_type, /* ptr to val set by function */ &comp_rt_num) /* ptr to val set by function */ == SD_SUCCESS) { if (comp_rt_type->el_tag == RT_INTEGER && comp_rt_type->u.p.el_len == 4) { /* must be INT32 */ *data = *(ST_INT32 *)((ST_CHAR *) base_va->data + comp_rt_type->mvluTypeInfo.offSet); ret = SD_SUCCESS; } else MVL_LOG_ERR1 ("Invalid type for '%s' attribute. Cannot use it.", flatname); } else MVLU_LOG_FLOW2 ("Cannot find '%s' attribute in this variable '%s'", flatname, base_va->name); return (ret); } /************************************************************************/ /* mvlu_get_leaf_val_int_any */ /* Get leaf value for any signed integer. Cast value to ST_INT32. */ /************************************************************************/ ST_RET mvlu_get_leaf_val_int_any (MVL_VAR_ASSOC *base_va, ST_CHAR *flatname, ST_INT32 *data) { RUNTIME_TYPE *comp_rt_type; /* first rt_type of component */ ST_INT comp_rt_num; /* num of rt_types in component */ ST_CHAR *raw_data; /* ptr to data. May be any integer size */ ST_INT8 tmp_int8; /* Used to get val as INT8, then cast to INT32 */ ST_INT16 tmp_int16; /* Used to get val as INT16, then cast to INT32 */ ST_RET retcode = SD_SUCCESS; /* Find the attribute type. */ if (mvlu_find_comp_type (base_va->type_id, flatname, /* flattened name */ &comp_rt_type, /* ptr to val set by function */ &comp_rt_num) /* ptr to val set by function */ == SD_SUCCESS) { raw_data = (ST_CHAR *) base_va->data + comp_rt_type->mvluTypeInfo.offSet; if (comp_rt_type->el_tag == RT_INTEGER) { if (comp_rt_type->u.p.el_len == 1) /* INT8 */ { tmp_int8 = *(ST_INT8 *) raw_data; *data = (ST_INT32) tmp_int8; } else if (comp_rt_type->u.p.el_len == 2) /* INT16 */ { tmp_int16 = *(ST_INT16 *) raw_data; *data = (ST_INT32) tmp_int16; } else if (comp_rt_type->u.p.el_len == 4) /* INT32 */ { *data = *(ST_INT32 *) raw_data; } else { MVL_LOG_ERR2 ("Unsupported integer size for '%s' attribute in variable '%s'", flatname, base_va->name); retcode = SD_FAILURE; } } else { MVL_LOG_ERR2 ("Invalid type for '%s' attribute in variable '%s'. Cannot get value.", flatname, base_va->name); retcode = SD_FAILURE; } } else { MVLU_LOG_FLOW2 ("Cannot find '%s' attribute in variable '%s'", flatname, base_va->name); retcode = SD_FAILURE; } return (retcode); } /************************************************************************/ /* mvlu_get_leaf_val_uint32 */ /* Get leaf data value for type ST_UINT32. */ /* Arguments: */ /* base_va base variable (i.e. logical node) */ /* flatname flattened leaf name (e.g. ST$Mod$stVal) */ /* data ptr to data written by this function */ /* RETURNS: SD_SUCCESS or SD_FAILURE */ /************************************************************************/ ST_RET mvlu_get_leaf_val_uint32 (MVL_VAR_ASSOC *base_va, ST_CHAR *flatname, ST_UINT32 *data) { RUNTIME_TYPE *comp_rt_type; /* first rt_type of component */ ST_INT comp_rt_num; /* num of rt_types in component */ ST_RET ret = SD_FAILURE; /* Find the attribute type. */ if (mvlu_find_comp_type (base_va->type_id, flatname, /* flattened name */ &comp_rt_type, /* ptr to val set by function */ &comp_rt_num) /* ptr to val set by function */ == SD_SUCCESS) { if (comp_rt_type->el_tag == RT_UNSIGNED && comp_rt_type->u.p.el_len == 4) { /* must be UINT32 */ *data = *(ST_UINT32 *)((ST_CHAR *) base_va->data + comp_rt_type->mvluTypeInfo.offSet); ret = SD_SUCCESS; } else MVL_LOG_ERR1 ("Invalid type for '%s' attribute. Cannot use it.", flatname); } else MVLU_LOG_FLOW2 ("Cannot find '%s' attribute in this variable '%s'", flatname, base_va->name); return (ret); } /************************************************************************/ /* mvlu_get_leaf_val_boolean */ /* Get leaf data value for type ST_BOOLEAN. */ /* Arguments: */ /* base_va base variable (i.e. logical node) */ /* flatname flattened leaf name (e.g. ST$Mod$stVal) */ /* data ptr to data written by this function */ /* RETURNS: SD_SUCCESS or SD_FAILURE */ /************************************************************************/ ST_RET mvlu_get_leaf_val_boolean (MVL_VAR_ASSOC *base_va, ST_CHAR *flatname, ST_BOOLEAN *data) { RUNTIME_TYPE *comp_rt_type; /* first rt_type of component */ ST_INT comp_rt_num; /* num of rt_types in component */ ST_RET ret = SD_FAILURE; /* Find the attribute type. */ if (mvlu_find_comp_type (base_va->type_id, flatname, /* flattened name */ &comp_rt_type, /* ptr to val set by function */ &comp_rt_num) /* ptr to val set by function */ == SD_SUCCESS) { if (comp_rt_type->el_tag == RT_BOOL) { /* must be BOOLEAN */ *data = *(ST_BOOLEAN *)((ST_CHAR *) base_va->data + comp_rt_type->mvluTypeInfo.offSet); ret = SD_SUCCESS; } else MVL_LOG_ERR1 ("Invalid type for '%s' attribute. Cannot use it.", flatname); } else MVLU_LOG_FLOW2 ("Cannot find '%s' attribute in this variable '%s'", flatname, base_va->name); return (ret); } /************************************************************************/ /* mvlu_get_leaf_val_bvstring */ /* Get leaf data value for type MMS_BVSTRING. */ /* Arguments: */ /* base_va base variable (i.e. logical node) */ /* flatname flattened leaf name (e.g. ST$Mod$stVal) */ /* data ptr to data written by this function */ /* RETURNS: SD_SUCCESS or SD_FAILURE */ /************************************************************************/ ST_RET mvlu_get_leaf_val_bvstring (MVL_VAR_ASSOC *base_va, ST_CHAR *flatname, MMS_BVSTRING *data, ST_INT max_num_bits) { RUNTIME_TYPE *comp_rt_type; /* first rt_type of component */ ST_INT comp_rt_num; /* num of rt_types in component */ ST_RET ret = SD_FAILURE; ST_INT num_bytes; /* Find the attribute type. */ if (mvlu_find_comp_type (base_va->type_id, flatname, /* flattened name */ &comp_rt_type, /* ptr to val set by function */ &comp_rt_num) /* ptr to val set by function */ == SD_SUCCESS) { /* NOTE: for Bvstring, el_len is negative. */ if (comp_rt_type->el_tag == RT_BIT_STRING && comp_rt_type->u.p.el_len < 0 && abs (comp_rt_type->u.p.el_len) <= max_num_bits) { num_bytes = 2 + (abs (comp_rt_type->u.p.el_len) + 7)/8; memcpy (data, (ST_CHAR *)base_va->data + comp_rt_type->mvluTypeInfo.offSet, num_bytes); ret = SD_SUCCESS; } else MVL_LOG_ERR1 ("Invalid type for '%s' attribute. Cannot use it.", flatname); } else MVLU_LOG_FLOW2 ("Cannot find '%s' attribute in this variable '%s'", flatname, base_va->name); return (ret); } /************************************************************************/ /* mvlu_get_leaf_data_ptr */ /* Get leaf data pointer (for any type of leaf). */ /* Arguments: */ /* base_va base variable (i.e. logical node) */ /* flatname flattened leaf name (e.g. ST$Mod$stVal) */ /* rt_type ptr to ptr to type (function sets "*rt_type") */ /* RETURNS: pointer to leaf data (NULL on error) */ /************************************************************************/ ST_VOID *mvlu_get_leaf_data_ptr (MVL_VAR_ASSOC *base_va, ST_CHAR *flatname, RUNTIME_TYPE **rt_type) { RUNTIME_TYPE *comp_rt_type; /* first rt_type of component */ ST_INT comp_rt_num; /* num of rt_types in component */ ST_VOID *data; /* Find the attribute type. */ if (mvlu_find_comp_type (base_va->type_id, flatname, /* flattened name */ &comp_rt_type, /* ptr to val set by function */ &comp_rt_num) /* ptr to val set by function */ == SD_SUCCESS) { data = ((ST_CHAR *) base_va->data + comp_rt_type->mvluTypeInfo.offSet); *rt_type = comp_rt_type; } else { data = NULL; MVLU_LOG_FLOW2 ("Cannot find '%s' attribute in this variable '%s'", flatname, base_va->name); } return (data); } /************************************************************************/ #endif /* defined(MVL_UCA) */ /************************************************************************/