Exemple #1
0
        /// <summary>
        /// Generates the next APDU for establishment of a association with the metering devices
        /// The number and content of the APDU will vary according to the HdlcParams configuration </summary>
        /// <returns> the array of bytes that represents the next APDU to be sent for connection establishment </returns>
        /// <exception cref="DlmsException"> </exception>
        public byte[] connectionRequest()
        {
            try
            {
                switch (state)
                {
                case yadi.dlms.cosem.Cosem.ConnectionState.DISCONNECTED:
                    connection.reset();
                    return(Aarq.request(parameters, connection));                    //OK

                case yadi.dlms.cosem.Cosem.ConnectionState.CONNECTED:
                    LnDescriptor           att    = new LnDescriptor(DlmsClass.ASSOCIATION_LN.id, new Obis("0.0.40.0.0.255"), 1);
                    byte[]                 data   = Security.processChallanger(parameters, connection);
                    System.IO.MemoryStream stream = new System.IO.MemoryStream();
                    stream.WriteByte(Constants.DataType.OCTET_STRING);
                    stream.WriteByte((byte)data.Length);

                    //Array.Reverse(data);
                    stream.Write(data, 0, data.Length);

                    att.setRequestData(stream.ToArray());
                    return(requestAction(att));

                case yadi.dlms.cosem.Cosem.ConnectionState.AUTHENTICATED:
                    throw new System.InvalidOperationException();

                default:
                    throw new System.InvalidOperationException();
                }
            }
            catch (IOException)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.INTERNAL_ERROR);
            }
        }
Exemple #2
0
 /// <summary>
 /// Generates the APDU for a GET request </summary>
 /// <param name="att"> LnDescriptor describing the object to be accessed </param>
 /// <returns> byte array representation of the APDU </returns>
 /// <exception cref="DlmsException"> </exception>
 public byte[] requestGet(LnDescriptor att)
 {
     try
     {
         System.IO.MemoryStream stream = new System.IO.MemoryStream();
         stream.WriteByte(Constants.xDlmsApdu.NoCiphering.GET_REQUEST);
         stream.WriteByte((byte)(connection.datablock.blockNum == 0 ? 1 : 2));
         stream.WriteByte((byte)(parameters.priority | parameters.serviceClass | Constants.INVOKE_ID));
         if (connection.datablock.blockNum != 0)
         {
             //stream.WriteByte(ByteBuffer.allocate(4).putInt(connection.datablock.blockNum).array());
             stream.Write(new byte[] { (byte)(connection.datablock.blockNum >> 24), (byte)(connection.datablock.blockNum >> 16), (byte)(connection.datablock.blockNum >> 8), (byte)(connection.datablock.blockNum) }, 0, 4);
         }
         else
         {
             //Array.Reverse(att.getClassId());
             stream.Write(att.getClassId(), 0, att.getClassId().Length);
             //Array.Reverse(att.getObis());
             stream.Write(att.getObis(), 0, att.getObis().Length);
             stream.WriteByte((byte)(att.getIndex()));
             stream.WriteByte((byte)(att.getRequestData().Length == 0 ? 0 : 1));
             //Array.Reverse(att.getRequestData());
             stream.Write(att.getRequestData(), 0, att.getRequestData().Length);
         }
         return(packFrame(Constants.xDlmsApdu.GlobalCiphering.GET_REQUEST, stream.ToArray()));
     }
     catch (IOException)
     {
         throw new DlmsException(DlmsException.DlmsExceptionReason.INTERNAL_ERROR);
     }
 }
