/// <summary> /// Parses the AARE response. /// </summary> /// <param name="reply"></param> /// <remarks> /// Parse method will update the following data: /// <ul> /// <li>DLMSVersion</li> /// <li>MaxReceivePDUSize</li> /// <li>UseLogicalNameReferencing</li> /// <li>LNSettings or SNSettings</li> /// </ul> /// LNSettings or SNSettings will be updated, depending on the referencing, /// Logical name or Short name. /// </remarks> /// <returns>The AARE response</returns> /// <seealso cref="AARQRequest"/> /// <seealso cref="UseLogicalNameReferencing"/> /// <seealso cref="DLMSVersion"/> /// <seealso cref="MaxReceivePDUSize"/> /// <seealso cref="LNSettings"/> /// <seealso cref="SNSettings"/> public GXDLMSTagCollection ParseAAREResponse(byte[] reply) { byte frame; int error, index = 0; List<byte> arr = new List<byte>(reply); bool packetFull, wrongCrc; byte command; m_Base.GetDataFromFrame(arr, index, out frame, true, out error, false, out packetFull, out wrongCrc, out command, false); if (!packetFull) { throw new GXDLMSException("Not enough data to parse frame."); } if (wrongCrc) { throw new GXDLMSException("Wrong Checksum."); } //Parse AARE data. GXDLMSTagCollection Tags = new GXDLMSTagCollection(); GXAPDU pdu = new GXAPDU(Tags); pdu.EncodeData(arr.ToArray(), ref index); UseLogicalNameReferencing = pdu.UseLN; if (UseLogicalNameReferencing) { System.Diagnostics.Debug.WriteLine("--- Logical Name settings are---\r\n"); } else { System.Diagnostics.Debug.WriteLine("--- Short Name settings are---\r\n"); } m_Base.StoCChallenge = pdu.Password; AssociationResult ret = pdu.ResultComponent; if (ret == AssociationResult.Accepted) { System.Diagnostics.Debug.WriteLine("- Client has accepted connection."); if (UseLogicalNameReferencing) { m_Base.LNSettings = new GXDLMSLNSettings(pdu.UserInformation.ConformanceBlock); } else { m_Base.SNSettings = new GXDLMSSNSettings(pdu.UserInformation.ConformanceBlock); } MaxReceivePDUSize = pdu.UserInformation.MaxReceivePDUSize; DLMSVersion = pdu.UserInformation.DLMSVersioNumber; } else { m_Base.LNSettings = null; m_Base.SNSettings = null; throw new GXDLMSException(ret, pdu.ResultDiagnosticValue); } IsAuthenticationRequired = pdu.ResultDiagnosticValue == SourceDiagnostic.AuthenticationRequired; if (IsAuthenticationRequired) { System.Diagnostics.Debug.WriteLine("Authentication is used."); } System.Diagnostics.Debug.WriteLine("- Server max PDU size is " + MaxReceivePDUSize); System.Diagnostics.Debug.WriteLine("- Value of quality of service is " + ValueOfQualityOfService); System.Diagnostics.Debug.WriteLine("- Server DLMS version number is " + DLMSVersion); if (DLMSVersion != 6) { throw new GXDLMSException("Invalid DLMS version number."); } System.Diagnostics.Debug.WriteLine("- Number of unused bits is " + NumberOfUnusedBits); return Tags; }
/// <summary> /// Parse AARQ request that client send and returns AARE request. /// </summary> /// <param name="data"></param> /// <returns></returns> byte[] HandleAARQRequest(byte[] data) { int index = 0, error; byte frame; List<byte> arr = new List<byte>(data); bool packetFull, wrongCrc; byte command; m_Base.GetDataFromFrame(arr, index, out frame, true, out error, false, out packetFull, out wrongCrc, out command, false); if (!packetFull) { throw new GXDLMSException("Not enough data to parse frame."); } if (wrongCrc) { throw new GXDLMSException("Wrong Checksum."); } GXAPDU aarq = new GXAPDU(null); aarq.UseLN = this.UseLogicalNameReferencing; int pos = 0; aarq.EncodeData(arr.ToArray(), ref pos); AssociationResult result = AssociationResult.Accepted; SourceDiagnostic diagnostic = SourceDiagnostic.None; m_Base.Authentication = aarq.Authentication; m_Base.CtoSChallenge = null; m_Base.StoCChallenge = null; if (aarq.Authentication >= Authentication.High) { m_Base.CtoSChallenge = aarq.Password; } if (this.UseLogicalNameReferencing != aarq.UseLN) { result = AssociationResult.PermanentRejected; diagnostic = SourceDiagnostic.ApplicationContextNameNotSupported; } else { GXAuthentication auth = null; foreach (GXAuthentication it in Authentications) { if (it.Type == aarq.Authentication) { auth = it; break; } } if (auth == null) { result = AssociationResult.PermanentRejected; //If authentication is required. if (aarq.Authentication == Authentication.None) { diagnostic = SourceDiagnostic.AuthenticationRequired; } else { diagnostic = SourceDiagnostic.AuthenticationMechanismNameNotRecognised; } } //If authentication is used check pw. else if (aarq.Authentication != Authentication.None) { if (aarq.Authentication == Authentication.Low) { //If Low authentication is used and pw don't match. if (aarq.Password == null || string.Compare(auth.Password, ASCIIEncoding.ASCII.GetString(aarq.Password)) != 0) { result = AssociationResult.PermanentRejected; diagnostic = SourceDiagnostic.AuthenticationFailure; } } else //If High authentication is used. { m_Base.StoCChallenge = GXDLMS.GenerateChallenge(); System.Diagnostics.Debug.WriteLine("StoC: " + BitConverter.ToString(m_Base.StoCChallenge)); result = AssociationResult.Accepted; diagnostic = SourceDiagnostic.AuthenticationRequired; } } } //Generate AARE packet. List<byte> buff = new List<byte>(); byte[] conformanceBlock; if (UseLogicalNameReferencing) { conformanceBlock = LNSettings.m_ConformanceBlock; } else { conformanceBlock = SNSettings.m_ConformanceBlock; } aarq.GenerateAARE(buff, aarq.Authentication, m_Base.StoCChallenge, MaxReceivePDUSize, conformanceBlock, result, diagnostic); if (this.InterfaceType == InterfaceType.General) { buff.InsertRange(0, Gurux.DLMS.Internal.GXCommon.LLCReplyBytes); } m_Base.ExpectedFrame = 0; m_Base.FrameSequence = -1; m_Base.ReceiveSequenceNo = 1; m_Base.SendSequenceNo = 0; return m_Base.AddFrame(m_Base.GenerateIFrame(), false, buff, 0, buff.Count); }
/// <summary> /// Generate AARQ request. /// </summary> /// <param name="Tags">Reserved for future use.</param> /// <returns>AARQ request as byte array.</returns> /// <seealso cref="ParseAAREResponse"/> /// <seealso cref="IsDLMSPacketComplete"/> public byte[][] AARQRequest(GXDLMSTagCollection Tags) { List<byte> buff = new List<byte>(); m_Base.CheckInit(); GXAPDU aarq = new GXAPDU(Tags); aarq.UseLN = this.UseLogicalNameReferencing; if (this.UseLogicalNameReferencing) { m_Base.SNSettings = null; m_Base.LNSettings = new GXDLMSLNSettings(new byte[] { 0x00, 0x7E, 0x1F }); aarq.UserInformation.ConformanceBlock = LNSettings.m_ConformanceBlock; } else { m_Base.LNSettings = null; m_Base.SNSettings = new GXDLMSSNSettings(new byte[] { 0x1C, 0x03, 0x20 }); aarq.UserInformation.ConformanceBlock = SNSettings.m_ConformanceBlock; } aarq.UserInformation.DLMSVersioNumber = DLMSVersion; aarq.UserInformation.MaxReceivePDUSize = MaxReceivePDUSize; m_Base.StoCChallenge = null; if (Authentication > Authentication.Low)//If High Security Level { m_Base.CtoSChallenge = GXDLMS.GenerateChallenge(); aarq.SetAuthentication(this.Authentication, m_Base.CtoSChallenge); } else { m_Base.CtoSChallenge = null; aarq.SetAuthentication(this.Authentication, Password); } aarq.CodeData(buff, this.InterfaceType); m_Base.FrameSequence = -1; m_Base.ExpectedFrame = -1; m_Base.ReceiveSequenceNo = m_Base.SendSequenceNo = -1; return m_Base.SplitToBlocks(buff, Command.None, false, null); }
/// <summary> /// Parse AARQ request that cliend send and returns AARE request. /// </summary> /// <param name="data"></param> /// <returns></returns> byte[] HandleAARQRequest(byte[] data) { int index = 0, error; byte frame; List<byte> arr = new List<byte>(data); bool packetFull, wrongCrc; byte command; m_Base.GetDataFromFrame(arr, index, out frame, true, out error, false, out packetFull, out wrongCrc, out command); if (!packetFull) { throw new GXDLMSException("Not enought data to parse frame."); } if (wrongCrc) { throw new GXDLMSException("Wrong Checksum."); } GXAPDU aarq = new GXAPDU(null); aarq.UseLN = this.UseLogicalNameReferencing; int pos = 0; aarq.EncodeData(arr.ToArray(), ref pos); AssociationResult result = AssociationResult.Accepted; SourceDiagnostic diagnostic = SourceDiagnostic.None; if (this.UseLogicalNameReferencing != aarq.UseLN) { result = AssociationResult.PermanentRejected; diagnostic = SourceDiagnostic.ApplicationContextNameNotSupported; } else { GXAuthentication auth = null; foreach (GXAuthentication it in Authentications) { if (it.Type == aarq.Authentication) { auth = it; break; } } if (auth == null) { result = AssociationResult.PermanentRejected; //If authentication is required. if (aarq.Authentication == Authentication.None) { diagnostic = SourceDiagnostic.AuthenticationRequired; } else { diagnostic = SourceDiagnostic.AuthenticationMechanismNameNotRecognised; } } //If authentication is used check pw. else if (aarq.Authentication != Authentication.None && auth.Password != aarq.Password && string.IsNullOrEmpty(auth.Password) != string.IsNullOrEmpty((aarq.Password))) { result = AssociationResult.PermanentRejected; diagnostic = SourceDiagnostic.AuthenticationFailure; } } //Generate AARE packet. List<byte> buff = new List<byte>(); byte[] conformanceBlock; if (UseLogicalNameReferencing) { conformanceBlock = LNSettings.m_ConformanceBlock; } else { conformanceBlock = SNSettings.m_ConformanceBlock; } aarq.GenerateAARE(buff, MaxReceivePDUSize, conformanceBlock, result, diagnostic); if (this.InterfaceType == InterfaceType.General) { buff.InsertRange(0, new byte[] { 0xE6, 0xE7, 0x00 }); } m_Base.ExpectedFrame = 0; m_Base.FrameSequence = -1; return m_Base.AddFrame(m_Base.GenerateIFrame(), false, buff, 0, buff.Count); }