"Fossies" - the Fresh Open Source Software Archive

Member "opensaf-5.21.09/src/imm/agent/imma_proc.cc" (14 Sep 2021, 141782 Bytes) of package /linux/misc/opensaf-5.21.09.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "imma_proc.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.21.06_vs_5.21.09.

    1 /*      -*- OpenSAF  -*-
    2  *
    3  * (C) Copyright 2008 The OpenSAF Foundation
    4  * Copyright (C) 2017, Oracle and/or its affiliates. All rights reserved.
    5  *
    6  * This program is distributed in the hope that it will be useful, but
    7  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    8  * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
    9  * under the GNU Lesser General Public License Version 2.1, February 1999.
   10  * The complete license can be accessed from the following location:
   11  * http://opensource.org/licenses/lgpl-license.php
   12  * See the Copying file included with the OpenSAF distribution for full
   13  * licensing terms.
   14  *
   15  * Author(s): Ericsson AB
   16  *
   17  */
   18 
   19 /*****************************************************************************
   20   DESCRIPTION:
   21 
   22   This file contains the IMMA processing routines callback
   23   processing routines etc.
   24 *****************************************************************************/
   25 
   26 #include "imma.h"
   27 #include "imm/common/immsv_api.h"
   28 #include "base/ncssysf_mem.h"
   29 #include "base/osaf_extended_name.h"
   30 #include <saAis.h>
   31 
   32 #include <string.h>
   33 
   34 /* For some reason I have to declare the strnlen function prototype.
   35    It does not help to include string.h */
   36 size_t strnlen(const char *s, size_t maxlen);
   37 
   38 static void imma_proc_ccbaug_setup(IMMA_CLIENT_NODE *cl_node,
   39                                    IMMA_CALLBACK_INFO *callback);
   40 
   41 extern SaAisErrorT immsv_om_augment_ccb_get_result(
   42     SaImmOiHandleT privateOmHandle, SaUint32T ccbId) __attribute__((weak));
   43 extern void immsv_om_handle_finalize(SaImmHandleT privateOmHandle)
   44     __attribute__((weak));
   45 
   46 static bool imma_process_callback_info(IMMA_CB *cb, IMMA_CLIENT_NODE *cl_node,
   47                                        IMMA_CALLBACK_INFO *callback,
   48                                        SaImmHandleT immHandle);
   49 
   50 static void imma_proc_free_callback(IMMA_CALLBACK_INFO *callback);
   51 
   52 /****************************************************************************
   53   Name          : imma_version_validate
   54 
   55   Description   : This routine Validates the received version
   56 
   57   Arguments     : SaVersionT *version - Version Info
   58 
   59   Return Values : SA_AIS_OK/SA_AIS<ERROR>
   60 
   61   Notes         : None
   62 ******************************************************************************/
   63 SaAisErrorT imma_version_validate(SaVersionT *version) {
   64   SaAisErrorT retCode = SA_AIS_OK;
   65 
   66   if ((version->releaseCode == IMMA_RELEASE_CODE) &&
   67       (version->majorVersion <= IMMA_MAJOR_VERSION)) {
   68     if ((version->releaseCode == 'A') && (version->majorVersion == 0x01)) {
   69       LOG_NO("ERR_VERSION: Version SAI-AIS-IMM-A.01.01 is not supported");
   70       retCode = SA_AIS_ERR_VERSION;
   71     } else if ((version->releaseCode == 'A') &&
   72                (version->majorVersion == 0x00)) {
   73       LOG_NO("ERR_VERSION: Version SAI-AIS-IMM-A.00.XX does not exist");
   74       retCode = SA_AIS_ERR_VERSION;
   75     }
   76   } else {
   77     TRACE_2("ERR_VERSION: IMMA - Version Incompatible %c %u not supported",
   78             version->releaseCode, version->majorVersion);
   79     retCode = SA_AIS_ERR_VERSION;
   80   }
   81 
   82   version->releaseCode = IMMA_RELEASE_CODE;
   83   version->majorVersion = IMMA_MAJOR_VERSION;
   84   version->minorVersion = IMMA_MINOR_VERSION;
   85 
   86   return retCode;
   87 }
   88 
   89 /****************************************************************************
   90   Name          : imma_callback_ipc_init
   91 
   92   Description   : This routine is used to initialize the queue for the
   93 callbacks.
   94 
   95   Arguments     : client_info - pointer to the client info
   96 
   97   Return Values : NCSCC_RC_SUCCESS/NCSCC_RC_FAILURE
   98 
   99   Notes         : None
  100 ******************************************************************************/
  101 uint32_t imma_callback_ipc_init(IMMA_CLIENT_NODE *client_info) {
  102   uint32_t rc = NCSCC_RC_SUCCESS;
  103   if ((rc = m_NCS_IPC_CREATE(&client_info->callbk_mbx)) == NCSCC_RC_SUCCESS) {
  104     if (m_NCS_IPC_ATTACH(&client_info->callbk_mbx) == NCSCC_RC_SUCCESS) {
  105       return NCSCC_RC_SUCCESS;
  106     }
  107     m_NCS_IPC_RELEASE(&client_info->callbk_mbx, NULL);
  108     TRACE_3("Failed to initialize callback queue");
  109   }
  110   return rc;
  111 }
  112 
  113 /****************************************************************************
  114   Name          : imma_client_cleanup_mbx
  115 
  116   Description   : This routine is used to destroy the queue for the callbacks.
  117 
  118   Arguments     : cl_node - pointer to the client info
  119 
  120   Return Values : NCSCC_RC_SUCCESS/NCSCC_RC_FAILURE
  121 
  122   Notes         : None
  123 ******************************************************************************/
  124 static bool imma_client_cleanup_mbx(NCSCONTEXT arg, NCSCONTEXT msg) {
  125   IMMA_CALLBACK_INFO *callback, *pnext;
  126 
  127   pnext = callback = (IMMA_CALLBACK_INFO *)msg;
  128 
  129   while (pnext) {
  130     pnext = callback->next;
  131     imma_proc_free_callback(callback);
  132     callback = pnext;
  133   }
  134 
  135   return true;
  136 }
  137 
  138 /****************************************************************************
  139   Name          : imma_callback_ipc_destroy
  140 
  141   Description   : This routine used to destroy the queue for the callbacks.
  142 
  143   Arguments     : client_info - pointer to the client info
  144 
  145   Return Values : NCSCC_RC_SUCCESS/NCSCC_RC_FAILURE
  146 
  147   Notes         : None
  148 ******************************************************************************/
  149 void imma_callback_ipc_destroy(IMMA_CLIENT_NODE *cl_node) {
  150   TRACE_ENTER();
  151   /* detach the mail box */
  152   m_NCS_IPC_DETACH(&cl_node->callbk_mbx, imma_client_cleanup_mbx, cl_node);
  153 
  154   /* delete the mailbox */
  155   m_NCS_IPC_RELEASE(&cl_node->callbk_mbx, NULL);
  156 }
  157 
  158 /****************************************************************************
  159   Name          : imma_finalize_client
  160 
  161   Description   : This routine is used to process the finalize request at IMMA.
  162 
  163   Arguments     : cb - IMMA CB.
  164                   cl_node - pointer to the client info
  165 
  166   Return Values : NCSCC_RC_SUCCESS/NCSCC_RC_FAILURE
  167 
  168   Notes         : None
  169 ******************************************************************************/
  170 uint32_t imma_finalize_client(IMMA_CB *cb, IMMA_CLIENT_NODE *cl_node) {
  171   SaImmAdminOwnerHandleT temp_hdl, *temp_ptr = NULL;
  172   IMMA_ADMIN_OWNER_NODE *adm_node = NULL;
  173   SaImmSearchHandleT search_tmp_hdl, *search_tmp_ptr = NULL;
  174   IMMA_SEARCH_NODE *search_node = NULL;
  175 
  176   /* Scan the entire Adm Owner DB and close the handles opened by client */
  177   while ((adm_node = (IMMA_ADMIN_OWNER_NODE *)ncs_patricia_tree_getnext(
  178               &cb->admin_owner_tree, (uint8_t *)temp_ptr))) {
  179     temp_hdl = adm_node->admin_owner_hdl;
  180     temp_ptr = &temp_hdl;
  181 
  182     if (adm_node->mImmHandle == cl_node->handle) {
  183       TRACE("Deleting admin owner node");
  184       imma_admin_owner_node_delete(cb, adm_node);
  185       temp_ptr = NULL; /* Redo iteration from start after delete. */
  186     }
  187   }
  188 
  189   /* Ccb nodes are removed by imma_admin_owner_delete */
  190 
  191   /* Remove any search nodes opened by the client */
  192   while ((search_node = (IMMA_SEARCH_NODE *)ncs_patricia_tree_getnext(
  193               &cb->search_tree, (uint8_t *)search_tmp_ptr))) {
  194     search_tmp_hdl = search_node->search_hdl;
  195     search_tmp_ptr = &search_tmp_hdl;
  196     if (search_node->mImmHandle == cl_node->handle) {
  197       if (imma_search_node_delete(cb, search_node) != NCSCC_RC_SUCCESS) {
  198         TRACE_4("ERROR imma_finalize_client could not delete search_node");
  199         break;
  200       } else
  201         cl_node->searchHandleSize--;
  202       search_tmp_ptr = NULL; /*Redo iteration from start after delete. */
  203     }
  204   }
  205 
  206   imma_callback_ipc_destroy(cl_node);
  207 
  208   TRACE("Deleting client node");
  209   osafassert(imma_client_node_delete(cb, cl_node) == NCSCC_RC_SUCCESS);
  210 
  211   return NCSCC_RC_SUCCESS;
  212 }
  213 
  214 /****************************************************************************
  215   Name          : entry point for SaImmOmAdminOperationInvokeAsyncCallbackT.
  216   Description   : This function will process the AdministartiveOperation
  217                   result up-call for the OM API.
  218   Arguments     : cb - IMMA CB.
  219                   evt - IMMA_EVT.
  220   Return Values : None
  221   Notes         : None
  222 ******************************************************************************/
  223 static void imma_proc_admin_op_async_rsp(IMMA_CB *cb, IMMA_EVT *evt) {
  224   TRACE_ENTER();
  225   IMMA_CALLBACK_INFO *callback;
  226   IMMA_CLIENT_NODE *cl_node = NULL;
  227 
  228   SaImmHandleT immHandleCont;
  229   SaInvocationT userInvoc;
  230   SaInt32T inv = m_IMMSV_UNPACK_HANDLE_LOW(evt->info.admOpRsp.invocation);
  231 
  232   /* get the CB Lock */
  233   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
  234     TRACE_3("Lock failure");
  235     return;
  236   }
  237 
  238   /*NOTE: should get handle from immnd also and verify. */
  239   if (!imma_popAsyncAdmOpContinuation(cb, inv, &immHandleCont, &userInvoc)) {
  240     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  241     TRACE_3(
  242         "Missmatch on continuation for SaImmOmAdminOperationInvokeCallbackT");
  243     return;
  244   }
  245 
  246   /* Get the Client info */
  247   imma_client_node_get(&cb->client_tree, &immHandleCont, &cl_node);
  248   if (!(cl_node && cl_node->isOm)) {
  249     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  250     TRACE_3("Failed to find client node");
  251     return;
  252   }
  253 
  254   imma_proc_decrement_pending_reply(cl_node, false);
  255 
  256   /* Allocate the Callback info */
  257   callback = (IMMA_CALLBACK_INFO *)calloc(1, sizeof(IMMA_CALLBACK_INFO));
  258   if (callback) {
  259     /* Fill the Call Back Info */
  260     callback->type = IMMA_CALLBACK_OM_ADMIN_OP_RSP;
  261     callback->lcl_imm_hdl = immHandleCont;
  262 
  263     TRACE_1("Creating callback for async admop inv:%llx rslt:%u err:%u",
  264             userInvoc, evt->info.admOpRsp.result, evt->info.admOpRsp.error);
  265 
  266     callback->invocation = userInvoc;
  267     callback->sa_err = evt->info.admOpRsp.error;
  268     if (callback->sa_err == SA_AIS_OK) {
  269       callback->retval = evt->info.admOpRsp.result;
  270     } else {
  271       callback->retval =
  272           SA_AIS_ERR_NO_SECTIONS;  // Bogus result since error is set
  273     }
  274 
  275     if (evt->info.admOpRsp.parms) {
  276       callback->params = imma_proc_get_params(evt->info.admOpRsp.parms);
  277       evt->info.admOpRsp.parms = NULL;
  278     }
  279 
  280     /* Send the event */
  281     (void)m_NCS_IPC_SEND(&cl_node->callbk_mbx, callback,
  282                          NCS_IPC_PRIORITY_NORMAL);
  283   }
  284 
  285   /* Release The Lock */
  286   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  287 
  288   TRACE_LEAVE();
  289 }
  290 
  291 SaImmAdminOperationParamsT_2 **imma_proc_get_params(
  292     IMMSV_ADMIN_OPERATION_PARAM *in_params) {
  293   int noOfParams = 0;
  294   IMMSV_ADMIN_OPERATION_PARAM *p = in_params;
  295   size_t paramDataSize = 0;
  296   SaImmAdminOperationParamsT_2 **out_params;
  297   int i = 0;
  298 
  299   while (p) {
  300     ++noOfParams;
  301     p = p->next;
  302   }
  303 
  304   paramDataSize = sizeof(SaImmAdminOperationParamsT_2 *) * (noOfParams + 1);
  305   out_params =
  306       (SaImmAdminOperationParamsT_2 **)calloc(1, paramDataSize); /*alloc-1 */
  307   p = in_params;
  308   for (; i < noOfParams; i++) {
  309     IMMSV_ADMIN_OPERATION_PARAM *prev = p;
  310     out_params[i] = (SaImmAdminOperationParamsT_2 *)malloc(
  311         sizeof(SaImmAdminOperationParamsT_2)); /*alloc-2 */
  312     out_params[i]->paramName =
  313         (char *)malloc(p->paramName.size + 1); /*alloc-3 */
  314     strncpy(out_params[i]->paramName, p->paramName.buf, p->paramName.size + 1);
  315     out_params[i]->paramName[p->paramName.size] =
  316         0; /*string too long=>truncate */
  317     free(p->paramName.buf);
  318     p->paramName.buf = NULL;
  319     p->paramName.size = 0;
  320     out_params[i]->paramType = (SaImmValueTypeT)p->paramType;
  321     out_params[i]->paramBuffer =
  322         imma_copyAttrValue3((SaImmValueTypeT)p->paramType, /*alloc-4 */
  323                             &(p->paramBuffer));
  324     immsv_evt_free_att_val(&(p->paramBuffer), (SaImmValueTypeT)p->paramType);
  325     p = p->next;
  326     prev->next = NULL;
  327     free(prev);
  328   }
  329   return (SaImmAdminOperationParamsT_2 **)out_params;
  330 }
  331 
  332 /****************************************************************************
  333   Name          : imma_proc_admop
  334   Description   : This function will process the AdministartiveOperation
  335                   up-call for the Object Implementer API.
  336   Arguments     : cb - IMMA CB.
  337                   evt - IMMA_EVT.
  338   Return Values : None
  339   Notes         : None
  340 ******************************************************************************/
  341 static void imma_proc_admop(IMMA_CB *cb, IMMA_EVT *evt) {
  342   IMMA_CALLBACK_INFO *callback;
  343   IMMA_CLIENT_NODE *cl_node = NULL;
  344   bool isPbeAdmOp = (evt->type == IMMA_EVT_ND2A_IMM_PBE_ADMOP);
  345 
  346   /*TODO: correct this, ugly use of continuationId */
  347   SaImmOiHandleT implHandle = evt->info.admOpReq.continuationId;
  348 
  349   /* get the CB Lock */
  350   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
  351     TRACE_3("Lock failure");
  352     return;
  353   }
  354 
  355   /* Get the Client info */
  356   imma_client_node_get(&cb->client_tree, &implHandle, &cl_node);
  357   if (!cl_node || cl_node->isOm) {
  358     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  359     TRACE_3("Failed to find client node");
  360     return;
  361   }
  362 
  363   if (isPbeAdmOp) {
  364     if (cl_node->isPbe) {
  365       TRACE_3("PBE-OI received PBE admin operation");
  366     } else {
  367       m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  368       LOG_ER(
  369           "Apparent PBE class create received at OI which is not PBE- ignoring");
  370       return;
  371     }
  372   }
  373 
  374   /* Allocate the Callback info */
  375   callback = (IMMA_CALLBACK_INFO *)calloc(1, sizeof(IMMA_CALLBACK_INFO));
  376   if (callback) {
  377     /* Fill the Call Back Info */
  378     if (isPbeAdmOp) {
  379       callback->type = IMMA_CALLBACK_PBE_ADMIN_OP;
  380     } else {
  381       callback->type = IMMA_CALLBACK_OM_ADMIN_OP;
  382     }
  383     callback->lcl_imm_hdl = implHandle;
  384 
  385     SaInvocationT saInv = m_IMMSV_PACK_HANDLE(evt->info.admOpReq.adminOwnerId,
  386                                               evt->info.admOpReq.invocation);
  387 
  388     callback->invocation = saInv;
  389 
  390     osaf_extended_name_steal(evt->info.admOpReq.objectName.buf,
  391                              &callback->name);
  392     evt->info.admOpReq.objectName.buf = NULL;
  393     evt->info.admOpReq.objectName.size = 0;
  394     callback->operationId = evt->info.admOpReq.operationId;
  395     callback->params = imma_proc_get_params(evt->info.admOpReq.params);
  396     evt->info.admOpReq.params = NULL;
  397     /* Send the event */
  398     (void)m_NCS_IPC_SEND(&cl_node->callbk_mbx, callback,
  399                          NCS_IPC_PRIORITY_NORMAL);
  400   }
  401 
  402   /* Release The Lock */
  403   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  404 }
  405 
  406 /****************************************************************************
  407   Name          : imma_determine_clients_to_resurrect
  408   Description   : Attempts to determine how many clients to attempt active
  409                   resurrection for. Active resurrection can only be done
  410                   when there is a selection object to generate an up-call on.
  411 
  412                   Re-active resurrection is also possible, but that is done
  413                   as a side effect when a stale handle is used in a blocking
  414                   IMM API call.
  415 
  416   Arguments     : cb - IMMA CB.
  417 ******************************************************************************/
  418 void imma_determine_clients_to_resurrect(IMMA_CB *cb, bool *locked) {
  419   /* We are LOCKED already, but we may unlock here => locked will be false*/
  420   IMMA_CLIENT_NODE *clnode;
  421   SaImmHandleT *temp_ptr = 0;
  422   SaImmHandleT temp_hdl = 0;
  423   SaUint32T clientHigh = 0;
  424   IMMSV_EVT clientHigh_evt;
  425 
  426   TRACE_ENTER();
  427   osafassert(locked && *locked); /* We must be entering locked. */
  428 
  429   /* Determine clientHigh count and if there are any clients with
  430      selection objects that can be resurrected */
  431 
  432   if (cb->dispatch_clients_to_resurrect) {
  433     /*
  434        Resurrections alredy in progress, possibly due to repeated
  435        init/close of IMMA library (first/last handle).
  436     */
  437 
  438     TRACE_3("Active resurrection of %u clients already ongoing",
  439             cb->dispatch_clients_to_resurrect);
  440     return;
  441   }
  442 
  443   while ((clnode = (IMMA_CLIENT_NODE *)ncs_patricia_tree_getnext(
  444               &cb->client_tree, (uint8_t *)temp_ptr))) {
  445     temp_hdl = clnode->handle;
  446     temp_ptr = &temp_hdl;
  447     SaUint32T clientId = m_IMMSV_UNPACK_HANDLE_HIGH(clnode->handle);
  448     SaUint32T nodeId = m_IMMSV_UNPACK_HANDLE_LOW(clnode->handle);
  449     if (clientId > clientHigh) {
  450       clientHigh = clientId;
  451     }
  452 
  453     if (!clnode->stale) {
  454       TRACE_3(
  455           "Found NON stale handle <%u, %x> when analyzing handles, "
  456           "bailing from attempt to actively resurrect.",
  457           clientId, nodeId);
  458 
  459       /* This case means we must have gotten IMMND DOWN/UP at least
  460          twice in quick succession.
  461       */
  462 
  463       cb->dispatch_clients_to_resurrect = 0; /* Reset. */
  464       goto done;
  465     }
  466 
  467     if (isExposed(cb, clnode)) {
  468       continue;
  469     }
  470     if (!clnode->selObjUsable) {
  471       continue;
  472     }
  473     ++(cb->dispatch_clients_to_resurrect);
  474     /* Only clients with selection objects can be resurrected actively.
  475        If selObjUsable is false then it means an attempt to actively
  476        resurrect has already started.
  477     */
  478   }
  479 
  480   if (clientHigh) {
  481     /* Inform the IMMND of highest used client ID. */
  482     memset(&clientHigh_evt, 0, sizeof(IMMSV_EVT));
  483     clientHigh_evt.type = IMMSV_EVT_TYPE_IMMND;
  484     clientHigh_evt.info.immnd.type = (cb->sv_id == NCSMDS_SVC_ID_IMMA_OM)
  485                                          ? IMMND_EVT_A2ND_IMM_OM_CLIENTHIGH
  486                                          : IMMND_EVT_A2ND_IMM_OI_CLIENTHIGH;
  487     clientHigh_evt.info.immnd.info.initReq.client_pid = clientHigh;
  488     TRACE_1("ClientHigh message high %u", clientHigh);
  489     /* Unlock before MDS Send */
  490     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  491     *locked = false;
  492     clnode = NULL;
  493 
  494     if (cb->is_immnd_up == false) {
  495       TRACE_3("IMMND is DOWN - clientHigh attempt failed. ");
  496       goto done;
  497     }
  498 
  499     /* send the clientHigh message to the IMMND asyncronously */
  500     if (imma_mds_msg_send(cb->imma_mds_hdl, &cb->immnd_mds_dest,
  501                           &clientHigh_evt,
  502                           NCSMDS_SVC_ID_IMMND) != NCSCC_RC_SUCCESS) {
  503       /* Failure to send clientHigh simply means the risk is higher that
  504          resurrects will fail, exposing the handle as BAD to the client.
  505       */
  506       TRACE_3("imma_determine_clients_to_resurrect: send failed");
  507     }
  508   }
  509 
  510 done:
  511   TRACE_LEAVE();
  512 }
  513 
  514 void imma_proc_terminate_oi_ccbs(IMMA_CB *cb, IMMA_CLIENT_NODE *cl_node) {
  515   TRACE_ENTER();
  516   /* We are NOT LOCKED on entry */
  517   osafassert(m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) == NCSCC_RC_SUCCESS);
  518 
  519   struct imma_oi_ccb_record *oiCcb = cl_node->activeOiCcbs;
  520 
  521   while (oiCcb != NULL) {
  522     SaAisErrorT err = SA_AIS_ERR_TIMEOUT;
  523     struct imma_oi_ccb_record *nextOiCcb = oiCcb->next;
  524     if (!(oiCcb->isStale)) {
  525       oiCcb = nextOiCcb;
  526       continue; /* Already processed or CCB created after resurrect. */
  527     }
  528 
  529     oiCcb->isStale = false; /* Avoid ccb termination upcall again. */
  530 
  531     if (oiCcb->isCritical) {
  532       SaImmHandleT handle = cl_node->handle;
  533       cl_node = NULL;
  534 
  535       SaImmOiCcbIdT ccbId = oiCcb->ccbId;
  536       osafassert(ccbId < 0xffffffff);
  537       osafassert(m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
  538                  NCSCC_RC_SUCCESS);
  539       err = imma_proc_recover_ccb_result(cb, (SaUint32T)ccbId);
  540       osafassert(m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) == NCSCC_RC_SUCCESS);
  541 
  542       /* We have been unlocked. Look up the client_node & ccb-record again.
  543          New ccb records are pushed on to top of list. Tail should be stable.
  544        */
  545       imma_client_node_get(&cb->client_tree, &handle, &cl_node);
  546       if (!cl_node) {
  547         LOG_WA(
  548             "Client node removed (handle closed) during termination processing");
  549         m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  550         return;
  551       }
  552 
  553       if (!imma_oi_ccb_record_exists(cl_node, ccbId)) {
  554         LOG_WA("Ccb OI record lost while recovering ccb %llx result", ccbId);
  555         oiCcb = cl_node->activeOiCcbs;
  556         continue;
  557       }
  558     } else {
  559       /* We expected non-critical stales to have been terminated by abort in
  560          imma_proc_stale_dispatch() */
  561       LOG_WA(
  562           "Discovered non critical and stale oi_ccb_record %llx in "
  563           "imma_proc_terminate_oi_ccbs",
  564           oiCcb->ccbId);
  565       err = SA_AIS_ERR_FAILED_OPERATION;
  566     }
  567 
  568     IMMA_CALLBACK_INFO *callback =
  569         (IMMA_CALLBACK_INFO *)calloc(1, sizeof(IMMA_CALLBACK_INFO));
  570     osafassert(callback);
  571     if (err == SA_AIS_OK) {
  572       callback->type = IMMA_CALLBACK_OI_CCB_APPLY;
  573     } else if (err == SA_AIS_ERR_FAILED_OPERATION) {
  574       callback->type = IMMA_CALLBACK_OI_CCB_ABORT;
  575     } else {
  576       TRACE_3(
  577           "WARNING: Failed to recover ccb outcome for critical oi ccb %llx err:%u",
  578           oiCcb->ccbId, err);
  579       free(callback);
  580       callback = NULL;
  581       osafassert(err == SA_AIS_ERR_TIMEOUT);
  582       continue;
  583     }
  584 
  585     callback->lcl_imm_hdl = cl_node->handle;
  586     callback->ccbID = (SaUint32T)oiCcb->ccbId;
  587 
  588     if (m_NCS_IPC_SEND(&cl_node->callbk_mbx, callback,
  589                        NCS_IPC_PRIORITY_NORMAL) != NCSCC_RC_SUCCESS) {
  590       /* Cant make it high priority because it could bypass a normal
  591          ccb-op upcall. That would confuse the OI! */
  592       TRACE_4("Failed to post ccb %llx stale-terminate ipc-message",
  593               oiCcb->ccbId);
  594     } else {
  595       TRACE_3("Posted ccb %llx stale-terminate ipc-message: %s", oiCcb->ccbId,
  596               (err == SA_AIS_OK) ? "APPLY" : "ABORT");
  597     }
  598     osafassert(oiCcb->isStale == false);
  599 
  600     TRACE_3("imma_proc_terminate_oi_ccbs: oi_ccb_record for %llx terminated",
  601             oiCcb->ccbId);
  602     osafassert(imma_oi_ccb_record_terminate(cl_node, oiCcb->ccbId));
  603     oiCcb = nextOiCcb;
  604     callback = NULL;
  605   }
  606 
  607   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  608   TRACE_LEAVE();
  609 }
  610 
  611 /****************************************************************************
  612   Name          : imma_proc_stale_dispatch
  613   Description   : Dispatch a stale-handle callback for a particular client.
  614 
  615 ******************************************************************************/
  616 void imma_proc_stale_dispatch(IMMA_CB *cb, IMMA_CLIENT_NODE *cl_node) {
  617   TRACE_ENTER();
  618   /* We are LOCKED already */
  619   IMMA_CALLBACK_INFO *callback = NULL;
  620   if (cl_node->selObjUsable) {
  621     struct imma_oi_ccb_record *oiCcb = cl_node->activeOiCcbs;
  622 
  623     /* Send the stale handle triggering ipc-message */
  624     callback = (IMMA_CALLBACK_INFO *)calloc(1, sizeof(IMMA_CALLBACK_INFO));
  625     osafassert(callback);
  626     callback->type = IMMA_CALLBACK_STALE_HANDLE;
  627     callback->lcl_imm_hdl = 0LL;
  628     callback->ccbID = 0;
  629 
  630     if (m_NCS_IPC_SEND(&cl_node->callbk_mbx, callback, NCS_IPC_PRIORITY_HIGH) !=
  631         NCSCC_RC_SUCCESS) {
  632       TRACE_4("Failed to post stale handle ipc-message");
  633     } else {
  634       TRACE_3("Posted stale handle ipc-message");
  635     }
  636 
  637     /*Avoid redoing this dispatch for the same stale connection*/
  638     cl_node->selObjUsable = false;
  639     /*If a resurrect succeds cl_node->selObjUsable will be set back to true*/
  640 
  641     /* Abort any active but non-critical OI CCBs */
  642     while (oiCcb != NULL) {
  643       struct imma_oi_ccb_record *nextOiCcb = oiCcb->next;
  644       if (!(oiCcb->isStale)) {
  645         TRACE_4(
  646             "ERROR?: Discovered non stale oi_ccb_record %llx in stale dispatch",
  647             oiCcb->ccbId);
  648         oiCcb = nextOiCcb;
  649         continue;
  650       }
  651 
  652       if (oiCcb->isCritical) {
  653         TRACE_3(
  654             "Postponing termination upcall apply/abort for critical CCB %llx",
  655             oiCcb->ccbId);
  656         oiCcb = nextOiCcb;
  657         continue;
  658       }
  659 
  660       /* Non critical & stale CCB must have been aborted by server side.
  661          Generate abort upcall immediately, i.e. no need to wait for resurrect.
  662        */
  663       callback = (IMMA_CALLBACK_INFO *)calloc(1, sizeof(IMMA_CALLBACK_INFO));
  664       osafassert(callback);
  665       callback->type = IMMA_CALLBACK_OI_CCB_ABORT;
  666       callback->lcl_imm_hdl = cl_node->handle;
  667       callback->ccbID = oiCcb->ccbId;
  668       if (m_NCS_IPC_SEND(&cl_node->callbk_mbx, callback,
  669                          NCS_IPC_PRIORITY_NORMAL) != NCSCC_RC_SUCCESS) {
  670         /* Cant make it high priority because it could bypass a normal
  671            ccb-op upcall. That would confuse the OI! */
  672         TRACE_4("Failed to post ccb stale abort ipc-message");
  673       } else {
  674         TRACE_3("Posted ccb %llx stale abort ipc-message", oiCcb->ccbId);
  675       }
  676       oiCcb->isStale = false; /* Avoid sending the abort message again. */
  677 
  678       TRACE_3("imma_proc_stale_dispatch: oi_ccb_record for %llx terminated",
  679               oiCcb->ccbId);
  680       osafassert(imma_oi_ccb_record_terminate(cl_node, oiCcb->ccbId));
  681       oiCcb = nextOiCcb;
  682       callback = NULL;
  683     }
  684   }
  685   TRACE_LEAVE();
  686 }
  687 
  688 SaAisErrorT imma_proc_recover_ccb_result(IMMA_CB *cb, SaUint32T ccbId) {
  689   IMMSV_EVT evt;
  690   IMMSV_EVT *out_evt = NULL;
  691   uint32_t proc_rc = NCSCC_RC_SUCCESS;
  692   SaAisErrorT err = SA_AIS_ERR_TIMEOUT;
  693   unsigned int sleep_delay_ms = 500;
  694   unsigned int max_waiting_time_ms = 10 * 1000; /* 10 secs */
  695   unsigned int msecs_waited = 0;
  696 
  697   TRACE_ENTER();
  698   /* We are NOT locked on entry. */
  699   memset(&evt, 0, sizeof(IMMSV_EVT));
  700   evt.type = IMMSV_EVT_TYPE_IMMND;
  701   evt.info.immnd.type = IMMND_EVT_A2ND_RECOVER_CCB_OUTCOME;
  702   evt.info.immnd.info.ccbId = ccbId;
  703 
  704   do {
  705     if (err == SA_AIS_ERR_TRY_AGAIN) {
  706       usleep(sleep_delay_ms * 1000);
  707       msecs_waited += sleep_delay_ms;
  708       err = SA_AIS_ERR_TIMEOUT;
  709       proc_rc = NCSCC_RC_SUCCESS;
  710     }
  711 
  712     if (cb->is_immnd_up == false) {
  713       err = SA_AIS_ERR_TRY_AGAIN;
  714       continue;
  715     }
  716 
  717     proc_rc = imma_mds_msg_sync_send(cb->imma_mds_hdl, &cb->immnd_mds_dest,
  718                                      &evt, &out_evt, IMMSV_WAIT_TIME);
  719 
  720     if (proc_rc != NCSCC_RC_SUCCESS) {
  721       if (proc_rc != SA_AIS_ERR_TIMEOUT) {
  722         TRACE_4("ERR_TRY_AGAIN: Mds returned unexpected error code: %u",
  723                 proc_rc);
  724       }
  725       err = SA_AIS_ERR_TRY_AGAIN;
  726     }
  727 
  728     if (!out_evt) {
  729       TRACE("No out_evt");
  730       err = SA_AIS_ERR_TRY_AGAIN;
  731     } else {
  732       err = out_evt->info.imma.info.errRsp.error;
  733       free(out_evt);
  734       out_evt = NULL;
  735       if ((err != SA_AIS_OK) && (err != SA_AIS_ERR_FAILED_OPERATION) &&
  736           (err != SA_AIS_ERR_TRY_AGAIN)) {
  737         /* We have a problem, abandon the effort.*/
  738         /* ERR_NO_RESOURCES is IMMND saying it cant find the ccb-id*/
  739         if (err != SA_AIS_ERR_NO_RESOURCES) {
  740           TRACE_4(
  741               "ERR_TIMEOUT: Received unexpected error %u from IMMND, "
  742               "returning ERR_TIMEOUT",
  743               err);
  744         }
  745         err = SA_AIS_ERR_TIMEOUT;
  746       }
  747     }
  748 
  749     if (msecs_waited >= max_waiting_time_ms) {
  750       err = SA_AIS_ERR_TIMEOUT;
  751     }
  752 
  753   } while (err == SA_AIS_ERR_TRY_AGAIN);
  754   TRACE_5("imma_proc_recover_ccb_result returning err %u after waiting %u secs",
  755           err, msecs_waited / 1000);
  756 
  757   TRACE_LEAVE();
  758   return err;
  759 }
  760 /****************************************************************************
  761   Name          : imma_proc_rt_attr_update
  762   Description   : This function will generate the SaImmOiRtAttrUpdateCallbackT
  763                   up-call for the Object Implementer API.
  764   Arguments     : cb - IMMA CB.
  765                   evt - IMMA_EVT.
  766   Return Values : None
  767   Notes         : None
  768 ******************************************************************************/
  769 static void imma_proc_rt_attr_update(IMMA_CB *cb, IMMA_EVT *evt) {
  770   IMMA_CALLBACK_INFO *callback;
  771   IMMA_CLIENT_NODE *cl_node = NULL;
  772 
  773   /* NOTE: correct this, ugly use of continuationId */
  774   SaImmOiHandleT implHandle = evt->info.searchRemote.client_hdl;
  775   TRACE_ENTER();
  776 
  777   /* get the CB Lock */
  778   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
  779     TRACE_3("Lock failure");
  780     TRACE_LEAVE();
  781     return;
  782   }
  783 
  784   /* Get the Client info */
  785   imma_client_node_get(&cb->client_tree, &implHandle, &cl_node);
  786   if (!cl_node || cl_node->isOm) {
  787     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  788     TRACE_3("Failed to find client node");
  789     TRACE_LEAVE();
  790     return;
  791   }
  792 
  793   /* Allocate the Callback info */
  794   callback = (IMMA_CALLBACK_INFO *)calloc(1, sizeof(IMMA_CALLBACK_INFO));
  795   if (callback) {
  796     /* Fill the Call Back Info */
  797     callback->type = IMMA_CALLBACK_OI_RT_ATTR_UPDATE;
  798     callback->lcl_imm_hdl = implHandle;
  799 
  800     osaf_extended_name_steal(evt->info.searchRemote.objectName.buf,
  801                              &callback->name);
  802     evt->info.searchRemote.objectName.buf = NULL;
  803     evt->info.searchRemote.objectName.size = 0;
  804 
  805     /* steal the attributeNames list. */
  806     callback->attrNames = evt->info.searchRemote.attributeNames;
  807     evt->info.searchRemote.attributeNames = NULL;
  808 
  809     SaInvocationT saInv = m_IMMSV_PACK_HANDLE(
  810         evt->info.searchRemote.remoteNodeId, evt->info.searchRemote.searchId);
  811     callback->invocation = saInv;
  812 
  813     callback->requestNodeId = evt->info.searchRemote.requestNodeId;
  814 
  815     /* Send the event */
  816     TRACE("Posting RT UPDATE CALLBACK to IPC mailbox");
  817     (void)m_NCS_IPC_SEND(&cl_node->callbk_mbx, callback,
  818                          NCS_IPC_PRIORITY_NORMAL);
  819   }
  820 
  821   /* Release The Lock */
  822   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  823   TRACE_LEAVE();
  824 }
  825 
  826 /****************************************************************************
  827   Name          : imma_proc_ccb_completed
  828   Description   : This function will process the ccb completed
  829                   up-call for the Object Implementer API.
  830   Arguments     : cb - IMMA CB.
  831                   evt - IMMA_EVT.
  832   Return Values : None
  833   Notes         : None
  834 ******************************************************************************/
  835 static void imma_proc_ccb_completed(IMMA_CB *cb, IMMA_EVT *evt) {
  836   IMMA_CALLBACK_INFO *callback;
  837   IMMA_CLIENT_NODE *cl_node = NULL;
  838   bool isPrtObj = (evt->info.ccbCompl.ccbId == 0);
  839 
  840   SaImmOiHandleT implHandle = evt->info.ccbCompl.immHandle;
  841 
  842   /* get the CB Lock */
  843   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
  844     TRACE_3("Lock failure");
  845     return;
  846   }
  847 
  848   /* Get the Client info */
  849   imma_client_node_get(&cb->client_tree, &implHandle, &cl_node);
  850   if (!cl_node || cl_node->isOm) {
  851     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  852     TRACE_3("Could not find client node");
  853     return;
  854   }
  855 
  856   if (isPrtObj) {
  857     if (cl_node->isPbe) {
  858       TRACE_3("PBE-OI received runtime object deletes completed");
  859     } else {
  860       m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  861       LOG_ER(
  862           "Apparent runtime object deletes completed received at OI "
  863           "which is not PBE - ignoring");
  864       return;
  865     }
  866   }
  867 
  868   if (cl_node->isPbe && !isPrtObj && (evt->info.ccbCompl.invocation == 0)) {
  869     if (imma_oi_ccb_record_exists(cl_node, evt->info.ccbCompl.ccbId)) {
  870       LOG_WA("Redundant & anonymous CCB-completed UC for %u => ignore",
  871              evt->info.ccbCompl.ccbId);
  872       m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  873       return;
  874     } else {
  875       LOG_WA(
  876           "Re-inserting Ccb record %u in ccb-completed upcall => PBE recovery,",
  877           evt->info.ccbCompl.ccbId);
  878       imma_oi_ccb_record_add(cl_node, evt->info.ccbCompl.ccbId,
  879                              1 /* Hack! Op was initialized to 1*/);
  880     }
  881   }
  882 
  883   /* Allocate the Callback info */
  884   callback = (IMMA_CALLBACK_INFO *)calloc(1, sizeof(IMMA_CALLBACK_INFO));
  885   if (callback) {
  886     /* Fill the Call Back Info */
  887     if (isPrtObj) {
  888       callback->type = IMMA_CALLBACK_PBE_PRTO_DELETES_COMPLETED;
  889     } else {
  890       callback->type = IMMA_CALLBACK_OI_CCB_COMPLETED;
  891     }
  892     callback->lcl_imm_hdl = implHandle;
  893     callback->ccbID = evt->info.ccbCompl.ccbId;
  894     callback->implId = evt->info.ccbCompl.implId;
  895     callback->inv = evt->info.ccbCompl.invocation;
  896 
  897     /* Send the event */
  898     (void)m_NCS_IPC_SEND(&cl_node->callbk_mbx, callback,
  899                          NCS_IPC_PRIORITY_NORMAL);
  900     TRACE("Posted IMMA_CALLBACK_OI_CCB_COMPLETED");
  901   }
  902 
  903   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  904 }
  905 
  906 /****************************************************************************
  907   Name          : imma_proc_ccb_apply
  908   Description   : This function will process the ccb apply
  909                   up-call for the Object Implementer API.
  910   Arguments     : cb - IMMA CB.
  911                   evt - IMMA_EVT.
  912   Return Values : None
  913   Notes         : None
  914 ******************************************************************************/
  915 static void imma_proc_ccb_apply(IMMA_CB *cb, IMMA_EVT *evt) {
  916   IMMA_CALLBACK_INFO *callback;
  917   IMMA_CLIENT_NODE *cl_node = NULL;
  918 
  919   SaImmOiHandleT implHandle = evt->info.ccbCompl.immHandle;
  920 
  921   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
  922     TRACE_3("Lock failure");
  923     return;
  924   }
  925 
  926   imma_client_node_get(&cb->client_tree, &implHandle, &cl_node);
  927   if (!cl_node || cl_node->isOm) {
  928     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  929     TRACE_3("Could not find client node");
  930     return;
  931   }
  932 
  933   callback = (IMMA_CALLBACK_INFO *)calloc(1, sizeof(IMMA_CALLBACK_INFO));
  934   if (callback) {
  935     callback->type = IMMA_CALLBACK_OI_CCB_APPLY;
  936     callback->lcl_imm_hdl = implHandle;
  937     callback->ccbID = evt->info.ccbCompl.ccbId;
  938     /*callback->implId = evt->info.ccbCompl.implId;*/
  939     /*callback->inv = evt->info.ccbCompl.invocation;*/
  940 
  941     (void)m_NCS_IPC_SEND(&cl_node->callbk_mbx, callback,
  942                          NCS_IPC_PRIORITY_NORMAL);
  943     TRACE("Posted IMMA_CALLBACK_OI_CCB_APPLY");
  944   }
  945 
  946   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  947 }
  948 
  949 /****************************************************************************
  950   Name          : imma_proc_ccb_abort
  951   Description   : This function will process the ccb abort
  952                   up-call for the Object Implementer API.
  953   Arguments     : cb - IMMA CB.
  954                   evt - IMMA_EVT.
  955   Return Values : None
  956   Notes         : None
  957 ******************************************************************************/
  958 static void imma_proc_ccb_abort(IMMA_CB *cb, IMMA_EVT *evt) {
  959   IMMA_CALLBACK_INFO *callback;
  960   IMMA_CLIENT_NODE *cl_node = NULL;
  961 
  962   SaImmOiHandleT implHandle = evt->info.ccbCompl.immHandle;
  963 
  964   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
  965     TRACE_3("Lock failure");
  966     return;
  967   }
  968 
  969   imma_client_node_get(&cb->client_tree, &implHandle, &cl_node);
  970   if (!cl_node || cl_node->isOm) {
  971     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  972     TRACE_3("Could not find client node");
  973     return;
  974   }
  975 
  976   callback = (IMMA_CALLBACK_INFO *)calloc(1, sizeof(IMMA_CALLBACK_INFO));
  977   if (callback) {
  978     callback->type = IMMA_CALLBACK_OI_CCB_ABORT;
  979     callback->lcl_imm_hdl = implHandle;
  980     callback->ccbID = evt->info.ccbCompl.ccbId;
  981     /*callback->implId = evt->info.ccbCompl.implId;*/
  982 
  983     (void)m_NCS_IPC_SEND(&cl_node->callbk_mbx, callback,
  984                          NCS_IPC_PRIORITY_NORMAL);
  985     TRACE("Posted IMMA_CALLBACK_OI_CCB_ABORT for ccb %u",
  986           evt->info.ccbCompl.ccbId);
  987     if (imma_oi_ccb_record_abort(cl_node, evt->info.ccbCompl.ccbId)) {
  988       TRACE_2("CCB-ABORT-UC: oi_ccb_record for %u aborted",
  989               evt->info.ccbCompl.ccbId);
  990     } else {
  991       TRACE_4("ERROR: CCB-ABORT-UC - CCB record for ccb %u non existent",
  992               evt->info.ccbCompl.ccbId);
  993     }
  994   }
  995 
  996   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  997 }
  998 
  999 /****************************************************************************
 1000   Name          : imma_proc_obj_delete
 1001   Description   : This function will process the Object Delete
 1002                   up-call for the Object Implementer API.
 1003   Arguments     : cb - IMMA CB.
 1004                   evt - IMMA_EVT.
 1005   Return Values : None
 1006 ******************************************************************************/
 1007 static void imma_proc_obj_delete(IMMA_CB *cb, bool hasLongDn, IMMA_EVT *evt) {
 1008   IMMA_CALLBACK_INFO *callback;
 1009   IMMA_CLIENT_NODE *cl_node = NULL;
 1010   bool isPrtObj = ((evt->info.objDelete.ccbId == 0) &&
 1011                    (evt->info.objDelete.adminOwnerId != 0));
 1012   bool isSpApplRto = ((evt->info.objDelete.ccbId == 0) &&
 1013                       (evt->info.objDelete.adminOwnerId == 0));
 1014   if (isSpApplRto) {
 1015     TRACE_3(
 1016         "imma_proc_obj_delete CCBID==0 admoId=0  SPECIAL applier RTO delete");
 1017   }
 1018 
 1019   SaImmOiHandleT implHandle = evt->info.objDelete.immHandle;
 1020 
 1021   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1022     TRACE_3("Lock failure");
 1023     return;
 1024   }
 1025 
 1026   imma_client_node_get(&cb->client_tree, &implHandle, &cl_node);
 1027   if (!cl_node || cl_node->isOm || cl_node->exposed) {
 1028     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1029     TRACE_3("Could not find valid client node");
 1030     return;
 1031   }
 1032 
 1033   if (isPrtObj) {
 1034     if (cl_node->isPbe) {
 1035       TRACE_3("PBE-OI received runtime object delete");
 1036     } else {
 1037       m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1038       LOG_ER(
 1039           "Apparent runtime object delete received at OI which is not PBE - ignoring");
 1040       return;
 1041     }
 1042   }
 1043 
 1044   callback = (IMMA_CALLBACK_INFO *)calloc(1, sizeof(IMMA_CALLBACK_INFO));
 1045   if (callback) {
 1046     if (isPrtObj) {
 1047       callback->type = IMMA_CALLBACK_PBE_PRT_OBJ_DELETE;
 1048     } else {
 1049       callback->type = IMMA_CALLBACK_OI_CCB_DELETE;
 1050     }
 1051     callback->lcl_imm_hdl = implHandle;
 1052     callback->ccbID = evt->info.objDelete.ccbId;
 1053     callback->inv = evt->info.objDelete.adminOwnerId; /*ugly */
 1054     if (!callback->inv) {
 1055       /* callback->inv == 0 means PBE (CCB or PRTO) or applier upcall, no reply.
 1056        */
 1057       osafassert(cl_node->isPbe || cl_node->isApplier);
 1058     }
 1059 
 1060     osaf_extended_name_steal(evt->info.objDelete.objectName.buf,
 1061                              &callback->name);
 1062     evt->info.objDelete.objectName.buf = NULL;
 1063     evt->info.objDelete.objectName.size = 0;
 1064 
 1065     if (hasLongDn) { /* $$$$ */
 1066       TRACE("Long DN detected for delete callback.");
 1067       callback->hasLongRdnOrDn = true;
 1068     }
 1069 
 1070     /* Send the event */
 1071     (void)m_NCS_IPC_SEND(&cl_node->callbk_mbx, callback,
 1072                          NCS_IPC_PRIORITY_NORMAL);
 1073     TRACE("Posted IMMA_CALLBACK_OI_CCB_DELETE for ccb %u",
 1074           evt->info.objDelete.ccbId);
 1075     if (isPrtObj) {
 1076       /* PRTO delete arrives at PBE. Count how many in same subtree #1809.
 1077          Sum verified in completed upcall.
 1078          This to overcome silent message loss in MDS local transport, see #1795.
 1079        */
 1080       SaImmOiCcbIdT ccbId = 0LL;
 1081       ccbId = callback->inv + 0x100000000LL; /* pseudo ccb-id */
 1082 
 1083       imma_oi_ccb_record_add(cl_node, ccbId, 0);
 1084     } else if (isSpApplRto) {
 1085       TRACE("Special applier RTO delete for %s",
 1086             evt->info.objDelete.objectName.buf);
 1087     } else {
 1088       /* Regular CCB object delete arrives at... */
 1089       if (cl_node->isApplier) { /* applier*/
 1090         osafassert(callback->inv == 0);
 1091       } else if (cl_node->isPbe) { /* PBE. */
 1092         TRACE("PBe case inv:%u", callback->inv);
 1093         if ((callback->inv != 0) &&
 1094             strcmp(osaf_extended_name_borrow(&callback->name),
 1095                    OPENSAF_IMM_OBJECT_DN) != 0) {
 1096           /* callback->inv must be zero, except for operations on
 1097            OPENSAF_IMM_OBJECT_DN  */
 1098           LOG_ER("PBE: callback->inv != 0, LINE:%u", __LINE__);
 1099           abort();
 1100         }
 1101       } else { /*regular OI. */
 1102         osafassert(callback->inv);
 1103       }
 1104       imma_oi_ccb_record_add(cl_node, evt->info.objDelete.ccbId, callback->inv);
 1105     }
 1106   }
 1107 
 1108   /* Release The Lock */
 1109   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1110 }
 1111 
 1112 /****************************************************************************
 1113   Name          : imma_proc_obj_create
 1114   Description   : This function will process the Object Create
 1115                   up-call for the Object Implementer API.
 1116   Arguments     : cb - IMMA CB.
 1117                   evt - IMMA_EVT.
 1118   Return Values : None
 1119 ******************************************************************************/
 1120 static void imma_proc_obj_create(IMMA_CB *cb, bool dnOrRdnIsLong,
 1121                                  IMMA_EVT *evt) {
 1122   IMMA_CALLBACK_INFO *callback;
 1123   IMMA_CLIENT_NODE *cl_node = NULL;
 1124   bool isPrtObj = ((evt->info.objCreate.ccbId == 0) &&
 1125                    (evt->info.objCreate.adminOwnerId != 0));
 1126   bool isSpApplRto = ((evt->info.objCreate.ccbId == 0) &&
 1127                       (evt->info.objCreate.adminOwnerId == 0));
 1128   if (isSpApplRto) {
 1129     TRACE_3(
 1130         "imma_proc_obj_create CCBID==0 admoId=0  SPECIAL applier RTO create");
 1131   }
 1132 
 1133   SaImmOiHandleT implHandle = evt->info.objCreate.immHandle;
 1134 
 1135   /* get the CB Lock */
 1136   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1137     TRACE_3("Lock failure");
 1138     return;
 1139   }
 1140 
 1141   /* Get the Client info */
 1142   imma_client_node_get(&cb->client_tree, &implHandle, &cl_node);
 1143   if (!cl_node || cl_node->isOm) {
 1144     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1145     TRACE_3("Could not find client node");
 1146     return;
 1147   }
 1148 
 1149   if (isPrtObj) {
 1150     if (cl_node->isPbe) {
 1151       TRACE_3("PBE-OI received runtime object create");
 1152     } else {
 1153       m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1154       LOG_ER(
 1155           "Apparent runtime object create received at OI which is not PBE - ignoring");
 1156       return;
 1157     }
 1158   }
 1159 
 1160   /* Allocate the Callback info */
 1161   callback = (IMMA_CALLBACK_INFO *)calloc(1, sizeof(IMMA_CALLBACK_INFO));
 1162   if (callback) {
 1163     /* Fill the Call Back Info */
 1164     if (isPrtObj) {
 1165       callback->type = IMMA_CALLBACK_PBE_PRT_OBJ_CREATE;
 1166     } else {
 1167       callback->type = IMMA_CALLBACK_OI_CCB_CREATE;
 1168     }
 1169     callback->lcl_imm_hdl = implHandle;
 1170     callback->ccbID = evt->info.objCreate.ccbId;
 1171     callback->inv =
 1172         evt->info.objCreate.adminOwnerId; /*Actually continuationId */
 1173     if (!callback->inv) {
 1174       /* callback->inv == 0 means PBE CCB obj create upcall, NO reply.
 1175          But note that for PBE PRTO, callback->inv != 0 and we reply
 1176          immediately (no completed upcall).
 1177          Added support for applier & special applier OI. No reply to server
 1178          there either.
 1179        */
 1180       osafassert(cl_node->isPbe || cl_node->isApplier);
 1181     }
 1182 
 1183     osaf_extended_name_steal(evt->info.objCreate.parentOrObjectDn.buf,
 1184                              &callback->name);
 1185     evt->info.objCreate.parentOrObjectDn.buf = NULL;
 1186     evt->info.objCreate.parentOrObjectDn.size = 0;
 1187 
 1188     osafassert(strlen(evt->info.objCreate.className.buf) <=
 1189                evt->info.objCreate.className.size);
 1190     callback->className = evt->info.objCreate.className.buf;
 1191     evt->info.objCreate.className.buf = NULL; /*steal the string buffer */
 1192     evt->info.objCreate.className.size = 0;
 1193 
 1194     callback->attrValues = evt->info.objCreate.attrValues;
 1195     evt->info.objCreate.attrValues = NULL; /*steal attrValues list */
 1196 
 1197     if (dnOrRdnIsLong) { /* @@@@ */
 1198       TRACE("Long DN/RDN detected for create callback.");
 1199       callback->hasLongRdnOrDn = true;
 1200     }
 1201 
 1202     /* Send the event */
 1203     (void)m_NCS_IPC_SEND(&cl_node->callbk_mbx, callback,
 1204                          NCS_IPC_PRIORITY_NORMAL);
 1205     TRACE("Posted IMMA_CALLBACK_OI_CCB_CREATE for ccb %u",
 1206           evt->info.objCreate.ccbId);
 1207     if (!isPrtObj && !isSpApplRto) {
 1208       imma_oi_ccb_record_add(cl_node, evt->info.objCreate.ccbId, callback->inv);
 1209     }
 1210   }
 1211 
 1212   /* Release The Lock */
 1213   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1214 }
 1215 
 1216 /****************************************************************************
 1217   Name          : imma_proc_obj_modify
 1218   Description   : This function will process the Object Modify
 1219                   up-call for the Object Implementer API.
 1220   Arguments     : cb - IMMA CB.
 1221                   evt - IMMA_EVT.
 1222   Return Values : None
 1223 ******************************************************************************/
 1224 static void imma_proc_obj_modify(IMMA_CB *cb, bool hasLongDNs, IMMA_EVT *evt) {
 1225   IMMA_CALLBACK_INFO *callback;
 1226   IMMA_CLIENT_NODE *cl_node = NULL;
 1227   bool isPrtAttrs = ((evt->info.objModify.ccbId == 0) &&
 1228                      (evt->info.objModify.adminOwnerId != 0));
 1229   bool isSpApplRtu = ((evt->info.objModify.ccbId == 0) &&
 1230                       (evt->info.objModify.adminOwnerId == 0));
 1231   /* Can be a PRTO or a config obj with PRTAttrs. */
 1232   TRACE_ENTER();
 1233   if (isSpApplRtu) {
 1234     TRACE_3(
 1235         "imma_proc_obj_modify CCBID==0 admoId=0  SPECIAL applier RTA modify");
 1236   }
 1237   SaImmOiHandleT implHandle = evt->info.objModify.immHandle;
 1238 
 1239   /* get the CB Lock */
 1240   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1241     TRACE_3("Lock failure");
 1242     TRACE_LEAVE();
 1243     return;
 1244   }
 1245 
 1246   /* Get the Client info */
 1247   imma_client_node_get(&cb->client_tree, &implHandle, &cl_node);
 1248   if (!cl_node || cl_node->isOm) {
 1249     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1250     TRACE_3("Could not find client node");
 1251     TRACE_LEAVE();
 1252     return;
 1253   }
 1254 
 1255   if (isPrtAttrs) {
 1256     if (cl_node->isPbe) {
 1257       TRACE_3("PBE-OI received runtime attributes update");
 1258     } else {
 1259       m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1260       LOG_ER(
 1261           "Apparent runtime attributes update received at OI which is not PBE - ignoring");
 1262       return;
 1263     }
 1264   }
 1265 
 1266   /* Allocate the Callback info */
 1267   callback = (IMMA_CALLBACK_INFO *)calloc(1, sizeof(IMMA_CALLBACK_INFO));
 1268   if (callback) {
 1269     /* Fill the Call Back Info */
 1270     if (isPrtAttrs) {
 1271       callback->type = IMMA_CALLBACK_PBE_PRT_ATTR_UPDATE;
 1272     } else {
 1273       callback->type = IMMA_CALLBACK_OI_CCB_MODIFY;
 1274     }
 1275     callback->lcl_imm_hdl = implHandle;
 1276     callback->ccbID = evt->info.objModify.ccbId;
 1277     callback->inv = evt->info.objModify.adminOwnerId;
 1278     /*Actually continuationId */
 1279     if (!callback->inv) {
 1280       /* callback->inv == 0 means PBE CCB modify upcall, no reply. */
 1281       osafassert(cl_node->isPbe || cl_node->isApplier);
 1282     }
 1283 
 1284     osaf_extended_name_steal(evt->info.objModify.objectName.buf,
 1285                              &callback->name);
 1286     evt->info.objModify.objectName.buf = NULL;
 1287     evt->info.objModify.objectName.size = 0;
 1288 
 1289     callback->attrMods = evt->info.objModify.attrMods;
 1290     evt->info.objModify.attrMods = NULL; /*steal attrMods list */
 1291 
 1292     if (hasLongDNs) { /* #### */
 1293       TRACE("Long DN detected for modify callback.");
 1294       callback->hasLongRdnOrDn = true;
 1295     }
 1296 
 1297     /* Send the event */
 1298     (void)m_NCS_IPC_SEND(&cl_node->callbk_mbx, callback,
 1299                          NCS_IPC_PRIORITY_NORMAL);
 1300     TRACE("IMMA_CALLBACK_OI_CCB_MODIFY Posted for ccb %u",
 1301           evt->info.objModify.ccbId);
 1302     if (!isPrtAttrs && !isSpApplRtu) {
 1303       imma_oi_ccb_record_add(cl_node, evt->info.objModify.ccbId, callback->inv);
 1304     }
 1305   }
 1306 
 1307   /* Release The Lock */
 1308   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1309   TRACE_LEAVE();
 1310 }
 1311 
 1312 void imma_proc_free_pointers(IMMA_CB *cb, IMMA_EVT *evt) {
 1313   TRACE_ENTER();
 1314   switch (evt->type) {
 1315     case IMMA_EVT_ND2A_IMM_ADMOP:
 1316     case IMMA_EVT_ND2A_IMM_PBE_ADMOP:
 1317       /*TODO See TODO 12345 code repeated (almost) in imma_om_api.c
 1318         free-1 */
 1319       if (evt->info.admOpReq.objectName.size) {
 1320         free(evt->info.admOpReq.objectName.buf);
 1321         evt->info.admOpReq.objectName.buf = NULL;
 1322         evt->info.admOpReq.objectName.size = 0;
 1323       }
 1324       while (evt->info.admOpReq.params) {
 1325         IMMSV_ADMIN_OPERATION_PARAM *p = evt->info.admOpReq.params;
 1326         evt->info.admOpReq.params = p->next;
 1327 
 1328         if (p->paramName.buf) { /*free-3 */
 1329           free(p->paramName.buf);
 1330           p->paramName.buf = NULL;
 1331           p->paramName.size = 0;
 1332         }
 1333         immsv_evt_free_att_val(&(p->paramBuffer),
 1334                                (SaImmValueTypeT)p->paramType); /*free-4 */
 1335         p->next = NULL;
 1336         free(p); /*free-2 */
 1337       }
 1338       break;
 1339 
 1340     case IMMA_EVT_ND2A_ADMOP_RSP_2:
 1341       while (evt->info.admOpRsp.parms) {
 1342         IMMSV_ADMIN_OPERATION_PARAM *p = evt->info.admOpRsp.parms;
 1343         evt->info.admOpRsp.parms = p->next;
 1344 
 1345         if (p->paramName.buf) { /*free-3 */
 1346           free(p->paramName.buf);
 1347           p->paramName.buf = NULL;
 1348           p->paramName.size = 0;
 1349         }
 1350         immsv_evt_free_att_val(&(p->paramBuffer),
 1351                                (SaImmValueTypeT)p->paramType); /*free-4 */
 1352         p->next = NULL;
 1353         free(p); /*free-2 */
 1354       }
 1355       break;
 1356 
 1357     case IMMA_EVT_ND2A_ADMOP_RSP:
 1358       break;
 1359 
 1360     case IMMA_EVT_ND2A_SEARCH_REMOTE:
 1361       free(evt->info.searchRemote.objectName.buf);
 1362       evt->info.searchRemote.objectName.buf = NULL;
 1363       evt->info.searchRemote.objectName.size = 0;
 1364       immsv_evt_free_attrNames(evt->info.searchRemote.attributeNames);
 1365       evt->info.searchRemote.attributeNames = NULL;
 1366       break;
 1367 
 1368     case IMMA_EVT_ND2A_OI_OBJ_CREATE_LONG_UC:
 1369     case IMMA_EVT_ND2A_OI_OBJ_CREATE_UC:
 1370       free(evt->info.objCreate.className.buf);
 1371       evt->info.objCreate.className.buf = NULL;
 1372       evt->info.objCreate.className.size = 0;
 1373 
 1374       free(evt->info.objCreate.parentOrObjectDn.buf);
 1375       evt->info.objCreate.parentOrObjectDn.buf = NULL;
 1376       evt->info.objCreate.parentOrObjectDn.size = 0;
 1377 
 1378       immsv_free_attrvalues_list(evt->info.objCreate.attrValues);
 1379       evt->info.objCreate.attrValues = NULL;
 1380       break;
 1381 
 1382     case IMMA_EVT_ND2A_OI_OBJ_DELETE_UC:
 1383     case IMMA_EVT_ND2A_OI_OBJ_DELETE_LONG_UC:
 1384       free(evt->info.objDelete.objectName.buf);
 1385       evt->info.objDelete.objectName.buf = NULL;
 1386       evt->info.objDelete.objectName.size = 0;
 1387       break;
 1388 
 1389     case IMMA_EVT_ND2A_OI_OBJ_MODIFY_UC:
 1390     case IMMA_EVT_ND2A_OI_OBJ_MODIFY_LONG_UC:
 1391       free(evt->info.objModify.objectName.buf);
 1392       evt->info.objModify.objectName.buf = NULL;
 1393       evt->info.objModify.objectName.size = 0;
 1394 
 1395       immsv_free_attrmods(evt->info.objModify.attrMods);
 1396       evt->info.objModify.attrMods = NULL;
 1397       break;
 1398 
 1399     case IMMA_EVT_ND2A_OI_CCB_COMPLETED_UC:
 1400     case IMMA_EVT_ND2A_OI_CCB_APPLY_UC:
 1401     case IMMA_EVT_ND2A_OI_CCB_ABORT_UC:
 1402       break;
 1403 
 1404     case IMMA_EVT_ND2A_PROC_STALE_CLIENTS:
 1405       break;
 1406 
 1407     case IMMA_EVT_ND2A_IMM_SYNCR_TIMEOUT:
 1408       break;
 1409 
 1410     default:
 1411       TRACE_4("Unknown event type %u", evt->type);
 1412       break;
 1413   }
 1414   TRACE_LEAVE();
 1415 }
 1416 
 1417 /****************************************************************************
 1418   Name          : imma_proc_clm_status_changed
 1419   Description   : This function will process the clm state changes.
 1420   Arguments     : cb - IMMA CB.
 1421                   evt - IMMA_EVT.
 1422   Return Values : None
 1423 ******************************************************************************/
 1424 static void imma_proc_clm_status_changed(IMMA_CB *cb, IMMA_EVT *evt) {
 1425   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1426     TRACE_3("Lock failure");
 1427     return;
 1428   }
 1429 
 1430   if (evt->type == IMMA_EVT_ND2A_IMM_CLM_NODE_LEFT) {
 1431     cb->clmMemberNode = false;
 1432     LOG_NO("CLM node left the cluster");
 1433     imma_client_tree_mark_clmexposed(cb);
 1434   } else if (evt->type == IMMA_EVT_ND2A_IMM_CLM_NODE_JOINED) {
 1435     cb->clmMemberNode = true;
 1436     TRACE("CLM node join the cluster");
 1437   }
 1438   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1439 }
 1440 
 1441 static void imma_proc_syncr_timeout_update(IMMA_CB *cb, IMMA_EVT *evt) {
 1442   TRACE_ENTER();
 1443   IMMA_CLIENT_NODE *cl_node = NULL;
 1444   SaImmHandleT impl_handle = evt->info.immaTimeoutUpdate.immHandle;
 1445 
 1446   /* get the CB Lock */
 1447   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1448     TRACE_3("Lock failure");
 1449     return;
 1450   }
 1451 
 1452   /* Get the Client info */
 1453   imma_client_node_get(&cb->client_tree, &impl_handle, &cl_node);
 1454   if (cl_node == NULL) {
 1455     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1456     TRACE_3("Could not find client node impl_handle: %llx", impl_handle);
 1457     return;
 1458   }
 1459   cl_node->syncr_timeout = evt->info.immaTimeoutUpdate.syncrTimeout;
 1460   if (cl_node->syncr_timeout == 0) {
 1461     cl_node->syncr_timeout = imma_getSyncrTimeout();
 1462   }
 1463   TRACE_3("IMMA library syncronous timeout set to:%lld",
 1464           cl_node->syncr_timeout);
 1465   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1466   TRACE_LEAVE();
 1467 }
 1468 
 1469 /****************************************************************************
 1470   Name          : imma_process_evt
 1471   Description   : This routine will process the callback event received from
 1472                   IMMND.
 1473   Arguments     : cb - IMMA CB.
 1474                   evt - IMMSV_EVT.
 1475   Return Values : NCSCC_RC_SUCCESS/NCSCC_RC_FAILURE
 1476   Notes         : None
 1477 ******************************************************************************/
 1478 void imma_process_evt(IMMA_CB *cb, IMMSV_EVT *evt) {
 1479   TRACE("** Event type:%u", evt->info.imma.type);
 1480   switch (evt->info.imma.type) {
 1481     case IMMA_EVT_ND2A_IMM_PBE_ADMOP:
 1482     case IMMA_EVT_ND2A_IMM_ADMOP:
 1483       imma_proc_admop(cb, &evt->info.imma);
 1484       break;
 1485 
 1486     case IMMA_EVT_ND2A_ADMOP_RSP:
 1487     case IMMA_EVT_ND2A_ADMOP_RSP_2:
 1488       imma_proc_admin_op_async_rsp(cb, &evt->info.imma);
 1489       break;
 1490 
 1491     case IMMA_EVT_ND2A_SEARCH_REMOTE:
 1492       imma_proc_rt_attr_update(cb, &evt->info.imma);
 1493       break;
 1494 
 1495     case IMMA_EVT_ND2A_OI_OBJ_CREATE_LONG_UC:
 1496       imma_proc_obj_create(cb, true, &evt->info.imma);
 1497       break;
 1498 
 1499     case IMMA_EVT_ND2A_OI_OBJ_CREATE_UC:
 1500       imma_proc_obj_create(cb, false, &evt->info.imma);
 1501       break;
 1502 
 1503     case IMMA_EVT_ND2A_OI_OBJ_DELETE_LONG_UC:
 1504       imma_proc_obj_delete(cb, true, &evt->info.imma);
 1505       break;
 1506 
 1507     case IMMA_EVT_ND2A_OI_OBJ_DELETE_UC:
 1508       imma_proc_obj_delete(cb, false, &evt->info.imma);
 1509       break;
 1510 
 1511     case IMMA_EVT_ND2A_OI_OBJ_MODIFY_UC:
 1512       imma_proc_obj_modify(cb, false, &evt->info.imma);
 1513       break;
 1514 
 1515     case IMMA_EVT_ND2A_OI_OBJ_MODIFY_LONG_UC:
 1516       imma_proc_obj_modify(cb, true, &evt->info.imma);
 1517       break;
 1518 
 1519     case IMMA_EVT_ND2A_OI_CCB_COMPLETED_UC:
 1520       imma_proc_ccb_completed(cb, &evt->info.imma);
 1521       break;
 1522 
 1523     case IMMA_EVT_ND2A_OI_CCB_APPLY_UC:
 1524       imma_proc_ccb_apply(cb, &evt->info.imma);
 1525       break;
 1526 
 1527     case IMMA_EVT_ND2A_OI_CCB_ABORT_UC:
 1528       imma_proc_ccb_abort(cb, &evt->info.imma);
 1529       break;
 1530 
 1531     case IMMA_EVT_ND2A_PROC_STALE_CLIENTS:
 1532       LOG_IN("Received PROC_STALE_CLIENTS");
 1533       imma_process_stale_clients(cb);
 1534       break;
 1535 
 1536     case IMMA_EVT_ND2A_IMM_CLM_NODE_LEFT:
 1537     case IMMA_EVT_ND2A_IMM_CLM_NODE_JOINED:
 1538       imma_proc_clm_status_changed(cb, &evt->info.imma);
 1539       break;
 1540 
 1541     case IMMA_EVT_ND2A_IMM_SYNCR_TIMEOUT:
 1542       imma_proc_syncr_timeout_update(cb, &evt->info.imma);
 1543       break;
 1544 
 1545     default:
 1546       TRACE_4("Unknown event type %u", evt->info.imma.type);
 1547       break;
 1548   }
 1549   imma_proc_free_pointers(cb, &evt->info.imma);
 1550   return;
 1551 }
 1552 
 1553 /****************************************************************************
 1554   Name          : imma_callback_ipc_rcv
 1555 
 1556   Description   : This routine is used Receive the message posted to callback
 1557                   MBX.
 1558 
 1559   Return Values : pointer to the callback
 1560 
 1561   Notes         : None
 1562 ******************************************************************************/
 1563 IMMA_CALLBACK_INFO *imma_callback_ipc_rcv(IMMA_CLIENT_NODE *cl_node) {
 1564   /* remove it to the queue */
 1565   IMMA_CALLBACK_INFO *cb_info = (IMMA_CALLBACK_INFO *)m_NCS_IPC_NON_BLK_RECEIVE(
 1566       &cl_node->callbk_mbx, NULL);
 1567 
 1568   return cb_info;
 1569 }
 1570 
 1571 /****************************************************************************
 1572   Name          : imma_proc_resurrect_client
 1573 
 1574   Description   : Try to resurrect the provided handle. That is re-use
 1575                   the same handle value (which could be stored by the
 1576                   application) and the same client node. Above all the
 1577                   same IPC MBX which the user may be selecting/polling on.
 1578 
 1579                   Resurrecting the handle is done with a newly restarted IMMND.
 1580                   If the client was attached as an implementer, then
 1581                   the implementer also needs to be re-attached, but that
 1582                   is  done elsewhere (in imma_oi_resurrect in imma-oi_api.c).
 1583                   since it is only relevant for OI clients.
 1584                   If the client was attached via the OM interface, then
 1585                   it may be necessary to re-attach to admin-owner, but that
 1586                   is done elsewhere (imma_om_resurrect in in imma_om_api.c).
 1587 
 1588                   This function is used for both active and re-active
 1589                   resurrection.
 1590 
 1591                   The cb_lock should NOT be locked on entry here.
 1592 
 1593   Return Values : true => resurrect succeeded. false => BAD_HANDLE
 1594 
 1595   Notes         : None
 1596 ******************************************************************************/
 1597 uint32_t imma_proc_resurrect_client(IMMA_CB *cb, SaImmHandleT immHandle,
 1598                                     bool isOm, SaAisErrorT *err_resurrect) {
 1599   TRACE_ENTER();
 1600   IMMA_CLIENT_NODE *cl_node = NULL;
 1601   IMMSV_EVT resurrect_evt;
 1602   IMMSV_EVT *out_evt = NULL;
 1603   bool locked = false;
 1604   SaAisErrorT err;
 1605   unsigned int sleep_delay_ms = 500;
 1606   unsigned int max_waiting_time_ms = 2 * 1000; /* 2 secs */
 1607   unsigned int msecs_waited = 0;
 1608   SaTimeT timeout = IMMSV_WAIT_TIME;
 1609 
 1610   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1611     TRACE_3("Lock failure");
 1612     goto lock_fail;
 1613   }
 1614   locked = true;
 1615 
 1616   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 1617   if (cl_node == NULL || (cl_node->stale && cl_node->exposed)) {
 1618     TRACE_3("Client not found %p or already exposed %u - cant resurrect",
 1619             cl_node, cl_node ? cl_node->exposed : 0);
 1620     goto failure;
 1621   }
 1622   timeout = cl_node->syncr_timeout;
 1623   if (!cl_node->stale) {
 1624     TRACE_3(
 1625         "imma_proc_resurrect_client: Handle %llx was not stale, "
 1626         "resurrected by another thread ?",
 1627         immHandle);
 1628     goto skip_resurrect;
 1629   }
 1630 
 1631   if (cl_node->replyPending) {
 1632     TRACE_4(
 1633         "Can not resurrect client with pending replies, client now exposed");
 1634     /* Catches on-going async admin OM op as well as blocked calls */
 1635     cl_node->exposed = true;
 1636     goto failure;
 1637   }
 1638 
 1639   /* populate the structure */
 1640   memset(&resurrect_evt, 0, sizeof(IMMSV_EVT));
 1641   resurrect_evt.type = IMMSV_EVT_TYPE_IMMND;
 1642   resurrect_evt.info.immnd.type = (isOm) ? IMMND_EVT_A2ND_IMM_OM_RESURRECT
 1643                                          : IMMND_EVT_A2ND_IMM_OI_RESURRECT;
 1644   resurrect_evt.info.immnd.info.finReq.client_hdl = immHandle;
 1645   TRACE_1("Resurrect message for immHandle: %llx isOm: %u", immHandle, isOm);
 1646   /* Unlock before MDS Send */
 1647   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1648   locked = false;
 1649   cl_node = NULL;
 1650 
 1651   if (cb->is_immnd_up == false) {
 1652     TRACE_3("IMMND is DOWN - resurrect attempt failed. ");
 1653     goto exposed;
 1654   }
 1655 
 1656   err = SA_AIS_ERR_TRY_AGAIN;
 1657   while ((err == SA_AIS_ERR_TRY_AGAIN) &&
 1658          (msecs_waited < max_waiting_time_ms)) {
 1659     /* send the request to the IMMND */
 1660     if (imma_mds_msg_sync_send(cb->imma_mds_hdl, &(cb->immnd_mds_dest),
 1661                                &resurrect_evt, &out_evt,
 1662                                timeout) != NCSCC_RC_SUCCESS) {
 1663       TRACE_3("Failure in MDS send");
 1664       goto exposed;
 1665     }
 1666 
 1667     if (!out_evt) {
 1668       TRACE_3("Empty reply");
 1669       goto exposed;
 1670     }
 1671 
 1672     err = out_evt->info.imma.info.errRsp.error;
 1673     if (err == SA_AIS_ERR_TRY_AGAIN) {
 1674       usleep(sleep_delay_ms * 1000);
 1675       msecs_waited += sleep_delay_ms;
 1676     }
 1677     free(out_evt);
 1678     out_evt = NULL;
 1679   }
 1680   *err_resurrect = err;
 1681   if (err == SA_AIS_ERR_TRY_AGAIN) {
 1682     TRACE_3("Recieved TRY_AGAIN while resurrecting");
 1683     goto failure;
 1684   }
 1685 
 1686   if (err != SA_AIS_OK) {
 1687     TRACE_3("Recieved negative reply from IMMND %u", err);
 1688     goto exposed;
 1689   }
 1690 
 1691   TRACE("OK reply from IMMND on resurrect of handle %llx", immHandle);
 1692 
 1693   /* Take the lock again. */
 1694   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1695     TRACE_3("Lock failure");
 1696     goto lock_fail;
 1697   }
 1698   locked = true;
 1699 
 1700   /* Look up the client node again. */
 1701   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 1702   if (cl_node == NULL) {
 1703     TRACE_3("Client node missing after reply");
 1704     goto failure;
 1705   }
 1706 
 1707   if (cl_node->exposed) {
 1708     TRACE_3("Client node got exposed DURING resurrect attempt");
 1709     /* Could happen in a separate thread trying to use the same handle */
 1710     goto failure;
 1711   }
 1712 
 1713   /* Clear away stale marking */
 1714   cl_node->stale = false;
 1715 
 1716 /*cl_node->selObjUsable = true;   Done in OM/OI dispatch if relevant. */
 1717 
 1718 skip_resurrect:
 1719   if (locked) {
 1720     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1721   }
 1722 
 1723   TRACE_LEAVE();
 1724   return true;
 1725 
 1726 exposed:
 1727   /* Try to mark client as exposed */
 1728   if (locked ||
 1729       (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) == NCSCC_RC_SUCCESS)) {
 1730     locked = true;
 1731     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 1732     if (cl_node != NULL && cl_node->stale) {
 1733       cl_node->exposed = true;
 1734     }
 1735   }
 1736 
 1737 failure:
 1738   if (locked) {
 1739     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1740   }
 1741 
 1742 lock_fail:
 1743   TRACE_LEAVE();
 1744   return false;
 1745 }
 1746 
 1747 /****************************************************************************
 1748   Name          : imma_hdl_callbk_dispatch_one
 1749 
 1750   Description   : This routine dispatches one pending callback.
 1751 
 1752   Arguments     : cb      - ptr to the IMMA control block
 1753                   immHandle - IMM OM service handle
 1754 
 1755   Return Values : SA_AIS_OK/SA_AIS_ERR_<ERROR>
 1756 
 1757   Notes         : None
 1758 ******************************************************************************/
 1759 SaAisErrorT imma_hdl_callbk_dispatch_one(IMMA_CB *cb, SaImmHandleT immHandle) {
 1760   IMMA_CALLBACK_INFO *callback = NULL;
 1761   IMMA_CLIENT_NODE *cl_node = NULL;
 1762 
 1763   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1764     TRACE_3("Lock failure");
 1765     return SA_AIS_ERR_LIBRARY;
 1766   }
 1767 
 1768   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 1769 
 1770   if (cl_node == NULL) {
 1771     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1772     return SA_AIS_ERR_BAD_HANDLE;
 1773   }
 1774 
 1775   /* get it from the queue */
 1776   while ((callback = imma_callback_ipc_rcv(cl_node))) {
 1777     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 1778     if (cl_node) {
 1779       if (cl_node->stale) {
 1780         cl_node->exposed = true;
 1781         m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1782         return SA_AIS_ERR_BAD_HANDLE;
 1783       }
 1784       imma_proc_ccbaug_setup(cl_node, callback);
 1785       m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1786       if (!imma_process_callback_info(cb, cl_node, callback, immHandle)) {
 1787         IMMSV_EVT finalize_evt, *out_evt;
 1788         /* Callback protocol could not be honored due to some lack
 1789            of client capabilities. E.g. applier can not handle long DNs
 1790            while regular OI can, or there is no regular OI. The capabilties
 1791            of the main OI can not be termined in the context of the applier
 1792            callback.
 1793         */
 1794         TRACE("client capability failure");
 1795         /* Not locked. But setting some flags in client_node should be safe
 1796            assuming only the current thread is using this handle/client_node.
 1797         */
 1798         cl_node->stale = true;
 1799         cl_node->exposed = true;
 1800 
 1801         out_evt = NULL;
 1802         memset(&finalize_evt, 0, sizeof(IMMSV_EVT));
 1803         finalize_evt.type = IMMSV_EVT_TYPE_IMMND;
 1804         finalize_evt.info.immnd.type = IMMND_EVT_A2ND_IMM_FINALIZE;
 1805         finalize_evt.info.immnd.info.finReq.client_hdl = cl_node->handle;
 1806 
 1807         /* send the request to the IMMND */
 1808         imma_mds_msg_sync_send(cb->imma_mds_hdl, &(cb->immnd_mds_dest),
 1809                                &finalize_evt, &out_evt,
 1810                                cl_node->syncr_timeout);
 1811 
 1812         if (out_evt) {
 1813           free(out_evt);
 1814         }
 1815 
 1816         return SA_AIS_ERR_BAD_HANDLE;
 1817       }
 1818       return SA_AIS_OK;
 1819     } else {
 1820       imma_proc_free_callback(callback);
 1821       continue;
 1822     }
 1823   }
 1824 
 1825   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1826   return SA_AIS_OK;
 1827 }
 1828 
 1829 /****************************************************************************
 1830   Name          : imma_hdl_callbk_dispatch_all
 1831 
 1832   Description   : This routine dispatches all pending callback.
 1833 
 1834   Arguments     : cb      - ptr to the IMMA control block
 1835                   immHandle - IMM OM service handle
 1836 
 1837   Return Values : SA_AIS_OK/SA_AIS_ERR_<ERROR>
 1838 
 1839   Notes         : None
 1840 ******************************************************************************/
 1841 SaAisErrorT imma_hdl_callbk_dispatch_all(IMMA_CB *cb, SaImmHandleT immHandle) {
 1842   IMMA_CALLBACK_INFO *callback = NULL;
 1843   IMMA_CLIENT_NODE *cl_node = NULL;
 1844 
 1845   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1846     TRACE_3("Lock failure");
 1847     return SA_AIS_ERR_LIBRARY;
 1848   }
 1849 
 1850   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 1851 
 1852   if (cl_node == NULL) {
 1853     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1854     return SA_AIS_ERR_BAD_HANDLE;
 1855   }
 1856 
 1857   while ((callback = imma_callback_ipc_rcv(cl_node))) {
 1858     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 1859     if (cl_node) {
 1860       if (cl_node->stale) {
 1861         cl_node->exposed = true;
 1862         m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1863         return SA_AIS_ERR_BAD_HANDLE;
 1864       }
 1865 
 1866       imma_proc_ccbaug_setup(cl_node, callback);
 1867       m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1868       if (!imma_process_callback_info(cb, cl_node, callback, immHandle)) {
 1869         IMMSV_EVT finalize_evt, *out_evt;
 1870         /* Callback protocol could not be honored due to some lack
 1871            of client capabilities. E.g. applier can not handle long DNs
 1872            while regular OI can, or there is no regular OI. The capabilties
 1873            of the main OI can not be termined in the context of the applier
 1874            callback.
 1875         */
 1876         TRACE("client capability failure");
 1877         /* Not locked. But setting some flags in client_node should be safe
 1878            assuming only the current thread is using this handle/client_node.
 1879         */
 1880         cl_node->stale = true;
 1881         cl_node->exposed = true;
 1882 
 1883         out_evt = NULL;
 1884         memset(&finalize_evt, 0, sizeof(IMMSV_EVT));
 1885         finalize_evt.type = IMMSV_EVT_TYPE_IMMND;
 1886         finalize_evt.info.immnd.type = IMMND_EVT_A2ND_IMM_FINALIZE;
 1887         finalize_evt.info.immnd.info.finReq.client_hdl = cl_node->handle;
 1888 
 1889         /* send the request to the IMMND */
 1890         imma_mds_msg_sync_send(cb->imma_mds_hdl, &(cb->immnd_mds_dest),
 1891                                &finalize_evt, &out_evt,
 1892                                cl_node->syncr_timeout);
 1893 
 1894         if (out_evt) {
 1895           free(out_evt);
 1896         }
 1897 
 1898         return SA_AIS_ERR_BAD_HANDLE;
 1899       }
 1900     } else {
 1901       imma_proc_free_callback(callback);
 1902       break;
 1903     }
 1904 
 1905     if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1906       TRACE_3("Lock failure");
 1907       return SA_AIS_ERR_LIBRARY;
 1908     }
 1909 
 1910     /* Is this a way of detecting closed handle => terminate ? */
 1911     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 1912 
 1913     if (cl_node == NULL) {
 1914       m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1915       return SA_AIS_ERR_BAD_HANDLE;
 1916     }
 1917   }
 1918 
 1919   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1920   return SA_AIS_OK;
 1921 }
 1922 
 1923 /****************************************************************************
 1924   Name          : imma_hdl_callbk_dispatch_block
 1925 
 1926   Description   : This routine dispatches all pending callback and blocks
 1927                   when there are no more
 1928   Arguments     : cb      - ptr to the IMMA control block
 1929                   immHandle - immsv handle
 1930 
 1931   Return Values : SA_AIS_OK/SA_AIS_ERR_<ERROR>
 1932 
 1933   Notes         : None
 1934 ******************************************************************************/
 1935 SaAisErrorT imma_hdl_callbk_dispatch_block(IMMA_CB *cb,
 1936                                            SaImmHandleT immHandle) {
 1937   IMMA_CALLBACK_INFO *callback = NULL;
 1938   SYSF_MBX *callbk_mbx = NULL;
 1939   IMMA_CLIENT_NODE *client_info = NULL;
 1940 
 1941   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1942     TRACE_3("Lock failure");
 1943     return SA_AIS_ERR_LIBRARY;
 1944   }
 1945 
 1946   imma_client_node_get(&cb->client_tree, &immHandle, &client_info);
 1947 
 1948   if (client_info == NULL) {
 1949     /* Another thread called Finalize */
 1950     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1951     return SA_AIS_ERR_BAD_HANDLE;
 1952   }
 1953 
 1954   callbk_mbx = &(client_info->callbk_mbx);
 1955 
 1956   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1957 
 1958   callback = (IMMA_CALLBACK_INFO *)m_NCS_IPC_RECEIVE(callbk_mbx, NULL);
 1959   while (1) {
 1960     /* Take the CB Lock */
 1961     if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1962       TRACE_3("Lock failure");
 1963       return SA_AIS_ERR_LIBRARY;
 1964     }
 1965 
 1966     imma_client_node_get(&cb->client_tree, &immHandle, &client_info);
 1967 
 1968     if (callback) {
 1969       if (client_info) {
 1970         if (client_info->stale) {
 1971           client_info->exposed = true;
 1972           m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1973           return SA_AIS_ERR_BAD_HANDLE;
 1974         }
 1975 
 1976         imma_proc_ccbaug_setup(client_info, callback);
 1977         m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1978         if (!imma_process_callback_info(cb, client_info, callback, immHandle)) {
 1979           IMMSV_EVT finalize_evt, *out_evt;
 1980           /* Callback protocol could not be honored due to some lack
 1981              of client capabilities. E.g. applier can not handle long DNs
 1982              while regular OI can, or there is no regular OI. The capabilties
 1983              of the main OI can not be termined in the context of the applier
 1984              callback.
 1985           */
 1986           TRACE("client capability failure");
 1987           /* Not locked. But setting some flags in client_node should be safe
 1988              assuming only the current thread is using this handle/client_node.
 1989            */
 1990           client_info->stale = true;
 1991           client_info->exposed = true;
 1992 
 1993           out_evt = NULL;
 1994           memset(&finalize_evt, 0, sizeof(IMMSV_EVT));
 1995           finalize_evt.type = IMMSV_EVT_TYPE_IMMND;
 1996           finalize_evt.info.immnd.type = IMMND_EVT_A2ND_IMM_FINALIZE;
 1997           finalize_evt.info.immnd.info.finReq.client_hdl = client_info->handle;
 1998 
 1999           /* send the request to the IMMND */
 2000           imma_mds_msg_sync_send(cb->imma_mds_hdl, &(cb->immnd_mds_dest),
 2001                                  &finalize_evt, &out_evt,
 2002                                  client_info->syncr_timeout);
 2003 
 2004           if (out_evt) {
 2005             free(out_evt);
 2006           }
 2007 
 2008           return SA_AIS_ERR_BAD_HANDLE;
 2009         }
 2010       } else {
 2011         /* Another thread called Finalize? */
 2012         TRACE_3("Client dead?");
 2013 
 2014         imma_proc_free_callback(callback);
 2015         m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 2016         return SA_AIS_OK;
 2017       }
 2018     } else {
 2019       m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 2020       /* callbk_mbx can fail only when handle is finalized
 2021          If a NULL is returned by m_NCS_IPC_RECEIVE then handle is
 2022          considered as finalized and is a valid case.
 2023          so, SA_AIS_OK will be returned*/
 2024       return SA_AIS_OK;
 2025     }
 2026 
 2027     callback = (IMMA_CALLBACK_INFO *)m_NCS_IPC_RECEIVE(callbk_mbx, NULL);
 2028   }
 2029 
 2030   return SA_AIS_OK;
 2031 }
 2032 
 2033 int imma_popAsyncAdmOpContinuation(IMMA_CB *cb,               // in
 2034                                    SaInt32T invocation,       // in
 2035                                    SaImmHandleT *immHandle,   // out
 2036                                    SaInvocationT *userInvoc)  // out
 2037 {
 2038   IMMA_CONTINUATION_RECORD *cr = cb->imma_continuations;
 2039   IMMA_CONTINUATION_RECORD **prevCr = &(cb->imma_continuations);
 2040 
 2041   TRACE("POP continuation %i", invocation);
 2042 
 2043   while (cr) {
 2044     if (cr->invocation == invocation) {
 2045       *immHandle = cr->immHandle;
 2046       *userInvoc = cr->userInvoc;
 2047       *prevCr = cr->next;
 2048       cr->next = NULL;
 2049       free(cr);
 2050       return 1;
 2051     }
 2052 
 2053     prevCr = &(cr->next);
 2054     cr = cr->next;
 2055   }
 2056   TRACE_3("POP continuation %i not found", invocation);
 2057   return 0;
 2058 }
 2059 
 2060 static void imma_proc_ccbaug_setup(IMMA_CLIENT_NODE *cl_node,
 2061                                    IMMA_CALLBACK_INFO *callback) {
 2062   if (callback->type == IMMA_CALLBACK_OI_CCB_CREATE ||
 2063       callback->type == IMMA_CALLBACK_PBE_PRT_OBJ_CREATE) {
 2064     SaImmAttrValuesT_2 **attr = NULL;
 2065     size_t attrDataSize = 0;
 2066 
 2067     int noOfAttributes = 0;
 2068 
 2069     /* NOTE: The code below is practically a copy of the code
 2070        in immOm searchNext, for serving the attrValues structure.
 2071        This code should be factored out into some common function.
 2072      */
 2073     IMMSV_ATTR_VALUES_LIST *p = callback->attrValues;
 2074     int i = 0;
 2075     while (p) {
 2076       ++noOfAttributes;
 2077       p = p->next;
 2078     }
 2079 
 2080     p = callback->attrValues;
 2081 
 2082     if (cl_node->isImmA2fCbk) {
 2083       if (noOfAttributes) {
 2084         p = p->next;  // Skip RDN. RDN is the first attribute
 2085         noOfAttributes--;
 2086       }
 2087     }
 2088 
 2089     attrDataSize = sizeof(SaImmAttrValuesT_2 *) * (noOfAttributes + 1);
 2090     attr = (SaImmAttrValuesT_2 **)calloc(1, attrDataSize); /*alloc-1 */
 2091     for (; i < noOfAttributes && p; i++, p = p->next) {
 2092       IMMSV_ATTR_VALUES *q = &(p->n);
 2093       attr[i] = (SaImmAttrValuesT_2 *)calloc(
 2094           1, sizeof(SaImmAttrValuesT_2));                       /*alloc-2 */
 2095       attr[i]->attrName = (char *)malloc(q->attrName.size); /*alloc-3 */
 2096       strncpy(attr[i]->attrName, (const char *)q->attrName.buf,
 2097               q->attrName.size);
 2098       attr[i]->attrName[q->attrName.size-1] = 0; /*redundant. */
 2099       attr[i]->attrValuesNumber = q->attrValuesNumber;
 2100       attr[i]->attrValueType = (SaImmValueTypeT)q->attrValueType;
 2101       if (q->attrValuesNumber) {
 2102         attr[i]->attrValues = (SaImmAttrValueT *)calloc(
 2103             q->attrValuesNumber, sizeof(SaImmAttrValueT)); /*alloc-4 */
 2104         /*alloc-5 */
 2105         attr[i]->attrValues[0] = imma_copyAttrValue3(
 2106             (SaImmValueTypeT)q->attrValueType, &(q->attrValue));
 2107 
 2108         if (q->attrValuesNumber > 1) {
 2109           int ix;
 2110           IMMSV_EDU_ATTR_VAL_LIST *r = q->attrMoreValues;
 2111           for (ix = 1; ix < q->attrValuesNumber; ++ix) {
 2112             osafassert(r);
 2113             attr[i]->attrValues[ix] = /*alloc-5 */
 2114                 imma_copyAttrValue3((SaImmValueTypeT)q->attrValueType, &(r->n));
 2115             r = r->next;
 2116           }         // for
 2117         }           // if
 2118       }             // if
 2119     }               // for
 2120     attr[i] = NULL; /*redundant */
 2121 
 2122     /* Save a copy of the attrvals pointer in the callback to allow
 2123        saImmOiAugmentCcbInitialize to get access to the ccbCreateContext.
 2124        We cant use callback->attrValues because it is partially stolen
 2125        from (caused to be incomplete) in the loop above (see
 2126        imma_copyAttrValue3). The callback->attrValsForCreateUc will be freed at
 2127        IMMA_CALLBACK_OI_CCB_CREATE or IMMA_CALLBACK_PBE_PRT_OBJ_CREATE in
 2128        imma_process_callback_info.
 2129      */
 2130 
 2131     callback->attrValsForCreateUc = (const SaImmAttrValuesT_2 **)attr;
 2132   }
 2133 
 2134   if (cl_node->isApplier) {
 2135     return;
 2136   }
 2137 
 2138   /* Locked on entry */
 2139   switch (callback->type) {
 2140     case IMMA_CALLBACK_OI_CCB_CREATE:
 2141     case IMMA_CALLBACK_OI_CCB_DELETE:
 2142     case IMMA_CALLBACK_OI_CCB_MODIFY:
 2143     case IMMA_CALLBACK_OI_CCB_COMPLETED:
 2144       if (!(imma_oi_ccb_record_note_callback(cl_node, callback->ccbID,
 2145                                              callback))) {
 2146         TRACE_3(
 2147             "Failed to note callback for ccb %u, "
 2148             "Ccb augment not possible",
 2149             callback->ccbID);
 2150       }
 2151       break;
 2152 
 2153     default:
 2154       imma_oi_ccb_record_note_callback(cl_node, callback->ccbID, NULL);
 2155   }
 2156 }
 2157 
 2158 /****************************************************************************
 2159   Name          : imma_process_callback_info
 2160 
 2161   Description   : This routine invokes the registered callback routine.
 2162 
 2163   Arguments     : cb  - ptr to the IMMA control block
 2164                   cl_node - Client Node
 2165                   callback - ptr to the registered callbacks
 2166                   immHandle - handle used to re-fetch cl_node if necessary.
 2167 
 2168   Return Values : bool if false => capability error, break dispatch.
 2169 
 2170   Notes         : None
 2171 ******************************************************************************/
 2172 static bool imma_process_callback_info(IMMA_CB *cb, IMMA_CLIENT_NODE *cl_node,
 2173                                        IMMA_CALLBACK_INFO *callback,
 2174                                        SaImmHandleT immHandle) {
 2175   /* Not locked => the use of cl_node is a bit unsafe here.
 2176      We should at least have a dont-delete marking in the client node.
 2177    */
 2178   TRACE_ENTER();
 2179   bool clientCapable = true; /* Used to break dispatching if client is found
 2180                                 lacking in capability. */
 2181 
 2182 /* invoke the corresponding callback */
 2183 #ifdef IMMA_OM
 2184   switch (callback->type) {
 2185     case IMMA_CALLBACK_OM_ADMIN_OP_RSP: /*Async reply via OM. */
 2186       /* ABT decide if it is A.2.1 or A.2.11 callback. */
 2187       if (cl_node->isImmA2bCbk) {
 2188         if (!osaf_is_extended_names_enabled() &&
 2189             callback->params) {
 2190           int i = 0;
 2191           while (callback->params[i]) {
 2192             if (callback->params[i]->paramType == SA_IMM_ATTR_SANAMET &&
 2193                 !osaf_is_extended_name_valid(
 2194                     (SaNameT *)callback->params[i]->paramBuffer)) {
 2195               if (callback->retval == SA_AIS_OK) {
 2196                 callback->retval = SA_AIS_ERR_NAME_TOO_LONG;
 2197               }
 2198               osaf_extended_name_free(
 2199                   (SaNameT *)callback->params[i]->paramBuffer);
 2200               osaf_extended_name_clear(
 2201                   (SaNameT *)callback->params[i]->paramBuffer);
 2202             }
 2203             i++;
 2204           }
 2205         }
 2206 
 2207         cl_node->o.mCallbkA2b.saImmOmAdminOperationInvokeCallback(
 2208             callback->invocation, callback->retval, callback->sa_err,
 2209             (const SaImmAdminOperationParamsT_2 **)callback->params);
 2210       } else if (cl_node->o.mCallbk.saImmOmAdminOperationInvokeCallback) {
 2211         TRACE("Upcall for callback for async admop inv:%llx rslt:%u err:%u",
 2212               callback->invocation, callback->retval, callback->sa_err);
 2213 
 2214         cl_node->o.mCallbk.saImmOmAdminOperationInvokeCallback(
 2215             callback->invocation, callback->retval, callback->sa_err);
 2216       } else {
 2217         TRACE_3(
 2218             "No callback to deliver AdminOperationInvokeAsync - invoc:%llx ret:%u err:%u",
 2219             callback->invocation, callback->retval, callback->sa_err);
 2220       }
 2221 
 2222       /* callback->params freed by imma_proc_free_callback(callback) below */
 2223 
 2224       break;
 2225 
 2226     case IMMA_CALLBACK_STALE_HANDLE:
 2227       TRACE("Stale OM handle upcall completed");
 2228       /* Do nothing. */
 2229       osafassert(
 2230           !cl_node
 2231                ->isPbe); /* Should have exited in imma_mark_clients_stale() */
 2232       break;
 2233 
 2234     default:
 2235       TRACE_3("Unrecognized OM callback type:%u", callback->type);
 2236       break;
 2237   }
 2238 #endif
 2239 
 2240 #ifdef IMMA_OI
 2241   bool isPbeOp = false;
 2242   bool isExtendedNameValid = false;
 2243   bool isAttrExtendedName = false;
 2244   switch (callback->type) {
 2245     case IMMA_CALLBACK_PBE_ADMIN_OP:
 2246       isPbeOp = true;
 2247       osafassert(cl_node->isPbe);
 2248       TRACE("PBE Admin OP callback");
 2249     case IMMA_CALLBACK_OM_ADMIN_OP:
 2250       isExtendedNameValid = osaf_is_extended_name_valid(&(callback->name));
 2251       if (isExtendedNameValid && !osaf_is_extended_names_enabled() &&
 2252           callback->params) {
 2253         SaImmAdminOperationParamsT_2 **params =
 2254             (SaImmAdminOperationParamsT_2 **)callback->params;
 2255         int i;
 2256         for (i = 0; !isAttrExtendedName && params[i]; i++) {
 2257           if (params[i]->paramType == SA_IMM_ATTR_SANAMET &&
 2258               params[i]->paramBuffer) {
 2259             isAttrExtendedName =
 2260                 osaf_is_an_extended_name((SaNameT *)params[i]->paramBuffer);
 2261           }
 2262         }
 2263       }
 2264       cl_node->callbackInvocationSet.insert(callback->invocation);
 2265       if (cl_node->o.iCallbk.saImmOiAdminOperationCallback &&
 2266           isExtendedNameValid && !isAttrExtendedName) {
 2267         if (cl_node->isImmA2fCbk) {
 2268           cl_node->o.iCallbkA2f.saImmOiAdminOperationCallback(
 2269               callback->lcl_imm_hdl, callback->invocation,
 2270               osaf_extended_name_borrow(&(callback->name)),
 2271               callback->operationId,
 2272               (const SaImmAdminOperationParamsT_2 **)callback->params);
 2273         } else {
 2274           cl_node->o.iCallbk.saImmOiAdminOperationCallback(
 2275               callback->lcl_imm_hdl, callback->invocation, &(callback->name),
 2276               callback->operationId,
 2277               (const SaImmAdminOperationParamsT_2 **)callback->params);
 2278         }
 2279       } else {
 2280         SaAisErrorT error = (SaAisErrorT)IMMSV_IMPOSSIBLE_ERROR;
 2281         if (!isExtendedNameValid) {
 2282           if (osaf_is_extended_names_enabled()) {
 2283             TRACE_3("Object name is too long: %s",
 2284                     osaf_extended_name_borrow(&callback->name));
 2285           } else {
 2286             TRACE_3(
 2287                 "Extended name feature is disabled. Object name is too long: %s",
 2288                 osaf_extended_name_borrow(&callback->name));
 2289           }
 2290           error = SA_AIS_ERR_BAD_OPERATION;
 2291         } else if (isAttrExtendedName) {
 2292           TRACE_3("At least one SaNameT attribute has extended name");
 2293           error = SA_AIS_ERR_NAME_TOO_LONG;
 2294         }
 2295         /*No callback registered for admin-op!! */
 2296         SaAisErrorT localErr = saImmOiAdminOperationResult(
 2297             callback->lcl_imm_hdl, callback->invocation, error);
 2298         if (localErr == SA_AIS_OK) {
 2299           TRACE_3(
 2300               "Object %s has implementer but "
 2301               "saImmOiAdminOperationCallback is set to NULL",
 2302               osaf_extended_name_borrow(&callback->name));
 2303         } else {
 2304           TRACE_3(
 2305               "Object %s has implementer but "
 2306               "saImmOiAdminOperationCallback is set to NULL "
 2307               "and could not send error result, error: %u",
 2308               osaf_extended_name_borrow(&callback->name), localErr);
 2309         }
 2310       }
 2311       break;
 2312 
 2313     case IMMA_CALLBACK_PBE_PRTO_DELETES_COMPLETED:
 2314       isPbeOp = true;
 2315       osafassert(cl_node->isPbe);
 2316     case IMMA_CALLBACK_OI_CCB_COMPLETED:
 2317       TRACE("%s-completed op callback", isPbeOp ? "Pbe-Prto-Deletes" : "ccb");
 2318       do {
 2319         SaAisErrorT localEr = SA_AIS_OK;
 2320         IMMSV_EVT ccbCompletedRpl;
 2321         bool locked = false;
 2322         SaStringT errorStr = NULL;
 2323         /* cl_node->o is union, and callback function order is the same for
 2324          * iCallbk and iCallbkA2f. So, it's not needed to check if
 2325          * cl_node->o.iCallbkA2f.saImmOiCcbCompletedCallback is NULL or not */
 2326         if (cl_node->o.iCallbk.saImmOiCcbCompletedCallback) {
 2327           SaImmOiCcbIdT ccbid = 0LL;
 2328 
 2329           if (isPbeOp) {
 2330             osafassert(callback->ccbID == 0);
 2331             /* Pseudo ccb towards PBE for PRTO deletes */
 2332             ccbid = callback->inv + 0x100000000LL;
 2333 
 2334             /* PRTO delete reply only on completed*/
 2335             // callback->inv = 0;
 2336             TRACE("Pseudo ccb %llx for PRTO deletes completed upcall on %s",
 2337                   ccbid, osaf_extended_name_borrow(&callback->name));
 2338             if (!imma_oi_ccb_record_ok_for_critical(cl_node, ccbid,
 2339                                                     callback->implId)) {
 2340               TRACE(
 2341                   "ERROR: RtObjectDelete record for pseudo-ccb %llx does not have"
 2342                   "correct op-count",
 2343                   ccbid); /* Already logged in ok_for_critical */
 2344               imma_oi_ccb_record_terminate(cl_node, ccbid);
 2345               localEr = SA_AIS_ERR_FAILED_OPERATION;
 2346               goto skip_completed_upcall;
 2347             }
 2348 
 2349             imma_oi_ccb_record_terminate(cl_node, ccbid);
 2350           } else {
 2351             ccbid = callback->ccbID;
 2352             if (!(cl_node->isApplier)) {
 2353               imma_oi_ccb_allow_error_string(cl_node, ccbid);
 2354             }
 2355             /*Verify op-count before PBE commit of ccb.
 2356               This to eliminate the risk of the CCB committing in PBE
 2357               yet failing in imma_oi_ccb_record_set_critical below after the
 2358               PBE transaction. */
 2359             if (!imma_oi_ccb_record_ok_for_critical(cl_node, ccbid,
 2360                                                     callback->inv)) {
 2361               LOG_WA(
 2362                   "WARNING: CCB record for %u does not have correct op-count",
 2363                   callback->ccbID);
 2364               localEr = SA_AIS_ERR_FAILED_OPERATION;
 2365               goto skip_completed_upcall;
 2366             }
 2367           }
 2368 
 2369           if (cl_node->isImmA2fCbk) {
 2370             localEr = cl_node->o.iCallbkA2f.saImmOiCcbCompletedCallback(
 2371                 callback->lcl_imm_hdl, ccbid);
 2372           } else {
 2373             localEr = cl_node->o.iCallbk.saImmOiCcbCompletedCallback(
 2374                 callback->lcl_imm_hdl, ccbid);
 2375           }
 2376           if (!(localEr == SA_AIS_OK || localEr == SA_AIS_ERR_NO_MEMORY ||
 2377                 localEr == SA_AIS_ERR_NO_RESOURCES ||
 2378                 localEr == SA_AIS_ERR_BAD_OPERATION)) {
 2379             TRACE_3(
 2380                 "Illegal return value from "
 2381                 "saImmOiCcbCompletedCallback %u. "
 2382                 "Allowed are %u %u %u %u",
 2383                 localEr, SA_AIS_OK, SA_AIS_ERR_NO_MEMORY,
 2384                 SA_AIS_ERR_NO_RESOURCES, SA_AIS_ERR_BAD_OPERATION);
 2385             localEr = SA_AIS_ERR_FAILED_OPERATION;
 2386           }
 2387 
 2388           if (isPbeOp) {
 2389             cl_node->o.iCallbk.saImmOiCcbApplyCallback(callback->lcl_imm_hdl,
 2390                                                        ccbid);
 2391           }
 2392 
 2393         } else {
 2394           /* No callback function registered for completed upcall.
 2395              The standard is not clear on how this case should be handled.
 2396              We take the strict approach of demanding that, if there is
 2397              a registered implementer, then that implementer must
 2398              implement the completed callback, for the callback to succeed
 2399           */
 2400           TRACE_2(
 2401               "ERR_FAILED_OPERATION: saImmOiCcbCompletedCallback is not implemented, yet "
 2402               "implementer is registered and CCBs are used. Ccb will fail");
 2403           localEr = SA_AIS_ERR_FAILED_OPERATION;
 2404         }
 2405       skip_completed_upcall:
 2406 
 2407         memset(&ccbCompletedRpl, 0, sizeof(IMMSV_EVT));
 2408         ccbCompletedRpl.type = IMMSV_EVT_TYPE_IMMND;
 2409         if (isPbeOp) {
 2410           ccbCompletedRpl.info.immnd.type =
 2411               IMMND_EVT_A2ND_PBE_PRTO_DELETES_COMPLETED_RSP;
 2412         } else {
 2413           ccbCompletedRpl.info.immnd.type = IMMND_EVT_A2ND_CCB_COMPLETED_RSP;
 2414           ccbCompletedRpl.info.immnd.info.ccbUpcallRsp.ccbId = callback->ccbID;
 2415         }
 2416         ccbCompletedRpl.info.immnd.info.ccbUpcallRsp.result = localEr;
 2417         ccbCompletedRpl.info.immnd.info.ccbUpcallRsp.oi_client_hdl =
 2418             callback->lcl_imm_hdl;
 2419         ccbCompletedRpl.info.immnd.info.ccbUpcallRsp.implId = callback->implId;
 2420         ccbCompletedRpl.info.immnd.info.ccbUpcallRsp.inv = callback->inv;
 2421 
 2422         osafassert(m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 2423                    NCSCC_RC_SUCCESS);
 2424         locked = true;
 2425         /*async  fevs */
 2426 
 2427         imma_client_node_get(&cb->client_tree, &(immHandle), &cl_node);
 2428         osafassert(cl_node);
 2429 
 2430         /* Close window for setting error strings also for the OK case. #2233 */
 2431         errorStr = imma_oi_ccb_record_get_error(cl_node, callback->ccbID);
 2432 
 2433         if (localEr == SA_AIS_OK) {
 2434           /* replying OK => entering critical phase for this OI and this CCB.
 2435              There can be many simultaneous OM clients starting CCBs that impact
 2436              the same OI. Some OIs may not accept this and may reject
 2437              overlapping CCBs, but we can not assume this in the IMMSv
 2438              implementation.
 2439           */
 2440           if (isPbeOp || imma_oi_ccb_record_set_critical(
 2441                              cl_node, callback->ccbID, callback->inv)) {
 2442             TRACE_2("Sending normal OK response on completed for ccb %u. ",
 2443                     callback->ccbID);
 2444             if (!isPbeOp) {
 2445               TRACE_2("The oi_ccb_record now marked as critical.");
 2446             }
 2447           } else {
 2448             TRACE_2("CCB record for %u non existent - must have been aborted",
 2449                     callback->ccbID);
 2450             osafassert(m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 2451                        NCSCC_RC_SUCCESS);
 2452             locked = false;
 2453             break; /* out of while */
 2454           }
 2455         } else {
 2456           TRACE_2("Sending FAILED_OP response on completed. for ccb %u.",
 2457                   callback->ccbID);
 2458           if (errorStr) {
 2459             ccbCompletedRpl.info.immnd.type =
 2460                 IMMND_EVT_A2ND_CCB_COMPLETED_RSP_2;
 2461             ccbCompletedRpl.info.immnd.info.ccbUpcallRsp.errorString.size =
 2462                 strlen(errorStr) + 1;
 2463             ccbCompletedRpl.info.immnd.info.ccbUpcallRsp.errorString.buf =
 2464                 errorStr;
 2465           }
 2466         }
 2467 
 2468         if (!(cl_node->isApplier) || (isPbeOp && cl_node->isPbe)) {
 2469           SaImmHandleT privateAugOmHandle = 0LL;
 2470           /* Appliers dont reply on completed except PBE slave replying on
 2471              completed for PRTO- delete. PRTO-delete means ccb-id is in the high
 2472              rannge. So PBE slave does NOT reply on completed for regular CCBs.
 2473           */
 2474 
 2475           // Add code for closing safe-read augmentations in completed callback.
 2476           if (!imma_oi_ccb_record_close_augment(cl_node, callback->ccbID,
 2477                                                 &privateAugOmHandle, false)) {
 2478             TRACE_3(
 2479                 "CcbObjectCompletedCallback: imma_oi_ccb_record_close_augment "
 2480                 "returned false for ccb %u",
 2481                 callback->ccbID);
 2482           }
 2483 
 2484           if (privateAugOmHandle) {
 2485             osafassert(locked);
 2486             osafassert(m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 2487                        NCSCC_RC_SUCCESS);
 2488             locked = false;
 2489 
 2490             osafassert(immsv_om_augment_ccb_get_result);
 2491             SaAisErrorT augResult = immsv_om_augment_ccb_get_result(
 2492                 privateAugOmHandle, callback->ccbID);
 2493 
 2494             osafassert(m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 2495                        NCSCC_RC_SUCCESS);
 2496             locked = true;
 2497 
 2498             if (augResult != SA_AIS_OK) {
 2499               TRACE(
 2500                   "A non-ok result %u from an augmented CCB overrides the reply from "
 2501                   "the OI %u on completed",
 2502                   augResult,
 2503                   ccbCompletedRpl.info.immnd.info.ccbUpcallRsp.result);
 2504 
 2505               ccbCompletedRpl.info.immnd.info.ccbUpcallRsp.result = augResult;
 2506             }
 2507           }
 2508 
 2509           localEr = imma_evt_fake_evs(cb, &ccbCompletedRpl, NULL, 0,
 2510                                       cl_node->handle, &locked, false);
 2511           if (localEr != NCSCC_RC_SUCCESS) {
 2512             /*Cant do anything but log error and drop this reply. */
 2513             TRACE_3("CcbCompletedCallback: send reply to IMMND failed");
 2514           }
 2515         }
 2516 
 2517         if (locked) {
 2518           osafassert(m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 2519                      NCSCC_RC_SUCCESS);
 2520           locked = false;
 2521         }
 2522       } while (0);
 2523       break;
 2524 
 2525     case IMMA_CALLBACK_OI_CCB_APPLY:
 2526       TRACE("ccb-apply op callback");
 2527       do {
 2528         /* Anoying type diff for ccbid between OM and OI */
 2529         SaImmOiCcbIdT ccbid = callback->ccbID;
 2530         SaImmHandleT privateAugOmHandle = 0LL;
 2531 
 2532         /* cl_node->o is union, and callback function order is the same for
 2533          * iCallbk and iCallbkA2f */
 2534         if (cl_node->o.iCallbk.saImmOiCcbApplyCallback) {
 2535           if (cl_node->isImmA2fCbk) {
 2536             cl_node->o.iCallbkA2f.saImmOiCcbApplyCallback(callback->lcl_imm_hdl,
 2537                                                           ccbid);
 2538           } else {
 2539             cl_node->o.iCallbk.saImmOiCcbApplyCallback(callback->lcl_imm_hdl,
 2540                                                        ccbid);
 2541           }
 2542         } else {
 2543           /* No callback function registered for apply upcall.
 2544              There is nothing we can do about this since the CCB is
 2545              commited already. It also makes sense that some applications
 2546              may want to ignore the apply upcall.
 2547           */
 2548           TRACE_3(
 2549               "saImmOiCcbApplyCallback is not implemented, yet "
 2550               "implementer is registered and CCBs are used. Ccb will commit in any case");
 2551         }
 2552         osafassert(m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 2553                    NCSCC_RC_SUCCESS);
 2554         if (!imma_oi_ccb_record_close_augment(cl_node, ccbid,
 2555                                               &privateAugOmHandle, true)) {
 2556           TRACE_2(
 2557               "saImmOiCcbApplyCallback: imma_oi_ccb_record_close_augment returned false "
 2558               "for ccb %llu",
 2559               ccbid);
 2560         }
 2561 
 2562         if (imma_oi_ccb_record_terminate(cl_node, ccbid)) {
 2563           TRACE_2(
 2564               "CCB-APPLY-UC for %llu received from IMMND - oi_ccb_record terminated",
 2565               ccbid);
 2566         } else {
 2567           TRACE_4("ERROR: CCB-APPLY-UC - CCB record non existentfor ccb %llu",
 2568                   ccbid);
 2569         }
 2570         osafassert(m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 2571                    NCSCC_RC_SUCCESS);
 2572 
 2573         if (privateAugOmHandle) {
 2574           osafassert(immsv_om_handle_finalize);
 2575           immsv_om_handle_finalize(privateAugOmHandle);
 2576         }
 2577       } while (0);
 2578       break;
 2579 
 2580     case IMMA_CALLBACK_PBE_PRT_OBJ_CREATE:
 2581       isPbeOp = true;
 2582       osafassert(cl_node->isPbe);
 2583     case IMMA_CALLBACK_OI_CCB_CREATE:
 2584       TRACE("%sobject-create callback", isPbeOp ? "Pbe-Runtime-" : "Ccb-");
 2585       do {
 2586         SaAisErrorT localEr = SA_AIS_OK;
 2587         IMMSV_EVT ccbObjCrRpl;
 2588         bool locked = false;
 2589         SaImmAttrValuesT_2 **attr = NULL;
 2590         /* No need to check for o.iCallbkA2f.saImmOiCcbObjectCreateCallback
 2591          * "o" is union and o.iCallbk.saImmOiCcbObjectCreateCallback is same
 2592          * as o.iCallbkA2f.saImmOiCcbObjectCreateCallback */
 2593         if (cl_node->o.iCallbk.saImmOiCcbObjectCreateCallback) {
 2594           SaStringT objectName = NULL;
 2595           SaImmOiCcbIdT ccbid = 0LL;
 2596           if (isPbeOp) {
 2597             osafassert(callback->ccbID == 0);
 2598             /* Pseudo ccb towards PBE for PRTO create */
 2599             ccbid = callback->inv + 0x100000000LL;
 2600           } else {
 2601             ccbid = callback->ccbID;
 2602             if (!(cl_node->isApplier)) {
 2603               /* Error strings are not relevant for PRT ops. */
 2604               imma_oi_ccb_allow_error_string(cl_node, callback->ccbID);
 2605             }
 2606           }
 2607 
 2608           const SaImmClassNameT className = callback->className; /*0 */
 2609           callback->className = NULL;
 2610 
 2611           if (cl_node->isImmA2fCbk && !callback->attrValsForCreateUc) {
 2612             /* There must be at least one attribute value */
 2613             localEr = SA_AIS_ERR_BAD_OPERATION;
 2614             clientCapable = false;
 2615           }
 2616 
 2617           if (localEr == SA_AIS_OK && cl_node->isImmA2fCbk) {
 2618             /* RDN is the first attribute in the list */
 2619             IMMSV_ATTR_VALUES *q = &(callback->attrValues->n);
 2620             size_t parentNameLen = osaf_extended_name_length(&callback->name);
 2621             size_t sz = parentNameLen + strnlen(q->attrValue.val.x.buf,
 2622                                                 q->attrValue.val.x.size);
 2623             objectName = (SaStringT)malloc(sz + 2); /*alloc-6 */
 2624             osafassert(objectName);
 2625             strncpy(objectName, q->attrValue.val.x.buf,
 2626                     q->attrValue.val.x.size);
 2627             objectName[q->attrValue.val.x.size] = 0;
 2628             if (parentNameLen > 0) {
 2629               strcat(objectName, ",");
 2630               strcat(objectName, osaf_extended_name_borrow(&callback->name));
 2631             }
 2632           }
 2633 
 2634           TRACE("ccb-object-create make the callback");
 2635           /* Save a copy of the attrvals pointer in the callback to allow
 2636              saImmOiAugmentCcbInitialize to get access to the ccbCreateContext.
 2637              We cant use callback->attrValues because it is partially stolen
 2638              from (caused to be incomplete) in the loop above (see
 2639              imma_copyAttrValue3).
 2640            */
 2641 
 2642           if (localEr == SA_AIS_OK && !osaf_is_extended_names_enabled() &&
 2643               (callback->hasLongRdnOrDn)) {
 2644             /* (callback->hasLongRdnOrDn) set above at '@@@@' here means
 2645                that the create callback has one or more of the following
 2646                properties:
 2647                a) Parent DN is a longDN.
 2648                b) RDN appended with parent DN, i.e. object DN, is a long DN.
 2649                c) The RDN is of type SaStringT and longer than 64 bytes.
 2650                d) One or more long DNs appear in attribute list.
 2651                Any of these properties are not compatible for a client that
 2652                does not support long DNs. These cases are detected in the server
 2653                and communicated here to the generic client code.
 2654             */
 2655             LOG_WA(
 2656                 "Extended names not enabled. RDN, or ParentDN(%zu) or parentDN+RDN too long. ccb: %u",
 2657                 strlen(osaf_extended_name_borrow(&(callback->name))),
 2658                 callback->ccbID);
 2659             localEr = SA_AIS_ERR_BAD_OPERATION;
 2660             if (cl_node->isApplier) {
 2661               /* We cannot uphold the contract for an applier that is not long
 2662                  DN capable. For relgular OI this is not a problem since an
 2663                  error can be returned to the server aborting the CCB. But
 2664                  appliers can not reply. If the OI/OIs are capable but some
 2665                  applier(s) are not then we have a problem for those appliers.
 2666                  We can not just silently skip the applier callback while the
 2667                  CCB goes on to commit. Instead we break the dispatch loop.
 2668                */
 2669               clientCapable = false;
 2670             }
 2671 
 2672           } else if (localEr == SA_AIS_OK &&
 2673                      osaf_is_extended_name_valid(
 2674                          &(callback->name))) { /* Only checks length of parent
 2675                                                   name. */
 2676             if (cl_node->isImmA2fCbk) {
 2677               localEr = cl_node->o.iCallbkA2f.saImmOiCcbObjectCreateCallback(
 2678                   callback->lcl_imm_hdl, ccbid, className, objectName,
 2679                   callback->attrValsForCreateUc);
 2680             } else {
 2681               localEr = cl_node->o.iCallbk.saImmOiCcbObjectCreateCallback(
 2682                   callback->lcl_imm_hdl, ccbid, className, &(callback->name),
 2683                   callback->attrValsForCreateUc);
 2684             }
 2685           } else if (localEr == SA_AIS_OK) {
 2686             /* We should never get here. This should be caught already in the
 2687                MDS thread for the obj-create case. Search for two times '@@@@'
 2688                above.
 2689              */
 2690             TRACE_3(
 2691                 "Extended name feature is disabled. Parent name is too long: %zu ccb: %u",
 2692                 strlen(osaf_extended_name_borrow(&(callback->name))),
 2693                 callback->ccbID);
 2694             localEr = SA_AIS_ERR_BAD_OPERATION;
 2695           }
 2696 
 2697           TRACE("ccb-object-create callback returned RC:%u", localEr);
 2698           if (!(localEr == SA_AIS_OK || localEr == SA_AIS_ERR_NO_MEMORY ||
 2699                 localEr == SA_AIS_ERR_NO_RESOURCES ||
 2700                 localEr == SA_AIS_ERR_BAD_OPERATION)) {
 2701             TRACE_2(
 2702                 "ERR_FAILED_OPERATION: Illegal return value from "
 2703                 "saImmOiCcbObjectCreateCallback %u. "
 2704                 "Allowed are %u %u %u %u",
 2705                 localEr, SA_AIS_OK, SA_AIS_ERR_NO_MEMORY,
 2706                 SA_AIS_ERR_NO_RESOURCES, SA_AIS_ERR_BAD_OPERATION);
 2707             localEr = SA_AIS_ERR_FAILED_OPERATION;
 2708             /*Change to BAD_OP if only aborting create and not ccb. */
 2709           }
 2710 
 2711           free(className);  /*free-0 */
 2712           free(objectName); /*free-6 */
 2713           attr = (SaImmAttrValuesT_2 **)callback->attrValsForCreateUc;
 2714           for (int i = 0; attr[i]; ++i) {
 2715             free(attr[i]->attrName); /*free-3 */
 2716             attr[i]->attrName = 0;
 2717             if (attr[i]->attrValuesNumber) {
 2718               SaUint32T j;
 2719               for (j = 0; j < attr[i]->attrValuesNumber; ++j) {
 2720                 imma_freeAttrValue3(attr[i]->attrValues[j],
 2721                                     attr[i]->attrValueType); /*free-5 */
 2722                 attr[i]->attrValues[j] = 0;
 2723               }
 2724               free(attr[i]->attrValues); /*4 */
 2725               /* SaImmAttrValueT[] array-of-void* */
 2726               attr[i]->attrValues = 0;
 2727             }
 2728             free(attr[i]); /*2 */
 2729             /* SaImmAttrValuesT struct */
 2730             attr[i] = 0;
 2731           }
 2732           free(attr); /*1 */
 2733                       /* SaImmAttrValuesT*[]  array-off-pointers */
 2734         } else {
 2735           /* No callback function registered for obj-create upcall.
 2736              The standard is not clear on how this case should be
 2737              handled. We take the strict approach of demanding that,
 2738              if there is a registered implementer, then that
 2739              implementer must implement the create callback, for the
 2740              callback to succeed.
 2741           */
 2742           TRACE_2(
 2743               "ERR_FAILED_OPERATION: saImmOiCcbObjectCreateCallback is not implemented, "
 2744               "yet implementer is registered and CCBs are used. Ccb will fail");
 2745 
 2746           localEr = SA_AIS_ERR_FAILED_OPERATION;
 2747         }
 2748         if (callback->inv) {
 2749           SaStringT errorStr = NULL;
 2750           SaImmHandleT privateAugOmHandle = 0LL;
 2751           osafassert(m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 2752                      NCSCC_RC_SUCCESS);
 2753           locked = true;
 2754           memset(&ccbObjCrRpl, 0, sizeof(IMMSV_EVT));
 2755           ccbObjCrRpl.type = IMMSV_EVT_TYPE_IMMND;
 2756           if (isPbeOp) {
 2757             ccbObjCrRpl.info.immnd.type = IMMND_EVT_A2ND_PBE_PRT_OBJ_CREATE_RSP;
 2758           } else {
 2759             ccbObjCrRpl.info.immnd.type = IMMND_EVT_A2ND_CCB_OBJ_CREATE_RSP;
 2760             ccbObjCrRpl.info.immnd.info.ccbUpcallRsp.ccbId = callback->ccbID;
 2761           }
 2762           ccbObjCrRpl.info.immnd.info.ccbUpcallRsp.result = localEr;
 2763           ccbObjCrRpl.info.immnd.info.ccbUpcallRsp.oi_client_hdl =
 2764               callback->lcl_imm_hdl;
 2765           ccbObjCrRpl.info.immnd.info.ccbUpcallRsp.inv = callback->inv;
 2766 
 2767           /* Closes window for setting error strings also for the OK case. #2233
 2768            */
 2769           errorStr = imma_oi_ccb_record_get_error(cl_node, callback->ccbID);
 2770 
 2771           if (localEr != SA_AIS_OK) {
 2772             if (errorStr) {
 2773               ccbObjCrRpl.info.immnd.type = IMMND_EVT_A2ND_CCB_OBJ_CREATE_RSP_2;
 2774               ccbObjCrRpl.info.immnd.info.ccbUpcallRsp.errorString.size =
 2775                   strlen(errorStr) + 1;
 2776               ccbObjCrRpl.info.immnd.info.ccbUpcallRsp.errorString.buf =
 2777                   errorStr;
 2778             }
 2779           }
 2780 
 2781           if (!imma_oi_ccb_record_close_augment(cl_node, callback->ccbID,
 2782                                                 &privateAugOmHandle, false)) {
 2783             TRACE_3(
 2784                 "CcbObjectCreatedCallback: imma_oi_ccb_record_close_augment "
 2785                 "returned false for ccb %u",
 2786                 callback->ccbID);
 2787           }
 2788 
 2789           if (privateAugOmHandle) {
 2790             osafassert(m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 2791                        NCSCC_RC_SUCCESS);
 2792             locked = false;
 2793 
 2794             osafassert(immsv_om_augment_ccb_get_result);
 2795             SaAisErrorT augResult = immsv_om_augment_ccb_get_result(
 2796                 privateAugOmHandle, callback->ccbID);
 2797 
 2798             osafassert(m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 2799                        NCSCC_RC_SUCCESS);
 2800             locked = true;
 2801 
 2802             if (augResult != SA_AIS_OK) {
 2803               TRACE(
 2804                   "A non-ok result %u from an augmented CCB overrides the reply from "
 2805                   "the OI %u on create-uc",
 2806                   augResult, ccbObjCrRpl.info.immnd.info.ccbUpcallRsp.result);
 2807 
 2808               ccbObjCrRpl.info.immnd.info.ccbUpcallRsp.result = augResult;
 2809             }
 2810           }
 2811 
 2812           /*async fevs */
 2813           localEr = imma_evt_fake_evs(cb, &ccbObjCrRpl, NULL, 0,
 2814                                       cl_node->handle, &locked, false);
 2815         }
 2816 
 2817         if (locked) {
 2818           osafassert(m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 2819                      NCSCC_RC_SUCCESS);
 2820           locked = false;
 2821         }
 2822 
 2823         if (localEr != NCSCC_RC_SUCCESS) {
 2824           /*Cant do anything but log error and drop this reply. */
 2825           TRACE_3("CcbObjectCreatedCallback: send reply to IMMND failed");
 2826         }
 2827       } while (0);
 2828       break;
 2829 
 2830     case IMMA_CALLBACK_PBE_PRT_OBJ_DELETE:
 2831       isPbeOp = true;
 2832       osafassert(cl_node->isPbe);
 2833     case IMMA_CALLBACK_OI_CCB_DELETE:
 2834       TRACE("%sobject-delete op callback", isPbeOp ? "Pbe-Runtime-" : "Ccb-");
 2835       do {
 2836         SaAisErrorT localEr = SA_AIS_OK;
 2837         IMMSV_EVT ccbObjDelRpl;
 2838         bool locked = false;
 2839 
 2840         if (cl_node->o.iCallbk.saImmOiCcbObjectDeleteCallback) {
 2841           SaImmOiCcbIdT ccbid = 0LL;
 2842           if (isPbeOp) {
 2843             osafassert(callback->ccbID == 0);
 2844             /* Pseudo ccb towards PBE for PRTO deletes */
 2845             ccbid = callback->inv + 0x100000000LL;
 2846 
 2847             /* PRTO delete reply only on completed*/
 2848             callback->inv = 0;
 2849             TRACE("Pseudo ccb %llx for PRTO delete upcall on %s", ccbid,
 2850                   osaf_extended_name_borrow(&callback->name));
 2851           } else {
 2852             ccbid = callback->ccbID;
 2853             if (!(cl_node->isApplier)) {
 2854               imma_oi_ccb_allow_error_string(cl_node, ccbid);
 2855             }
 2856           }
 2857 
 2858           if (!osaf_is_extended_names_enabled() && (callback->hasLongRdnOrDn)) {
 2859             /* (callback->hasLongRdnOrDn) set above at '$$$$' here means
 2860                that the delete callback has a long DN.
 2861                This property is not compatible for a client that does not
 2862                support long DNs. This case is detected in the server
 2863                and communicated here to the generic client code.
 2864             */
 2865             LOG_WA("Extended names not enabled. DN(%zu) too long. ccb: %u",
 2866                    strlen(osaf_extended_name_borrow(&(callback->name))),
 2867                    callback->ccbID);
 2868             localEr = SA_AIS_ERR_BAD_OPERATION;
 2869             if (cl_node->isApplier) {
 2870               /* We cannot uphold the contract for an applier that is not long
 2871                  DN capable. For regular OI this is not a problem since an error
 2872                  can be returned to the server aborting the CCB. But appliers
 2873                  can not reply. If the OI/OIs are capable but some applier(s)
 2874                  are not then we have a problem for those appliers. We can not
 2875                  just silently skip the applier callback while the CCB goes on
 2876                  to commit. Instead we break the dispatch loop.
 2877                */
 2878               clientCapable = false;
 2879             }
 2880           } else if (osaf_is_extended_name_valid(&(callback->name))) {
 2881             if (cl_node->isImmA2fCbk) {
 2882               localEr = cl_node->o.iCallbkA2f.saImmOiCcbObjectDeleteCallback(
 2883                   callback->lcl_imm_hdl, ccbid,
 2884                   osaf_extended_name_borrow(&(callback->name)));
 2885             } else {
 2886               localEr = cl_node->o.iCallbk.saImmOiCcbObjectDeleteCallback(
 2887                   callback->lcl_imm_hdl, ccbid, &(callback->name));
 2888             }
 2889           } else {
 2890             /* We should never get here. This should be caught already in the
 2891                MDS thread for the obj-delete case. Search for two times '$$$$'
 2892                above.
 2893             */
 2894             if (osaf_is_extended_names_enabled()) {
 2895               TRACE_3("Object name is too long: %s",
 2896                       osaf_extended_name_borrow(&(callback->name)));
 2897             } else {
 2898               TRACE_3(
 2899                   "Extended name feature is disabled. Object name is too long: %s",
 2900                   osaf_extended_name_borrow(&(callback->name)));
 2901             }
 2902             localEr = SA_AIS_ERR_BAD_OPERATION;
 2903           }
 2904 
 2905           TRACE("ccb-object-delete callback returned RC:%u", localEr);
 2906           if (!(localEr == SA_AIS_OK || localEr == SA_AIS_ERR_NO_MEMORY ||
 2907                 localEr == SA_AIS_ERR_NO_RESOURCES ||
 2908                 localEr == SA_AIS_ERR_BAD_OPERATION)) {
 2909             TRACE_2(
 2910                 "ERR_FAILED_OPERATION: Illegal return value from "
 2911                 "saImmOiCcbObjectDeleteCallback %u. "
 2912                 "Allowed are %u %u %u %u",
 2913                 localEr, SA_AIS_OK, SA_AIS_ERR_NO_MEMORY,
 2914                 SA_AIS_ERR_NO_RESOURCES, SA_AIS_ERR_BAD_OPERATION);
 2915             localEr = SA_AIS_ERR_FAILED_OPERATION;
 2916             /*Change to BAD_OP if only aborting delete and not ccb. */
 2917           }
 2918         } else {
 2919           /* No callback function registered for obj delete upcall.
 2920              The standard is not clear on how this case should be handled.
 2921              We take the strict approach of demanding that, if there is
 2922              a registered implementer, then that implementer must
 2923              implement the delete callback, for the callback to succeed
 2924           */
 2925           TRACE_2(
 2926               "ERR_FAILED_OPERATION: saImmOiCcbObjectDeleteCallback is not implemented, yet "
 2927               "implementer is registered and CCBs are used. Ccb will fail");
 2928           localEr = SA_AIS_ERR_FAILED_OPERATION;
 2929         }
 2930 
 2931         if (callback->inv) {
 2932           SaStringT errorStr = NULL;
 2933           SaImmHandleT privateAugOmHandle = 0LL;
 2934           memset(&ccbObjDelRpl, 0, sizeof(IMMSV_EVT));
 2935           ccbObjDelRpl.type = IMMSV_EVT_TYPE_IMMND;
 2936           ccbObjDelRpl.info.immnd.type = IMMND_EVT_A2ND_CCB_OBJ_DELETE_RSP;
 2937           ccbObjDelRpl.info.immnd.info.ccbUpcallRsp.result = localEr;
 2938           ccbObjDelRpl.info.immnd.info.ccbUpcallRsp.oi_client_hdl =
 2939               callback->lcl_imm_hdl;
 2940           ccbObjDelRpl.info.immnd.info.ccbUpcallRsp.ccbId = callback->ccbID;
 2941           ccbObjDelRpl.info.immnd.info.ccbUpcallRsp.inv = callback->inv;
 2942           osaf_extended_name_lend(
 2943               osaf_extended_name_borrow(&(callback->name)),
 2944               &(ccbObjDelRpl.info.immnd.info.ccbUpcallRsp.name));
 2945 
 2946           osafassert(m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 2947                      NCSCC_RC_SUCCESS);
 2948           locked = true;
 2949 
 2950           /* Closes window for setting error strings also for the OK case. #2233
 2951            */
 2952           errorStr = imma_oi_ccb_record_get_error(cl_node, callback->ccbID);
 2953 
 2954           if (localEr != SA_AIS_OK) {
 2955             if (errorStr) {
 2956               ccbObjDelRpl.info.immnd.type =
 2957                   IMMND_EVT_A2ND_CCB_OBJ_DELETE_RSP_2;
 2958               ccbObjDelRpl.info.immnd.info.ccbUpcallRsp.errorString.size =
 2959                   strlen(errorStr) + 1;
 2960               ccbObjDelRpl.info.immnd.info.ccbUpcallRsp.errorString.buf =
 2961                   errorStr;
 2962             }
 2963           }
 2964 
 2965           if (!imma_oi_ccb_record_close_augment(cl_node, callback->ccbID,
 2966                                                 &privateAugOmHandle, false)) {
 2967             TRACE_3(
 2968                 "CcbObjectDeleteCallback: imma_oi_ccb_record_close_augment "
 2969                 "returned false for ccb %u",
 2970                 callback->ccbID);
 2971           }
 2972 
 2973           if (privateAugOmHandle) {
 2974             osafassert(m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 2975                        NCSCC_RC_SUCCESS);
 2976             locked = false;
 2977 
 2978             osafassert(immsv_om_augment_ccb_get_result);
 2979             SaAisErrorT augResult = immsv_om_augment_ccb_get_result(
 2980                 privateAugOmHandle, callback->ccbID);
 2981 
 2982             osafassert(m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 2983                        NCSCC_RC_SUCCESS);
 2984             locked = true;
 2985 
 2986             if (augResult != SA_AIS_OK) {
 2987               TRACE(
 2988                   "A non-ok result %u from an augmented CCB overrides the reply from "
 2989                   "the OI %u on delete-op",
 2990                   augResult, ccbObjDelRpl.info.immnd.info.ccbUpcallRsp.result);
 2991 
 2992               ccbObjDelRpl.info.immnd.info.ccbUpcallRsp.result = augResult;
 2993             }
 2994           }
 2995 
 2996           /*async  fevs */
 2997           localEr = imma_evt_fake_evs(cb, &ccbObjDelRpl, NULL, 0,
 2998                                       cl_node->handle, &locked, false);
 2999           if (localEr != NCSCC_RC_SUCCESS) {
 3000             /*Cant do anything but log error and drop this reply. */
 3001             TRACE_3("CcbObjectDeleteCallback: send reply to IMMND failed");
 3002           }
 3003         }
 3004 
 3005         if (locked) {
 3006           osafassert(m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 3007                      NCSCC_RC_SUCCESS);
 3008           locked = false;
 3009         }
 3010       } while (0);
 3011 
 3012       break;
 3013 
 3014     case IMMA_CALLBACK_PBE_PRT_ATTR_UPDATE:
 3015       isPbeOp = true; /*Actually isPrtAttr would be better name here. */
 3016       osafassert(cl_node->isPbe);
 3017     case IMMA_CALLBACK_OI_CCB_MODIFY:
 3018       TRACE("%s op callback", isPbeOp ? "Pbe-runtime update" : "ccb");
 3019       do {
 3020         SaAisErrorT localEr = SA_AIS_OK;
 3021         IMMSV_EVT ccbObjModRpl;
 3022         bool locked = false;
 3023         SaImmAttrModificationT_2 **attr = NULL;
 3024         if (cl_node->o.iCallbk.saImmOiCcbObjectModifyCallback) {
 3025           /* Anoying type diff for ccbid between OM and OI */
 3026           SaImmOiCcbIdT ccbid = 0LL;
 3027           if (isPbeOp) {
 3028             osafassert(callback->ccbID == 0);
 3029             /* Pseudo ccb towards PBE for PRTO create */
 3030             ccbid = callback->inv + 0x100000000LL;
 3031           } else {
 3032             ccbid = callback->ccbID;
 3033             if (!(cl_node->isApplier)) {
 3034               /* Error strings are not relevant for PRT ops. */
 3035               imma_oi_ccb_allow_error_string(cl_node, callback->ccbID);
 3036             }
 3037           }
 3038 
 3039           int noOfAttrMods = 0;
 3040 
 3041           IMMSV_ATTR_MODS_LIST *p = callback->attrMods;
 3042           while (p) {
 3043             ++noOfAttrMods;
 3044             p = p->next;
 3045           }
 3046 
 3047           /*alloc-1 */
 3048           attr = (SaImmAttrModificationT_2 **)calloc(
 3049               noOfAttrMods + 1, sizeof(SaImmAttrModificationT_2 *));
 3050           p = callback->attrMods;
 3051           for (int i = 0; i < noOfAttrMods; i++, p = p->next) {
 3052             attr[i] = (SaImmAttrModificationT_2 *)calloc(
 3053                 1, sizeof(SaImmAttrModificationT_2)); /*alloc-2 */
 3054             attr[i]->modType = (SaImmAttrModificationTypeT)p->attrModType;
 3055 
 3056             attr[i]->modAttr.attrName =
 3057                 p->attrValue.attrName.buf; /* steal/alloc-3 */
 3058             p->attrValue.attrName.buf = NULL;
 3059             p->attrValue.attrName.size = 0;
 3060             attr[i]->modAttr.attrValuesNumber = p->attrValue.attrValuesNumber;
 3061             attr[i]->modAttr.attrValueType =
 3062                 (SaImmValueTypeT)p->attrValue.attrValueType;
 3063             if (p->attrValue.attrValuesNumber) {
 3064               attr[i]->modAttr.attrValues = (SaImmAttrValueT *)calloc(
 3065                   p->attrValue.attrValuesNumber,
 3066                   sizeof(SaImmAttrValueT)); /*alloc-4 */
 3067               /*alloc-5 */
 3068               attr[i]->modAttr.attrValues[0] = imma_copyAttrValue3(
 3069                   (SaImmValueTypeT)p->attrValue.attrValueType,
 3070                   &(p->attrValue.attrValue));
 3071 
 3072               if (p->attrValue.attrValuesNumber > 1) {
 3073                 int ix;
 3074                 IMMSV_EDU_ATTR_VAL_LIST *r = p->attrValue.attrMoreValues;
 3075                 for (ix = 1; ix < p->attrValue.attrValuesNumber; ++ix) {
 3076                   osafassert(r);
 3077                   attr[i]->modAttr.attrValues[ix] = imma_copyAttrValue3(
 3078                       (SaImmValueTypeT)p->attrValue.attrValueType,
 3079                       &(r->n)); /*alloc-5 */
 3080 
 3081                   r = r->next;
 3082                 }  // for all extra values
 3083               }    // if multivalued
 3084             }      // if there was any value
 3085           }        // for all attrMods
 3086           /*attr[noOfAttrMods] = NULL; redundant */
 3087 
 3088           /*Need a separate const pointer just to avoid an INCORRECT warning
 3089             by the stupid compiler. This compiler warns when assigning
 3090             non-const to a const !!!! and it is not even possible to do the
 3091             cast in the function call. Note: const is MORE restrictive than
 3092             non-const so assigning to a const should ALWAYS be allowed.
 3093           */
 3094           TRACE("ccb-object-modify: make the callback");
 3095           const SaImmAttrModificationT_2 **constPtrForStupidCompiler =
 3096               (const SaImmAttrModificationT_2 **)attr;
 3097 
 3098           if (!osaf_is_extended_names_enabled() && (callback->hasLongRdnOrDn)) {
 3099             /* (callback->hasLongRdnOrDn) set above at '####' here means
 3100                that the modify callback has one or more of the following
 3101                properties:
 3102                a) Object DN is a longDN.
 3103                b) One or more long DNs appear in attribute list.
 3104                Any of these properties are not compatible for a client that
 3105                does not support long DNs. These cases are detected in the server
 3106                and communicated here to the generic client code.
 3107             */
 3108             LOG_WA(
 3109                 "Extended names not enabled. object-DN or SaNamet "
 3110                 "attribute value too long. ccb: %u",
 3111                 callback->ccbID);
 3112             localEr = SA_AIS_ERR_BAD_OPERATION;
 3113             if (cl_node->isApplier) {
 3114               /* We cannot uphold the contract for an applier that is not long
 3115                  DN capable. For relgular OI this is not a problem since an
 3116                  error can be returned to the server aborting the CCB. But
 3117                  appliers can not reply. If the OI/OIs are capable but some
 3118                  applier(s) are not then we have a problem for those appliers.
 3119                  We can not just silently skip the applier callback while the
 3120                  CCB goes on to commit. Instead we break the dispatch loop.
 3121                */
 3122               clientCapable = false;
 3123             }
 3124           } else if (osaf_is_extended_name_valid(&(callback->name))) {
 3125             if (cl_node->isImmA2fCbk) {
 3126               localEr = cl_node->o.iCallbkA2f.saImmOiCcbObjectModifyCallback(
 3127                   callback->lcl_imm_hdl, ccbid,
 3128                   osaf_extended_name_borrow(&(callback->name)),
 3129                   constPtrForStupidCompiler);
 3130             } else {
 3131               localEr = cl_node->o.iCallbk.saImmOiCcbObjectModifyCallback(
 3132                   callback->lcl_imm_hdl, ccbid, &(callback->name),
 3133                   constPtrForStupidCompiler);
 3134             }
 3135           } else {
 3136             /* We should never get here. This should be caught already in the
 3137                MDS thread for the obj-create case. Search for two times '####'
 3138                above.
 3139              */
 3140             TRACE_3("Object name is too long: %s",
 3141                     osaf_extended_name_borrow(&(callback->name)));
 3142             localEr = SA_AIS_ERR_BAD_OPERATION;
 3143           }
 3144 
 3145           TRACE("ccb-object-modify callback returned RC:%u", localEr);
 3146           if (!(localEr == SA_AIS_OK || localEr == SA_AIS_ERR_NO_MEMORY ||
 3147                 localEr == SA_AIS_ERR_NO_RESOURCES ||
 3148                 localEr == SA_AIS_ERR_BAD_OPERATION)) {
 3149             TRACE_2(
 3150                 "ERR_FAILED_OPERATION: Illegal return value from "
 3151                 "saImmOiCcbObjectModifyCallback %u. "
 3152                 "Allowed are %u %u %u %u",
 3153                 localEr, SA_AIS_OK, SA_AIS_ERR_NO_MEMORY,
 3154                 SA_AIS_ERR_NO_RESOURCES, SA_AIS_ERR_BAD_OPERATION);
 3155             localEr = SA_AIS_ERR_FAILED_OPERATION;
 3156           }
 3157 
 3158           for (int i = 0; attr[i]; ++i) {
 3159             free(attr[i]->modAttr.attrName); /*free-3 */
 3160             attr[i]->modAttr.attrName = 0;
 3161             if (attr[i]->modAttr.attrValuesNumber) {
 3162               SaUint32T j;
 3163               for (j = 0; j < attr[i]->modAttr.attrValuesNumber; ++j) {
 3164                 imma_freeAttrValue3(attr[i]->modAttr.attrValues[j],
 3165                                     attr[i]->modAttr.attrValueType); /*free-5 */
 3166                 attr[i]->modAttr.attrValues[j] = 0;
 3167               }
 3168               free(attr[i]->modAttr.attrValues); /*4 */
 3169               /* SaImmAttrValueT[] array-of-void* */
 3170               attr[i]->modAttr.attrValues = 0;
 3171             }
 3172             free(attr[i]); /*2 */
 3173             /* SaImmAttrValuesT struct */
 3174             attr[i] = 0;
 3175           }
 3176           free(attr); /*1 */
 3177                       /* SaImmAttrValuesT*[]  array-off-pointers */
 3178         } else {
 3179           /* No callback function registered for obj-modify upcall.
 3180              The standard is not clear on how this case should be
 3181              handled. We take the strict approach of demanding that,
 3182              if there is a registered implementer, then that
 3183              implementer must implement the create callback, for the
 3184              callback to succeed.
 3185           */
 3186           TRACE_2(
 3187               "ERR_FAILED_OPERATION: saImmOiCcbObjectModifyCallback is not implemented, "
 3188               "yet implementer is registered and CCBs are used. Ccb will fail");
 3189 
 3190           localEr = SA_AIS_ERR_FAILED_OPERATION;
 3191           /*Change to BAD_OP if only aborting modify and not ccb. */
 3192         }
 3193         if (callback->inv) {
 3194           SaStringT errorStr = NULL;
 3195           SaImmHandleT privateAugOmHandle = 0LL;
 3196           osafassert(m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 3197                      NCSCC_RC_SUCCESS);
 3198           locked = true;
 3199           memset(&ccbObjModRpl, 0, sizeof(IMMSV_EVT));
 3200           ccbObjModRpl.type = IMMSV_EVT_TYPE_IMMND;
 3201           if (isPbeOp) {
 3202             ccbObjModRpl.info.immnd.type =
 3203                 IMMND_EVT_A2ND_PBE_PRT_ATTR_UPDATE_RSP;
 3204           } else {
 3205             ccbObjModRpl.info.immnd.type = IMMND_EVT_A2ND_CCB_OBJ_MODIFY_RSP;
 3206             ccbObjModRpl.info.immnd.info.ccbUpcallRsp.ccbId = callback->ccbID;
 3207           }
 3208           ccbObjModRpl.info.immnd.info.ccbUpcallRsp.result = localEr;
 3209           ccbObjModRpl.info.immnd.info.ccbUpcallRsp.oi_client_hdl =
 3210               callback->lcl_imm_hdl;
 3211           ccbObjModRpl.info.immnd.info.ccbUpcallRsp.inv = callback->inv;
 3212 
 3213           /* Closes window for setting error strings also for the OK case. #2233
 3214            */
 3215           errorStr = imma_oi_ccb_record_get_error(cl_node, callback->ccbID);
 3216 
 3217           if (localEr != SA_AIS_OK) {
 3218             if (errorStr) {
 3219               ccbObjModRpl.info.immnd.type =
 3220                   IMMND_EVT_A2ND_CCB_OBJ_MODIFY_RSP_2;
 3221               ccbObjModRpl.info.immnd.info.ccbUpcallRsp.errorString.size =
 3222                   strlen(errorStr) + 1;
 3223               ccbObjModRpl.info.immnd.info.ccbUpcallRsp.errorString.buf =
 3224                   errorStr;
 3225             }
 3226           }
 3227 
 3228           if (!imma_oi_ccb_record_close_augment(cl_node, callback->ccbID,
 3229                                                 &privateAugOmHandle, false)) {
 3230             TRACE_3(
 3231                 "CcbObjectModifyCallback: imma_oi_ccb_record_close_augment "
 3232                 "returned false for ccb %u",
 3233                 callback->ccbID);
 3234           }
 3235 
 3236           if (privateAugOmHandle) {
 3237             osafassert(m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 3238                        NCSCC_RC_SUCCESS);
 3239             locked = false;
 3240 
 3241             osafassert(immsv_om_augment_ccb_get_result);
 3242             SaAisErrorT augResult = immsv_om_augment_ccb_get_result(
 3243                 privateAugOmHandle, callback->ccbID);
 3244 
 3245             osafassert(m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 3246                        NCSCC_RC_SUCCESS);
 3247             locked = true;
 3248 
 3249             if (augResult != SA_AIS_OK) {
 3250               TRACE(
 3251                   "A non-ok result %u from an augmented CCB overrides the reply from "
 3252                   "the OI %u on modify-uc",
 3253                   augResult, ccbObjModRpl.info.immnd.info.ccbUpcallRsp.result);
 3254 
 3255               ccbObjModRpl.info.immnd.info.ccbUpcallRsp.result = augResult;
 3256             }
 3257           }
 3258 
 3259           /*async fevs */
 3260           localEr = imma_evt_fake_evs(cb, &ccbObjModRpl, NULL, 0,
 3261                                       cl_node->handle, &locked, false);
 3262         }
 3263 
 3264         if (locked) {
 3265           osafassert(m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 3266                      NCSCC_RC_SUCCESS);
 3267           locked = false;
 3268         }
 3269 
 3270         if (localEr != NCSCC_RC_SUCCESS) {
 3271           /*Cant do anything but log error and drop this reply. */
 3272           TRACE_3("CcbObjectModifyCallback: send reply to IMMND failed");
 3273         }
 3274       } while (0);
 3275       break;
 3276 
 3277     case IMMA_CALLBACK_OI_CCB_ABORT:
 3278       TRACE("ccb-abort op callback");
 3279       do {
 3280         /* Anoying type diff for ccbid between OM and OI */
 3281         SaImmOiCcbIdT ccbid = callback->ccbID;
 3282         SaImmHandleT privateAugOmHandle = 0LL;
 3283         /* cl_node->o is union, and callback function order is the same for
 3284          * iCallbk and iCallbkA2f */
 3285         if (cl_node->o.iCallbk.saImmOiCcbAbortCallback) {
 3286           if (cl_node->isImmA2fCbk) {
 3287             cl_node->o.iCallbkA2f.saImmOiCcbAbortCallback(callback->lcl_imm_hdl,
 3288                                                           ccbid);
 3289           } else {
 3290             cl_node->o.iCallbk.saImmOiCcbAbortCallback(callback->lcl_imm_hdl,
 3291                                                        ccbid);
 3292           }
 3293         } else {
 3294           /* No callback function registered for abort upcall.
 3295              There is nothing we can do about this since the CCB is
 3296              commited already.
 3297           */
 3298           TRACE_3(
 3299               "saImmOiCcbAbortCallback is not implemented, yet "
 3300               "implementer is registered and CCBs are used. "
 3301               "Ccb %llu will abort anyway",
 3302               ccbid);
 3303         }
 3304         osafassert(m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 3305                    NCSCC_RC_SUCCESS);
 3306         if (!imma_oi_ccb_record_close_augment(cl_node, ccbid,
 3307                                               &privateAugOmHandle, true)) {
 3308           TRACE_3(
 3309               "CcbAbortCallback: imma_oi_ccb_record_close_augment "
 3310               "returned false for ccb %llu",
 3311               ccbid);
 3312         }
 3313         imma_oi_ccb_record_terminate(cl_node, ccbid);
 3314         osafassert(m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE) ==
 3315                    NCSCC_RC_SUCCESS);
 3316         if (privateAugOmHandle) {
 3317           osafassert(immsv_om_handle_finalize);
 3318           immsv_om_handle_finalize(privateAugOmHandle);
 3319         }
 3320       } while (0);
 3321       break;
 3322 
 3323     case IMMA_CALLBACK_OI_RT_ATTR_UPDATE:
 3324       TRACE("rt-attr-update callback");
 3325       do {
 3326         SaAisErrorT localEr = SA_AIS_OK;
 3327         uint32_t proc_rc = NCSCC_RC_SUCCESS;
 3328         IMMSV_EVT rtAttrUpdRpl;
 3329 
 3330         if (cl_node->o.iCallbk.saImmOiRtAttrUpdateCallback) {
 3331           SaImmAttrNameT *attributeNames;
 3332           int noOfAttrNames = 0;
 3333           int i = 0;
 3334 
 3335           IMMSV_ATTR_NAME_LIST *p = callback->attrNames;
 3336           while (p) {
 3337             ++noOfAttrNames;
 3338             p = p->next;
 3339           }
 3340           osafassert(noOfAttrNames); /*alloc-1 */
 3341           attributeNames = (SaImmAttrNameT *)calloc(noOfAttrNames + 1,
 3342                                                     sizeof(SaImmAttrNameT));
 3343           p = callback->attrNames;
 3344           for (; i < noOfAttrNames; i++, p = p->next) {
 3345             attributeNames[i] = p->name.buf;
 3346           }
 3347 
 3348           /*attributeNames[noOfAttrNames] = NULL; calloc=> redundant */
 3349 
 3350           if (osaf_is_extended_name_valid(&(callback->name))) {
 3351             TRACE("Invoking saImmOiRtAttrUpdateCallback");
 3352             if (cl_node->isImmA2fCbk) {
 3353               localEr = cl_node->o.iCallbkA2f.saImmOiRtAttrUpdateCallback(
 3354                   callback->lcl_imm_hdl,
 3355                   osaf_extended_name_borrow(&callback->name), attributeNames);
 3356             } else {
 3357               localEr = cl_node->o.iCallbk.saImmOiRtAttrUpdateCallback(
 3358                   callback->lcl_imm_hdl, &callback->name, attributeNames);
 3359             }
 3360           } else {
 3361             if (osaf_is_extended_names_enabled()) {
 3362               TRACE_3("Object name is too long: %s",
 3363                       osaf_extended_name_borrow(&(callback->name)));
 3364             } else {
 3365               TRACE_3(
 3366                   "Extended name feature is disabled. Object name is too long: %s",
 3367                   osaf_extended_name_borrow(&(callback->name)));
 3368             }
 3369             localEr = SA_AIS_ERR_BAD_OPERATION;
 3370           }
 3371 
 3372           TRACE("saImmOiRtAttrUpdateCallback returned RC:%u", localEr);
 3373           if (!(localEr == SA_AIS_OK || localEr == SA_AIS_ERR_NO_MEMORY ||
 3374                 localEr == SA_AIS_ERR_NO_RESOURCES ||
 3375                 localEr == SA_AIS_ERR_FAILED_OPERATION)) {
 3376             TRACE_2(
 3377                 "ERR_FAILED_OPERATION: Illegal return value from "
 3378                 "saImmOiRtAttrUpdateCallback %u. "
 3379                 "Allowed are %u %u %u %u",
 3380                 localEr, SA_AIS_OK, SA_AIS_ERR_NO_MEMORY,
 3381                 SA_AIS_ERR_NO_RESOURCES, SA_AIS_ERR_FAILED_OPERATION);
 3382             localEr = SA_AIS_ERR_FAILED_OPERATION;
 3383           }
 3384 
 3385           free(attributeNames); /*We do not leak the attr names here because
 3386                                   they are still attached to, and deallocated
 3387                                   by, the callback structure. */
 3388         } else {
 3389           /* No callback function registered for rt-attr-update upcall.
 3390              The standard is not clear on how this case should be
 3391              handled. We take the strict approach of demanding that,
 3392              if there is a registered implementer, then that
 3393              implementer must implement the callback, for the
 3394              callback to succeed.
 3395           */
 3396           TRACE_2(
 3397               "ERR_FAILED_OPERATION: saImmOiRtAttrUpdateCallback is not implemented, "
 3398               "yet implementer is registered and pure runtime attrs are fetched.");
 3399 
 3400           localEr = SA_AIS_ERR_FAILED_OPERATION;
 3401         }
 3402         memset(&rtAttrUpdRpl, 0, sizeof(IMMSV_EVT));
 3403         rtAttrUpdRpl.type = IMMSV_EVT_TYPE_IMMND;
 3404         rtAttrUpdRpl.info.immnd.type = IMMND_EVT_A2ND_RT_ATT_UPPD_RSP;
 3405         rtAttrUpdRpl.info.immnd.info.rtAttUpdRpl.result = localEr;
 3406         rtAttrUpdRpl.info.immnd.info.rtAttUpdRpl.sr.client_hdl =
 3407             callback->lcl_imm_hdl;
 3408 
 3409         SaInt32T owner = m_IMMSV_UNPACK_HANDLE_HIGH(callback->invocation);
 3410         SaInt32T inv = m_IMMSV_UNPACK_HANDLE_LOW(callback->invocation);
 3411 
 3412         rtAttrUpdRpl.info.immnd.info.rtAttUpdRpl.sr.searchId = inv;
 3413         rtAttrUpdRpl.info.immnd.info.rtAttUpdRpl.sr.remoteNodeId = owner;
 3414 
 3415         /*Adding one to get the terminating null sent */
 3416         rtAttrUpdRpl.info.immnd.info.rtAttUpdRpl.sr.objectName.size =
 3417             osaf_extended_name_length(&callback->name) + 1;
 3418         /* Only borowing the name string from the SaName in the callback */
 3419         rtAttrUpdRpl.info.immnd.info.rtAttUpdRpl.sr.objectName.buf =
 3420             (char *)osaf_extended_name_borrow(&callback->name);
 3421         /* Only borowing the attributeNames list from callback. */
 3422         rtAttrUpdRpl.info.immnd.info.rtAttUpdRpl.sr.attributeNames =
 3423             callback->attrNames;
 3424         rtAttrUpdRpl.info.immnd.info.rtAttUpdRpl.sr.requestNodeId =
 3425             callback->requestNodeId;
 3426         /* No structures allocated, all pointers borowed => nothing to free. */
 3427 
 3428         if (cb->is_immnd_up == false) {
 3429           proc_rc = SA_AIS_ERR_NO_RESOURCES;
 3430           TRACE_2("ERR_NO_RESOURCES: IMMND_DOWN");
 3431         } else {
 3432           /* send the reply to the IMMND asyncronously */
 3433           proc_rc = imma_mds_msg_send(cb->imma_mds_hdl, &cb->immnd_mds_dest,
 3434                                       &rtAttrUpdRpl, NCSMDS_SVC_ID_IMMND);
 3435           if (proc_rc != NCSCC_RC_SUCCESS) {
 3436             /*Cant do anything but log error and drop this reply. */
 3437             TRACE_3("oiRtAttrUpdateCallback: send reply to IMMND failed");
 3438           }
 3439         }
 3440       } while (0);
 3441       break;
 3442 
 3443     case IMMA_CALLBACK_STALE_HANDLE:
 3444       TRACE("Stale OI handle upcall completed");
 3445       imma_proc_terminate_oi_ccbs(cb, cl_node);
 3446       break;
 3447 
 3448     default:
 3449       TRACE_3("Unrecognized OI callback type: %u", callback->type);
 3450       break;
 3451   }
 3452 #endif /* ifdef IMMA_OI */
 3453 
 3454   /* free the callback info. Note - we are not locked. Still should be ok since
 3455      the callback was dequeue'd by this call. */
 3456   /* Also verify that we free any/all pointer structures that have not
 3457      been set to NULL */
 3458   imma_proc_free_callback(callback);
 3459   TRACE_LEAVE();
 3460   return clientCapable;
 3461 }
 3462 
 3463 static void imma_proc_free_callback(IMMA_CALLBACK_INFO *callback) {
 3464   if (!callback) return;
 3465   if (callback->params) {
 3466     int i;
 3467     for (i = 0; callback->params[i]; ++i) {
 3468       SaImmAdminOperationParamsT_2 *q = callback->params[i];
 3469       imma_freeAttrValue3(q->paramBuffer, q->paramType); /*free-4 */
 3470 
 3471       free(q->paramName); /*free-3 */
 3472       q->paramName = NULL;
 3473       free(q); /*free-2 */
 3474     }
 3475 
 3476     free(callback->params); /*free-1 */
 3477   }
 3478 
 3479   if (callback->attrValues) {
 3480     immsv_free_attrvalues_list(callback->attrValues);
 3481     callback->attrValues = NULL;
 3482   }
 3483 
 3484   if (callback->attrMods) {
 3485     immsv_free_attrmods(callback->attrMods);
 3486     callback->attrMods = NULL;
 3487   }
 3488 
 3489   if (callback->attrNames) {
 3490     immsv_evt_free_attrNames(callback->attrNames);
 3491     callback->attrNames = NULL;
 3492   }
 3493 
 3494   osaf_extended_name_free(&callback->name);
 3495   free(callback);
 3496 }
 3497 
 3498 /*******************************************************************
 3499  * imma_proc_check_stale internal function
 3500  *     Checks if the imma handle has turned stale, e.g. on timeout
 3501  *     return from a syncronous call towards IMMND.
 3502  *     Note the timeout could be a "normal" timeout caused say by an
 3503  *     object-implementer not responding. In that case the input
 3504  *     defaultErr will be returned. But if the client is stale
 3505  *     it indicates that the IMMND crashed during the call and we
 3506  *     return ERR_BAD_HANDLE since the handle can not be recovered.
 3507  * NOTE: The CB must be UNLOCKED on entry of this function!!
 3508  *******************************************************************/
 3509 SaAisErrorT imma_proc_check_stale(IMMA_CB *cb, SaImmHandleT immHandle,
 3510                                   SaAisErrorT defaultEr) {
 3511   SaAisErrorT err = defaultEr;
 3512   IMMSV_EVT cutSyncCall_evt;
 3513   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) == NCSCC_RC_SUCCESS) {
 3514     IMMA_CLIENT_NODE *cl_node = 0;
 3515     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 3516     if (!cl_node || cl_node->stale) {
 3517       /* We dont set exposed here because we are not exposed yet. */
 3518       err = SA_AIS_ERR_BAD_HANDLE;
 3519       TRACE_3("Client handle turned bad, IMMND restarted ?");
 3520     } else {
 3521       /* Prepare message for truncating this syncronous call (which just
 3522          got ERR_TIMEOUT) in local immnd. This drastically reduces the
 3523          number of accepted retries at new use of this handle for
 3524          syncronous calls. Before this timeout, any other attempts
 3525          to use this handle (by other threads concurrently) is actually
 3526          not allowed. But after the timeout on this call, renewed use
 3527          of this handle is allowed. On the client side, the previous
 3528          syncronous call has now terminated with ERR_TIMEOUT. When
 3529          the server receives the asyncronous CL_TIMEOUT message sent
 3530          below, the previous syncronous call can also be terminated in
 3531          the local immnd server, at its discretion.
 3532        */
 3533       memset(&cutSyncCall_evt, 0, sizeof(IMMSV_EVT));
 3534       cutSyncCall_evt.type = IMMSV_EVT_TYPE_IMMND;
 3535       cutSyncCall_evt.info.immnd.type = IMMND_EVT_A2ND_CL_TIMEOUT;
 3536       cutSyncCall_evt.info.immnd.info.finReq.client_hdl = cl_node->handle;
 3537     }
 3538 
 3539     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 3540 
 3541     if (err == SA_AIS_ERR_TIMEOUT && cb->is_immnd_up) {
 3542       if (imma_mds_msg_send(cb->imma_mds_hdl, &cb->immnd_mds_dest,
 3543                             &cutSyncCall_evt,
 3544                             NCSMDS_SVC_ID_IMMND) != NCSCC_RC_SUCCESS) {
 3545         /* Inform local immnd that this client has timed out*/
 3546         TRACE_3("imma_proc_check_stale: asyncronous send failed");
 3547       }
 3548     }
 3549   }
 3550 
 3551   return err;
 3552 }
 3553 
 3554 /*******************************************************************
 3555  * imma_evt_fake_evs internal function
 3556  *
 3557  * NOTE: The CB must be LOCKED on entry of this function!!
 3558  *       It will usually be unlocked on exit, as reflected in the 'locked'
 3559  *       parameter.
 3560  *******************************************************************/
 3561 SaAisErrorT imma_evt_fake_evs(IMMA_CB *cb, IMMSV_EVT *i_evt, IMMSV_EVT **o_evt,
 3562                               SaTimeT timeout, SaImmHandleT immHandle,
 3563                               bool *locked, bool checkWritable) {
 3564   SaAisErrorT rc = SA_AIS_OK;
 3565   IMMSV_EVT fevs_evt;
 3566   uint32_t proc_rc;
 3567   char *tmpData = NULL;
 3568   char *data = NULL;
 3569   NCS_UBAID uba;
 3570   uba.start = NULL;
 3571   int32_t size;
 3572 
 3573   osafassert(locked && (*locked));
 3574   /*Pack the message for sending over multiple hops. */
 3575 
 3576   if (ncs_enc_init_space(&uba) != NCSCC_RC_SUCCESS) {
 3577     TRACE_2("ERR_LIBRARY: Failed init ubaid");
 3578     rc = SA_AIS_ERR_LIBRARY;
 3579     goto fail;
 3580   }
 3581 
 3582   /* Encode non-flat since we broadcast to unknown receivers. */
 3583   proc_rc = immsv_evt_enc(i_evt, &uba);
 3584 
 3585   /* Validation of the number of objects in the trasaction is done in
 3586   immsv_evt_enc. In case if the number of objects is greater then the limit,
 3587   then NCSCC_RC_NO_OBJECT is returned back.*/
 3588   if (proc_rc == NCSCC_RC_NO_OBJECT) {
 3589     TRACE_2("ERR_NO_RESOURCES: Failed to pre-pack");
 3590     rc = SA_AIS_ERR_NO_RESOURCES;
 3591     goto fail;
 3592   }
 3593 
 3594   if (proc_rc != NCSCC_RC_SUCCESS) {
 3595     TRACE_2("ERR_LIBRARY: Failed to pre-pack");
 3596     rc = SA_AIS_ERR_LIBRARY;
 3597     goto fail;
 3598   }
 3599 
 3600   size = uba.ttl;
 3601   /*NOTE: should check against "payload max-size" */
 3602 
 3603   tmpData = (char *)malloc(size);
 3604   data = m_MMGR_DATA_AT_START(uba.start, size, tmpData);
 3605 
 3606   memset(&fevs_evt, 0, sizeof(IMMSV_EVT));
 3607   fevs_evt.type = IMMSV_EVT_TYPE_IMMND;
 3608   if (i_evt->info.immnd.type == IMMND_EVT_A2ND_OBJ_SYNC_2) {
 3609     fevs_evt.info.immnd.type = IMMND_EVT_A2ND_IMM_FEVS_2;
 3610     fevs_evt.info.immnd.info.fevsReq.isObjSync = 0x1;
 3611   } else {
 3612     fevs_evt.info.immnd.type = IMMND_EVT_A2ND_IMM_FEVS;
 3613     fevs_evt.info.immnd.info.fevsReq.isObjSync = 0x0;
 3614 
 3615     if ((i_evt->info.immnd.type == IMMND_EVT_A2ND_IMM_ADMOP) ||
 3616         (i_evt->info.immnd.type == IMMND_EVT_A2ND_IMM_ADMOP_ASYNC)) {
 3617       /* Overloaded use of sender_count IMMA->IMMND we use values
 3618          larger than 1 as a marker for admop to pre-register
 3619          request continuation, before forwarding request over fevs
 3620          (see ticket #1690). This is to avoid the rare case of the
 3621          reply, which does not use fevs, bypassing the request at
 3622          the client processor.
 3623       */
 3624       osafassert(!checkWritable);
 3625       SaInvocationT saInv =
 3626           m_IMMSV_PACK_HANDLE(i_evt->info.immnd.info.admOpReq.adminOwnerId,
 3627                               i_evt->info.immnd.info.admOpReq.invocation);
 3628 
 3629       osafassert(saInv > 1);
 3630       fevs_evt.info.immnd.info.fevsReq.sender_count = (SaUint64T)saInv;
 3631     }
 3632   }
 3633 
 3634   fevs_evt.info.immnd.info.fevsReq.client_hdl = immHandle;
 3635 
 3636   if (checkWritable) {
 3637     /*Overloaded use of sender_count IMMA->IMMND we use the value
 3638       of 1 as a marker if imm writability should be checked before
 3639       forwarding request over fevs. This is a pure performance
 3640       enhancing feature.
 3641     */
 3642     fevs_evt.info.immnd.info.fevsReq.sender_count = 0x1;
 3643   }
 3644 
 3645   fevs_evt.info.immnd.info.fevsReq.msg.size = size;
 3646   fevs_evt.info.immnd.info.fevsReq.msg.buf = data;
 3647 
 3648   /* Unlock before MDS Send */
 3649   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 3650   *locked = false;
 3651 
 3652   /* IMMND GOES DOWN */
 3653   if (cb->is_immnd_up == false) {
 3654     rc = SA_AIS_ERR_TRY_AGAIN;
 3655     TRACE_2("ERR_TRY_AGAIN: IMMND is DOWN");
 3656     goto fail;
 3657   }
 3658 
 3659   if (o_evt) {
 3660     /* Send the evt to IMMND syncronously (reply expected) */
 3661     proc_rc = imma_mds_msg_sync_send(cb->imma_mds_hdl, &(cb->immnd_mds_dest),
 3662                                      &fevs_evt, o_evt, timeout);
 3663   } else {
 3664     /*Send evt to IMMND asyncronously, no reply expected. */
 3665     osafassert(timeout == 0);
 3666     proc_rc = imma_mds_msg_send(cb->imma_mds_hdl, &(cb->immnd_mds_dest),
 3667                                 &fevs_evt, NCSMDS_SVC_ID_IMMND);
 3668   }
 3669 
 3670   /* Generate rc from proc_rc */
 3671   switch (proc_rc) {
 3672     case NCSCC_RC_SUCCESS:
 3673       break;
 3674     case NCSCC_RC_REQ_TIMOUT:
 3675       osafassert(o_evt); /* timeout has to be on syncronous. */
 3676       rc = imma_proc_check_stale(cb, immHandle, SA_AIS_ERR_TIMEOUT);
 3677       break;
 3678 
 3679     default:
 3680       rc = SA_AIS_ERR_LIBRARY;
 3681       TRACE_1("ERR_LIBRARY: MDS returned unexpected error code %u", proc_rc);
 3682       break;
 3683   }
 3684 
 3685 fail:
 3686 
 3687   if (tmpData) {
 3688     free(tmpData);
 3689     tmpData = NULL;
 3690   }
 3691 
 3692   if (uba.start) {
 3693     m_MMGR_FREE_BUFR_LIST(uba.start);
 3694   }
 3695 
 3696   return rc;
 3697 }
 3698 
 3699 SaAisErrorT imma_proc_increment_pending_reply(IMMA_CLIENT_NODE *cl_node,
 3700                                               bool isSync) {
 3701   if (isSync) {
 3702     if (cl_node->isBusy) return SA_AIS_ERR_LIBRARY;
 3703     cl_node->isBusy = true;
 3704   }
 3705 
 3706   if (cl_node->replyPending < 0xff) {
 3707     cl_node->replyPending++;
 3708   } else {
 3709     TRACE_3("More than 255 concurrent PENDING replies on handle!");
 3710   }
 3711 
 3712   return SA_AIS_OK;
 3713 }
 3714 
 3715 SaAisErrorT imma_proc_decrement_pending_reply(IMMA_CLIENT_NODE *cl_node,
 3716                                               bool isSync) {
 3717   if (cl_node->replyPending) {
 3718     if (cl_node->replyPending < 0xff) {
 3719       cl_node->replyPending--;
 3720     } else {
 3721       /* If reply Pending has reached 255 then we stop keeping track.
 3722          The consequence is: in case of IMMND restart we will not be
 3723          able to resurrect this handle. The client will be forced to
 3724          deal with an SA_AIS_ERR_BAD_HANDLE.
 3725        */
 3726       TRACE_3("Lost track of concurrent pending replies on handle %llx.",
 3727               cl_node->handle);
 3728     }
 3729   } else {
 3730     /* Decrementing from zero implies a bug in the library logic.
 3731        The real count has been lost. Set the value to 255. This does not
 3732        disturb current function, but makes the handle not resurrectable in
 3733        case of iMMND restart while handle is still open. */
 3734     TRACE_3("Will not decrement zero pending reply count for handle %llx",
 3735             cl_node->handle);
 3736     cl_node->replyPending = 0xff;
 3737   }
 3738 
 3739   if (isSync) {
 3740     if (!cl_node->isBusy) return SA_AIS_ERR_LIBRARY;
 3741     cl_node->isBusy = false;
 3742   }
 3743 
 3744   return SA_AIS_OK;
 3745 }
 3746 
 3747 /**
 3748  * Validate a value type
 3749  * @param theType
 3750  *
 3751  * @return int
 3752  */
 3753 int imma_proc_is_valid_type(const SaImmValueTypeT theType) {
 3754   switch (theType) {
 3755     case SA_IMM_ATTR_SAINT32T:
 3756     case SA_IMM_ATTR_SAUINT32T:
 3757     case SA_IMM_ATTR_SAINT64T:
 3758     case SA_IMM_ATTR_SAUINT64T:
 3759     case SA_IMM_ATTR_SATIMET:
 3760     case SA_IMM_ATTR_SAFLOATT:
 3761     case SA_IMM_ATTR_SADOUBLET:
 3762     case SA_IMM_ATTR_SANAMET:
 3763     case SA_IMM_ATTR_SASTRINGT:
 3764     case SA_IMM_ATTR_SAANYT:
 3765       return 1;
 3766     default:
 3767       return 0;
 3768   }
 3769 }
 3770 
 3771 /**
 3772  * Validate admin op params
 3773  * @param params
 3774  *
 3775  * @return int
 3776  */
 3777 int imma_proc_is_adminop_params_valid(
 3778     const SaImmAdminOperationParamsT_2 **params) {
 3779   int i = 0;
 3780 
 3781   /* Validate type for parameters */
 3782   while (params[i] != NULL) {
 3783     if (params[i]->paramName == NULL) {
 3784       TRACE_3("no name for param: %d", i);
 3785       return 0;
 3786     }
 3787 
 3788     if (!imma_proc_is_valid_type(params[i]->paramType)) {
 3789       TRACE_3("wrong type for param: %s", params[i]->paramName);
 3790       return 0;
 3791     }
 3792 
 3793     if (params[i]->paramBuffer == NULL) {
 3794       TRACE_3("no value for param: %d", i);
 3795       return 0;
 3796     }
 3797 
 3798     i++;
 3799   }
 3800 
 3801   return 1;
 3802 }