示例#1
0
static void UnmatchedState (struct session * session, struct channel * channel, struct message * message) 

{ 
	slac_session (session); 
	slac_debug (session, 0, __func__, "Sounding ..."); 
	if (evse_cm_start_atten_char (session, channel, message)) 
	{ 
		session->state = EVSE_STATE_UNOCCUPIED; 
		return; 
	} 
	if (evse_cm_mnbc_sound (session, channel, message)) 
	{ 
		session->state = EVSE_STATE_UNOCCUPIED; 
		return; 
	} 
	if (evse_cm_atten_char (session, channel, message)) 
	{ 
		session->state = EVSE_STATE_UNOCCUPIED; 
		return; 
	} 
	slac_debug (session, 0, __func__, "Matching ..."); 
	if (evse_cm_slac_match (session, channel, message)) 
	{ 
		session->state = EVSE_STATE_UNOCCUPIED; 
		return; 
	} 
	session->state = EVSE_STATE_MATCHED; 
	return; 
} 
示例#2
0
static void MatchedState (struct session * session, struct channel * channel, struct message * message) 

{ 
	slac_debug (session, 0, __func__, "Connecting ..."); 

#if SLAC_AVLN_EVSE

	if (evse_cm_set_key (session, channel, message)) 
	{ 
		session->state = EVSE_STATE_UNOCCUPIED; 
		return; 
	} 
	sleep (session->settletime); 

#endif
#if SLAC_AVLN_PEV

	slac_debug (session, 0, __func__, "waiting for pev to settle ..."); 
	sleep (session->settletime); 

#endif

	slac_debug (session, 0, __func__, "Charging (%d) ...\n\n", session->counter++); 
	sleep (session->chargetime); 
	slac_debug (session, 0, __func__, "Disconnecting ..."); 

#if SLAC_AVLN_EVSE

	memcpy (session->NMK, session->original_nmk, sizeof (session->NMK)); 
	memcpy (session->NID, session->original_nid, sizeof (session->NID)); 
	if (evse_cm_set_key (session, channel, message)) 
	{ 
		session->state = EVSE_STATE_UNOCCUPIED; 
		return; 
	} 
	sleep (session->settletime); 

#endif
#if SLAC_AVLN_PEV

	slac_debug (session, 0, __func__, "waiting for pev to settle ..."); 
	sleep (session->settletime); 

#endif

	session->state = EVSE_STATE_UNOCCUPIED; 
	return; 
} 
示例#3
0
static void UnoccupiedState (struct session * session, struct channel * channel, struct message * message) 

{ 
	slac_session (session); 
	slac_debug (session, 0, __func__, "Listening ..."); 
	while (evse_cm_slac_param (session, channel, message)); 
	session->state = EVSE_STATE_UNMATCHED; 
	return; 
} 
示例#4
0
signed slac_connect (struct session * session) 

{ 
	unsigned group = 0; 
	unsigned total = 0; 
	if (session->NumGroups > SIZEOF (session->AAG)) 
	{ 
		return (slac_debug (session, session->exit, __func__, "Too much data to analyse!")); 
	} 
	if (session->NumGroups > 0) 
	{ 
		char string [512]; 
		while (group < session->NumGroups) 
		{ 
			total += session->AAG [group]; 
			group++; 
		} 
		total /= group; 
		if (total > session->limit) 
		{ 
			char string [512]; 
			slac_debug (session, 0, __func__, "Average attenuation (%u) more than limit (%u) frow %d groups", total, session->limit, group); 
			slac_debug (session, 0, __func__, "%s", HEXSTRING (string, session->AAG)); 
			return (- 1); 
		} 
		if (total > 0) 
		{ 
			slac_debug (session, 0, __func__, "Average attenuation (%u) less than limit (%u) from %d groups", total, session->limit, group); 
			slac_debug (session, 0, __func__, "%s", HEXSTRING (string, session->AAG)); 
			return (0); 
		} 
	} 
	return (slac_debug (session, session->exit, __func__, "Nothing to analyse")); 
} 
signed evse_cm_mnbc_sound (struct session * session, struct channel * channel, struct message * message)

