/****************************************************************************
  Name          : avnd_evt_mds_avd_up
 
  Description   : This routine processes the AvD up event from MDS. It sends 
                  the node-up message to AvD. it also starts AvD supervision
		  we are on a controller and the up event is for our node.
 
  Arguments     : cb  - ptr to the AvND control block
                  evt - ptr to the AvND event
 
  Return Values : NCSCC_RC_SUCCESS/NCSCC_RC_FAILURE
 
  Notes         : None.
******************************************************************************/
uns32 avnd_evt_mds_avd_up_evh(AVND_CB *cb, AVND_EVT *evt)
{
	TRACE_ENTER2("%llx", evt->info.mds.mds_dest);
	
	/* Validate whether this is a ADEST or VDEST */
	if (m_MDS_DEST_IS_AN_ADEST(evt->info.mds.mds_dest)) {
		NCS_NODE_ID node_id, my_node_id = ncs_get_node_id();
		node_id = m_NCS_NODE_ID_FROM_MDS_DEST(evt->info.mds.mds_dest);

		if ((node_id == my_node_id) && (cb->type == AVSV_AVND_CARD_SYS_CON)) {
			TRACE("Starting hb supervision of local avd");
			avnd_stop_tmr(cb, &cb->hb_duration_tmr);
			avnd_start_tmr(cb, &cb->hb_duration_tmr,
				AVND_TMR_HB_DURATION, cb->hb_duration, 0);
		}
	} else {
		/* Avd is already UP, reboot the node */
		if (m_AVND_CB_IS_AVD_UP(cb)) {
                        opensaf_reboot(avnd_cb->node_info.nodeId, (char *)avnd_cb->node_info.executionEnvironment.value,
                                        "AVD already up");
			goto done;
		}

		m_AVND_CB_AVD_UP_SET(cb);

		/* store the AVD MDS address */
		cb->avd_dest = evt->info.mds.mds_dest;

		avnd_send_node_up_msg();
	}

done:
	TRACE_LEAVE();
	return NCSCC_RC_SUCCESS;
}
/**
 * Initialize the RDE server.
 * 
 * @return int, 0=OK
 */
