signed evse_cm_slac_match (struct session * session, struct channel * channel, struct message * message)

{
	struct cm_slac_match_request * request = (struct cm_slac_match_request *) (message);
	struct cm_slac_match_confirm * confirm = (struct cm_slac_match_confirm *) (message);
	while (readmessage (channel, message, HOMEPLUG_MMV, (CM_SLAC_MATCH | MMTYPE_REQ)) > 0)
	{
		if (! memcmp (session->RunID, request->MatchVarField.RunID, sizeof (session->RunID)))
		{
			slac_debug (session, 0, __func__, "<-- CM_SLAC_MATCH.REQ");
			memcpy (session->PEV_ID, request->MatchVarField.PEV_ID, sizeof (session->PEV_ID));
			memcpy (session->PEV_MAC, request->MatchVarField.PEV_MAC, sizeof (session->PEV_MAC));
			memcpy (session->RunID, request->MatchVarField.RunID, sizeof (session->RunID));

#if SLAC_DEBUG

			if (_anyset (session->flags, SLAC_VERBOSE))
			{
				char string [256];
				slac_debug (session, 0, __func__, "CM_SLAC_MATCH.REQ.APPLICATION_TYPE %d", request->APPLICATION_TYPE);
				slac_debug (session, 0, __func__, "CM_SLAC_MATCH.REQ.SECURITY_TYPE %d", request->SECURITY_TYPE);
				slac_debug (session, 0, __func__, "CM_SLAC_MATCH.REQ.MVFLength %d", LE16TOH (request->MVFLength));
				slac_debug (session, 0, __func__, "CM_SLAC_MATCH.REQ.PEV_ID %s", HEXSTRING (string, request->MatchVarField.PEV_ID));
				slac_debug (session, 0, __func__, "CM_SLAC_MATCH.REQ.PEV_MAC %s", HEXSTRING (string, request->MatchVarField.PEV_MAC));
				slac_debug (session, 0, __func__, "CM_SLAC_MATCH.REQ.EVSE_ID %s", HEXSTRING (string, request->MatchVarField.EVSE_ID));
				slac_debug (session, 0, __func__, "CM_SLAC_MATCH.REQ.EVSE_MAC %s", HEXSTRING (string, request->MatchVarField.EVSE_MAC));
				slac_debug (session, 0, __func__, "CM_SLAC_MATCH.REQ.RunID %s", HEXSTRING (string, request->MatchVarField.RunID));
			}

#endif

			slac_debug (session, 0, __func__, "--> CM_SLAC_MATCH.CNF");
			memset (message, 0, sizeof (* message));
			EthernetHeader (& confirm->ethernet, session->PEV_MAC, channel->host, channel->type);
			HomePlugHeader1 (& confirm->homeplug, HOMEPLUG_MMV, (CM_SLAC_MATCH | MMTYPE_CNF));
			confirm->APPLICATION_TYPE = session->APPLICATION_TYPE;
			confirm->SECURITY_TYPE = session->SECURITY_TYPE;
			confirm->MVFLength = HTOLE16 (sizeof (confirm->MatchVarField));
			memcpy (confirm->MatchVarField.PEV_ID, session->PEV_ID, sizeof (confirm->MatchVarField.PEV_ID));
			memcpy (confirm->MatchVarField.PEV_MAC, session->PEV_MAC, sizeof (confirm->MatchVarField.PEV_MAC));
			memcpy (confirm->MatchVarField.EVSE_ID, session->EVSE_ID, sizeof (confirm->MatchVarField.EVSE_ID));
			memcpy (confirm->MatchVarField.EVSE_MAC, session->EVSE_MAC, sizeof (confirm->MatchVarField.EVSE_MAC));
			memcpy (confirm->MatchVarField.RunID, session->RunID, sizeof (confirm->MatchVarField.RunID));
			memcpy (confirm->MatchVarField.NID, session->NID, sizeof (confirm->MatchVarField.NID));
			memcpy (confirm->MatchVarField.NMK, session->NMK, sizeof (confirm->MatchVarField.NMK));
			if (sendmessage (channel, message, sizeof (* confirm)) <= 0)
			{
				return (slac_debug (session, 1, __func__, CHANNEL_CANTSEND));
			}
			return (0);
		}
	}
	return (slac_debug (session, session->exit, __func__, "<-- CM_SLAC_MATCH.REQ ?"));
}
signed evse_cm_atten_char (struct session * session, struct channel * channel, struct message * message)