{
	struct timeval ts;
	struct timeval tc;
	signed timer = 100 * session->TIME_OUT;
	unsigned AAG [SLAC_GROUPS];
	unsigned sounds = 0;
	ssize_t length;
	session->sounds = 0;
	memset (AAG, 0, sizeof (AAG));
	memset (session->AAG, 0, sizeof (session->AAG));
	if (gettimeofday (& ts, NULL) == - 1)
	{
		slac_debug (session, 1, __func__, CANT_START_TIMER);
	}
	while ((length = readpacket (channel, message, sizeof (* message))) >= 0)
	{
		struct homeplug * homeplug = (struct homeplug *) (message);
		if (! length)
		{
		}
		else if (ntohs (homeplug->ethernet.MTYPE) != ETH_P_HPAV)
		{
			slac_debug (session, session->exit, __func__, "bad MTYPE");
		}
		else if (homeplug->homeplug.MMV != HOMEPLUG_MMV)
		{
			slac_debug (session, session->exit, __func__, "bad MMV");
		}
		else if (LE16TOH (homeplug->homeplug.MMTYPE) == (CM_MNBC_SOUND | MMTYPE_IND))
		{
			struct cm_mnbc_sound_indicate * indicate = (struct cm_mnbc_sound_indicate *) (message);
			if (! memcmp (session->RunID, indicate->MSVarField.RunID, sizeof (session->RunID)))
			{
				slac_debug (session, 0, __func__, "<-- CM_MNBC_SOUND.IND (%d)", sounds);

#if SLAC_DEBUG

				if (_anyset (session->flags, SLAC_VERBOSE))
				{
					char string [256];
					slac_debug (session, 0, __func__, "CM_MNBC_SOUND.IND.APPLICATION_TYPE %d", indicate->APPLICATION_TYPE);
					slac_debug (session, 0, __func__, "CM_MNBC_SOUND.IND.SECURITY_TYPE %d", indicate->SECURITY_TYPE);
					slac_debug (session, 0, __func__, "CM_MNBC_SOUND.IND.MSVarField.SenderID %s", HEXSTRING (string, indicate->MSVarField.SenderID));
					slac_debug (session, 0, __func__, "CM_MNBC_SOUND.IND.MSVarField.Count %d", indicate->MSVarField.CNT);
					slac_debug (session, 0, __func__, "CM_MNBC_SOUND.IND.MSVarField.RunID %s", HEXSTRING (string, indicate->MSVarField.RunID));
					slac_debug (session, 0, __func__, "CM_MNBC_SOUND.IND.MSVarField.RND %s", HEXSTRING (string, indicate->MSVarField.RND));
				}

#endif

				if (memcmp (session->PEV_MAC, indicate->ethernet.OSA, sizeof (session->PEV_MAC)))
				{
					slac_debug (session, session->exit, __func__, "Unexpected OSA");
				}
				sounds++;
			}
		}
		else if (LE16TOH (homeplug->homeplug.MMTYPE) == (CM_ATTEN_PROFILE | MMTYPE_IND))
		{
			struct cm_atten_profile_indicate * indicate = (struct cm_atten_profile_indicate *) (message);
			if (! memcmp (session->PEV_MAC, indicate->PEV_MAC, sizeof (session->PEV_MAC)))
			{
				slac_debug (session, 0, __func__, "<-- CM_ATTEN_PROFILE.IND (%d)", session->sounds);

#if SLAC_DEBUG

				if (_anyset (session->flags, SLAC_VERBOSE))
				{
					char string [256];
					slac_debug (session, 0, __func__, "CM_ATTEN_PROFILE.PEV_MAC %s", HEXSTRING (string, indicate->PEV_MAC));
					slac_debug (session, 0, __func__, "CM_ATTEN_PROFILE.NumGroups %d", indicate->NumGroups);
					slac_debug (session, 0, __func__, "CM_ATTEN_PROFILE.AAG %s", hexstring (string, sizeof (string), indicate->AAG, indicate->NumGroups));
				}

#endif

				for (session->NumGroups = 0; session->NumGroups < indicate->NumGroups; session->NumGroups++)
				{
					AAG [session->NumGroups] += indicate->AAG [session->NumGroups];
				}
				session->NumGroups = indicate->NumGroups;
				session->sounds++;
			}
		}
		if (gettimeofday (& tc, NULL) == - 1)
		{
			slac_debug (session, 1, __func__, CANT_RESET_TIMER);
		}
		if ((MILLISECONDS (ts, tc) < timer) && (session->sounds < session->NUM_SOUNDS))
		{
			continue;
		}
		if (session->sounds > 0)
		{
			for (session->NumGroups = 0; session->NumGroups < SLAC_GROUPS; ++ session->NumGroups)
			{
				session->AAG [session->NumGroups] = AAG [session->NumGroups] / session->sounds;
			}
		}
		return (0);
	}
	return (slac_debug (session, session->exit, __func__, "Sound timeout"));
}
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 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 ?"));
}
示例#8
0
int main (int argc, char const * argv []) 

