Hi Minh,
Regard Id:2 and Id:3, I remove the old values.
I implement all comments.
Best Regards,
Thanh


-----Original Message-----
From: Minh Hon Chau <minh.c...@dektech.com.au> 
Sent: Tuesday, 7 July 2020 11:43 AM
To: Thanh Nguyen <thanh.ngu...@dektech.com.au>; Thang Duc Nguyen 
<thang.d.ngu...@dektech.com.au>; Thuan Tran <thuan.t...@dektech.com.au>
Cc: opensaf-devel@lists.sourceforge.net
Subject: Re: [PATCH 1/1] ntf: Enhance attribute change notification [#3196]

Hi a Thanh

Some comments inline.

Thanks

Minh

On 6/7/20 10:59 am, Thanh Nguyen wrote:
> 1) When IMM changes an attribute with NOTIFY flag, ntfimcn
> currently sends the changed attribute values in notification data.
> With the enhancement, ntfimcn fetches the old attribute values,
> corresponding to the changed attribute values, if exist in IMM,
> and include the old attribute values in notification data.
> 2) Test suite ntftest is updated.
> ---
>   src/ntf/Makefile.am                 |    2 +
>   src/ntf/apitest/test_ntf_imcn.cc    | 1051 ++++++++++++++++-----------
>   src/ntf/apitest/tet_ntf_common.cc   |   82 +++
>   src/ntf/apitest/tet_ntf_common.h    |    2 +
>   src/ntf/ntfimcnd/ntfimcn_common.c   |  221 ++++++
>   src/ntf/ntfimcnd/ntfimcn_common.h   |   65 ++
>   src/ntf/ntfimcnd/ntfimcn_imm.c      |   31 +-
>   src/ntf/ntfimcnd/ntfimcn_main.h     |    2 +
>   src/ntf/ntfimcnd/ntfimcn_notifier.c |  219 +++++-
>   9 files changed, 1259 insertions(+), 416 deletions(-)
>   create mode 100755 src/ntf/ntfimcnd/ntfimcn_common.c
>   create mode 100755 src/ntf/ntfimcnd/ntfimcn_common.h
>
> diff --git a/src/ntf/Makefile.am b/src/ntf/Makefile.am
> index a03eab10c..95210ae5d 100644
> --- a/src/ntf/Makefile.am
> +++ b/src/ntf/Makefile.am
> @@ -108,6 +108,7 @@ noinst_HEADERS += \
>       src/ntf/ntfimcnd/ntfimcn_imm.h \
>       src/ntf/ntfimcnd/ntfimcn_main.h \
>       src/ntf/ntfimcnd/ntfimcn_notifier.h \
> +     src/ntf/ntfimcnd/ntfimcn_common.h \
>       src/ntf/tools/ntfclient.h \
>       src/ntf/tools/ntfconsumer.h
>   
> @@ -171,6 +172,7 @@ bin_osafntfimcnd_CPPFLAGS = \
>   bin_osafntfimcnd_SOURCES = \
>       src/ntf/ntfimcnd/ntfimcn_main.c \
>       src/ntf/ntfimcnd/ntfimcn_notifier.c \
> +     src/ntf/ntfimcnd/ntfimcn_common.c \
>       src/ntf/ntfimcnd/ntfimcn_imm.c
>   
>   bin_osafntfimcnd_LDADD = \
> diff --git a/src/ntf/apitest/test_ntf_imcn.cc 
> b/src/ntf/apitest/test_ntf_imcn.cc
> index 6fc5fc831..d06c60dd5 100644
> --- a/src/ntf/apitest/test_ntf_imcn.cc
> +++ b/src/ntf/apitest/test_ntf_imcn.cc
> @@ -24,10 +24,13 @@
>   #include <sys/stat.h>
>   #include <fcntl.h>
>   #include <assert.h>
> +#include <cfloat>
> +#include <cmath>
>   #include <saAis.h>
>   #include <saImmOi.h>
>   #include <saImmOm.h>
>   #include <saNtf.h>
> +#include <string>
>   #include "base/time.h"
>   #include "osaf/immutil/immutil.h"
>   #include "osaf/apitest/util.h"
> @@ -55,6 +58,8 @@ static char BUF1_STR[sizeof(BUF1) + 1] = { '\0' };
>   static char BUF2_STR[sizeof(BUF2) + 1] = { '\0' };
>   static char BUF3_STR[sizeof(BUF3) + 1] = { '\0' };
>   
> +#define OLD_ATTR_PRESENT_DEFAULT SA_FALSE
> +
>   /**
>    * Callback routine, called when subscribed notification arrives.
>    */
> @@ -168,6 +173,123 @@ static SaBoolT bufs_equal1(const SaUint8T *recbuf,
>     return rc;
>   }
>   
> +static void print_notification_attr(SaNtfNotificationHandleT nHandle,
> +    SaNtfElementIdT attributeId,
> +    SaNtfValueTypeT attributeType,
> +    SaNtfValueT* value,
> +    int idx) {
> +  SaUint16T numElem = 0;
> +  char *str = NULL;
> +  SaAisErrorT rc = SA_AIS_OK;
> +
> +  switch (attributeType) {
> +  case SA_NTF_VALUE_STRING: {
> +    rc = saNtfPtrValGet(
> +        nHandle,
> +        value,
> +        reinterpret_cast<void **>(&str), &numElem);
> +    if (rc == SA_AIS_OK) {
> +      printf("[%d]: Id:%d Type:%d Value:(%d)%s\n", idx,
> +        attributeId, attributeType, numElem, str);
> +    } else {
> +      printf("[%d]: Id:%d Type:%d Value:(%d)%s\n", idx,
> +        attributeId, attributeType, numElem, "<Empty>");
> +    }
> +    break;
> +  }
> +  case SA_NTF_VALUE_UINT32: {
> +    printf("[%d]: Id:%d Type:%d Value:%u\n", idx,
> +        attributeId, attributeType, value->uint32Val);
> +    break;
> +  }
> +  case SA_NTF_VALUE_INT32: {
> +    printf("[%d]: Id:%d Type:%d Value:%d\n", idx,
> +        attributeId, attributeType, value->int32Val);
> +    break;
> +  }
> +  case SA_NTF_VALUE_UINT64: {
> +    printf("[%d]: Id:%d Type:%d Value:%llu\n", idx,
> +        attributeId, attributeType, value->uint64Val);
> +    break;
> +  }
> +  case SA_NTF_VALUE_INT64: {
> +    printf("[%d]: Id:%d Type:%d Value:%lld\n", idx,
> +        attributeId, attributeType, value->int64Val);
> +    break;
> +  }
> +  case SA_NTF_VALUE_FLOAT: {
> +    printf("[%d]: Id:%d Type:%d Value:%f\n", idx,
> +        attributeId, attributeType, value->floatVal);
> +    break;
> +  }
> +  case SA_NTF_VALUE_DOUBLE: {
> +    printf("[%d]: Id:%d Type:%d Value:%f\n", idx,
> +        attributeId, attributeType, value->doubleVal);
> +    break;
> +  }
> +  case SA_NTF_VALUE_LDAP_NAME:
> +  case SA_NTF_VALUE_BINARY: {
> +    SaUint8T *binptr = NULL;
> +    rc = saNtfPtrValGet(
> +        nHandle,
> +        value,
> +        reinterpret_cast<void **>(&binptr), &numElem);
> +    if (rc == SA_AIS_OK) {
> +      printf("[%d]: Id:%d Type:%d NumBytes:%u\n", idx,
> +             attributeId, attributeType,
> +             numElem);
> +      print_mem((const unsigned char*) binptr, numElem);
> +    } else {
> +      printf("[%d]: Id:%d Type:%d NumBytes:(%u)%s\n", idx,
> +        attributeId, attributeType, numElem, "<Empty>");
> +    }
> +    break;
> +  }
> +  default:
> +    printf("Unsupported attribute type: %d\n",
> +        attributeType);
> +    break;
> +  }
> +}
> +
> +static void print_old_attrs(SaNtfNotificationHandleT nHandle,
> +    SaNtfAttributeChangeT* attrChange, SaUint16T numAttributes) {
> +  // Skip of none of the attribute exist
> +  int count = -1;
> +  for (int i = 0; i < numAttributes; ++i) {
> +    // There is at least one old attribute value
> +    if (attrChange[i].oldAttributePresent == SA_TRUE) {
> +      count = i;
> +      break;
> +    }
> +  }
> +  // Nothing found, skip
> +  if (count == -1)
> +    return;
> +  printf("Num possible old attributes    : %d\n", numAttributes);
> +  for (int i = 0; i < numAttributes; ++i) {
> +    if (attrChange[i].oldAttributePresent == SA_FALSE) {
> +      printf("[%d]: Old Attribute not present\n", i);
> +      continue;
> +    }
> +    print_notification_attr(nHandle,
> +        attrChange[i].attributeId,
> +        attrChange[i].attributeType,
> +        &attrChange[i].oldAttributeValue, i);
> +  }
> +}
> +
> +static void print_new_attrs(SaNtfNotificationHandleT nHandle,
> +    SaNtfAttributeChangeT* attrChange, SaUint16T numAttributes) {
> +  printf("Num changed attributes   : %d\n", numAttributes);
> +  for (int i = 0; i < numAttributes; ++i) {
> +    print_notification_attr(nHandle,
> +        attrChange[i].attributeId,
> +        attrChange[i].attributeType,
> +        &attrChange[i].newAttributeValue, i);
> +  }
> +}
> +
>   /**
>    * Display the content of a notification.
>    */
> @@ -245,99 +367,10 @@ static void print_notif(NotifData *n) {
>              nHeader->additionalInfo[i].infoType, numElem, str);
>     }
>     if (n->evType == SA_NTF_ATTRIBUTE_CHANGED) {
> -    printf("Num changed attributes   : %d\n",
> -           n->a_c_notif_ptr->numAttributes);
> -    for (i = 0; i < n->a_c_notif_ptr->numAttributes; i++) {
> -      if (n->a_c_notif_ptr->changedAttributes[i]
> -        .attributeType == SA_NTF_VALUE_STRING) {
> -        safassert(saNtfPtrValGet(
> -            n->nHandle,
> -            &n->a_c_notif_ptr->changedAttributes[i].newAttributeValue,
> -            reinterpret_cast<void **>(&str), &numElem), SA_AIS_OK);
> -        printf("[%d]: Id:%d Type:%d Value:(%d)%s\n", i,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeId,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeType,
> -               numElem, str);
> -      } else if (n->a_c_notif_ptr->changedAttributes[i]
> -               .attributeType == SA_NTF_VALUE_UINT32) {
> -        printf("[%d]: Id:%d Type:%d Value:%u\n", i,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeId,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeType,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .newAttributeValue.uint32Val);
> -      } else if (n->a_c_notif_ptr->changedAttributes[i]
> -               .attributeType == SA_NTF_VALUE_INT32) {
> -        printf("[%d]: Id:%d Type:%d Value:%d\n", i,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeId,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeType,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .newAttributeValue.int32Val);
> -      } else if (n->a_c_notif_ptr->changedAttributes[i]
> -               .attributeType == SA_NTF_VALUE_UINT64) {
> -        printf("[%d]: Id:%d Type:%d Value:%llu\n", i,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeId,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeType,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .newAttributeValue.uint64Val);
> -      } else if (n->a_c_notif_ptr->changedAttributes[i]
> -               .attributeType == SA_NTF_VALUE_INT64) {
> -        printf("[%d]: Id:%d Type:%d Value:%lld\n", i,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeId,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeType,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .newAttributeValue.int64Val);
> -      } else if (n->a_c_notif_ptr->changedAttributes[i]
> -               .attributeType == SA_NTF_VALUE_FLOAT) {
> -        printf("[%d]: Id:%d Type:%d Value:%f\n", i,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeId,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeType,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .newAttributeValue.floatVal);
> -      } else if (n->a_c_notif_ptr->changedAttributes[i]
> -               .attributeType == SA_NTF_VALUE_DOUBLE) {
> -        printf("[%d]: Id:%d Type:%d Value:%f\n", i,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeId,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeType,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .newAttributeValue.doubleVal);
> -      } else if (n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeType ==
> -               SA_NTF_VALUE_BINARY ||
> -           n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeType ==
> -               SA_NTF_VALUE_LDAP_NAME) {
> -        SaUint8T *binptr = NULL;
> -        safassert(saNtfPtrValGet(
> -            n->nHandle,
> -            &n->a_c_notif_ptr->changedAttributes[i].newAttributeValue,
> -            reinterpret_cast<void **>(&binptr), &numElem), SA_AIS_OK);
> -        printf("[%d]: Id:%d Type:%d NumBytes:%u\n", i,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeId,
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeType,
> -               numElem);
> -        print_buf(binptr, numElem);
> -      } else {
> -        printf("Unsupported attribute type: %d\n",
> -               n->a_c_notif_ptr->changedAttributes[i]
> -             .attributeType);
> -      }
> -    }
> +    print_new_attrs(n->nHandle, n->a_c_notif_ptr->changedAttributes,
> +        n->a_c_notif_ptr->numAttributes);
> +    print_old_attrs(n->nHandle, n->a_c_notif_ptr->changedAttributes,
> +        n->a_c_notif_ptr->numAttributes);
>     } else if (n->evType == SA_NTF_OBJECT_CREATION ||
>          n->evType == SA_NTF_OBJECT_DELETION) {
>       printf("Num attributes           : %d\n",
> @@ -516,6 +549,171 @@ static SaBoolT is_equal_add_info(NotifData *n_exp, 
> NotifData *n_rec) {
>     return rc;
>   }
>   
> +static SaBoolT is_equal_binary_attr(SaNtfNotificationHandleT eHandle,
> +    SaNtfNotificationHandleT rHandle,
> +    SaNtfValueT* eVal,
> +    SaNtfValueT* rVal) {
> +  SaBoolT res = SA_FALSE;
> +  do {
> +    SaUint8T *recptr = NULL;
> +    SaUint8T *expptr = NULL;
> +    SaUint16T exp_ln = 0;
> +    SaUint16T rec_ln = 0;
> +    SaAisErrorT rc = saNtfPtrValGet(
> +      rHandle,
> +      rVal,
> +      reinterpret_cast<void **>(&recptr), &rec_ln);
> +    if (rc != SA_AIS_OK) {
> +      break;
> +    }
> +    rc = saNtfPtrValGet(
> +      eHandle,
> +      eVal,
> +      reinterpret_cast<void **>(&expptr), &exp_ln);
> +    if (rc != SA_AIS_OK) {
> +      break;
> +    }
> +    if (rec_ln == exp_ln &&
> +        bufs_equal(recptr, expptr,
> +             rec_ln)) {
> +      res = SA_TRUE;
> +    } else if ((rec_ln * 2) == exp_ln &&
> +         bufs_equal1(recptr, expptr,
> +               rec_ln)) {
> +      res = SA_TRUE;
> +    }
> +  } while (false);
> +  return res;
> +}
> +
> +static SaBoolT is_equal_str_attr(SaNtfNotificationHandleT eHandle,
> +    SaNtfNotificationHandleT rHandle,
> +    SaNtfValueT* eVal,
> +    SaNtfValueT* rVal) {
> +  SaBoolT res = SA_FALSE;
> +  do {
> +    char *eStr = NULL;
> +    char *rStr = NULL;
> +    SaUint16T elen = 0;
> +    SaUint16T rlen = 0;
> +    SaAisErrorT rc = saNtfPtrValGet(
> +        eHandle,
> +        eVal,
> +        reinterpret_cast<void **>(&eStr), &elen);
> +    if (rc != SA_AIS_OK) {
> +      break;
> +    }
> +    rc = saNtfPtrValGet(
> +        rHandle,
> +        rVal,
> +        reinterpret_cast<void **>(&rStr), &rlen);
> +    if (rc != SA_AIS_OK) {
> +      break;
> +    }
> +    if (!strncmp(eStr, "immcfg", 6)) {
> +      elen = rlen = 6;
> +    }
> +    if (elen == rlen && !strncmp(eStr, rStr, elen)) {
> +      res = SA_TRUE;
> +    }
> +  } while (false);
> +  return res;
> +}
> +
> +static SaBoolT is_equal_scalar_attr(SaNtfAttributeChangeT* n_exp,
> +    SaNtfAttributeChangeT* n_rec) {
> +  SaBoolT rc = SA_FALSE;
> +  switch (n_rec->attributeType) {
> +  case SA_NTF_VALUE_UINT32: {
> +    if (n_exp->newAttributeValue.uint32Val ==
> +        n_rec->newAttributeValue.uint32Val) {
> +      if (n_exp->oldAttributePresent) {
> +        if (n_exp->oldAttributeValue.uint32Val ==
> +            n_rec->oldAttributeValue.uint32Val) {
> +          rc = SA_TRUE;
> +        }
> +      } else {
> +        rc = SA_TRUE;
> +      }
> +    }
> +    break;
> +  }
> +  case SA_NTF_VALUE_INT32: {
> +    if (n_exp->newAttributeValue.int32Val ==
> +        n_rec->newAttributeValue.int32Val) {
> +      if (n_exp->oldAttributePresent) {
> +        if (n_exp->oldAttributeValue.int32Val ==
> +            n_rec->oldAttributeValue.int32Val) {
> +          rc = SA_TRUE;
> +        }
> +      } else {
> +        rc = SA_TRUE;
> +      }
> +    }
> +    break;
> +  }
> +  case SA_NTF_VALUE_UINT64: {
> +    if (n_exp->newAttributeValue.uint64Val ==
> +        n_rec->newAttributeValue.uint64Val) {
> +      if (n_exp->oldAttributePresent) {
> +        if (n_exp->oldAttributeValue.uint64Val ==
> +            n_rec->oldAttributeValue.uint64Val) {
> +          rc = SA_TRUE;
> +        }
> +      } else {
> +        rc = SA_TRUE;
> +      }
> +    }
> +    break;
> +  }
> +  case SA_NTF_VALUE_INT64: {
> +    if (n_exp->newAttributeValue.int64Val ==
> +        n_rec->newAttributeValue.int64Val) {
> +      if (n_exp->oldAttributePresent) {
> +        if (n_exp->oldAttributeValue.int64Val ==
> +            n_rec->oldAttributeValue.int64Val) {
> +          rc = SA_TRUE;
> +        }
> +      } else {
> +        rc = SA_TRUE;
> +      }
> +     }
> +    break;
> +  }
> +  case SA_NTF_VALUE_FLOAT: {
> +    if (fabs(n_exp->newAttributeValue.floatVal -
> +        n_rec->newAttributeValue.floatVal) < FLT_EPSILON ) {
> +      if (n_exp->oldAttributePresent) {
> +        if (fabs(n_exp->oldAttributeValue.floatVal -
> +            n_rec->oldAttributeValue.floatVal) < FLT_EPSILON ) {
> +          rc = SA_TRUE;
> +        }
> +      } else {
> +        rc = SA_TRUE;
> +      }
> +    }
> +    break;
> +  }
> +  case SA_NTF_VALUE_DOUBLE: {
> +    if (fabs(n_exp->newAttributeValue.doubleVal -
> +        n_rec->newAttributeValue.doubleVal) < DBL_EPSILON  ) {
> +      if (n_exp->oldAttributePresent) {
> +        if (fabs(n_exp->oldAttributeValue.doubleVal -
> +            n_rec->oldAttributeValue.doubleVal) < DBL_EPSILON  ) {
> +          rc = SA_TRUE;
> +        }
> +      } else {
> +        rc = SA_TRUE;
> +      }
> +    }
> +    break;
> +  }
> +  default:
> +    rc = SA_FALSE;
> +  }
> +  return rc;
> +}
> +
>   /**
>    * Check whether the attributes list data is equal between received and 
> expected
>    * attribute change notification.
> @@ -525,16 +723,14 @@ static SaBoolT is_equal_ch_attr(const NotifData *n_exp,
>     SaBoolT rc = SA_TRUE;
>     int i = 0;
>     int j = 0;
> -  char *exp_str = NULL;
> -  char *rec_str = NULL;
> -  SaUint16T exp_ln = 0;
> -  SaUint16T rec_ln = 0;
>   
>     char elemVerified[256];
>     memset(elemVerified, 0, n_rec->a_c_notif_ptr->numAttributes);
> -  for (i = 0; i < n_rec->a_c_notif_ptr->numAttributes; i++) {
> +  // For every received notification
> +  for (i = 0; i < n_rec->a_c_notif_ptr->numAttributes; ++i) {
>       rc = SA_FALSE;
> -    for (j = 0; j < n_exp->a_c_notif_ptr->numAttributes; j++) {
> +    // Look for a match in every expected notification
> +    for (j = 0; j < n_exp->a_c_notif_ptr->numAttributes; ++j) {
>         if ((n_exp->a_c_notif_ptr->changedAttributes[j]
>            .attributeType ==
>              n_rec->a_c_notif_ptr->changedAttributes[i]
> @@ -544,56 +740,23 @@ static SaBoolT is_equal_ch_attr(const NotifData *n_exp,
>              n_rec->a_c_notif_ptr->changedAttributes[i]
>            .oldAttributePresent) &&
>             elemVerified[j] == 0) {
> -        if (n_exp->a_c_notif_ptr->changedAttributes[j]
> -          .attributeType == SA_NTF_VALUE_STRING) {
> -          safassert(saNtfPtrValGet(
> -              n_exp->nHandle,
> -              &n_exp->a_c_notif_ptr->changedAttributes[j].newAttributeValue,
> -              reinterpret_cast<void **>(&exp_str), &exp_ln), SA_AIS_OK);
> -          safassert(saNtfPtrValGet(
> +        switch (n_exp->a_c_notif_ptr->changedAttributes[j] .attributeType) {
> +        case SA_NTF_VALUE_STRING: {
> +          rc = is_equal_str_attr(n_exp->nHandle,
>                 n_rec->nHandle,
> -              &n_rec->a_c_notif_ptr->changedAttributes[i].newAttributeValue,
> -              reinterpret_cast<void **>(&rec_str), &rec_ln), SA_AIS_OK);
> -          if (!strncmp(rec_str, "immcfg", 6)) {
> -            exp_ln = 6;
> -            rec_ln = 6;
> -          }
> -          if (exp_ln == rec_ln &&
> -              !strncmp(exp_str, rec_str,
> -                 exp_ln)) {
> -            rc = SA_TRUE;
> -            break;
> -          }
> -        } else if (n_exp->a_c_notif_ptr
> -                 ->changedAttributes[j]
> -                 .attributeType ==
> -             SA_NTF_VALUE_UINT32) {
> -          if (n_exp->a_c_notif_ptr
> -            ->changedAttributes[j]
> -            .newAttributeValue.uint32Val ==
> -              n_rec->a_c_notif_ptr
> -            ->changedAttributes[i]
> -            .newAttributeValue.uint32Val) {
> -            rc = SA_TRUE;
> -            break;
> -          }
> -        } else if (n_exp->a_c_notif_ptr
> -                 ->changedAttributes[j]
> -                 .attributeType ==
> -             SA_NTF_VALUE_INT32) {
> -          if (n_exp->a_c_notif_ptr
> -            ->changedAttributes[j]
> -            .newAttributeValue.int32Val ==
> -              n_rec->a_c_notif_ptr
> -            ->changedAttributes[i]
> -            .newAttributeValue.int32Val) {
> -            rc = SA_TRUE;
> -            break;
> +              &n_exp->a_c_notif_ptr->changedAttributes[j].newAttributeValue,
> +              &n_rec->a_c_notif_ptr->changedAttributes[i].newAttributeValue);
> +
> +          if ((rc == SA_TRUE) &&
> +            n_exp->a_c_notif_ptr->changedAttributes[j].oldAttributePresent) {
> +            rc = is_equal_str_attr(n_exp->nHandle,
> +                n_rec->nHandle,
> +                
> &n_exp->a_c_notif_ptr->changedAttributes[j].oldAttributeValue,
> +                
> &n_rec->a_c_notif_ptr->changedAttributes[i].oldAttributeValue);
>             }
> -        } else if (n_exp->a_c_notif_ptr
> -                 ->changedAttributes[j]
> -                 .attributeType ==
> -             SA_NTF_VALUE_UINT64) {
> +          break;
> +        }
> +        case SA_NTF_VALUE_UINT64: {
>             /*
>              * CCB ID is of this type. Check whether
>              * it is the ccb id attribute and that a
> @@ -609,99 +772,54 @@ static SaBoolT is_equal_ch_attr(const NotifData *n_exp,
>                   ->changedAttributes[i]
>                   .attributeId) {
>               rc = SA_TRUE;
> -            break;
> -          } else if (n_exp->a_c_notif_ptr
> -                   ->changedAttributes[j]
> -                   .newAttributeValue
> -                   .uint64Val ==
> -               n_rec->a_c_notif_ptr
> -                   ->changedAttributes[i]
> -                   .newAttributeValue
> -                   .uint64Val) {
> -            rc = SA_TRUE;
> -            break;
> -          }
> -        } else if (n_exp->a_c_notif_ptr
> -                 ->changedAttributes[j]
> -                 .attributeType ==
> -             SA_NTF_VALUE_INT64) {
> -          if (n_exp->a_c_notif_ptr
> -            ->changedAttributes[j]
> -            .newAttributeValue.int64Val ==
> -              n_rec->a_c_notif_ptr
> -            ->changedAttributes[i]
> -            .newAttributeValue.int64Val) {
> -            rc = SA_TRUE;
> -            break;
> -          }
> -        } else if (n_exp->a_c_notif_ptr
> -                 ->changedAttributes[j]
> -                 .attributeType ==
> -             SA_NTF_VALUE_FLOAT) {
> -          if (n_exp->a_c_notif_ptr
> -            ->changedAttributes[j]
> -            .newAttributeValue.floatVal ==
> -              n_rec->a_c_notif_ptr
> -            ->changedAttributes[i]
> -            .newAttributeValue.floatVal) {
> -            rc = SA_TRUE;
> -            break;
> -          }
> -        } else if (n_exp->a_c_notif_ptr
> -                 ->changedAttributes[j]
> -                 .attributeType ==
> -             SA_NTF_VALUE_DOUBLE) {
> -          if (n_exp->a_c_notif_ptr
> -            ->changedAttributes[j]
> -            .newAttributeValue.doubleVal ==
> -              n_rec->a_c_notif_ptr
> -            ->changedAttributes[i]
> -            .newAttributeValue.doubleVal) {
> +          } else if (is_equal_scalar_attr(
> +              &n_exp->a_c_notif_ptr->changedAttributes[j],
> +              &n_rec->a_c_notif_ptr->changedAttributes[i])) {
>               rc = SA_TRUE;
> -            break;
>             }
> -        } else if (n_exp->a_c_notif_ptr
> -               ->changedAttributes[j]
> -               .attributeType ==
> -                 SA_NTF_VALUE_BINARY ||
> -             n_exp->a_c_notif_ptr
> -               ->changedAttributes[j]
> -               .attributeType ==
> -                 SA_NTF_VALUE_LDAP_NAME) {
> -          SaUint8T *recptr = NULL;
> -          SaUint8T *expptr = NULL;
> -          safassert(
> -              saNtfPtrValGet(
> -            n_rec->nHandle,
> -            &n_rec->a_c_notif_ptr->changedAttributes[i].newAttributeValue,
> -            reinterpret_cast<void **>(&recptr), &rec_ln), SA_AIS_OK);
> -          safassert(
> -              saNtfPtrValGet(
> -            n_exp->nHandle,
> -            &n_exp->a_c_notif_ptr->changedAttributes[j].newAttributeValue,
> -            reinterpret_cast<void **>(&expptr), &exp_ln), SA_AIS_OK);
> -          if (rec_ln == exp_ln &&
> -              bufs_equal(recptr, expptr,
> -                   rec_ln)) {
> -            rc = SA_TRUE;
> -            break;
> -          } else if ((rec_ln * 2) == exp_ln &&
> -               bufs_equal1(recptr, expptr,
> -                     rec_ln)) {
> -            rc = SA_TRUE;
> -            break;
> +          break;
> +        }
> +        case SA_NTF_VALUE_BINARY:
> +        case SA_NTF_VALUE_LDAP_NAME: {
> +          rc = is_equal_binary_attr(n_exp->nHandle,
> +              n_rec->nHandle,
> +              &n_exp->a_c_notif_ptr->changedAttributes[j].newAttributeValue,
> +              &n_rec->a_c_notif_ptr->changedAttributes[i].newAttributeValue);
> +          if ((rc == SA_TRUE) &&
> +              
> n_exp->a_c_notif_ptr->changedAttributes[j].oldAttributePresent) {
> +            rc = is_equal_binary_attr(n_exp->nHandle,
> +                n_rec->nHandle,
> +                
> &n_exp->a_c_notif_ptr->changedAttributes[j].oldAttributeValue,
> +                
> &n_rec->a_c_notif_ptr->changedAttributes[i].oldAttributeValue);
>             }
> -        } else {
>             break;
>           }
> -      }
> -    }
> -    if (rc == SA_FALSE) {
> -      break;
> +        // No need to parse the following cases individually
> +        // No need to remove these comments either
> +        // case SA_NTF_VALUE_UINT32:
> +        // case SA_NTF_VALUE_INT32:
> +        // case SA_NTF_VALUE_INT64:
> +        // case SA_NTF_VALUE_FLOAT:
> +        // case SA_NTF_VALUE_DOUBLE:
> +        default:
> +          rc = is_equal_scalar_attr(&n_exp->a_c_notif_ptr
> +                        ->changedAttributes[j],
> +                        &n_rec->a_c_notif_ptr
> +                        ->changedAttributes[i]);
> +          break;
> +        }
> +        // Found a match in expected notification data
> +        if (rc == SA_TRUE) {
> +          break;
> +        }
> +      }   // Compare attributes
> +    }   // Looking for a match in expected notification
> +    if (rc == SA_TRUE) {
> +     elemVerified[j] = 1;
>       } else {
> -      elemVerified[j] = 1;
> +      break;
>       }
> -  }
> +  }  // For all received notification
>     return rc;
>   }
>   
> @@ -1162,7 +1280,9 @@ static SaAisErrorT set_attr_str(
>           &n_exp->c_d_notif_ptr->objectAttributes[idx]
>          .attributeValue);
>       if (error == SA_AIS_OK) {
> -      strcpy(reinterpret_cast<char *>(temp), attrValue);
> +      //  strcpy(reinterpret_cast<char *>(temp), attrValue);
> +      snprintf(reinterpret_cast<char *>(temp), strlen(attrValue) + 1,
> +          "%s", attrValue);
>         n_exp->c_d_notif_ptr->objectAttributes[idx]
>             .attributeId = attrId;
>         n_exp->c_d_notif_ptr->objectAttributes[idx]
> @@ -1281,29 +1401,51 @@ static SaAisErrorT set_attr_extended_name(
>   static SaAisErrorT set_attr_change_str(
>       NotifData *n_exp, SaUint16T idx,
>       SaNtfElementIdT attrId,
> -    const char *newValue) {
> +    const char *newValue,
> +    SaBoolT oldAttrPresent = OLD_ATTR_PRESENT_DEFAULT,
> +    const char *oldValue = NULL) {
>     SaAisErrorT error = SA_AIS_OK;
>     SaUint8T *temp = NULL;
>   
> -  if (n_exp->a_c_notif_ptr != NULL) {
> +  do {
> +    if (n_exp->a_c_notif_ptr == NULL) {
> +      error = SA_AIS_ERR_FAILED_OPERATION;
> +      break;
> +    }
> +
>       n_exp->a_c_notif_ptr->changedAttributes[idx]
> -        .oldAttributePresent = SA_FALSE;
> +        .oldAttributePresent = oldAttrPresent;
>       error = saNtfPtrValAllocate(
>           n_exp->nHandle, strlen(newValue) + 1, reinterpret_cast<void 
> **>(&temp),
>           &n_exp->a_c_notif_ptr->changedAttributes[idx]
>          .newAttributeValue);
> -    if (error == SA_AIS_OK) {
> -      strcpy(reinterpret_cast<char *>(temp), newValue);
> -      n_exp->a_c_notif_ptr->changedAttributes[idx]
> -          .attributeId = attrId;
> -      n_exp->a_c_notif_ptr->changedAttributes[idx]
> -          .attributeType = SA_NTF_VALUE_STRING;
> -    } else {
> +    if (error != SA_AIS_OK) {
>         error = SA_AIS_ERR_FAILED_OPERATION;
> +      break;
>       }
> -  } else {
> -    error = SA_AIS_ERR_FAILED_OPERATION;
> -  }
> +    //  strcpy(reinterpret_cast<char *>(temp), newValue);
> +    snprintf(reinterpret_cast<char *>(temp),
> +        strlen(newValue) + 1, "%s", newValue);
> +    n_exp->a_c_notif_ptr->changedAttributes[idx]
> +        .attributeId = attrId;
> +    n_exp->a_c_notif_ptr->changedAttributes[idx]
> +        .attributeType = SA_NTF_VALUE_STRING;
> +    if (!oldAttrPresent || !oldValue)
> +      break;
> +    SaUint8T *otmp = NULL;
> +    error = saNtfPtrValAllocate(
> +        n_exp->nHandle, strlen(oldValue) + 1, reinterpret_cast<void 
> **>(&otmp),
> +        &n_exp->a_c_notif_ptr->changedAttributes[idx]
> +       .oldAttributeValue);
> +    if (error != SA_AIS_OK) {
> +      error = SA_AIS_ERR_FAILED_OPERATION;
> +      break;
> +    }
> +    //  strcpy(reinterpret_cast<char *>(otmp), oldValue);
> +    snprintf(reinterpret_cast<char *>(otmp),
> +        strlen(oldValue) + 1, "%s", oldValue);
> +  } while (false);
> +
>     return error;
>   }
>   
> @@ -1314,7 +1456,9 @@ static SaAisErrorT set_attr_change_buf(
>       NotifData *n_exp, SaUint16T idx,
>       SaNtfElementIdT attrId,
>       SaNtfValueTypeT valType,
> -    void *newValue) {
> +    void *newValue,
> +    SaBoolT oldAttrPresent = OLD_ATTR_PRESENT_DEFAULT,
> +    void* oldValue = NULL) {
>     SaAisErrorT error = SA_AIS_OK;
>     SaUint16T numAlloc = (valType == SA_NTF_VALUE_BINARY)
>            ? (reinterpret_cast<SaAnyT *>(newValue))->bufferSize
> @@ -1323,26 +1467,45 @@ static SaAisErrorT set_attr_change_buf(
>     SaUint8T *srcPtr = (valType == SA_NTF_VALUE_BINARY)
>                ? (reinterpret_cast<SaAnyT *>(newValue))->bufferAddr
>                : (reinterpret_cast<SaNameT *>(newValue))->value;
> -
> -  if (n_exp->a_c_notif_ptr != NULL) {
> +  do {
> +    if (n_exp->a_c_notif_ptr == NULL) {
> +      error = SA_AIS_ERR_FAILED_OPERATION;
> +      break;
> +    }
>       n_exp->a_c_notif_ptr->changedAttributes[idx]
> -        .oldAttributePresent = SA_FALSE;
> +        .oldAttributePresent = oldAttrPresent;
>       error = saNtfPtrValAllocate(
>           n_exp->nHandle, numAlloc, reinterpret_cast<void **>(&temp),
>           &n_exp->a_c_notif_ptr->changedAttributes[idx]
>          .newAttributeValue);
> -    if (error == SA_AIS_OK) {
> -      memcpy(temp, srcPtr, numAlloc);
> -      n_exp->a_c_notif_ptr->changedAttributes[idx]
> -          .attributeId = attrId;
> -      n_exp->a_c_notif_ptr->changedAttributes[idx]
> -          .attributeType = valType;
> -    } else {
> +    if (error != SA_AIS_OK) {
>         error = SA_AIS_ERR_FAILED_OPERATION;
> +      break;
>       }
> -  } else {
> -    error = SA_AIS_ERR_FAILED_OPERATION;
> -  }
> +    memcpy(temp, srcPtr, numAlloc);
> +    n_exp->a_c_notif_ptr->changedAttributes[idx]
> +        .attributeId = attrId;
> +    n_exp->a_c_notif_ptr->changedAttributes[idx]
> +        .attributeType = valType;
> +    if (!oldAttrPresent || !oldValue)
> +      break;
> +    SaUint16T onumAlloc = (valType == SA_NTF_VALUE_BINARY)
> +           ? (reinterpret_cast<SaAnyT *>(oldValue))->bufferSize
> +           : (reinterpret_cast<SaNameT *>(oldValue))->length;
> +    SaUint8T *otemp = NULL;
> +    SaUint8T *osrcPtr = (valType == SA_NTF_VALUE_BINARY)
> +               ? (reinterpret_cast<SaAnyT *>(oldValue))->bufferAddr
> +               : (reinterpret_cast<SaNameT *>(oldValue))->value;
> +    error = saNtfPtrValAllocate(
> +        n_exp->nHandle, onumAlloc, reinterpret_cast<void **>(&otemp),
> +        &n_exp->a_c_notif_ptr->changedAttributes[idx]
> +       .oldAttributeValue);
> +    if (error != SA_AIS_OK) {
> +      error = SA_AIS_ERR_FAILED_OPERATION;
> +      break;
> +    }
> +    memcpy(otemp, osrcPtr, onumAlloc);
> +  } while (false);
>     return error;
>   }
>   
> @@ -1351,7 +1514,9 @@ static SaAisErrorT set_attr_change_extended_name(
>       SaUint16T idx,
>       SaNtfElementIdT attrId,
>       SaNtfValueTypeT valType,
> -    void *newValue) {
> +    void *newValue,
> +    SaBoolT oldAttrPresent = OLD_ATTR_PRESENT_DEFAULT,
> +    void *oldValue = NULL) {
>     assert(valType == SA_NTF_VALUE_LDAP_NAME);
>     SaAisErrorT error = SA_AIS_OK;
>     SaUint16T numAlloc = strlen(saAisNameBorrow(
> @@ -1359,26 +1524,43 @@ static SaAisErrorT set_attr_change_extended_name(
>     SaUint8T *temp = nullptr;
>     SaUint8T *srcPtr = reinterpret_cast<SaUint8T*>(const_cast<char*>(
>         saAisNameBorrow(reinterpret_cast<SaNameT *>(newValue))));
> -
> -  if (n_exp->a_c_notif_ptr != NULL) {
> +  do {
> +    if (n_exp->a_c_notif_ptr == NULL) {
> +      error = SA_AIS_ERR_FAILED_OPERATION;
> +      break;
> +    }
>       n_exp->a_c_notif_ptr->changedAttributes[idx]
> -        .oldAttributePresent = SA_FALSE;
> +        .oldAttributePresent = oldAttrPresent;
>       error = saNtfPtrValAllocate(
>           n_exp->nHandle, numAlloc, reinterpret_cast<void **>(&temp),
>           &n_exp->a_c_notif_ptr->changedAttributes[idx]
>          .newAttributeValue);
> -    if (error == SA_AIS_OK) {
> -      memcpy(temp, srcPtr, numAlloc);
> -      n_exp->a_c_notif_ptr->changedAttributes[idx]
> -          .attributeId = attrId;
> -      n_exp->a_c_notif_ptr->changedAttributes[idx]
> -          .attributeType = valType;
> -    } else {
> +    if (error != SA_AIS_OK) {
>         error = SA_AIS_ERR_FAILED_OPERATION;
> +      break;
>       }
> -  } else {
> -    error = SA_AIS_ERR_FAILED_OPERATION;
> -  }
> +    memcpy(temp, srcPtr, numAlloc);
> +    n_exp->a_c_notif_ptr->changedAttributes[idx]
> +        .attributeId = attrId;
> +    n_exp->a_c_notif_ptr->changedAttributes[idx]
> +        .attributeType = valType;
> +    if (!oldAttrPresent || !oldValue)
> +      break;
> +    SaUint16T onumAlloc = strlen(saAisNameBorrow(
> +        reinterpret_cast<SaNameT *>(oldValue)));
> +    SaUint8T *otemp = nullptr;
> +    SaUint8T *osrcPtr = reinterpret_cast<SaUint8T*>(const_cast<char*>(
> +        saAisNameBorrow(reinterpret_cast<SaNameT *>(oldValue))));
> +    error = saNtfPtrValAllocate(
> +        n_exp->nHandle, numAlloc, reinterpret_cast<void **>(&otemp),
> +        &n_exp->a_c_notif_ptr->changedAttributes[idx]
> +       .oldAttributeValue);
> +    if (error != SA_AIS_OK) {
> +      error = SA_AIS_ERR_FAILED_OPERATION;
> +      break;
> +    }
> +    memcpy(otemp, osrcPtr, onumAlloc);
> +  } while (false);
>     return error;
>   }
>   
> @@ -1390,31 +1572,57 @@ static SaAisErrorT set_attr_change_scalar(
>       NotifData *n_exp, SaUint16T idx,
>       SaNtfElementIdT attrId,
>       SaNtfValueTypeT valType,
> -    void *newValue) {
> +    void *newValue,
> +    SaBoolT oldAttrPresent = OLD_ATTR_PRESENT_DEFAULT,
> +    void *oldValue = NULL) {
>     SaAisErrorT error = SA_AIS_OK;
>   
>     n_exp->a_c_notif_ptr->changedAttributes[idx].attributeId = attrId;
>     n_exp->a_c_notif_ptr->changedAttributes[idx].attributeType = valType;
>     n_exp->a_c_notif_ptr->changedAttributes[idx].oldAttributePresent =
> -      SA_FALSE;
> +      oldAttrPresent;
>     if (valType == SA_NTF_VALUE_UINT32) {
>       n_exp->a_c_notif_ptr->changedAttributes[idx]
>           .newAttributeValue.uint32Val = *reinterpret_cast<SaUint32T 
> *>(newValue);
> +    if (oldAttrPresent && oldValue) {
> +      n_exp->a_c_notif_ptr->changedAttributes[idx]
> +        .oldAttributeValue.uint32Val = *reinterpret_cast<SaUint32T 
> *>(oldValue);
> +    }
>     } else if (valType == SA_NTF_VALUE_INT32) {
>       n_exp->a_c_notif_ptr->changedAttributes[idx]
>           .newAttributeValue.int32Val = *reinterpret_cast<SaInt32T 
> *>(newValue);
> +    if (oldAttrPresent && oldValue) {
> +      n_exp->a_c_notif_ptr->changedAttributes[idx]
> +        .oldAttributeValue.int32Val = *reinterpret_cast<SaInt32T 
> *>(oldValue);
> +    }
>     } else if (valType == SA_NTF_VALUE_UINT64) {
>       n_exp->a_c_notif_ptr->changedAttributes[idx]
>           .newAttributeValue.uint64Val = *reinterpret_cast<SaUint64T 
> *>(newValue);
> +    if (oldAttrPresent && oldValue) {
> +      n_exp->a_c_notif_ptr->changedAttributes[idx]
> +        .oldAttributeValue.uint64Val = *reinterpret_cast<SaUint64T 
> *>(oldValue);
> +    }
>     } else if (valType == SA_NTF_VALUE_INT64) {
>       n_exp->a_c_notif_ptr->changedAttributes[idx]
>           .newAttributeValue.int64Val = *reinterpret_cast<SaInt64T 
> *>(newValue);
> +    if (oldAttrPresent && oldValue) {
> +      n_exp->a_c_notif_ptr->changedAttributes[idx]
> +        .oldAttributeValue.int64Val = *reinterpret_cast<SaInt64T 
> *>(oldValue);
> +    }
>     } else if (valType == SA_NTF_VALUE_FLOAT) {
>       n_exp->a_c_notif_ptr->changedAttributes[idx]
>           .newAttributeValue.floatVal = *reinterpret_cast<SaFloatT 
> *>(newValue);
> +    if (oldAttrPresent && oldValue) {
> +      n_exp->a_c_notif_ptr->changedAttributes[idx]
> +        .oldAttributeValue.floatVal = *reinterpret_cast<SaFloatT 
> *>(oldValue);
> +    }
>     } else if (valType == SA_NTF_VALUE_DOUBLE) {
>       n_exp->a_c_notif_ptr->changedAttributes[idx]
>           .newAttributeValue.doubleVal = *reinterpret_cast<SaDoubleT 
> *>(newValue);
> +    if (oldAttrPresent && oldValue) {
> +      n_exp->a_c_notif_ptr->changedAttributes[idx]
> +        .oldAttributeValue.doubleVal = *reinterpret_cast<SaDoubleT 
> *>(oldValue);
> +    }
>     } else {
>       error = SA_AIS_ERR_FAILED_OPERATION;
>     }
> @@ -3289,7 +3497,9 @@ void objectModifyTest_21(void) {
>   
>     /* modify an object */
>     SaUint32T ivar = UINT32VAR2;
> +  SaUint32T oivar = UINT32VAR1;
>     SaFloatT fvar = FLOATVAR2;
> +  SaFloatT ofvar = FLOATVAR1;
>     snprintf(command, MAX_DATA, "immcfg -t 20 -a testUint32Cfg=%u"
>              " -a testFloatCfg=%f %s", ivar, fvar, DNTESTCFG);
>     assert(system(command) != -1);
> @@ -3320,23 +3530,22 @@ void objectModifyTest_21(void) {
>           SA_AIS_OK);
>       safassert(set_add_info(&n_exp, 5, 5, "testFloatCfg"),
>           SA_AIS_OK);
> -    safassert(set_attr_change_str(&n_exp, 0, 0, "immcfg_xxx"),
> -        SA_AIS_OK);
> +    safassert(set_attr_change_str(&n_exp, 0, 0, "immcfg_xxx"), SA_AIS_OK);
>       safassert(set_attr_change_str(&n_exp, 1, 1, "OsafNtfCmTestCFG"),
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 4, 4,
> -             SA_NTF_VALUE_UINT32, &ivar),
> +             SA_NTF_VALUE_UINT32, &ivar, SA_TRUE, &oivar),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 5, 5,
> -             SA_NTF_VALUE_FLOAT, &fvar),
> +             SA_NTF_VALUE_FLOAT, &fvar, SA_TRUE, &ofvar),
>           SA_AIS_OK);
>   
>       if (!compare_notifs(&n_exp, &rec_notif_data)) {
> @@ -3367,8 +3576,13 @@ void objectModifyTest_22(void) {
>   
>     SaNameT var1 = {.length = sizeof(NAME2)};
>     memcpy(var1.value, NAME2, sizeof(NAME2));
> +  SaNameT var1old = {.length = sizeof(NAME1)};
> +  memcpy(var1old.value, NAME1, sizeof(NAME1));
> +
>     SaAnyT var2 = {.bufferSize = sizeof(BUF2),
>              .bufferAddr = const_cast<SaUint8T *>(BUF2)};
> +  SaAnyT var2old = {.bufferSize = sizeof(BUF1),
> +           .bufferAddr = const_cast<SaUint8T *>(BUF1)};
>   
>     /* modify an object */
>     snprintf(command, MAX_DATA, "immcfg -t 20 -a testNameCfg=%s "
> @@ -3405,17 +3619,17 @@ void objectModifyTest_22(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
>       safassert(set_attr_change_buf(&n_exp, 4, 4,
> -                SA_NTF_VALUE_LDAP_NAME, &var1),
> +                SA_NTF_VALUE_LDAP_NAME, &var1, SA_TRUE, &var1old),
>           SA_AIS_OK);
>       safassert(set_attr_change_buf(&n_exp, 5, 5, SA_NTF_VALUE_BINARY,
> -                &var2),
> +                &var2, SA_TRUE, &var2old),
>           SA_AIS_OK);
>   
>       if (!compare_notifs(&n_exp, &rec_notif_data)) {
> @@ -3481,17 +3695,17 @@ void objectModifyTest_23(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 4, 4,
> -             SA_NTF_VALUE_INT32, &addvar),
> +             SA_NTF_VALUE_INT32, &addvar, SA_FALSE),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 5, 4,
> -             SA_NTF_VALUE_INT32, &oldvar),
> +             SA_NTF_VALUE_INT32, &oldvar, SA_TRUE, &oldvar),
>           SA_AIS_OK);
>   
>       if (!compare_notifs(&n_exp, &rec_notif_data)) {
> @@ -3557,17 +3771,17 @@ void objectModifyTest_24(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 4, 4,
> -             SA_NTF_VALUE_UINT32, &addvar),
> +             SA_NTF_VALUE_UINT32, &addvar, SA_FALSE),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 5, 4,
> -             SA_NTF_VALUE_UINT32, &oldvar),
> +             SA_NTF_VALUE_UINT32, &oldvar, SA_TRUE, &oldvar),
>           SA_AIS_OK);
>   
>       if (!compare_notifs(&n_exp, &rec_notif_data)) {
> @@ -3633,17 +3847,17 @@ void objectModifyTest_25(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 4, 4,
> -             SA_NTF_VALUE_INT64, &addvar),
> +             SA_NTF_VALUE_INT64, &addvar, SA_FALSE),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 5, 4,
> -             SA_NTF_VALUE_INT64, &oldvar),
> +             SA_NTF_VALUE_INT64, &oldvar, SA_TRUE, &oldvar),
>           SA_AIS_OK);
>   
>       if (!compare_notifs(&n_exp, &rec_notif_data)) {
> @@ -3709,17 +3923,17 @@ void objectModifyTest_26(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 4, 4,
> -             SA_NTF_VALUE_UINT64, &addvar),
> +             SA_NTF_VALUE_UINT64, &addvar, SA_FALSE),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 5, 4,
> -             SA_NTF_VALUE_UINT64, &oldvar),
> +             SA_NTF_VALUE_UINT64, &oldvar, SA_TRUE, &oldvar),
>           SA_AIS_OK);
>   
>       if (!compare_notifs(&n_exp, &rec_notif_data)) {
> @@ -3785,17 +3999,17 @@ void objectModifyTest_27(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 4, 4,
>                SA_NTF_VALUE_FLOAT, &addvar),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 5, 4,
> -             SA_NTF_VALUE_FLOAT, &oldvar),
> +             SA_NTF_VALUE_FLOAT, &oldvar, SA_TRUE, &oldvar),
>           SA_AIS_OK);
>   
>       if (!compare_notifs(&n_exp, &rec_notif_data)) {
> @@ -3861,17 +4075,17 @@ void objectModifyTest_28(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 4, 4,
>                SA_NTF_VALUE_DOUBLE, &addvar),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 5, 4,
> -             SA_NTF_VALUE_DOUBLE, &oldvar),
> +             SA_NTF_VALUE_DOUBLE, &oldvar, SA_TRUE, &oldvar),
>           SA_AIS_OK);
>   
>       if (!compare_notifs(&n_exp, &rec_notif_data)) {
> @@ -3936,17 +4150,17 @@ void objectModifyTest_29(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 4, 4,
>                SA_NTF_VALUE_INT64, &addvar),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 5, 4,
> -             SA_NTF_VALUE_INT64, &oldvar),
> +             SA_NTF_VALUE_INT64, &oldvar, SA_TRUE, &oldvar),
>           SA_AIS_OK);
>   
>       if (!compare_notifs(&n_exp, &rec_notif_data)) {
> @@ -4012,14 +4226,15 @@ void objectModifyTest_30(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
>       safassert(set_attr_change_str(&n_exp, 4, 4, addvar), SA_AIS_OK);
> -    safassert(set_attr_change_str(&n_exp, 5, 4, oldvar), SA_AIS_OK);
> +    safassert(set_attr_change_str(&n_exp, 5, 4, oldvar,
> +        SA_TRUE, oldvar), SA_AIS_OK);
>   
>       if (!compare_notifs(&n_exp, &rec_notif_data)) {
>         print_notif(&n_exp);
> @@ -4086,14 +4301,14 @@ void objectModifyTest_31(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
>       safassert(set_attr_change_buf(&n_exp, 4, 4,
> -                SA_NTF_VALUE_LDAP_NAME, &oldvar),
> +                SA_NTF_VALUE_LDAP_NAME, &oldvar, SA_TRUE, &oldvar),
>           SA_AIS_OK);
>       safassert(set_attr_change_buf(&n_exp, 5, 4,
>                   SA_NTF_VALUE_LDAP_NAME, &addvar),
> @@ -4167,14 +4382,14 @@ void objectModifyTest_32(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
>       safassert(set_attr_change_buf(&n_exp, 4, 4, SA_NTF_VALUE_BINARY,
> -                &oldvar),
> +                &oldvar, SA_TRUE, &oldvar),
>           SA_AIS_OK);
>       safassert(set_attr_change_buf(&n_exp, 5, 4, SA_NTF_VALUE_BINARY,
>                   &addvar),
> @@ -4208,7 +4423,9 @@ void objectModifyTest_33(void) {
>   
>     /* modify an object */
>     SaStringT svar = STRINGVAR3;
> +  SaStringT svarOld = STRINGVAR1;
>     SaDoubleT dvar = DOUBLEVAR3;
> +  SaDoubleT dvarOld = DOUBLEVAR1;
>     snprintf(command, MAX_DATA,
>       "immcfg -t 20 -a testStringCfg=%s -a testDoubleCfg=%lf %s",
>       svar, dvar, DNTESTCFG);
> @@ -4246,15 +4463,16 @@ void objectModifyTest_33(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
> -    safassert(set_attr_change_str(&n_exp, 4, 4, svar), SA_AIS_OK);
> +    safassert(set_attr_change_str(&n_exp, 4, 4, svar,
> +        SA_TRUE, svarOld), SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 5, 5,
> -             SA_NTF_VALUE_DOUBLE, &dvar),
> +             SA_NTF_VALUE_DOUBLE, &dvar, SA_TRUE, &dvarOld),
>           SA_AIS_OK);
>   
>       if (!compare_notifs(&n_exp, &rec_notif_data)) {
> @@ -4285,6 +4503,7 @@ void objectModifyTest_34(void) {
>   
>     /* modify an object */
>     SaTimeT tvar = TIMEVAR3;
> +  SaTimeT tvarOld = TIMEVAR1;
>     snprintf(command, MAX_DATA, "immcfg -t 20 -a testTimeCfg=%lld %s",
>              (SaInt64T)tvar,  DNTESTCFG);
>     assert(system(command) != -1);
> @@ -4318,14 +4537,14 @@ void objectModifyTest_34(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 4, 4,
> -             SA_NTF_VALUE_INT64, &tvar),
> +             SA_NTF_VALUE_INT64, &tvar, SA_TRUE, &tvarOld),
>           SA_AIS_OK);
>   
>       if (!compare_notifs(&n_exp, &rec_notif_data)) {
> @@ -4397,24 +4616,24 @@ void objectModifyTest_35(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
>       safassert(set_attr_change_str(&n_exp, 4, 4, saddvar),
>           SA_AIS_OK);
> -    safassert(set_attr_change_str(&n_exp, 5, 4, soldvar),
> +    safassert(set_attr_change_str(&n_exp, 5, 4, soldvar, SA_TRUE, soldvar),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 6, 5,
>                SA_NTF_VALUE_INT32, &iaddvar),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 7, 5,
> -             SA_NTF_VALUE_INT32, &ioldvar1),
> +             SA_NTF_VALUE_INT32, &ioldvar1, SA_TRUE, &ioldvar1),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 8, 5,
> -             SA_NTF_VALUE_INT32, &ioldvar2),
> +             SA_NTF_VALUE_INT32, &ioldvar2, SA_TRUE, &ioldvar2),
>           SA_AIS_OK);
>   
>       if (!compare_notifs(&n_exp, &rec_notif_data)) {
> @@ -4486,19 +4705,19 @@ void objectModifyTest_36(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
> -    safassert(set_attr_change_str(&n_exp, 4, 4, soldvar),
> +    safassert(set_attr_change_str(&n_exp, 4, 4, soldvar, SA_TRUE, soldvar),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 5, 5,
> -             SA_NTF_VALUE_INT32, &ivar1),
> +             SA_NTF_VALUE_INT32, &ivar2, SA_TRUE, &idelvar),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 6, 5,
> -             SA_NTF_VALUE_INT32, &ivar2),
> +             SA_NTF_VALUE_INT32, &ivar1, SA_TRUE, &ivar1),
>           SA_AIS_OK);
>   
>       if (!compare_notifs(&n_exp, &rec_notif_data)) {
> @@ -4611,44 +4830,49 @@ void objectModifyTest_37(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 4, 4,
> -             SA_NTF_VALUE_INT32, &i32var1),
> +             SA_NTF_VALUE_INT32, &i32var1, SA_TRUE, &i32var1),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 5, 4,
>                SA_NTF_VALUE_INT32, &i32var11),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(
> -            &n_exp, 6, 4, SA_NTF_VALUE_INT32, &i32var111),
> +            &n_exp, 6, 4, SA_NTF_VALUE_INT32, &i32var111,
> +            SA_TRUE, &i32var111),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(
>               &n_exp, 7, 5, SA_NTF_VALUE_UINT32, &ui32var2),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(
> -            &n_exp, 8, 5, SA_NTF_VALUE_UINT32, &ui32var22),
> +            &n_exp, 8, 5, SA_NTF_VALUE_UINT32, &ui32var22,
> +            SA_TRUE, &ui32var22),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(
> -            &n_exp, 9, 5, SA_NTF_VALUE_UINT32, &ui32var222),
> +            &n_exp, 9, 5, SA_NTF_VALUE_UINT32, &ui32var222,
> +            SA_TRUE, &ui32var222),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 10, 6,
> -             SA_NTF_VALUE_INT64, &i64var3),
> +             SA_NTF_VALUE_INT64, &i64var3, SA_TRUE, &i64var3),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 11, 6,
> -             SA_NTF_VALUE_INT64, &i64var33),
> +             SA_NTF_VALUE_INT64, &i64var33, SA_TRUE, &i64var33),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(
>               &n_exp, 12, 6, SA_NTF_VALUE_INT64, &i64var333),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(
> -            &n_exp, 13, 7, SA_NTF_VALUE_UINT64, &ui64var4),
> +            &n_exp, 13, 7, SA_NTF_VALUE_UINT64, &ui64var4,
> +            SA_TRUE, &ui64var4),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(
> -            &n_exp, 14, 7, SA_NTF_VALUE_UINT64, &ui64var44),
> +            &n_exp, 14, 7, SA_NTF_VALUE_UINT64, &ui64var44,
> +            SA_TRUE, &ui64var44),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(
>               &n_exp, 15, 7, SA_NTF_VALUE_UINT64, &ui64var444),
> @@ -4657,44 +4881,45 @@ void objectModifyTest_37(void) {
>                SA_NTF_VALUE_FLOAT, &fvar5),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 17, 8,
> -             SA_NTF_VALUE_FLOAT, &fvar55),
> +             SA_NTF_VALUE_FLOAT, &fvar55, SA_TRUE, &fvar55),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 18, 8,
> -             SA_NTF_VALUE_FLOAT, &fvar555),
> +             SA_NTF_VALUE_FLOAT, &fvar555, SA_TRUE, &fvar555),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 19, 9,
>                SA_NTF_VALUE_DOUBLE, &dvar66),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 20, 9,
> -             SA_NTF_VALUE_DOUBLE, &dvar666),
> +             SA_NTF_VALUE_DOUBLE, &dvar666, SA_TRUE, &dvar666),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 21, 10,
>                SA_NTF_VALUE_INT64, &tvar77),
>           SA_AIS_OK);
>       safassert(set_attr_change_scalar(&n_exp, 22, 10,
> -             SA_NTF_VALUE_INT64, &tvar777),
> +             SA_NTF_VALUE_INT64, &tvar777, SA_TRUE, &tvar777),
>           SA_AIS_OK);
>       safassert(set_attr_change_str(&n_exp, 23, 11, svar8),
>           SA_AIS_OK);
> -    safassert(set_attr_change_str(&n_exp, 24, 11, svar888),
> +    safassert(set_attr_change_str(&n_exp, 24, 11, svar888,
> +        SA_TRUE, svar888),
>           SA_AIS_OK);
>       safassert(set_attr_change_buf(&n_exp, 25, 12,
>                   SA_NTF_VALUE_LDAP_NAME, &nvar9),
>           SA_AIS_OK);
>       safassert(set_attr_change_buf(&n_exp, 26, 12,
> -                SA_NTF_VALUE_LDAP_NAME, &nvar99),
> +                SA_NTF_VALUE_LDAP_NAME, &nvar99, SA_TRUE, &nvar99),
>           SA_AIS_OK);
>       safassert(set_attr_change_buf(&n_exp, 27, 12,
> -                SA_NTF_VALUE_LDAP_NAME, &nvar999),
> +                SA_NTF_VALUE_LDAP_NAME, &nvar999, SA_TRUE, &nvar999),
>           SA_AIS_OK);
>       safassert(set_attr_change_buf(&n_exp, 28, 13,
>                   SA_NTF_VALUE_BINARY, &avar10),
>           SA_AIS_OK);
>       safassert(set_attr_change_buf(&n_exp, 29, 13,
> -                SA_NTF_VALUE_BINARY, &avar100),
> +                SA_NTF_VALUE_BINARY, &avar100, SA_TRUE, &avar100),
>           SA_AIS_OK);
>       safassert(set_attr_change_buf(&n_exp, 30, 13,
> -                SA_NTF_VALUE_BINARY, &avar1000),
> +                SA_NTF_VALUE_BINARY, &avar1000, SA_TRUE, &avar1000),
>           SA_AIS_OK);
>   
>       if (!compare_notifs(&n_exp, &rec_notif_data)) {
> @@ -4725,8 +4950,12 @@ void objectMultiCcbTest_38(void) {
>     /* modify an object */
>     SaUint32T var1 = 32000;
>     SaInt32T var2 = -32000;
> +  SaUint32T var1old = UINT32VAR2;
> +  SaInt32T var2old = INT32VAR1;
>     SaUint64T var3 = 64000;
>     SaInt64T var4 = -64000;
> +  SaUint64T var3old = UINT64VAR1;
> +  SaInt64T var4old = INT64VAR1;
>     SaImmHandleT omHandle = 0;
>     SaImmAdminOwnerHandleT ownerHandle = 0;
>     SaImmCcbHandleT immCcbHandle = 0;
> @@ -4806,7 +5035,6 @@ void objectMultiCcbTest_38(void) {
>         if (!rec_notif_data.populated)
>           base::Sleep(base::kOneMillisecond);
>       }
> -
>       NotifData n_exp;
>       if (rec_notif_data.populated && noOfNotifs == 0) {
>         safassert(set_ntf(&n_exp, SA_NTF_ATTRIBUTE_CHANGED,
> @@ -4829,24 +5057,26 @@ void objectMultiCcbTest_38(void) {
>         safassert(
>             set_attr_change_str(&n_exp, 0, 0, "multiCcbOwner"),
>             SA_AIS_OK);
> -      safassert(set_attr_change_str(&n_exp, 1, 1,
> -                  "OsafNtfCmTestCFG"),
> +      safassert(set_attr_change_str(&n_exp, 1, 1, "OsafNtfCmTestCFG"),
>             SA_AIS_OK);
>         SaUint64T ccidVar = 3;
>         safassert(set_attr_change_scalar(&n_exp, 2, 2,
>                  SA_NTF_VALUE_UINT64,
> -               &ccidVar),
> +               &ccidVar, SA_TRUE, &ccidVar),
>             SA_AIS_OK);
> -      SaUint32T ccbLast = 0;
> +      SaUint32T ccbLast = 0;  // 0 when uncomment other cases
>         safassert(set_attr_change_scalar(&n_exp, 3, 3,
>                  SA_NTF_VALUE_UINT32,
> -               &ccbLast),
> +               &ccbLast, SA_TRUE, &ccbLast),
>             SA_AIS_OK);
> +
>         safassert(set_attr_change_scalar(
> -              &n_exp, 4, 4, SA_NTF_VALUE_UINT32, &var1),
> +              &n_exp, 4, 4, SA_NTF_VALUE_UINT32, &var1, SA_TRUE,
> +              reinterpret_cast<void*>(&var1old)),
>             SA_AIS_OK);
> -      safassert(set_attr_change_scalar(
> -              &n_exp, 5, 5, SA_NTF_VALUE_INT32, &var2),
> +     safassert(set_attr_change_scalar(
> +              &n_exp, 5, 5, SA_NTF_VALUE_INT32, &var2, SA_TRUE,
> +              reinterpret_cast<void*>(&var2old)),
>             SA_AIS_OK);
>       } else if (rec_notif_data.populated && noOfNotifs == 1) {
>         safassert(set_ntf(&n_exp, SA_NTF_ATTRIBUTE_CHANGED,
> @@ -4869,24 +5099,27 @@ void objectMultiCcbTest_38(void) {
>         safassert(
>             set_attr_change_str(&n_exp, 0, 0, "multiCcbOwner"),
>             SA_AIS_OK);
> -      safassert(set_attr_change_str(&n_exp, 1, 1,
> -                  "OsafNtfCmTestCFG"),
> +      safassert(set_attr_change_str(&n_exp, 1, 1, "OsafNtfCmTestCFG"),
>             SA_AIS_OK);
>         SaUint64T ccidVar = 3;
>         safassert(set_attr_change_scalar(&n_exp, 2, 2,
>                  SA_NTF_VALUE_UINT64,
> -               &ccidVar),
> +               &ccidVar, SA_TRUE, &ccidVar),
>             SA_AIS_OK);
>         SaUint32T ccbLast = 1;
>         safassert(set_attr_change_scalar(&n_exp, 3, 3,
>                  SA_NTF_VALUE_UINT32,
> -               &ccbLast),
> +               &ccbLast, SA_TRUE, &ccbLast),
>             SA_AIS_OK);
>         safassert(set_attr_change_scalar(
> -              &n_exp, 4, 4, SA_NTF_VALUE_UINT64, &var3),
> +              &n_exp, 4, 4, SA_NTF_VALUE_UINT64, &var3,
> +              SA_TRUE,
> +              reinterpret_cast<void*>(&var3old)),
>             SA_AIS_OK);
>         safassert(set_attr_change_scalar(
> -              &n_exp, 5, 5, SA_NTF_VALUE_INT64, &var4),
> +              &n_exp, 5, 5, SA_NTF_VALUE_INT64, &var4,
> +              SA_TRUE,
> +              reinterpret_cast<void*>(&var4old)),
>             SA_AIS_OK);
>       } else {
>         error = SA_AIS_ERR_FAILED_OPERATION;
> @@ -4920,6 +5153,7 @@ void objectMultiCcbTest_39(void) {
>     /* modify an object */
>     SaUint32T var1 = 32323;
>     SaUint32T oldvar1 = 32000;
> +  SaInt32T oldivar1 = -32000;
>     SaInt32T var2 = -32323;
>     SaUint64T var3 = 64000;
>     SaInt64T var4 = -64000;
> @@ -5057,25 +5291,24 @@ void objectMultiCcbTest_39(void) {
>         safassert(
>             set_attr_change_str(&n_exp, 0, 0, "multiCcbOwner"),
>             SA_AIS_OK);
> -      safassert(set_attr_change_str(&n_exp, 1, 1,
> -                  "OsafNtfCmTestCFG"),
> +      safassert(set_attr_change_str(&n_exp, 1, 1, "OsafNtfCmTestCFG"),
>             SA_AIS_OK);
>         SaUint64T ccidVar = 3;
>         safassert(set_attr_change_scalar(&n_exp, 2, 2,
>                  SA_NTF_VALUE_UINT64,
> -               &ccidVar),
> +               &ccidVar, SA_TRUE, &ccidVar),
>             SA_AIS_OK);
>         SaUint32T ccbLast = 0;
>         safassert(set_attr_change_scalar(&n_exp, 3, 3,
>                  SA_NTF_VALUE_UINT32,
> -               &ccbLast),
> +               &ccbLast, SA_TRUE, &ccbLast),
>             SA_AIS_OK);
>         safassert(set_attr_change_scalar(
>                 &n_exp, 4, 4, SA_NTF_VALUE_UINT32, &var1),
>             SA_AIS_OK);
>         safassert(set_attr_change_scalar(&n_exp, 5, 4,
>                  SA_NTF_VALUE_UINT32,
> -               &oldvar1),
> +               &oldvar1, SA_TRUE, &oldvar1),
>             SA_AIS_OK);
>       } else if (rec_notif_data.populated && noOfNotifs == 1) {
>         safassert(set_ntf(&n_exp, SA_NTF_ATTRIBUTE_CHANGED,
> @@ -5096,21 +5329,20 @@ void objectMultiCcbTest_39(void) {
>         safassert(
>             set_attr_change_str(&n_exp, 0, 0, "multiCcbOwner"),
>             SA_AIS_OK);
> -      safassert(set_attr_change_str(&n_exp, 1, 1,
> -                  "OsafNtfCmTestCFG"),
> +      safassert(set_attr_change_str(&n_exp, 1, 1, "OsafNtfCmTestCFG"),
>             SA_AIS_OK);
>         SaUint64T ccidVar = 3;
>         safassert(set_attr_change_scalar(&n_exp, 2, 2,
>                  SA_NTF_VALUE_UINT64,
> -               &ccidVar),
> +               &ccidVar, SA_TRUE, &ccidVar),
>             SA_AIS_OK);
>         SaUint32T ccbLast = 0;
>         safassert(set_attr_change_scalar(&n_exp, 3, 3,
>                  SA_NTF_VALUE_UINT32,
> -               &ccbLast),
> +               &ccbLast, SA_TRUE, &ccbLast),
>             SA_AIS_OK);
>         safassert(set_attr_change_scalar(
> -              &n_exp, 4, 4, SA_NTF_VALUE_INT32, &var2),
> +              &n_exp, 4, 4, SA_NTF_VALUE_INT32, &var2, SA_TRUE, &oldivar1),
>             SA_AIS_OK);
>       } else if (rec_notif_data.populated && noOfNotifs == 2) {
>         /*
> @@ -5142,31 +5374,30 @@ void objectMultiCcbTest_39(void) {
>         safassert(
>             set_attr_change_str(&n_exp, 0, 0, "multiCcbOwner"),
>             SA_AIS_OK);
> -      safassert(set_attr_change_str(&n_exp, 1, 1,
> -                  "OsafNtfCmTestCFG"),
> +      safassert(set_attr_change_str(&n_exp, 1, 1, "OsafNtfCmTestCFG"),
>             SA_AIS_OK);
>         SaUint64T ccidVar = 3;
>         safassert(set_attr_change_scalar(&n_exp, 2, 2,
>                  SA_NTF_VALUE_UINT64,
> -               &ccidVar),
> +               &ccidVar, SA_TRUE, &ccidVar),
>             SA_AIS_OK);
>         SaUint32T ccbLast =
>             1; /* Last notification of the CCB */
>         safassert(set_attr_change_scalar(&n_exp, 3, 3,
>                  SA_NTF_VALUE_UINT32,
> -               &ccbLast),
> +               &ccbLast, SA_TRUE, &ccbLast),
>             SA_AIS_OK);
>         safassert(set_attr_change_scalar(&n_exp, 4, 6,
>                  SA_NTF_VALUE_FLOAT,
> -               &oldvar6),
> +               &oldvar6, SA_TRUE, &var6),
>             SA_AIS_OK);
>         safassert(set_attr_change_scalar(&n_exp, 5, 6,
>                  SA_NTF_VALUE_FLOAT,
> -               &oldvar66),
> +               &oldvar66, SA_TRUE, &oldvar66),
>             SA_AIS_OK);
>         safassert(set_attr_change_scalar(&n_exp, 6, 7,
>                  SA_NTF_VALUE_DOUBLE,
> -               &oldvar5),
> +               &oldvar5, SA_TRUE, &oldvar5),
>             SA_AIS_OK);
>   
>       } else {
> @@ -5966,6 +6197,11 @@ void objectModifyTest_3506(void) {
>   
>     SaAnyT var2 = {.bufferSize = sizeof(BUF2),
>              .bufferAddr = const_cast<SaUint8T *>(BUF2)};
> +  SaNameT var1old;
> +  saAisNameLend((SaConstStringT)&extended_name_string_01,
> +          &var1old);
> +  SaAnyT var2old = {.bufferSize = sizeof(BUF1),
> +           .bufferAddr = const_cast<SaUint8T *>(BUF1)};
>   
>     /* modify an object */
>     snprintf(command, MAX_DATA, "immcfg -t 20 -a testNameCfg=%s"
> @@ -6002,17 +6238,19 @@ void objectModifyTest_3506(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
>       safassert(set_attr_change_extended_name(
> -            &n_exp, 4, 4, SA_NTF_VALUE_LDAP_NAME, &var1),
> +            &n_exp, 4, 4, SA_NTF_VALUE_LDAP_NAME, &var1,
> +            SA_TRUE,
> +            reinterpret_cast<void*>(&var1old)),
>           SA_AIS_OK);
>       safassert(set_attr_change_buf(&n_exp, 5, 5, SA_NTF_VALUE_BINARY,
> -                &var2),
> +                &var2, SA_TRUE, &var2old),
>           SA_AIS_OK);
>   
>       if (!compare_notifs(&n_exp, &rec_notif_data)) {
> @@ -6080,14 +6318,14 @@ void objectModifyTest_3507(void) {
>           SA_AIS_OK);
>       SaUint64T ccidVar = 3;
>       safassert(set_attr_change_scalar(&n_exp, 2, 2,
> -             SA_NTF_VALUE_UINT64, &ccidVar),
> +             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
>           SA_AIS_OK);
>       SaUint32T ccbLast = 1;
>       safassert(set_attr_change_scalar(&n_exp, 3, 3,
> -             SA_NTF_VALUE_UINT32, &ccbLast),
> +             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
>           SA_AIS_OK);
>       safassert(set_attr_change_extended_name(
> -            &n_exp, 4, 4, SA_NTF_VALUE_LDAP_NAME, &oldvar),
> +            &n_exp, 4, 4, SA_NTF_VALUE_LDAP_NAME, &oldvar, SA_TRUE, &oldvar),
>           SA_AIS_OK);
>       safassert(set_attr_change_extended_name(
>               &n_exp, 5, 4, SA_NTF_VALUE_LDAP_NAME, &addvar),
> @@ -6181,6 +6419,7 @@ void objectModifyTest_empty_sanamet(void) {
>     test_validate(error, SA_AIS_OK);
>   }
>   
> +// cppcheck-suppress unusedFunction
>   __attribute__((constructor)) static void ntf_imcn_constructor(void) {
>     struct stat buf;
>     int rc = 0;
> @@ -6190,25 +6429,19 @@ __attribute__((constructor)) static void 
> ntf_imcn_constructor(void) {
>      */
>     if (stat("//tmp//ntfsv_test_classes.xml", &buf) != 0) {
>       rc = system(
> -        "find / -name ntfsv_test_classes.xml > /tmp/ntftemp.txt");
> +        "find /srv -name ntfsv_test_classes.xml > /tmp/ntftemp.txt");
>       if (rc == 0) {
>         FILE *f = fopen("/tmp/ntftemp.txt", "r");
>         if (f != NULL) {
>           char line[80];
>           if (fgets(line, 80, f) != NULL) {
>             if (strstr(line, ".xml") != NULL) {
> -            char cp_cmd[80];
> -            snprintf(cp_cmd, sizeof(cp_cmd), "cp ");
> -            if ((strlen(line) - 1) > (sizeof(cp_cmd) - sizeof("cp "))) {
> -              printf("line: %s too long", line);
> -              if (fclose(f) != 0)
> -                printf("fclose failed: %i", errno);
> -              return;
> -            }
> -            line[strlen(line)] = '\0';
> -            strcat(cp_cmd, line);  // don't add newline
> -            strncat(cp_cmd, " /tmp/.", 80 - strlen(cp_cmd));
> -            rc = system(cp_cmd);
> +            // For gcc 8 warning message
> +            std::string cp_cmd = "cp ";
> +            line[strlen(line) -1] = '\0';  // Don't add new line
> +            cp_cmd += line;
> +            cp_cmd += " /tmp/.";
> +            rc = system(cp_cmd.c_str());
>             } else {
>               rc = -1;
>             }
> diff --git a/src/ntf/apitest/tet_ntf_common.cc 
> b/src/ntf/apitest/tet_ntf_common.cc
> index 6bb1ff72f..039f015b7 100644
> --- a/src/ntf/apitest/tet_ntf_common.cc
> +++ b/src/ntf/apitest/tet_ntf_common.cc
> @@ -1444,3 +1444,85 @@ void fprintf_p(FILE *f, const char *format, ...) {
>     va_end(argptr);
>     fflush(f);
>   }
> +
> +static void print_hex_ascii_line(const unsigned char *payload,
> +    int len, int offset) {
> +    int i;
> +    const unsigned char *ch;
> +
> +    // offset
> +    printf("%05d   ", offset);
> +
> +    // hex
> +    ch = payload;
> +    for (i = 0; i < len; ++i) {
> +        printf("%02x ", *ch);
> +        ++ch;
> +        // print extra space after 8th byte for visual aid
> +        if (i == 7)
> +            printf(" ");
> +    }
> +    // print space to handle line less than 8 bytes
> +    if (len < 8)
> +        printf(" ");
> +
> +    // fill hex gap with spaces if not full line
> +    if (len < 16) {
> +        int gap = 16 - len;
> +        for (i = 0; i < gap; ++i) {
> +            printf("   ");
> +        }
> +    }
> +    printf("   ");
> +
> +    // ascii (if printable)
> +    ch = payload;
> +    for (i = 0; i < len; ++i) {
> +        if (isprint(*ch))
> +            printf("%c", *ch);
> +        else
> +            printf(".");
> +        ++ch;
> +    }
> +
> +    printf("\n");
> +
> +    return;
> +}
> +
> +void print_mem(const unsigned char *mem, int len) {
> +    if (len <= 0 || !mem)
> +        return;
> +    const unsigned char *ch = mem;
> +
> +    // data fits on one line
> +    int line_width = 16;          // number of bytes per line
> +    int offset = 0;               // zero-based offset counter
> +    if (len <= line_width) {
> +        print_hex_ascii_line(ch, len, offset);
> +        return;
> +    }
> +
> +    // data spans multiple lines
> +    int len_rem = len;
> +    for ( ;; ) {
> +        // compute current line length
> +        int line_len = line_width % len_rem;
> +        // print line
> +        print_hex_ascii_line(ch, line_len, offset);
> +        // compute total remaining /
> +        len_rem = len_rem - line_len;
> +        // shift pointer to remaining bytes to print
> +        ch = ch + line_len;
> +        // add offset
> +        offset = offset + line_width;
> +        // check if we have line width chars or less
> +        if (len_rem <= line_width) {
> +            // print last line and get out
> +            print_hex_ascii_line(ch, len_rem, offset);
> +            break;
> +        }
> +    }
> +    return;
> +}
> +
> diff --git a/src/ntf/apitest/tet_ntf_common.h 
> b/src/ntf/apitest/tet_ntf_common.h
> index 7a8912aac..52d3bd4ba 100644
> --- a/src/ntf/apitest/tet_ntf_common.h
> +++ b/src/ntf/apitest/tet_ntf_common.h
> @@ -384,6 +384,8 @@ extern "C" {
>   
>   extern void saAisNameLend(SaConstStringT value, SaNameT *name);
>   extern SaConstStringT saAisNameBorrow(const SaNameT *name);
> +extern void print_mem(const unsigned char *mem, int len);
> +
>   
>   #ifdef  __cplusplus
>   }
> diff --git a/src/ntf/ntfimcnd/ntfimcn_common.c 
> b/src/ntf/ntfimcnd/ntfimcn_common.c
> new file mode 100755
> index 000000000..9eeb74490
> --- /dev/null
> +++ b/src/ntf/ntfimcnd/ntfimcn_common.c
> @@ -0,0 +1,221 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2013 The OpenSAF Foundation
[M] Year is 2020
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include "ntfimcn_common.h"
> +#include "osaf/immutil/immutil.h"
> +#include "ntfimcn_main.h"
> +#include "base/logtrace.h"
> +
> +extern ntfimcn_cb_t ntfimcn_cb; /* See ntfimcn_main.c */
> +
> +// cppcheck-suppress unusedFunction
> +SaAisErrorT get_current_attrs(const SaNameT *objectName,
> +    const SaImmAttrModificationT_2 **attrMods,
> +    SaImmAttrValuesT_2 ***curAttr)
> +{
> +  TRACE_ENTER();
> +  SaAisErrorT rc = SA_AIS_OK;
> +  // There is no new attribute modifications
> +  if (attrMods == NULL) {
> +    *curAttr = NULL;
> +    return SA_AIS_ERR_INVALID_PARAM;
> +  }
> +  int len;
> +  for (len = 0; attrMods[len] != NULL; ++len) ;
> +  SaImmAttrNameT *attrNames = calloc((len + 1), sizeof(SaImmAttrNameT));
> +  if (attrNames == NULL) {
> +    *curAttr = NULL;
> +    return SA_AIS_ERR_NO_MEMORY;
> +  }
> +  for (int i = 0; i < len; ++i) {
> +    attrNames[i] = attrMods[i]->modAttr.attrName;
> +  }
> +  attrNames[len] = NULL;
> +  // Get current attributes for the given attribute names
> +  SaImmAttrValuesT_2 **resAttr;
> +  rc = immutil_saImmOmAccessorGet_2(ntfimcn_cb.immAccessorHandle,
> +      objectName, attrNames, &resAttr);
> +  if (SA_AIS_OK == rc) {
> +     *curAttr = imm_attributes_cpy((const SaImmAttrValuesT_2**) resAttr);
> +  } else {
> +    TRACE("immutil_saImmOmAccessorGet_2 failed rc = %u", rc);
> +    *curAttr = NULL;
> +  }
> +  free(attrNames);
> +  TRACE_LEAVE2("rc = %u", rc);
> +  return rc;
> +}
> +
> +static size_t imm_attr_value_size(SaImmValueTypeT type)
> +{
> +  size_t valueSize = 0;
> +
> +  switch (type) {
> +  case SA_IMM_ATTR_SAINT32T:
> +    valueSize = sizeof(SaInt32T);
> +    break;
> +  case SA_IMM_ATTR_SAUINT32T:
> +    valueSize = sizeof(SaUint32T);
> +    break;
> +  case SA_IMM_ATTR_SAINT64T:
> +    valueSize = sizeof(SaInt64T);
> +    break;
> +  case SA_IMM_ATTR_SAUINT64T:
> +    valueSize = sizeof(SaUint64T);
> +    break;
> +  case SA_IMM_ATTR_SATIMET:
> +    valueSize = sizeof(SaTimeT);
> +    break;
> +  case SA_IMM_ATTR_SANAMET:
> +    valueSize = sizeof(SaNameT);
> +    break;
> +  case SA_IMM_ATTR_SAFLOATT:
> +    valueSize = sizeof(SaFloatT);
> +    break;
> +  case SA_IMM_ATTR_SADOUBLET:
> +    valueSize = sizeof(SaDoubleT);
> +    break;
> +  case SA_IMM_ATTR_SASTRINGT:
> +    valueSize = sizeof(SaStringT);
> +    break;
> +  case SA_IMM_ATTR_SAANYT:
> +    valueSize = sizeof(SaAnyT);
> +    break;
> +  }
> +  return valueSize;
> +
> +}
> +
> +static void imm_attr_cpy(SaImmAttrValuesT_2 **dest,
> +    const SaImmAttrValuesT_2 *src)
> +{
> +  SaImmAttrValuesT_2 *tdest =
> +      (SaImmAttrValuesT_2*) calloc(1, sizeof(SaImmAttrValuesT_2));
> +  tdest->attrName = strdup(src->attrName);
> +
> +  tdest->attrValueType = src->attrValueType;
> +  tdest->attrValuesNumber = src->attrValuesNumber;
> +  SaUint32T count = src->attrValuesNumber;
> +  size_t valSize = imm_attr_value_size(src->attrValueType);
> +  if (src->attrValues == NULL) {
> +     *dest = tdest;
> +    return;
> +  }
> +  tdest->attrValues = (SaImmAttrValueT*) malloc(
> +      sizeof(SaImmAttrValueT) * count);
> +
> +  for (unsigned int i = 0; i < count; ++i) {
> +    if (src->attrValues[i] == NULL) {
> +      tdest->attrValues[i] = NULL;
> +      continue;
> +    }
> +    tdest->attrValues[i] = malloc(valSize);
> +    switch (src->attrValueType) {
> +    case SA_IMM_ATTR_SASTRINGT: {
> +      *((SaStringT*) tdest->attrValues[i]) =
> +          strdup(*((SaStringT*) src->attrValues[i]));
> +      break;
> +    }
> +    case SA_IMM_ATTR_SANAMET: {
> +      SaNameT* nameSrc = (SaNameT*) src->attrValues[i];
> +      SaNameT* nameDest = (SaNameT*) tdest->attrValues[i];
> +      osaf_extended_name_alloc(osaf_extended_name_borrow(nameSrc), nameDest);
> +      break;
> +    }
> +    case SA_IMM_ATTR_SAANYT: {
> +      SaAnyT *anySrc = (SaAnyT*) src->attrValues[i];
> +      SaAnyT *anyDest = (SaAnyT*) tdest->attrValues[i];
> +      anyDest->bufferSize = anySrc->bufferSize;
> +      if (anyDest->bufferSize) {
> +        anyDest->bufferAddr = (SaUint8T*) malloc(anyDest->bufferSize);
> +        memcpy(anyDest->bufferAddr, anySrc->bufferAddr, anyDest->bufferSize);
> +      }
> +      else {
> +        anyDest->bufferAddr = NULL;
> +      }
> +      break;
> +    }
> +    default:
> +      memcpy(tdest->attrValues[i], src->attrValues[i], valSize);
> +      break;
> +    }
> +  }
> +  *dest = tdest;
> +}
> +
> +SaImmAttrValuesT_2** imm_attributes_cpy(const SaImmAttrValuesT_2 **src)
> +{
> +  // Return if there is no source
> +  if (src == NULL) {
> +    TRACE("src is null");
> +    return NULL;
> +  }
> +  // Return if the source is just an array of NULL
> +  int len = 0;
> +  while (src[len] != NULL) ++len;
> +  if (!len) {
> +    TRACE("src length is null");
> +    return NULL;
> +  }
> +  SaImmAttrValuesT_2 **attr =
> +      (SaImmAttrValuesT_2**) malloc((len + 1) * sizeof(SaImmAttrValuesT_2*));
> +  if (attr == NULL) {
> +    TRACE("Failed to allocate memory");
> +    return NULL;
> +  }
> +  // Deep clone the source to destination
> +  for (int i = 0; i < len; ++i) {
> +    imm_attr_cpy(&attr[i], src[i]);
> +  }
> +  attr[len] = NULL;
> +  return attr;
> +}
> +
> +// cppcheck-suppress unusedFunction
> +void free_imm_attrs(SaImmAttrValuesT_2 **attrs)
> +{
> +  if (attrs == NULL)
> +    return;
> +  SaImmAttrValuesT_2 *attr;
> +  SaImmAttrValueT value;
> +  for (int i = 0; (attr = attrs[i]) != NULL; ++i) {
> +    free(attr->attrName);
> +    if (attr->attrValues == NULL) {
> +      continue;
> +    }
> +    for (unsigned int j = 0; j < attr->attrValuesNumber; ++j) {
> +      value = attr->attrValues[j];
> +      if (value == NULL) {
> +        continue;
> +      }
> +      if (attr->attrValueType == SA_IMM_ATTR_SASTRINGT) {
> +        free(*((SaStringT*) value));
> +      } else if (attr->attrValueType == SA_IMM_ATTR_SANAMET) {
> +        osaf_extended_name_free((SaNameT*) value);
> +      } else if (attr->attrValueType == SA_IMM_ATTR_SAANYT) {
> +        free(((SaAnyT*) value)->bufferAddr);
> +      }
> +      free(value);
> +    }
> +    free(attr->attrValues);
> +    free(attr);
> +  }
> +  free(attrs);
> +}
> diff --git a/src/ntf/ntfimcnd/ntfimcn_common.h 
> b/src/ntf/ntfimcnd/ntfimcn_common.h
> new file mode 100755
> index 000000000..fcc97507f
> --- /dev/null
> +++ b/src/ntf/ntfimcnd/ntfimcn_common.h
> @@ -0,0 +1,65 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2013 The OpenSAF Foundation
[M] Year is 2020
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#ifndef NTF_NTFIMCND_NTFIMCN_COMMON_H_
> +#define NTF_NTFIMCND_NTFIMCN_COMMON_H_
> +
> +#include <saNtf.h>
> +#include <saImmOi.h>
> +#include <saImmOm.h>
> +#include "base/osaf_extended_name.h"
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +
> +/**
> + * For a given array of IMM Attribute Modifications, fetch the
> + * corresponding current IMM Attribute Values. The return data
> + * curAttr is managed by IMM unless a copy is requested.
> + * Deep clone method is used to copy the returned IMM Attribute Values
> + *
> + * @param *objectName[in]
> + * @param **attrMods[in]
> + * @param ***curAttr[out]
> + * @param copy[in]
> + * @return SaAisErrorT
> + */
> +SaAisErrorT get_current_attrs(const SaNameT *objectName,
> +   const SaImmAttrModificationT_2 **attrMods, SaImmAttrValuesT_2 ***curAttr);
> +
> +/**
> + * Deep clone IMM Attribute Values
> + *
> + * @param **src[in]
> + */
> +SaImmAttrValuesT_2** imm_attributes_cpy(const SaImmAttrValuesT_2 **src);
> +
> +/**
> + * Deallocate memory used for deep cloning IMM Attribute Values
> + *
> + * @param **attrs[in]
> + */
> +void free_imm_attrs(SaImmAttrValuesT_2 **attrs);
> +
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif  // NTF_NTFIMCND_NTFIMCN_COMMON_H_
[M]: The content of new functions are mainly dealing with imm, they can 
go into the existing ntfimcn_imm module.
> diff --git a/src/ntf/ntfimcnd/ntfimcn_imm.c b/src/ntf/ntfimcnd/ntfimcn_imm.c
> index 3f2c1a873..84cdcafd0 100644
> --- a/src/ntf/ntfimcnd/ntfimcn_imm.c
> +++ b/src/ntf/ntfimcnd/ntfimcn_imm.c
> @@ -40,6 +40,7 @@
>   
>   #include "ntfimcn_main.h"
>   #include "ntfimcn_notifier.h"
> +#include "ntfimcn_common.h"
>   
>   /*
>    * Global variables
> @@ -289,6 +290,13 @@ static void free_ccb_data(CcbUtilCcbData_t *ccb_data) {
>                       osaf_extended_name_free(ccb_data->userData);
>                       free(ccb_data->userData);
>               }
> +             // Free userData in CcbUtilOperationData
> +             struct CcbUtilOperationData* oper_data =
> +                             ccb_data->operationListHead;
> +             for (; oper_data!= NULL; oper_data = oper_data->next) {
> +                     free_imm_attrs((SaImmAttrValuesT_2**)
> +                        oper_data->userData);
> +             }
>               ccbutil_deleteCcbData(ccb_data);
>       }
>   }
> @@ -565,6 +573,20 @@ saImmOiCcbObjectModifyCallback(SaImmOiHandleT 
> immOiHandle, SaImmOiCcbIdT ccbId,
>       SaNameT *invoker_name_ptr;
>       invoker_name_ptr = ccbUtilCcbData->userData;
>   
> +     /* Memorize the current attribute values with the modification */
> +     if (ccbId > 0) {
> +             struct CcbUtilOperationData *ccbOperData;
> +             ccbOperData = ccbUtilCcbData->operationListTail;
> +             SaImmAttrValuesT_2 **curAttr;
> +             rc = get_current_attrs(objectName, attrMods, &curAttr);
> +             if (SA_AIS_OK == rc) {
> +                     ccbOperData->userData = curAttr;
> +             } else {
> +                     ccbOperData->userData = NULL;
> +                     LOG_NO("Failed to get current attributes rc = %u", rc);
[M]: It's LOG_ER here, the rc is returned from get_current_attrs() but 
not SA_AIS_OK, is all from error case.
> +             }
> +     }
> +
>       if (ccbId == 0) {
>               /* Attribute change object create */
>               ccbUtilOperationData = ccbUtilCcbData->operationListHead;
> @@ -718,7 +740,6 @@ static void saImmOiCcbApplyCallback(SaImmOiHandleT 
> immOiHandle,
>   
>               case CCBUTIL_MODIFY:
>                       invoke_name_ptr = ccbUtilCcbData->userData;
> -
>                       /* send_object_modify_notification */
>                       internal_rc = ntfimcn_send_object_modify_notification(
>                           ccbUtilOperationData, invoke_name_ptr, ccbLast);
> @@ -727,12 +748,11 @@ static void saImmOiCcbApplyCallback(SaImmOiHandleT 
> immOiHandle,
>                                   "%s send_object_modify_notification %s 
> fail",
>                                   __FUNCTION__,
>                                   osaf_extended_name_borrow(
> -                                         &ccbUtilOperationData->objectName));
> +                                 &ccbUtilOperationData->objectName));
>                               goto done;
>                       }
>                       break;
>               }
> -
>               ccbUtilOperationData = ccbUtilOperationData->next;
>       }
>   
> @@ -912,6 +932,11 @@ int ntfimcn_imm_init(ntfimcn_cb_t *cb)
>       if (initializeImmOmHandle(&cb->immOmHandle) == false) {
>               internal_rc = NTFIMCN_INTERNAL_ERROR;
>       }
> +     cb->immAccessorHandle = 0;
> +     if (immutil_saImmOmAccessorInitialize(cb->immOmHandle,
> +             &cb->immAccessorHandle) == false) {
> +             internal_rc = NTFIMCN_INTERNAL_ERROR;
> +     }
>   
>   done:
>       TRACE_LEAVE();
> diff --git a/src/ntf/ntfimcnd/ntfimcn_main.h b/src/ntf/ntfimcnd/ntfimcn_main.h
> index de6b67664..1e12bbc80 100644
> --- a/src/ntf/ntfimcnd/ntfimcn_main.h
> +++ b/src/ntf/ntfimcnd/ntfimcn_main.h
> @@ -42,6 +42,8 @@ extern "C" {
>   typedef struct {
>     SaImmHandleT immOmHandle; /* Handle form IMM OM Initialize */
>     SaImmOiHandleT immOiHandle; /* Handle from IMM OI initialize */
> +  SaImmAccessorHandleT
> +       immAccessorHandle;  /* Handle from IMM Accessor Interface */
>     SaSelectionObjectT
>         immSelectionObject;  /* Selection Object to wait for IMM events */
>     SaNtfHandleT ntf_handle; /* Handle from NTF initialize */
> diff --git a/src/ntf/ntfimcnd/ntfimcn_notifier.c 
> b/src/ntf/ntfimcnd/ntfimcn_notifier.c
> index af1b6da7b..09300dd1e 100644
> --- a/src/ntf/ntfimcnd/ntfimcn_notifier.c
> +++ b/src/ntf/ntfimcnd/ntfimcn_notifier.c
> @@ -37,6 +37,8 @@
>   #include "base/osaf_extended_name.h"
>   
>   #include "ntfimcn_main.h"
> +#include "ntfimcn_common.h"
> +
>   
>   /* Release code, major version, minor version */
>   const SaVersionT kNtfVersion = {'A', 0x01, 0x01};
> @@ -44,6 +46,23 @@ const unsigned int sleep_delay_ms = 500;
>   const unsigned int max_waiting_time_ms = 7 * 1000;       /* 7 secs */
>   const unsigned int max_init_waiting_time_ms = 60 * 1000; /* 60 secs */
>   
> +static const SaImmAttrValuesT_2* find_attr_from_name(
> +   const SaImmAttrValuesT_2** attrs, SaImmAttrNameT name)
> +{
> +     const SaImmAttrValuesT_2* result = NULL;
> +     if (!attrs)
> +             return result;
> +
> +     const SaImmAttrValuesT_2* attr = NULL;
> +     for (int i = 0; (attr = attrs[i]) != NULL; ++i) {
> +             if (strcmp(attr->attrName, name) == 0) {
> +                     result = attr;
> +                     break;
> +             }
> +     }
> +     return result;
> +}
> +
[M] This find_attr_from_name() is IMM utility function, should it go 
with get_current_attrs()/imm_attributes_cpy()/free_imm_attrs into 
ntfimcn_common or ntfimcn_imm
>   /*
>    * Global variables
>    */
> @@ -245,6 +264,124 @@ done:
>       return internal_rc;
>   }
>   
> +
> +#if 0
> +
> +/**
> + * Fill in the old attribute value.
> + * Refer to fill_attribute_value() for detailed description of parameters.
> + * For each new attribute filled in by fill_attribute_value(),
> + * if the old attribute value exist, it will be filled in by this
> + * function.
> + * The old attribute value has the same attribute type and attribute Id
> + * as the new attribute.
> + *
> + * @param notificationHandle[in]
> + * @param attrValueType_in[in]
> + * @param *attrValues_in[in]
> + * @param attrValues_index_in[in]
> + * @param *value_out[out]
> + *
> + * @return (-1) on error
> + */
> +static int fill_old_attribute_value(
> +         SaNtfNotificationHandleT notificationHandle,
> +         SaImmValueTypeT attrValueType_in,
> +         SaImmAttrValueT *attrValues_in,
> +         SaUint32T attrValues_index_in,
> +         SaNtfValueT *value_out)
> +{
> +     int internal_rc = 0;
> +     SaSizeT str_len = 0;
> +     SaAnyT any_value;
> +     SaNameT name_value;
> +
> +     TRACE_ENTER();
> +
> +     /* Insert value dependent on type.
> +      * For possible types see SaImmValueTypeT */
> +     switch (attrValueType_in) {
> +     case SA_IMM_ATTR_SAINT32T:
> +             value_out->int32Val =
> +                 *((SaInt32T *)attrValues_in[attrValues_index_in]);
> +             break;
> +     case SA_IMM_ATTR_SAUINT32T:
> +             value_out->uint32Val =
> +                 *((SaUint32T *)attrValues_in[attrValues_index_in]);
> +             break;
> +     case SA_IMM_ATTR_SATIMET: /* SaTimeT (SaInt64T) */
> +     case SA_IMM_ATTR_SAINT64T:
> +             value_out->int64Val =
> +                 *((SaInt64T *)attrValues_in[attrValues_index_in]);
> +             break;
> +     case SA_IMM_ATTR_SAUINT64T:
> +             value_out->uint64Val =
> +                 *((SaUint64T *)attrValues_in[attrValues_index_in]);
> +             break;
> +     case SA_IMM_ATTR_SAFLOATT:
> +             value_out->floatVal =
> +                 *((SaFloatT *)attrValues_in[attrValues_index_in]);
> +             break;
> +     case SA_IMM_ATTR_SADOUBLET:
> +             value_out->doubleVal =
> +                 *((SaDoubleT *)attrValues_in[attrValues_index_in]);
> +             break;
> +
> +     case SA_IMM_ATTR_SANAMET: /* SaNameT */
> +             name_value = *(SaNameT *)attrValues_in[attrValues_index_in];
> +             str_len = strlen(osaf_extended_name_borrow(&name_value));
> +             if (str_len == 0) ++str_len;
> +             internal_rc = fill_value_array(
> +                 notificationHandle,
> +                 (SaUint8T *)osaf_extended_name_borrow(&name_value),
> +                 str_len, value_out);
> +             if (internal_rc != 0) {
> +                     LOG_ER("%s: fill_value_array failed", __FUNCTION__);
> +                     goto done;
> +             }
> +             break;
> +
> +     case SA_IMM_ATTR_SASTRINGT:
> +             str_len =
> +                 strlen(*(SaStringT *)attrValues_in[attrValues_index_in]) +
> +                 1;
> +
> +             internal_rc = fill_value_array(
> +                 notificationHandle,
> +                 *(SaUint8T **)attrValues_in[attrValues_index_in], str_len,
> +                 value_out);
> +             if (internal_rc != 0) {
> +                     LOG_ER("%s: fill_value_array failed", __FUNCTION__);
> +                     goto done;
> +             }
> +             break;
> +
> +     case SA_IMM_ATTR_SAANYT: /* SaAnyT, SA_NTF_VALUE_BINARY */
> +             any_value = *(SaAnyT *)attrValues_in[attrValues_index_in];
> +             internal_rc = fill_value_array(notificationHandle,
> +                                            (SaUint8T *)any_value.bufferAddr,
> +                                            any_value.bufferSize, value_out);
> +             if (internal_rc != 0) {
> +                     LOG_ER("%s: fill_value_array failed", __FUNCTION__);
> +                     goto done;
> +             }
> +             break;
> +
> +     default:
> +             LOG_ER("%s Invalid attributeType %d", __FUNCTION__,
> +                    attrValueType_in);
> +             internal_rc = (-1);
> +             break;
> +     }
> +
> +done:
> +     TRACE_LEAVE();
> +     return internal_rc;
> +}
> +
> +
> +#endif
> +
[M] The fill_old_attribute_value is not used, please remove it.
>   /**
>    * Fill in the attribute value and type. The value can be of
>    * different types and may also be a multi-value which is an array of values
> @@ -747,7 +884,8 @@ done:
>    */
>   static int fill_attribute_info_modify(
>       SaImmOiCcbIdT CcbId, SaConstStringT invoke_name,
> -    const SaImmAttrModificationT_2 **imm_attr_mods_in,
> +    const SaImmAttrModificationT_2 **imm_attr_mods_in, // New attributes
> +    const SaImmAttrValuesT_2** userData,       // Old attributes if exist
>       SaNtfAttributeChangeNotificationT *SaNtfAttributeChangeNotification,
>       SaBoolT ccbLast)
>   {
> @@ -792,6 +930,7 @@ static int fill_attribute_info_modify(
>                       }
>   
>                       /* Fill Corresponding Attribute Value */
> +                     /* The old value exists in IMM but not populated */
>                       changedAttributes = &SaNtfAttributeChangeNotification
>                                                ->changedAttributes[1];
>                       changedAttributes->oldAttributePresent = SA_FALSE;
> @@ -810,7 +949,6 @@ static int fill_attribute_info_modify(
>                                      __FUNCTION__);
>                               goto done;
>                       }
> -
>               } else if (strcmp(imm_attr_mods->modAttr.attrName,
>                                 NTFIMCN_IMPLEMENTER_NAME) == 0) {
>                       /* Do not handle here since it is handled separately.
> @@ -834,6 +972,14 @@ static int fill_attribute_info_modify(
>                               goto done;
>                       }
>   
> +                     // Get old attribute values corresponding to the
> +                     // new attributes below. Can be multi value or
> +                     // no value
> +                     const SaImmAttrValuesT_2* old_imm_attr_value =
> +                        find_attr_from_name(userData,
> +                          imm_attr_mods->modAttr.attrName);
> +                     TRACE("old_imm_attr_value is <%s>",
> +                                     old_imm_attr_value? "not null": "null");
>                       /* Fill Corresponding Attribute Value
>                        * Can be a multi value or no value.
>                        */
> @@ -863,6 +1009,31 @@ static int fill_attribute_info_modify(
>                                           __FUNCTION__);
>                                       goto done;
>                               }
> +                             // There can be more new attribute values than
> +                             // old attribute values
> +                             if (old_imm_attr_value &&
> +                                (vindex < old_imm_attr_value
> +                                 ->attrValuesNumber)) {
> +                                     changedAttributes->oldAttributePresent =
> +                                        SA_TRUE;
> +                                     internal_rc = fill_attribute_value(
> +                                       SaNtfAttributeChangeNotification
> +                                       ->notificationHandle,
> +                                       imm_attr_mods->modAttr.attrValueType,
> +                                       old_imm_attr_value->attrValues,
> +                                       vindex,  /* Index of attrValues in */
> +                                       add_index, /* Attribute Id */
> +                                       &changedAttributes->attributeId,
> +                                       &changedAttributes->attributeType,
> +                                       &changedAttributes
> +                                       ->oldAttributeValue);
> +                                     if (internal_rc != 0) {
> +                                        LOG_ER(
> +                                        "%s: fill_attribute_value failed",
> +                                        __FUNCTION__);
> +                                             goto done;
> +                                     }
> +                             }
>                       }
>   
>                       var_index += vindex;
> @@ -900,6 +1071,7 @@ static int fill_attribute_info_modify(
>       }
>   
>       /* Fill Corresponding Attribute Value */
> +     /* The old value exists in IMM but not populated */
>       changedAttributes =
>           &SaNtfAttributeChangeNotification->changedAttributes[0];
>       changedAttributes->oldAttributePresent = SA_FALSE;
> @@ -937,7 +1109,6 @@ static int fill_attribute_info_modify(
>               /* Fill Corresponding Attribute Value */
>               changedAttributes =
>                   &SaNtfAttributeChangeNotification->changedAttributes[2];
> -             changedAttributes->oldAttributePresent = SA_FALSE;
>               internal_rc = fill_attribute_value(
>                   SaNtfAttributeChangeNotification->notificationHandle,
>                   my_imm_attr_mod.modAttr.attrValueType,
> @@ -951,6 +1122,26 @@ static int fill_attribute_info_modify(
>                       LOG_ER("%s: fill_attribute_value failed", __FUNCTION__);
>                       goto done;
>               }
> +             if (userData) {
> +                     changedAttributes->oldAttributePresent = SA_TRUE;
> +                     internal_rc = fill_attribute_value(
> +                        SaNtfAttributeChangeNotification
> +                        ->notificationHandle,
> +                        my_imm_attr_mod.modAttr.attrValueType,
> +                        my_imm_attr_mod.modAttr.attrValues,
> +                        0,    /* Index of attrValues in */
> +                        2, /* Attribute Id */
> +                        &changedAttributes->attributeId,
> +                        &changedAttributes->attributeType,
> +                        &changedAttributes->oldAttributeValue);
> +                     if (internal_rc != 0) {
> +                        LOG_ER("%s: fill_attribute_value failed",
> +                        __FUNCTION__);
> +                        goto done;
> +                     }
> +             } else {
> +                     changedAttributes->oldAttributePresent = SA_FALSE;
> +             }
[M] Id=2, do we need oldValue for this special attribute?
>       }
>   
>       /* Id 3: ccbLast
> @@ -975,7 +1166,6 @@ static int fill_attribute_info_modify(
>               /* Fill Corresponding Attribute Value */
>               changedAttributes =
>                   &SaNtfAttributeChangeNotification->changedAttributes[3];
> -             changedAttributes->oldAttributePresent = SA_FALSE;
>               internal_rc = fill_attribute_value(
>                   SaNtfAttributeChangeNotification->notificationHandle,
>                   my_imm_attr_mod.modAttr.attrValueType,
> @@ -989,6 +1179,26 @@ static int fill_attribute_info_modify(
>                       LOG_ER("%s: fill_attribute_value failed", __FUNCTION__);
>                       goto done;
>               }
> +             if (userData) {
> +                     changedAttributes->oldAttributePresent = SA_TRUE;
> +                     internal_rc = fill_attribute_value(
> +                         SaNtfAttributeChangeNotification
> +                         ->notificationHandle,
> +                         my_imm_attr_mod.modAttr.attrValueType,
> +                         my_imm_attr_mod.modAttr.attrValues,
> +                         0,  /* Index of attrValues in */
> +                         3,  /* Attribute Id */
> +                         &changedAttributes->attributeId,
> +                         &changedAttributes->attributeType,
> +                         &changedAttributes->oldAttributeValue);
> +                     if (internal_rc != 0) {
> +                             LOG_ER("%s: fill_attribute_value failed",
> +                                __FUNCTION__);
> +                             goto done;
> +                     }
> +             } else {
> +                     changedAttributes->oldAttributePresent = SA_FALSE;
> +             }
[M] Id=3, do we need oldValue for this special attribute?
>       }
>   
>   done:
> @@ -1391,6 +1601,7 @@ int ntfimcn_send_object_modify_notification(
>        */
>       internal_rc = fill_attribute_info_modify(
>           CcbId, invoke_name_str, CcbUtilOperationData->param.modify.attrMods,
> +         (const SaImmAttrValuesT_2**) CcbUtilOperationData->userData,
>           &SaNtfAttributeChangeNotification, ccbLast);
>       if (internal_rc != 0) {
>               LOG_ER("%s: ntfimcn_fill_attribute_info failed", __FUNCTION__);

_______________________________________________
Opensaf-devel mailing list
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to