{
	struct cm_atten_char_indicate * indicate = (struct cm_atten_char_indicate *) (message);
	struct cm_atten_char_response * response = (struct cm_atten_char_response *) (message);
	slac_debug (session, 0, __func__, "--> CM_ATTEN_CHAR.IND");
	memset (message, 0, sizeof (* message));
	EthernetHeader (& indicate->ethernet, session->PEV_MAC, channel->host, channel->type);
	HomePlugHeader1 (& indicate->homeplug, HOMEPLUG_MMV, (CM_ATTEN_CHAR | MMTYPE_IND));
	indicate->APPLICATION_TYPE = session->APPLICATION_TYPE;
	indicate->SECURITY_TYPE = session->SECURITY_TYPE;
	memcpy (indicate->ACVarField.SOURCE_ADDRESS, session->PEV_MAC, sizeof (indicate->ACVarField.SOURCE_ADDRESS));
	memcpy (indicate->ACVarField.RunID, session->RunID, sizeof (indicate->ACVarField.RunID));
	memset (indicate->ACVarField.SOURCE_ID, 0, sizeof (indicate->ACVarField.SOURCE_ID));
	memset (indicate->ACVarField.RESP_ID, 0, sizeof (indicate->ACVarField.RESP_ID));
	indicate->ACVarField.NUM_SOUNDS = session->sounds;
	indicate->ACVarField.ATTEN_PROFILE.NumGroups = session->NumGroups;
	memcpy (indicate->ACVarField.ATTEN_PROFILE.AAG, session->AAG, session->NumGroups);
	if (sendmessage (channel, message, sizeof (* indicate)) <= 0)
	{
		return (slac_debug (session, 1, __func__, CHANNEL_CANTSEND));
	}
	if (readmessage (channel, message, HOMEPLUG_MMV, (CM_ATTEN_CHAR | MMTYPE_RSP)) > 0)
	{
		if (! memcmp (session->RunID, response->ACVarField.RunID, sizeof (session->RunID)))
		{
			slac_debug (session, 0, __func__, "<-- CM_ATTEN_CHAR.RSP");

#if SLAC_DEBUG

			if (_anyset (session->flags, SLAC_VERBOSE))
			{
				char string [256];
				slac_debug (session, 0, __func__, "CM_ATTEN_CHAR.RSP.APPLICATION_TYPE %d", response->APPLICATION_TYPE);
				slac_debug (session, 0, __func__, "CM_ATTEN_CHAR.RSP.SECURITY_TYPE %d", response->SECURITY_TYPE);
				slac_debug (session, 0, __func__, "CM_ATTEN_CHAR.RSP.ACVarfield.SOURCE_ADDRESS %s", HEXSTRING (string, response->ACVarField.SOURCE_ADDRESS));
				slac_debug (session, 0, __func__, "CM_ATTEN_CHAR.RSP.ACVarFIeld.RunID %s", HEXSTRING (string, response->ACVarField.RunID));
				slac_debug (session, 0, __func__, "CM_ATTEN_CHAR.RSP.ACVarField.SOURCE_ID %s", HEXSTRING (string, response->ACVarField.SOURCE_ID));
				slac_debug (session, 0, __func__, "CM_ATTEN_CHAR.RSP.ACVarField.RESP_ID %s", HEXSTRING (string, response->ACVarField.RESP_ID));
				slac_debug (session, 0, __func__, "CM_ATTEN_CHAR.RSP.ACVarField.Result %d", response->ACVarField.Result);
			}

#endif

			return (0);
		}
	}
	return (slac_debug (session, session->exit, __func__, "<-- CM_ATTEN_CHAR.RSP ?"));
}
signed pev_cm_slac_param (struct session * session, struct channel * channel, struct message * message) 