{ 
	extern struct channel channel; 
	static char const * optv [] = 
	{ 
		"cCdi:p:qs:t:vx", 
		"", 
		"Qualcomm Atheros Electric Vehicle Supply Equipment Emulator", 
		"c\tprint template configuration file on stdout", 
		"C\tstop on count mismatch", 
		"d\tdisplay debug information", 

#if defined (WINPCAP) || defined (LIBPCAP)

		"i n\thost interface is (n) [" LITERAL (CHANNEL_ETHNUMBER) "]", 

#else

		"i s\thost interface is (s) [" LITERAL (CHANNEL_ETHDEVICE) "]", 

#endif

		"p s\tconfiguration profile is (s) [" LITERAL (PROFILE) "]", 
		"s s\tconfiguration section is (s) [" LITERAL (SECTION) "]", 
		"q\tquiet mode", 
		"t n\tread timeout is (n) milliseconds [" LITERAL (SLAC_TIMEOUT) "]", 
		"v\tverbose mode", 
		"x\texit on error", 
		(char const *) (0)
	}; 
	struct session session; 
	struct message message; 
	char const * profile = PROFILE; 
	char const * section = SECTION; 
	signed c; 
	memset (& session, 0, sizeof (session)); 
	memset (& message, 0, sizeof (message)); 
	channel.timeout = SLAC_TIMEOUT; 
	if (getenv (PLCDEVICE)) 
	{ 

#if defined (WINPCAP) || defined (LIBPCAP)

		channel.ifindex = atoi (getenv (PLCDEVICE)); 

#else

		channel.ifname = strdup (getenv (PLCDEVICE)); 

#endif

	} 
	optind = 1; 
	while (~ (c = getoptv (argc, argv, optv))) 
	{ 
		switch (c) 
		{ 
		case 'c': 
			configure (); 
			return (0); 
		case 'C': 
			_setbits (session.flags, SLAC_COMPARE); 
			break; 
		case 'd': 
			_setbits (session.flags, (SLAC_VERBOSE | SLAC_SESSION)); 
			break; 
		case 'i': 

#if defined (WINPCAP) || defined (LIBPCAP)

			channel.ifindex = atoi (optarg); 

#else

			channel.ifname = optarg; 

#endif

			break; 
		case 'p': 
			profile = optarg; 
			break; 
		case 's': 
			section = optarg; 
			break; 
		case 'q': 
			_setbits (channel.flags, CHANNEL_SILENCE);
			_setbits (session.flags, SLAC_SILENCE); 
			break; 
		case 't': 
			channel.timeout = (signed) (uintspec (optarg, 0, UINT_MAX)); 
			break; 
		case 'v': 
			_setbits (channel.flags, CHANNEL_VERBOSE); 
			break; 
		case 'x': 
			session.exit = session.exit? 0: 1; 
			break; 
		default: 
			break; 
		} 
	} 
	argc -= optind; 
	argv += optind; 
	openchannel (&channel);
	desuid ();
	if (argc) 
	{ 
		slac_debug (& session, 1, __func__, ERROR_TOOMANY); 
	} 
	initialize (& session, profile, section); 
	identifier (& session, & channel); 
	if (evse_cm_set_key (& session, & channel, & message)) 
	{ 
		slac_debug (& session, 1, __func__, "Can't set key."); 
	} 
	sleep (session.settletime); 
	while (session.state) 
	{ 
		if (session.state == EVSE_STATE_UNOCCUPIED) 
		{ 
			UnoccupiedState (& session, & channel, & message); 
			continue; 
		} 
		if (session.state == EVSE_STATE_UNMATCHED) 
		{ 
			UnmatchedState (& session, & channel, & message); 
			continue; 
		} 
		if (session.state == EVSE_STATE_MATCHED) 
		{ 
			MatchedState (& session, & channel, & message); 
			continue; 
		} 
		slac_debug (& session, 1, __func__, "Illegal state!"); 
	} 
	closechannel (& channel); 
	exit (0); 
} 
示例#9
0
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 ?"));
}
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 evse_cm_start_atten_char (struct session * session, struct channel * channel, struct message * message) 

