Files

368 lines
11 KiB
C#

/*
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 <http://www.gnu.org/licenses/>.
*/
/*
* Copyright 2010 Evan Plaice <evanplaice@gmail.com>
* Copyright 2010 Chris Morgan <chmorgan@gmail.com>
*/
using System;
using System.Net;
using System.Net.NetworkInformation;
using PacketDotNet.Utils;
namespace PacketDotNet.LLDP
{
/// <summary>
/// A Chassis ID TLV
/// </summary>
public class ChassisID : 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
/// <summary>
/// Length of the sub type field in bytes
/// </summary>
private const int SubTypeLength = 1;
#region Constructors
/// <summary>
/// Creates a Chassis ID TLV by parsing a byte[]
/// </summary>
/// <param name="bytes">
/// </param>
/// <param name="offset">
/// The Chassis ID TLV's offset from the
/// origin of the LLDP
/// </param>
public ChassisID(byte[] bytes, int offset) :
base(bytes, offset)
{
log.Debug("");
}
/// <summary>
/// Creates a Chassis ID TLV and sets it value
/// </summary>
/// <param name="subType">
/// The ChassisID subtype
/// </param>
/// <param name="subTypeValue">
/// The subtype's value
/// </param>
public ChassisID(ChassisSubTypes subType, object subTypeValue)
{
log.DebugFormat("subType {0}", subType);
EmptyTLVDataInit();
Type = TLVTypes.ChassisID;
SubType = subType;
// method will resize the tlv
SubTypeValue = subTypeValue;
}
/// <summary>
/// Create a ChassisID given a mac address
/// </summary>
/// <param name="MACAddress">
/// A <see cref="PhysicalAddress"/>
/// </param>
public ChassisID(PhysicalAddress MACAddress)
{
log.DebugFormat("MACAddress {0}", MACAddress.ToString());
EmptyTLVDataInit();
Type = TLVTypes.ChassisID;
SubType = ChassisSubTypes.MACAddress;
SubTypeValue = MACAddress;
}
/// <summary>
/// Create a ChassisID given an interface name
/// http://tools.ietf.org/search/rfc2863 page 38
/// </summary>
/// <param name="InterfaceName">
/// A <see cref="System.String"/>
/// </param>
public ChassisID(string InterfaceName)
{
log.DebugFormat("InterfaceName {0}", InterfaceName);
EmptyTLVDataInit();
Type = TLVTypes.ChassisID;
SubType = ChassisSubTypes.InterfaceName;
SetSubTypeValue(InterfaceName);
}
#endregion
#region Properties
/// <value>
/// The type of the TLV subtype
/// </value>
public ChassisSubTypes SubType
{
get
{
return (ChassisSubTypes)tlvData.Bytes[ValueOffset];
}
set
{
// set the subtype
tlvData.Bytes[ValueOffset] = (byte)value;
}
}
/// <value>
/// The TLV subtype value
/// </value>
public object SubTypeValue
{
get { return GetSubTypeValue(); }
set { SetSubTypeValue(value); }
}
/// <summary>
/// If SubType is ChassisComponent
/// </summary>
public byte[] ChassisComponent
{
get { return (byte[])GetSubTypeValue(); }
set
{
SubType = ChassisSubTypes.ChassisComponent;
SetSubTypeValue(value);
}
}
/// <summary>
/// If SubType is InterfaceName the interface name
/// </summary>
public string InterfaceName
{
get { return (string)GetSubTypeValue(); }
set
{
SubType = ChassisSubTypes.InterfaceName;
SetSubTypeValue(value);
}
}
/// <summary>
/// If SubType is MACAddress the mac address
/// </summary>
public PhysicalAddress MACAddress
{
get { return (PhysicalAddress)GetSubTypeValue(); }
set
{
SubType = ChassisSubTypes.MACAddress;
SetSubTypeValue(value);
}
}
/// <summary>
/// If SubType is NetworkAddress the network address
/// </summary>
public LLDP.NetworkAddress NetworkAddress
{
get { return (LLDP.NetworkAddress)GetSubTypeValue(); }
set
{
SubType = ChassisSubTypes.NetworkAddress;
SetSubTypeValue(value);
}
}
/// <summary>
/// If SubType is PortComponent
/// </summary>
public byte[] PortComponent
{
get { return (byte[])GetSubTypeValue(); }
set
{
SubType = ChassisSubTypes.PortComponent;
SetSubTypeValue(value);
}
}
/// <summary>
/// If SubType is InterfaceAlias
/// </summary>
public byte[] InterfaceAlias
{
get { return (byte[])GetSubTypeValue(); }
set
{
SubType = ChassisSubTypes.InterfaceAlias;
SetSubTypeValue(value);
}
}
#endregion
#region Methods
/// <summary>
/// Helper method to reduce duplication in type specific constructors
/// </summary>
private void EmptyTLVDataInit()
{
var length = TLVTypeLength.TypeLengthLength + SubTypeLength;
var bytes = new byte[length];
int offset = 0;
tlvData = new ByteArraySegment(bytes, offset, length);
}
private object GetSubTypeValue()
{
byte[] val;
int dataOffset = ValueOffset + SubTypeLength;
int dataLength = Length - SubTypeLength;
switch (SubType)
{
case ChassisSubTypes.ChassisComponent:
case ChassisSubTypes.InterfaceAlias:
case ChassisSubTypes.LocallyAssigned:
case ChassisSubTypes.PortComponent:
val = new byte[dataLength];
Array.Copy(tlvData.Bytes, dataOffset,
val, 0,
dataLength);
return val;
case ChassisSubTypes.NetworkAddress:
return new NetworkAddress(tlvData.Bytes,
dataOffset,
dataLength);
case ChassisSubTypes.MACAddress:
val = new byte[dataLength];
Array.Copy(tlvData.Bytes, dataOffset,
val, 0,
dataLength);
return new PhysicalAddress(val);
case ChassisSubTypes.InterfaceName:
return System.Text.ASCIIEncoding.ASCII.GetString(tlvData.Bytes, dataOffset, dataLength);
default:
throw new ArgumentOutOfRangeException();
}
}
private void SetSubTypeValue(object val)
{
byte[] valBytes;
// make sure we have the correct type
switch (SubType)
{
case ChassisSubTypes.ChassisComponent:
case ChassisSubTypes.InterfaceAlias:
case ChassisSubTypes.LocallyAssigned:
case ChassisSubTypes.PortComponent:
if(!(val is byte[]))
{
throw new ArgumentOutOfRangeException("expected byte[] for type");
}
valBytes = (byte[])val;
SetSubTypeValue(valBytes);
break;
case ChassisSubTypes.NetworkAddress:
if(!(val is NetworkAddress))
{
throw new ArgumentOutOfRangeException("expected NetworkAddress instance for NetworkAddress");
}
valBytes = ((NetworkAddress)val).Bytes;
SetSubTypeValue(valBytes);
break;
case ChassisSubTypes.InterfaceName:
if(!(val is string))
{
throw new ArgumentOutOfRangeException("expected string for InterfaceName");
}
var interfaceName = (string)val;
valBytes = System.Text.ASCIIEncoding.ASCII.GetBytes(interfaceName);
SetSubTypeValue(valBytes);
break;
case ChassisSubTypes.MACAddress:
if(!(val is PhysicalAddress))
{
throw new ArgumentOutOfRangeException("expected PhysicalAddress for MACAddress");
}
var physicalAddress = (PhysicalAddress)val;
SetSubTypeValue(physicalAddress.GetAddressBytes());
break;
default:
throw new ArgumentOutOfRangeException();
}
}
private void SetSubTypeValue(byte[] subTypeValue)
{
// is the length different than the current length?
if(subTypeValue.Length != Length)
{
var headerLength = TLVTypeLength.TypeLengthLength + SubTypeLength;
var newTlvMemory = new byte[headerLength + subTypeValue.Length];
// copy the header data over
Array.Copy(tlvData.Bytes, tlvData.Offset, newTlvMemory, 0, headerLength);
// update the tlv memory pointer, offset and length
tlvData = new ByteArraySegment(newTlvMemory, 0, newTlvMemory.Length);
}
Array.Copy(subTypeValue, 0, tlvData.Bytes, ValueOffset + SubTypeLength,
subTypeValue.Length);
}
/// <summary>
/// Convert this Chassis ID TLV to a string.
/// </summary>
/// <returns>
/// A human readable string
/// </returns>
public override string ToString ()
{
return string.Format("[ChassisID: SubType={0}, SubTypeValue={1}]", SubType, SubTypeValue);
}
#endregion
}
}