Exemple #3
0
        /// <summary>
        /// Parses the response of the last connection APDU sent </summary>
        /// <param name="data"> array of bytes with the APDU received from the metering device </param>
        /// <returns> true if the connection is established and false if more steps are necessary </returns>
        /// <exception cref="DlmsException"> </exception>
        public bool parseConnectionResponse(byte[] data)
        {
            switch (state)
            {
            case yadi.dlms.cosem.Cosem.ConnectionState.DISCONNECTED:
                Aare.parseResponse(parameters, connection, data);
                state = ConnectionState.CONNECTED;
                return(parameters.authenticationType == AuthenticationType.PUBLIC || parameters.authenticationType == AuthenticationType.LLS);

            case yadi.dlms.cosem.Cosem.ConnectionState.CONNECTED:
                LnDescriptor att = new LnDescriptor(DlmsClass.ASSOCIATION_LN.id, new Obis("0.0.40.0.0.255"), 1);
                parseActionResponse(att, data);
                byte[] receivedData = att.getResponseData();
                if (receivedData == null || receivedData.Length < 3 || receivedData[0] != Constants.DataType.OCTET_STRING)
                {
                    throw new DlmsException(DlmsException.DlmsExceptionReason.CONNECTION_REJECTED);
                }
                if (receivedData[1] != receivedData.Length - 2)
                {
                    throw new DlmsException(DlmsException.DlmsExceptionReason.CONNECTION_REJECTED);
                }
                if (!Security.verifyChallenger(parameters, connection, helper.extensions.copyOfRange(receivedData, 2, receivedData.Length)))
                {
                    throw new DlmsException(DlmsException.DlmsExceptionReason.FAIL_TO_AUTHENTICATE_SERVER);
                }
                state = ConnectionState.AUTHENTICATED;
                return(true);

            case yadi.dlms.cosem.Cosem.ConnectionState.AUTHENTICATED:
                throw new System.InvalidOperationException();

            default:
                throw new System.InvalidOperationException();
            }
        }
Exemple #4
0
        /// <summary>
        /// Parses the APDU of a ACTION response </summary>
        /// <param name="att"> LnDescriptor describing the object accessed </param>
        /// <returns> true if the parse if finished, false if more apdu's are necessary (data block transfer) </returns>
        /// <exception cref="DlmsException"> </exception>
        public bool parseActionResponse(LnDescriptor att, byte[] data)
        {
            data = unpackFrame(Constants.xDlmsApdu.NoCiphering.ACTION_RESPONSE, Constants.xDlmsApdu.GlobalCiphering.ACTION_RESPONSE, data);

            if (data.Length > 6)
            {
                att.setResponseData(helper.extensions.copyOfRange(data, 5, data.Length));
            }

            return(true);
        }
Exemple #5
0
        /// <summary>
        /// Parses the APDU of a GET response </summary>
        /// <param name="att"> LnDescriptor describing the object accessed </param>
        /// <returns> true if the parse if finished, false if more apdu's are necessary (data block transfer) </returns>
        /// <exception cref="DlmsException"> </exception>
        public bool parseGetResponse(LnDescriptor att, byte[] data)
        {
            try
            {
                data = unpackFrame(Constants.xDlmsApdu.NoCiphering.GET_RESPONSE, Constants.xDlmsApdu.GlobalCiphering.GET_RESPONSE, data);

                if (data.Length < 4)
                {
                    throw new DlmsException(DlmsException.DlmsExceptionReason.RECEIVED_INVALID_GET_RESPONSE);
                }

                if (data[0] == Constants.GetResponse.NORMAL)
                {
                    verifyDataAccessResult(data[2]);
                    connection.datablock.lastBlock = true;
                    data = helper.extensions.copyOfRange(data, 3, data.Length);
                }
                else if (data[0] == Constants.GetResponse.DATA_BLOCK)
                {
                    if (data.Length < 10 || data[7] != 0)
                    {                     //TODO only supports raw-data for now
                        throw new DlmsException(DlmsException.DlmsExceptionReason.RECEIVED_INVALID_GET_RESPONSE);
                    }
                    connection.datablock.lastBlock = data[2] != 0;
                    //connection.datablock.blockNum = ByteBuffer.allocate(4).put(data,3,4).getInt(0);
                    connection.datablock.blockNum = BitConverter.ToInt32(new byte[] { data[6], data[5], data[4], data[3] }, 0);
                    data = getPayload(data, 8);
                }
                else
                {
                    throw new DlmsException(DlmsException.DlmsExceptionReason.RECEIVED_INVALID_GET_RESPONSE);
                }
                //Array.Reverse(data);
                connection.datablock.data.Write(data, 0, data.Length);

                if (connection.datablock.lastBlock)
                {
                    att.setResponseData(connection.datablock.data.ToArray());
                    connection.datablock.reset();
                    return(true);
                }

                return(false);
            }
            catch (IOException)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.INTERNAL_ERROR);
            }
        }
