ela-compil / BACnet

BACnet protocol library for .NET :satellite:
https://www.nuget.org/packages/bacnet/
MIT License
215 stars 95 forks source link

Decoding datetime objects - error on some devices #103

Open Afroboltski opened 2 years ago

Afroboltski commented 2 years ago

In Serialize/ASN1.cs:

The following method:

public static int decode_bacnet_time(byte[] buffer, int offset, out DateTime btime)
{
    int hour = buffer[offset + 0];
    int min = buffer[offset + 1];
    int sec = buffer[offset + 2];
    int hundredths = buffer[offset + 3];
    if (hour == 0xFF && min == 0xFF && sec == 0xFF && hundredths == 0xFF)
    {
        btime = new DateTime(1, 1, 1);
    }
    else
    {
        if (hundredths > 100) hundredths = 0; // sometimes set to 255
        btime = new DateTime(1, 1, 1, hour, min, sec, hundredths * 10);
    }
    return 4;
}

could be re-written with the following change, to be more device-agnostic as to when a particular value is deemed to be garbage or not:

public static int decode_bacnet_time(byte[] buffer, int offset, out DateTime btime)
{
    int hour = buffer[offset + 0];
    int min = buffer[offset + 1];
    int sec = buffer[offset + 2];
    int hundredths = buffer[offset + 3];
    if (hour > 23 || min > 59 || sec > 59) // This conditional check has been changed
        btime = new DateTime(1, 1, 1);
    else
    {
        if (hundredths > 100) hundredths = 0;   // sometimes set to 255
        btime = new DateTime(1, 1, 1, hour, min, sec, hundredths * 10);
    }
    return 4;
}

I found that when using the former version in a make-shift BACnet server I rigged up, it would crash (my exception handling was non-existent at the time) every time it tried to decode a date from a particular range of Siemens BACnet devices. The crash was to do with invalid values in the DateTime constructor. The invalid values were able to bypass the following check: if (hour == 0xFF && min == 0xFF && sec == 0xFF && hundredths == 0xFF) because the panel sends it's "garbage" value as:

hour == 0xFF;
min == 0xFF;
sec == 0xFF;
hundredths == 0x00;