{ 
	struct cm_start_atten_char_indicate * indicate = (struct cm_start_atten_char_indicate *) (message); 
	if (readmessage (channel, message, HOMEPLUG_MMV, (CM_START_ATTEN_CHAR | MMTYPE_IND)) > 0) 
	{ 
		if (! memcmp (session->RunID, indicate->ACVarField.RunID, sizeof (session->RunID))) 
		{ 
			slac_debug (session, 0, __func__, "<-- CM_START_ATTEN_CHAR.IND"); 

#if SLAC_DEBUG

			if (_anyset (session->flags, SLAC_VERBOSE)) 
			{ 
				char string [256]; 
				slac_debug (session, 0, __func__, "CM_START_ATTEN_CHAR.IND.APPLICATION_TYPE %d", indicate->APPLICATION_TYPE); 
				slac_debug (session, 0, __func__, "CM_START_ATTEN_CHAR.IND.SECURITY_TYPE %d", indicate->SECURITY_TYPE); 
				slac_debug (session, 0, __func__, "CM_START_ATTEN_CHAR.IND.ACVarField.NUM_SOUNDS %d", indicate->ACVarField.NUM_SOUNDS); 
				slac_debug (session, 0, __func__, "CM_START_ATTEN_CHAR.IND.ACVarField.TIME_OUT %d", indicate->ACVarField.TIME_OUT); 
				slac_debug (session, 0, __func__, "CM_START_ATTEN_CHAR.IND.ACVarField.RESP_TYPE %d", indicate->ACVarField.RESP_TYPE); 
				slac_debug (session, 0, __func__, "CM_START_ATTEN_CHAR.IND.ACVarField.FORWARDING_STA %s", HEXSTRING (string, indicate->ACVarField.FORWARDING_STA)); 
				slac_debug (session, 0, __func__, "CM_START_ATTEN_CHAR.IND.ACVarField.RunID %s", HEXSTRING (string, indicate->ACVarField.RunID)); 
			} 

#endif

			if (indicate->APPLICATION_TYPE != session->APPLICATION_TYPE) 
			{ 
				slac_debug (session, session->exit, __func__, "%s: APPLICATION_TYPE", __func__); 
			} 
			if (indicate->SECURITY_TYPE != session->SECURITY_TYPE) 
			{ 
				slac_debug (session, session->exit, __func__, "%s: SECURITY_TYPE", __func__); 
			} 
			session->NUM_SOUNDS = indicate->ACVarField.NUM_SOUNDS; 
			session->TIME_OUT = indicate->ACVarField.TIME_OUT; 
			if (indicate->ACVarField.RESP_TYPE != session->RESP_TYPE) 
			{ 
				slac_debug (session, session->exit, __func__, "%s: RESP_TYPE", __func__); 
			} 
			memcpy (session->FORWARDING_STA, indicate->ACVarField.FORWARDING_STA, sizeof (session->FORWARDING_STA)); 
			return (0); 
		} 
	} 
	return (slac_debug (session, session->exit, __func__, "CM_START_ATTEN_CHAR.IND ?")); 
}