コード例 #1
0
ファイル: BACnetPacket.cs プロジェクト: kyanha/bacnet-server
        public bool DecodeBACnet(byte[] buffer, int totalMessageLength)
        {
            int offset = 0;

            try
            {
                // this whole section http://www.bacnetwiki.com/wiki/index.php?title=BACnet_Virtual_Link_Control
                ADR sadr = null;

                if (buffer[offset] != BACnetEnums.BACNET_BVLC_TYPE_BIP)
                {
                    // todo3, panic log
                    _apm.MessageProtocolError("m0013 - Not a BACnet/IP message");
                    return(false);
                }

                // we could receive an original broadcast, a unicast, a forwarded here...
                // BVLC Function Types. See http://www.bacnetwiki.com/wiki/index.php?title=BVLC_Function

                switch ((BACnetEnums.BACNET_BVLC_FUNCTION)buffer[offset + 1])
                {
                case BACnetEnums.BACNET_BVLC_FUNCTION.BVLC_FORWARDED_NPDU:
                    npdu_offset = offset + 10;
                    break;

                case BACnetEnums.BACNET_BVLC_FUNCTION.BVLC_ORIGINAL_UNICAST_NPDU:
                case BACnetEnums.BACNET_BVLC_FUNCTION.BVLC_ORIGINAL_BROADCAST_NPDU:
                    // all these OK
                    npdu_offset = offset + 4;
                    break;

                default:
                    BACnetLibraryCL.Panic("m0012 nosuch bvlc function");
                    break;
                }


                // Investigate the NPDU
                // http://www.bacnetwiki.com/wiki/index.php?title=NPDU

                if (buffer[npdu_offset] != BACnetEnums.BACNET_PROTOCOL_VERSION)
                {
                    // we have a major problem, microprotocol version has changed. http://www.bacnetwiki.com/wiki/index.php?title=BACnet_Virtual_Link_Control
                    BACnetLibraryCL.Panic("m0011 BVLC microprotocol problem");
                    return(false);
                }

                // expecting reply?

                if ((buffer[npdu_offset + 1] & 0x04) == 0x04)
                {
                    npdu.expectingReply = true;
                }


                // destination address present?
                // http://www.bacnetwiki.com/wiki/index.php?title=NPCI

                if ((buffer[npdu_offset + 1] & 0x20) == 0x20)
                {
                    //da_present = true;
                    dadr = new ADR();

                    // dnet, dadr and hop count present

                    int dAddrOffset = npdu_offset + 2;
                    dadr.Decode(buffer, ref dAddrOffset);

                    if (dadr.MACaddress.length == 0)
                    {
                        npdu.isBroadcast = true;

                        // broadcast, but check the DNET
                        if (dadr.networkNumber != 0xffff)
                        {
                            throw new Exception("m0010 - Broadcast according to DLEN, but DNET not 0xffff");
                            // todo, this means directed broadcast, need to deal with this still
                        }
                    }
                    if (dadr.MACaddress.length != 1 && dadr.MACaddress.length != 6 && dadr.MACaddress.length != 0)
                    {
                        // panic
                        throw new Exception("m0009 - Unexpected DADR len");
                    }
                    // todo, pick up variable length destination address
                }


                // Source address present?
                // http://www.bacnetwiki.com/wiki/index.php?title=NPCI

                if ((buffer[npdu_offset + 1] & 0x08) == 0x08)
                {
                    //sa_present = true;

                    sadr = new ADR();

                    int sa_offset = npdu_offset + 2;

                    // however, if there is a destination address, move the sa_offset up appropriate amount

                    if (dadr != null)
                    {
                        sa_offset = npdu_offset + 2 + 3 + (int)dadr.MACaddress.length;
                    }

                    // means SADR, SNET present

                    sadr.Decode(buffer, ref sa_offset);

                    // SA exists (included MAC and so this means the received IP address needs to be the fromBIP
                }
                else
                {
                    // at this point, if SADR not discovered within the NPDU, then the SADR MAC address is the Ethernet/IP fromaddress
                    // and the device can (must) be considered 'direcly connected'
                    if (directlyConnectedIPEndPointOfDevice != null)
                    {
                        // and even though the device is directly connected, because we are a router, we have an allocated network number to provide
                        // the network number is available outside this class, and will be filled in by the calling function if it is relevant.
                        srcDevice.adr = new ADR(0, directlyConnectedIPEndPointOfDevice);
                    }
                    else
                    {
                        throw new Exception("m0063 - No From-Address can be determined");
                    }
                }



                if (dadr != null)
                {
                    if (sadr != null)
                    {
                        hopcount = (uint)(buffer[npdu_offset + 2 + 2 + 1 + dadr.MACaddress.length + 2 + 1 + sadr.MACaddress.length]);
                    }
                    else
                    {
                        hopcount = (uint)(buffer[npdu_offset + 2 + 2 + 1 + dadr.MACaddress.length]);
                    }
                    // true broadcast, but check the hopcount

                    if (hopcount == 0)
                    {
                        // out of hops, should never happen to us, so sound a warning
                        // todo, remove this for a functioning systems
                        System.Windows.Forms.MessageBox.Show("m0008 Hopcount of 0 detected");
                        return(false);
                    }
                }

                // finished resolving sadr, and dadr. Now populate our devices as required

                if (sadr != null)
                {
                    if (srcDevice.adr != null)
                    {
                        // means this adr was partially populated elsewhere.
                        srcDevice.adr.networkNumber = sadr.networkNumber;
                        srcDevice.adr.MACaddress    = sadr.MACaddress;
                    }
                    else
                    {
                        srcDevice.adr = sadr;
                    }
                }



                if ((buffer[npdu_offset + 1] & 0x80) == 0x80)  // todo magic number
                {
                    // NSDU contains Network Layer Message
                    // http://www.bacnetwiki.com/wiki/index.php?title=Network_Layer_Protocol_Control_Information

                    apdu_present       = false;
                    npdu.isNPDUmessage = true;

                    // calculate offset to the NSDU

                    nsdu_offset = npdu_offset + 2;

                    if (sadr != null)
                    {
                        nsdu_offset += 2 + 1 + (int)sadr.MACaddress.length;
                    }
                    if (dadr != null)
                    {
                        nsdu_offset += 2 + 1 + (int)dadr.MACaddress.length + 1;
                    }

                    npdu.function = (BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE)buffer[nsdu_offset];

                    switch (npdu.function)
                    {
                    case BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE.NETWORK_MESSAGE_I_AM_ROUTER_TO_NETWORK:
                        // there may be a list of network numbers after the header

                        if ((length - nsdu_offset >= 3))
                        {
                            numberList = new List <uint>();
                        }

                        for (int i = 0; i < (length - nsdu_offset - 1) / 2; i++)
                        {
                            int tref = nsdu_offset + 1 + i * 2;
                            numberList.Add(BACnetLibraryCL.ExtractUint16(buffer, ref tref));
                        }
                        break;

                    case BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE.NETWORK_MESSAGE_INIT_RT_TABLE_ACK:
                        int tiptr    = nsdu_offset + 1;
                        int numPorts = buffer[tiptr++];
                        routerPortList = new List <RouterPort>();

                        for (int i = 0; i < numPorts; i++)
                        {
                            RouterPort rp = new RouterPort();
                            rp.Decode(buffer, ref tiptr);
                            routerPortList.Add(rp);
                        }
                        break;

                    default:
                        // todo
                        break;
                    }
                }
                else
                {
                    // NSDU contains APDU
                    // http://www.bacnetwiki.com/wiki/index.php?title=Network_Layer_Protocol_Control_Information

                    // determine if SNET, SLEN, SADR present

                    apdu_present = true;

                    apdu_offset = npdu_offset + 2;

                    if (sadr != null)
                    {
                        apdu_offset += 2 + 1 + (int)sadr.MACaddress.length;
                    }
                    if (dadr != null)
                    {
                        apdu_offset += 2 + 1 + (int)dadr.MACaddress.length + 1;
                    }

                    apdu_length = length - apdu_offset;
                    if (apdu_length < 0)
                    {
                        _apm.MessagePanic("m0006 Illegal APDU length");
                        return(false);
                    }

                    // todo - need to extract the apdu for others to refer to. However, APDUs may be customer specific, so extract this as a buffer
                    // only for now, and do some spot checks for relevant functions such as I-Am and Who-Is.

                    apdu_buf = new byte[2000];

                    Buffer.BlockCopy(buffer, apdu_offset, apdu_buf, 0, apdu_length);

                    // the offset here is the APDU. Start parsing APDU.
                    // todo, decided to leave the enum values unshifted today 11/27/09
                    pduType = (BACnetEnums.BACNET_PDU_TYPE)(buffer[apdu_offset] & 0xf0);

                    // make sure that we can handle the rest of the packet

                    //if ((buffer[apdu_offset] & 0x0f) != 0 )
                    //{
                    //    throw new Exception("m0056 - Cannot handle segmented messages yet");
                    //}

                    int tptr = apdu_offset + 1;

                    if (pduType == BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
                    {
                        // some PDUs have max segs here
                        tptr++;
                    }

                    //_apm.MessageTodo("Remove apdu++");
                    //apdu_offset++;
                    //apdu_offset++;

                    // now the next byte is the invoke ID

                    invokeID = buffer[tptr++];

                    switch (pduType)
                    {
                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
                        // todo, offset is not always 1, depends on the flags in the first byte.
                        DecodeUnconfirmedService(apdu_buf, apdu_length);
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
                        DecodeConfirmedService(apdu_buf);
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_SIMPLE_ACK:
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_COMPLEX_ACK:
                        confirmedServiceChoice = (BACnetEnums.BACNET_CONFIRMED_SERVICE)buffer[apdu_offset + 2];
                        DecodeComplexACK(buffer, apdu_offset);
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_SEGMENT_ACK:
                        _apm.MessageTodo("m0093 - Segment ACK");
                        errorFlag = true;
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_ERROR:
                        _apm.MessageTodo("m0064 - Error");
                        errorFlag = true;
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_REJECT:
                        pduRejectReason = (BACnetEnums.BACNET_BACNET_REJECT_REASON)buffer[apdu_offset++];
                        errorFlag       = true;
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_ABORT:
                        _apm.MessageTodo("m0066 - PDU abort");
                        errorFlag = true;
                        break;

                    default:
                        throw new Exception("m0003 - Illegal PDU type");
                    }
                }
            }
            catch (Exception ex)
            {
                _apm.MessagePanic("m0001 - BACnet Decode Failed " + ex.ToString());
            }
            return(true);
        }
コード例 #2
0
 public void DumpException(AppManager apm)
 {
     apm.MessageProtocolError(message);
 }