Exemple #6
0
        /// <summary>
        /// Parses the APDU of a SET response </summary>
        /// <param name="att"> LnDescriptor describing the object accessed </param>
        /// <returns> true if the parse if finished, false if more apdu's are necessary (data block transfer) </returns>
        /// <exception cref="DlmsException"> </exception>
        public bool parseSetResponse(LnDescriptor att, byte[] data)
        {
            data = unpackFrame(Constants.xDlmsApdu.NoCiphering.SET_RESPONSE, Constants.xDlmsApdu.GlobalCiphering.SET_RESPONSE, data);

            if (data.Length < 3)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.RECEIVED_INVALID_SET_RESPONSE);
            }

            if (data[0] == Constants.SetResponse.NORMAL)
            {
                verifyDataAccessResult(data[2]);
                return(true);
            }
            else if (data[0] == Constants.SetResponse.DATA_BLOCK)
            {
                if (data.Length < 6)
                {
                    throw new DlmsException(DlmsException.DlmsExceptionReason.RECEIVED_INVALID_SET_RESPONSE);
                }
                //connection.datablock.ackBlock(ByteBuffer.allocate(4).put(data,2,4).getInt(0));
                connection.datablock.ackBlock(BitConverter.ToInt32(new byte[] { data[5], data[4], data[3], data[2] }, 0));
                return(connection.datablock.nextIsLast());
            }
            else if (data[0] == Constants.SetResponse.LAST_DATA_BLOCK)
            {
                if (data.Length < 7)
                {
                    throw new DlmsException(DlmsException.DlmsExceptionReason.RECEIVED_INVALID_SET_RESPONSE);
                }
                //if (ByteBuffer.allocate(4).put(data,3,4).getInt(0) != connection.datablock.nextBlockNum)
                if ((BitConverter.ToInt32(new byte[] { data[6], data[5], data[4], data[3] }, 0)) != connection.datablock.nextBlockNum)
                {
                    throw new DlmsException(DlmsException.DlmsExceptionReason.RECEIVED_INVALID_SET_RESPONSE);
                }
                //connection.datablock.ackBlock(ByteBuffer.allocate(4).put(data,3,4).getInt(0));
                connection.datablock.ackBlock(BitConverter.ToInt32(new byte[] { data[6], data[5], data[4], data[3] }, 0));
                verifyDataAccessResult(data[2]);
                return(true);
            }
            throw new DlmsException(DlmsException.DlmsExceptionReason.RECEIVED_INVALID_SET_RESPONSE);
        }
Exemple #7
0
 /// <summary>
 /// Generates the APDU for a ACTION request </summary>
 /// <param name="att"> LnDescriptor describing the object to be accessed </param>
 /// <returns> byte array representation of the APDU </returns>
 /// <exception cref="DlmsException"> </exception>
 public byte[] requestAction(LnDescriptor att)
 {
     try
     {
         System.IO.MemoryStream stream = new System.IO.MemoryStream();
         stream.WriteByte(Constants.xDlmsApdu.NoCiphering.ACTION_REQUEST);
         stream.WriteByte(1);
         stream.WriteByte((byte)(parameters.priority | parameters.serviceClass | Constants.INVOKE_ID));
         //Array.Reverse(att.getClassId());
         stream.Write(att.getClassId(), 0, att.getClassId().Length);
         //.Reverse(att.getObis());
         stream.Write(att.getObis(), 0, att.getObis().Length);
         stream.WriteByte((byte)(att.getIndex()));
         stream.WriteByte((byte)(att.getRequestData().Length == 0 ? 0 : 1));
         //Array.Reverse(att.getRequestData());
         stream.Write(att.getRequestData(), 0, att.getRequestData().Length);
         return(packFrame(Constants.xDlmsApdu.GlobalCiphering.ACTION_REQUEST, stream.ToArray()));
     }
     catch (IOException)
     {
         throw new DlmsException(DlmsException.DlmsExceptionReason.INTERNAL_ERROR);
     }
 }
