/* This file is part of PacketDotNet PacketDotNet is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. PacketDotNet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PacketDotNet. If not, see . */ /* * Copyright 2010 Evan Plaice * Copyright 2010 Chris Morgan */ using System; using System.Text; using MiscUtil.Conversion; using PacketDotNet.Utils; namespace PacketDotNet.LLDP { /// /// A Time to Live TLV /// /// [TLV Type Length : 2][Mgmt Addr length : 1][Mgmt Addr Subtype : 1][Mgmt Addr : 1-31] /// [Interface Subtype : 1][Interface number : 4][OID length : 1][OID : 0-128] /// /// public class ManagementAddress : TLV { // NOTE: No need to warn about lack of use, the compiler won't // put any calls to 'log' here but we need 'log' to exist to compile #pragma warning disable 0169, 0649 private static readonly ILogInactive log; #pragma warning restore 0169, 0649 /// /// Number of bytes in the AddressLength field /// private const int MgmtAddressLengthLength = 1; /// /// Number of bytes in the interface number subtype field /// private const int InterfaceNumberSubTypeLength = 1; /// /// Number of bytes in the interface number field /// private const int InterfaceNumberLength = 4; /// /// Number of bytes in the object identifier length field /// private const int ObjectIdentifierLengthLength = 1; /// /// Maximum number of bytes in the object identifier field /// private const int maxObjectIdentifierLength = 128; #region Constructors /// /// Creates a Management Address TLV /// /// /// The LLDP Data unit being modified /// /// /// The Management Address TLV's offset from the /// origin of the LLDP /// public ManagementAddress(byte[] bytes, int offset) : base(bytes, offset) { log.Debug(""); } /// /// Creates a Management Address TLV and sets it value /// /// /// The Management Address /// /// /// The Interface Numbering Sub Type /// /// /// The Interface Number /// /// /// The Object Identifier /// public ManagementAddress(NetworkAddress managementAddress, InterfaceNumbering interfaceSubType, uint ifNumber, string oid) { log.Debug(""); // NOTE: We presume that the mgmt address length and the // object identifier length are zero var length = TLVTypeLength.TypeLengthLength + MgmtAddressLengthLength + InterfaceNumberSubTypeLength + InterfaceNumberLength + ObjectIdentifierLengthLength; var bytes = new byte[length]; var offset = 0; tlvData = new ByteArraySegment(bytes, offset, length); // The lengths are both zero until the values are set AddressLength = 0; ObjIdLength = 0; Type = TLVTypes.ManagementAddress; MgmtAddress = managementAddress; InterfaceSubType = interfaceSubType; InterfaceNumber = ifNumber; ObjectIdentifier = oid; } #endregion #region Properties /// /// The Management Address Length /// public int AddressLength { get { return (int)tlvData.Bytes[ValueOffset]; } internal set { tlvData.Bytes[ValueOffset] = (byte)value; } } /// /// The Management Address Subtype /// /// Forward to the MgmtAddress instance /// public AddressFamily AddressSubType { get { return MgmtAddress.AddressFamily; } } /// /// The Management Address /// public NetworkAddress MgmtAddress { get { int offset = ValueOffset + MgmtAddressLengthLength; return new NetworkAddress(tlvData.Bytes, offset, AddressLength); } set { var valueLength = value.Length; var valueBytes = value.Bytes; // is the new address the same size as the old address? if(AddressLength != valueLength) { // need to resize the tlv and shift data fields down var newLength = TLVTypeLength.TypeLengthLength + MgmtAddressLengthLength + valueLength + InterfaceNumberSubTypeLength + InterfaceNumberLength + ObjectIdentifierLengthLength + ObjIdLength; var newBytes = new byte[newLength]; int headerLength = TLVTypeLength.TypeLengthLength + MgmtAddressLengthLength; int oldStartOfAfterData = ValueOffset + MgmtAddressLengthLength + AddressLength; int newStartOfAfterData = TLVTypeLength.TypeLengthLength + MgmtAddressLengthLength + value.Length; int afterDataLength = InterfaceNumberSubTypeLength + InterfaceNumberLength + ObjectIdentifierLengthLength + ObjIdLength; // copy the data before the mgmt address Array.Copy(tlvData.Bytes, tlvData.Offset, newBytes, 0, headerLength); // copy the data over after the mgmt address over Array.Copy(tlvData.Bytes, oldStartOfAfterData, newBytes, newStartOfAfterData, afterDataLength); var offset = 0; tlvData = new ByteArraySegment(newBytes, offset, newLength); // update the address length field AddressLength = valueLength; } // copy the new address into the appropriate position in the byte[] Array.Copy(valueBytes, 0, tlvData.Bytes, ValueOffset + MgmtAddressLengthLength, valueLength); } } /// /// Interface Number Sub Type /// public InterfaceNumbering InterfaceSubType { get { return (InterfaceNumbering)tlvData.Bytes[ValueOffset + MgmtAddressLengthLength + MgmtAddress.Length]; } set { tlvData.Bytes[ValueOffset + MgmtAddressLengthLength + MgmtAddress.Length] = (byte)value; } } private int InterfaceNumberOffset { get { return ValueOffset + MgmtAddressLengthLength + AddressLength + InterfaceNumberSubTypeLength; } } /// /// Interface Number /// public uint InterfaceNumber { get { return EndianBitConverter.Big.ToUInt32(tlvData.Bytes, InterfaceNumberOffset); } set { EndianBitConverter.Big.CopyBytes(value, tlvData.Bytes, InterfaceNumberOffset); } } private int ObjIdLengthOffset { get { return InterfaceNumberOffset + InterfaceNumberLength; } } /// /// Object ID Length /// public byte ObjIdLength { get { return tlvData.Bytes[ObjIdLengthOffset]; } internal set { tlvData.Bytes[ObjIdLengthOffset] = value; } } private int ObjectIdentifierOffset { get { return ObjIdLengthOffset + ObjectIdentifierLengthLength; } } /// /// Object ID /// public string ObjectIdentifier { get { return UTF8Encoding.UTF8.GetString(tlvData.Bytes, ObjectIdentifierOffset, ObjIdLength); } set { byte[] oid = UTF8Encoding.UTF8.GetBytes(value); // check for out-of-range sizes if(oid.Length > maxObjectIdentifierLength) { throw new System.ArgumentOutOfRangeException("ObjectIdentifier", "length > maxObjectIdentifierLength of " + maxObjectIdentifierLength); } // does the object identifier length match the existing one? if(ObjIdLength != oid.Length) { var oldLength = TLVTypeLength.TypeLengthLength + MgmtAddressLengthLength + AddressLength + InterfaceNumberSubTypeLength + InterfaceNumberLength + ObjectIdentifierLengthLength; var newLength = oldLength + oid.Length; var newBytes = new byte[newLength]; // copy the original bytes over Array.Copy(tlvData.Bytes, tlvData.Offset, newBytes, 0, oldLength); var offset = 0; tlvData = new ByteArraySegment(newBytes, offset, newLength); // update the length ObjIdLength = (byte)value.Length; } Array.Copy(oid, 0, tlvData.Bytes, ObjectIdentifierOffset, oid.Length); } } /// /// Convert this Management Address TLV to a string. /// /// /// A human readable string /// public override string ToString () { return string.Format("[ManagementAddress: AddressLength={0}, AddressSubType={1}, MgmtAddress={2}, InterfaceSubType={3}, InterfaceNumber={4}, ObjIdLength={5}, ObjectIdentifier={6}]", AddressLength, AddressSubType, MgmtAddress, InterfaceSubType, InterfaceNumber, ObjIdLength, ObjectIdentifier); } #endregion } }