static int initialize_rde(void)
{
	RDE_RDA_CB *rde_rda_cb = &rde_cb->rde_rda_cb;
	int rc = NCSCC_RC_FAILURE;
	char *val;

	/* Determine how this process was started, by NID or AMF */
	if (getenv("SA_AMF_COMPONENT_NAME") == NULL)
		rde_cb->rde_amf_cb.nid_started = true;

	if ((val = getenv("RDE_DISCOVER_PEER_TIMEOUT")) != NULL)
		discover_peer_timeout = strtoul(val, NULL, 0);

	TRACE("discover_peer_timeout=%d", discover_peer_timeout);

	if ((rc = ncs_core_agents_startup()) != NCSCC_RC_SUCCESS) {
		LOG_ER("ncs_core_agents_startup FAILED");
		goto init_failed;
	}

	if (rde_cb->rde_amf_cb.nid_started &&
		(rc = ncs_sel_obj_create(&usr1_sel_obj)) != NCSCC_RC_SUCCESS) {
		LOG_ER("ncs_sel_obj_create FAILED");
		goto init_failed;
	}

	if ((rc = ncs_ipc_create(&rde_cb->mbx)) != NCSCC_RC_SUCCESS) {
		LOG_ER("ncs_ipc_create FAILED");
		goto init_failed;
	}

	if ((rc = ncs_ipc_attach(&rde_cb->mbx)) != NCSCC_RC_SUCCESS) {
		LOG_ER("ncs_ipc_attach FAILED");
		goto init_failed;
	}

	rde_my_node_id = ncs_get_node_id();

	if ((rc = rde_rda_open(RDE_RDA_SOCK_NAME, rde_rda_cb)) != NCSCC_RC_SUCCESS)
		goto init_failed;

	if (rde_cb->rde_amf_cb.nid_started &&
		signal(SIGUSR1, sigusr1_handler) == SIG_ERR) {
		LOG_ER("signal USR1 FAILED: %s", strerror(errno));
		goto init_failed;
	}

	if (rde_mds_register(rde_cb) != NCSCC_RC_SUCCESS)
		goto init_failed;

	rc = NCSCC_RC_SUCCESS;

 init_failed:
	return rc;
}
uns32 rde_mds_register(RDE_CONTROL_BLOCK *cb)
{
	NCSADA_INFO ada_info;
	NCSMDS_INFO svc_info;
	MDS_SVC_ID svc_id[1] = { NCSMDS_SVC_ID_RDE };
	MDS_DEST mds_adest;

	TRACE_ENTER();

	ada_info.req = NCSADA_GET_HDLS;
	if (ncsada_api(&ada_info) != NCSCC_RC_SUCCESS) {
		LOG_ER("%s: NCSADA_GET_HDLS Failed", __FUNCTION__);
		return NCSCC_RC_FAILURE;
	}

	mds_hdl = ada_info.info.adest_get_hdls.o_mds_pwe1_hdl;
	mds_adest = ada_info.info.adest_get_hdls.o_adest;

	svc_info.i_mds_hdl = mds_hdl;
	svc_info.i_svc_id = NCSMDS_SVC_ID_RDE;
	svc_info.i_op = MDS_INSTALL;

	svc_info.info.svc_install.i_yr_svc_hdl = 0;
	svc_info.info.svc_install.i_install_scope = NCSMDS_SCOPE_NONE;	/*node specific */
	svc_info.info.svc_install.i_svc_cb = mds_callback;	/* callback */
	svc_info.info.svc_install.i_mds_q_ownership = FALSE;
	svc_info.info.svc_install.i_mds_svc_pvt_ver = RDE_MDS_PVT_SUBPART_VERSION;

	if (ncsmds_api(&svc_info) == NCSCC_RC_FAILURE) {
		LOG_ER("%s: MDS Install Failed", __FUNCTION__);
		return NCSCC_RC_FAILURE;
	}

	memset(&svc_info, 0, sizeof(NCSMDS_INFO));
	svc_info.i_mds_hdl = mds_hdl;
	svc_info.i_svc_id = NCSMDS_SVC_ID_RDE;
	svc_info.i_op = MDS_RED_SUBSCRIBE;
	svc_info.info.svc_subscribe.i_num_svcs = 1;
	svc_info.info.svc_subscribe.i_scope = NCSMDS_SCOPE_NONE;
	svc_info.info.svc_subscribe.i_svc_ids = svc_id;

	if (ncsmds_api(&svc_info) == NCSCC_RC_FAILURE) {
		LOG_ER("MDS Subscribe for redundancy Failed");
		return NCSCC_RC_FAILURE;
	}

	TRACE_LEAVE2("NodeId:%x, mds_adest:%llx", ncs_get_node_id(), mds_adest);

	return NCSCC_RC_SUCCESS;
}
/****************************************************************************
  Name          : avnd_mds_svc_evt
 
  Description   : This routine is invoked to inform AvND of MDS events. AvND 
                  had subscribed to these events during MDS registration.
 
  Arguments     : cb       - ptr to the AvND control block
                  evt_info - ptr to the MDS event info
 
  Return Values : NCSCC_RC_SUCCESS/NCSCC_RC_FAILURE
 
  Notes         : None.
******************************************************************************/
uns32 avnd_mds_svc_evt(AVND_CB *cb, MDS_CALLBACK_SVC_EVENT_INFO *evt_info)
{
	AVND_EVT *evt = 0;
	uns32 rc = NCSCC_RC_SUCCESS;

	/* assign mds-dest for AVD, AVND & AVA as per the MDS event */
	switch (evt_info->i_change) {
	case NCSMDS_UP:
		switch (evt_info->i_svc_id) {
		case NCSMDS_SVC_ID_AVD:
			/* create the mds event */
			evt = avnd_evt_create(cb, AVND_EVT_MDS_AVD_UP, 0, &evt_info->i_dest, 0, 0, 0);
			break;

		case NCSMDS_SVC_ID_AVA:
			/*  New AvA has come up. Dont do anything now */
			break;

		case NCSMDS_SVC_ID_AVND:
			/*  New AVND has come up. Update NODE_ID to MDS_DEST */
			/* Validate whether this is a ADEST or VDEST */
			if (!m_MDS_DEST_IS_AN_ADEST(evt_info->i_dest)) {
				return rc;
			}

			/* Create the mds event. 
			   if(evt_info->i_dest != cb->avnd_dest)
			   Store its own dest id also. This is useful in Proxy at Ctrl
			   registering external component.
			 */
			evt = avnd_evt_create(cb, AVND_EVT_MDS_AVND_UP, 0, &evt_info->i_dest, 0, 0, 0);
			break;

		case NCSMDS_SVC_ID_AVND_CNTLR:
			/* This is a VDEST. Store it for use in sending ext comp req
			   to this Vdest. This Vdest is of Contr AvND hosting ext comp. */
			/* Validate whether this is a ADEST or VDEST */
			if (m_MDS_DEST_IS_AN_ADEST(evt_info->i_dest)) {
				return rc;
			}
			cb->cntlr_avnd_vdest = evt_info->i_dest;
			return rc;
			break;

		default:
			assert(0);
		}
		break;

	case NCSMDS_DOWN:
		switch (evt_info->i_svc_id) {
		case NCSMDS_SVC_ID_AVD:
			/* Supervise our node local director */
			if (evt_info->i_node_id == ncs_get_node_id())
				opensaf_reboot(avnd_cb->node_info.nodeId, (char *)avnd_cb->node_info.executionEnvironment.value,
						"AMF director unexpectedly crasched");
			
			/* Validate whether this is a ADEST or VDEST */
			if (m_MDS_DEST_IS_AN_ADEST(evt_info->i_dest))
				return rc;
			
			/* reset the avd mds-dest */
			memset(&cb->avd_dest, 0, sizeof(MDS_DEST));
			
			/* create the mds event */
			evt = avnd_evt_create(cb, AVND_EVT_MDS_AVD_DN, 0, &evt_info->i_dest, 0, 0, 0);
			
			LOG_ER("Controller node not available");
			break;

		case NCSMDS_SVC_ID_AVA:
			/* create the mds event */
			evt = avnd_evt_create(cb, AVND_EVT_MDS_AVA_DN, 0, &evt_info->i_dest, 0, 0, 0);
			break;

		case NCSMDS_SVC_ID_AVND:
			/*  New AVND has come up. Update NODE_ID to MDS_DEST */
			/* Validate whether this is a ADEST or VDEST */
			if (!m_MDS_DEST_IS_AN_ADEST(evt_info->i_dest))
				return rc;

			/* Create the mds event. 
			   if(evt_info->i_dest != cb->avnd_dest)
			   Store its own dest id also. This is useful in Proxy at Ctrl
			   registering external component.
			 */
			evt = avnd_evt_create(cb, AVND_EVT_MDS_AVND_DN, 0, &evt_info->i_dest, 0, 0, 0);
			break;

		case NCSMDS_SVC_ID_AVND_CNTLR:
			break;

		default:
			assert(0);
		}
		break;

	default:
		break;
	}

	/* send the event */
	if (evt)
		rc = avnd_evt_send(cb, evt);

	/* if failure, free the event */
	if (NCSCC_RC_SUCCESS != rc && evt)
		avnd_evt_destroy(evt);

	return rc;
}