Exemple #8
0
        /// <summary>
        /// Generates the APDU for a SET request </summary>
        /// <param name="att"> LnDescriptor describing the object to be accessed </param>
        /// <returns> byte array representation of the APDU </returns>
        /// <exception cref="DlmsException"> </exception>
        public byte[] requestSet(LnDescriptor att)
        {
            try
            {
                System.IO.MemoryStream stream = new System.IO.MemoryStream();
                stream.WriteByte(Constants.xDlmsApdu.NoCiphering.SET_REQUEST);
                byte[] data = att.getRequestData();
                if (data.Length > (connection.maxPduSize - 50))
                {
                    if (connection.datablock.nextBlockNum == 1)
                    {
                        connection.datablock.setData(data, connection.maxPduSize - 50);
                        //Set-Request-With-First-Datablock
                        stream.WriteByte(2);
                        stream.WriteByte((byte)(parameters.priority | parameters.serviceClass | Constants.INVOKE_ID));
                        //Array.Reverse(att.getClassId());
                        stream.Write(att.getClassId(), 0, att.getClassId().Length);
                        //Array.Reverse(att.getObis());
                        stream.Write(att.getObis(), 0, att.getObis().Length);
                        stream.WriteByte((byte)(att.getIndex()));
                        stream.WriteByte(0);
                        stream.WriteByte(0);
                        //Array.Reverse(connection.datablock.getNextBlockNum());
                        stream.Write(connection.datablock.getNextBlockNum(), 0, connection.datablock.getNextBlockNum().Length);
                        byte[] blockdata = connection.datablock.getNextBlock();
                        if (blockdata.Length > 128)
                        {
                            stream.WriteByte(0x81);
                        }
                        stream.WriteByte((byte)(blockdata.Length));
                        //Array.Reverse(blockdata);
                        stream.Write(blockdata, 0, blockdata.Length);
                    }
                    else
                    {
                        //Set-Request-With-Datablock
                        stream.WriteByte(3);
                        stream.WriteByte((byte)(parameters.priority | parameters.serviceClass | Constants.INVOKE_ID));
                        if (connection.datablock.nextIsLast())
                        {
                            stream.WriteByte(1);
                        }
                        else
                        {
                            stream.WriteByte(0);
                        }
                        //Array.Reverse(connection.datablock.getNextBlockNum());
                        stream.Write(connection.datablock.getNextBlockNum(), 0, connection.datablock.getNextBlockNum().Length);
                        byte[] blockdata = connection.datablock.getNextBlock();
                        if (blockdata.Length > 128)
                        {
                            stream.WriteByte(0x81);
                        }
                        stream.WriteByte((byte)(blockdata.Length));
                        //Array.Reverse(blockdata);
                        stream.Write(blockdata, 0, blockdata.Length);
                    }
                }
                else
                {
                    //Set-Request-Normal
                    stream.WriteByte(1);
                    stream.WriteByte((byte)(parameters.priority | parameters.serviceClass | Constants.INVOKE_ID));
                    //Array.Reverse(att.getClassId());
                    stream.Write(att.getClassId(), 0, att.getClassId().Length);
                    //Array.Reverse(att.getObis());
                    stream.Write(att.getObis(), 0, att.getObis().Length);
                    stream.WriteByte((byte)(att.getIndex()));
                    stream.WriteByte(0);
                    //Array.Reverse(att.getRequestData());
                    stream.Write(att.getRequestData(), 0, att.getRequestData().Length);
                }

                return(packFrame(Constants.xDlmsApdu.GlobalCiphering.SET_REQUEST, stream.ToArray()));
            }
            catch (IOException)
            {
                throw new DlmsException(DlmsException.DlmsExceptionReason.INTERNAL_ERROR);
            }
        }