{ 
	extern byte const broadcast [ETHER_ADDR_LEN]; 
	struct cm_slac_param_request * request = (struct cm_slac_param_request *) (message); 
	struct cm_slac_param_confirm * confirm = (struct cm_slac_param_confirm *) (message); 
	slac_debug (session, 0, __func__, "--> CM_SLAC_PARAM.REQ"); 
	memset (message, 0, sizeof (* message)); 
	EthernetHeader (& request->ethernet, broadcast, channel->host, channel->type); 
	HomePlugHeader1 (& request->homeplug, HOMEPLUG_MMV, (CM_SLAC_PARAM | MMTYPE_REQ)); 
	request->APPLICATION_TYPE = session->APPLICATION_TYPE; 
	request->SECURITY_TYPE = session->SECURITY_TYPE; 
	memcpy (request->RunID, session->RunID, sizeof (request->RunID)); 
	request->CipherSuite [0] = HTOLE16 ((uint16_t) (session->counter)); 
	if (sendmessage (channel, message, (ETHER_MIN_LEN - ETHER_CRC_LEN)) <= 0) 
	{ 
		return (slac_debug (session, 1, __func__, CHANNEL_CANTSEND)); 
	} 
	while (readmessage (channel, message, HOMEPLUG_MMV, (CM_SLAC_PARAM | MMTYPE_CNF)) > 0) 
	{ 
		if (! memcmp (session->RunID, confirm->RunID, sizeof (session->RunID))) 
		{ 
			slac_debug (session, 0, __func__, "<-- CM_SLAC_PARAM.CNF"); 
			if (confirm->APPLICATION_TYPE != session->APPLICATION_TYPE) 
			{ 
				slac_debug (session, session->exit, __func__, "Unexpected APPLICATION_TYPE"); 
			} 
			if (confirm->SECURITY_TYPE != session->SECURITY_TYPE) 
			{ 
				slac_debug (session, session->exit, __func__, "Unexpected SECURITY_TYPE"); 
			} 
			if (_anyset (session->flags, SLAC_COMPARE)) 
			{ 
				if (LE16TOH (confirm->CipherSuite) != (uint16_t) (session->counter)) 
				{ 
					slac_debug (session, session->exit, __func__, "session->counter mismatch! PEV=(%d) EVSE=(%d)", LE16TOH (confirm->CipherSuite), session->counter); 
				} 
			} 

#if SLAC_DEBUG

			if (_anyset (session->flags, SLAC_VERBOSE)) 
			{ 
				char string [256]; 
				slac_debug (session, 0, __func__, "CM_SLAC_PARAM.CNF.MSOUND_TARGET %s", HEXSTRING (string, confirm->MSOUND_TARGET)); 
				slac_debug (session, 0, __func__, "CM_SLAC_PARAM.CNF.NUM_SOUNDS %d", confirm->NUM_SOUNDS); 
				slac_debug (session, 0, __func__, "CM_SLAC_PARAM.CNF.TIME_OUT %d", confirm->TIME_OUT); 
				slac_debug (session, 0, __func__, "CM_SLAC_PARAM.CNF.RESP_TYPE %d", confirm->RESP_TYPE); 
				slac_debug (session, 0, __func__, "CM_SLAC_PARAM.CNF.FORWARDING_STA %s", HEXSTRING (string, confirm->FORWARDING_STA)); 
				slac_debug (session, 0, __func__, "CM_SLAC_PARAM.CNF.APPLICATION_TYPE %d", confirm->APPLICATION_TYPE); 
				slac_debug (session, 0, __func__, "CM_SLAC_PARAM.CNF.SECURITY_TYPE %d", confirm->SECURITY_TYPE); 
				slac_debug (session, 0, __func__, "CM_SLAC_PARAM.CNF.RunID %s", HEXSTRING (string, confirm->RunID)); 
				slac_debug (session, 0, __func__, "CM_SLAC_PARAM.CNF.CipherSuite %d", confirm->CipherSuite); 
			} 

#endif

			memcpy (session->FORWARDING_STA, confirm->FORWARDING_STA, sizeof (session->FORWARDING_STA)); 
			memcpy (session->MSOUND_TARGET, confirm->MSOUND_TARGET, sizeof (session->MSOUND_TARGET)); 
			session->NUM_SOUNDS = confirm->NUM_SOUNDS; 
			session->TIME_OUT = confirm->TIME_OUT; 
			session->RESP_TYPE = confirm->RESP_TYPE; 
			return (0); 
		} 
	} 
	return (slac_debug (session, 0, __func__, "<-- CM_SLAC_PARAM.CNF ?")); 
} 
signed pev_cm_set_key (struct session * session, struct channel * channel, struct message * message)

{

#ifndef __GNUC__
#pragma pack(push,1)
#endif

	struct __packed cm_set_key_request
	{
		struct ethernet_hdr ethernet;
		struct homeplug_fmi homeplug;
		uint8_t KEYTYPE;
		uint32_t MYNOUNCE;
		uint32_t YOURNOUNCE;
		uint8_t PID;
		uint16_t PRN;
		uint8_t PMN;
		uint8_t CCOCAP;
		uint8_t NID [SLAC_NID_LEN];
		uint8_t NEWEKS;
		uint8_t NEWKEY [SLAC_NMK_LEN];
		uint8_t RSVD [3];
	}
	* request = (struct cm_set_key_request *) (message);
	struct __packed cm_set_key_confirm
	{
		struct ethernet_hdr ethernet;
		struct homeplug_fmi homeplug;
		uint8_t RESULT;
		uint32_t MYNOUNCE;
		uint32_t YOURNOUNCE;
		uint8_t PID;
		uint16_t PRN;
		uint8_t PMN;
		uint8_t CCOCAP;
		uint8_t RSVD [27];
	}
	* confirm = (struct cm_set_key_confirm *) (message);

#ifndef __GNUC__
#pragma pack (pop)
#endif

	memset (message, 0, sizeof (* message));
	slac_debug (session, 0, __func__, "--> CM_SET_KEY.REQ");
	EthernetHeader (& request->ethernet, channel->peer, channel->host, channel->type);
	HomePlugHeader1 (& request->homeplug, HOMEPLUG_MMV, (CM_SET_KEY | MMTYPE_REQ));
	request->KEYTYPE = SLAC_CM_SETKEY_KEYTYPE;
	memset (& request->MYNOUNCE, 0xAA, sizeof (request->MYNOUNCE));
	memset (& request->YOURNOUNCE, 0x00, sizeof (request->YOURNOUNCE));
	request->PID = SLAC_CM_SETKEY_PID;
	request->PRN = HTOLE16 (SLAC_CM_SETKEY_PRN);
	request->PMN = SLAC_CM_SETKEY_PMN;
	request->CCOCAP = SLAC_CM_SETKEY_CCO;
	memcpy (request->NID, session->NID, sizeof (request->NID));
	request->NEWEKS = SLAC_CM_SETKEY_EKS;
	memcpy (request->NEWKEY, session->NMK, sizeof (request->NEWKEY));

#if SLAC_DEBUG

	if (_anyset (session->flags, SLAC_VERBOSE))
	{
		char string [1024];
		slac_debug (session, 0, __func__, "CM_SET_KEY.KEYTYPE %d", request->KEYTYPE);
		slac_debug (session, 0, __func__, "CM_SET_KEY.MYNOUNCE %s", hexstring (string, sizeof (string), & request->MYNOUNCE, sizeof (request->MYNOUNCE)));
		slac_debug (session, 0, __func__, "CM_SET_KEY.YOURNOUNCE %s", hexstring (string, sizeof (string), & request->YOURNOUNCE, sizeof (request->MYNOUNCE)));
		slac_debug (session, 0, __func__, "CM_SET_KEY.PID %d", request->PID);
		slac_debug (session, 0, __func__, "CM_SET_KEY.PRN %d", LE32TOH (request->PRN));
		slac_debug (session, 0, __func__, "CM_SET_KEY.PMN %d", request->PMN);
		slac_debug (session, 0, __func__, "CM_SET_KEY.CCoCAP %d", request->CCOCAP);
		slac_debug (session, 0, __func__, "CM_SET_KEY.NID %s", HEXSTRING (string, request->NID));
		slac_debug (session, 0, __func__, "CM_SET_KEY.NEWEKS %d", request->NEWEKS);
		slac_debug (session, 0, __func__, "CM_SET_KEY.NEWKEY %s", HEXSTRING (string, request->NEWKEY));
	}

#endif

	if (sendpacket (channel, request, sizeof (* request)) <= 0)
	{
		return (slac_debug (session, 1, __func__, CHANNEL_CANTSEND));
	}
	while (readpacket (channel, confirm, sizeof (* confirm)) > 0)
	{
		if (ntohs (confirm->ethernet.MTYPE) != ETH_P_HPAV)
		{
			slac_debug (session, session->exit, __func__, "Ignore MTYPE 0x%04X", htons (confirm->ethernet.MTYPE));
			continue;
		}
		if (confirm->homeplug.MMV != HOMEPLUG_MMV)
		{
			slac_debug (session, session->exit, __func__, "Ignore MMV 0x%02X", confirm->homeplug.MMV);
			continue;
		}
		if (LE32TOH (confirm->homeplug.MMTYPE) != (CM_SET_KEY | MMTYPE_CNF))
		{
			slac_debug (session, session->exit, __func__, "Ignore MMTYPE 0x%04X", LE32TOH (confirm->homeplug.MMTYPE));
			continue;
		}
		slac_debug (session, 0, __func__, "<-- CM_SET_KEY.CNF");
		if (! confirm->RESULT)
		{
			return (slac_debug (session, session->exit, __func__, "Can't set keys"));
		}

#if SLAC_DEBUG

		if (_anyset (session->flags, SLAC_VERBOSE))
		{
			char string [1024];
			slac_debug (session, 0, __func__, "CM_SET_KEY.RESULT %d", confirm->RESULT);
			slac_debug (session, 0, __func__, "CM_SET_KEY.MYNOUNCE %s", hexstring (string, sizeof (string), & confirm->MYNOUNCE, sizeof (confirm->MYNOUNCE)));
			slac_debug (session, 0, __func__, "CM_SET_KEY.YOURNOUNCE %s", hexstring (string, sizeof (string), & confirm->YOURNOUNCE, sizeof (confirm->MYNOUNCE)));
			slac_debug (session, 0, __func__, "CM_SET_KEY.PID %d", confirm->PID);
			slac_debug (session, 0, __func__, "CM_SET_KEY.PRN %d", LE32TOH (confirm->PRN));
			slac_debug (session, 0, __func__, "CM_SET_KEY.PMN %d", confirm->PMN);
			slac_debug (session, 0, __func__, "CM_SET_KEY.CCoCAP %d", confirm->CCOCAP);
		}

#endif

		return (0);
	}
	return (slac_debug (session, session->exit, __func__, "<-- CM_SET_KEY.CNF ?"));
}