Commit d933da7e authored by Brickner_cp's avatar Brickner_cp

IPv6

parent f1e3ddd5
......@@ -320,28 +320,28 @@ namespace PcapDotNet.Packets.IpV6
/// <summary>
/// RFC 6089
/// </summary>
FlowSummaryMobilityOption = 0x2C,
FlowSummary = 0x2C,
/// <summary>
/// RFC 6089.
/// </summary>
FlowIdentificationMobilityOption = 0x2D,
FlowIdentification = 0x2D,
/// <summary>
/// RFC 6463.
/// Redirect-Capability Mobility Option.
/// </summary>
RedirectCapabilityMobilityOption = 0x2E,
RedirectCapability = 0x2E,
/// <summary>
/// RFC 6463.
/// </summary>
RedirectMobilityOption = 0x2F,
Redirect = 0x2F,
/// <summary>
/// RFC 6463.
/// </summary>
LoadInformationMobilityOption = 0x30,
LoadInformation = 0x30,
/// <summary>
/// RFC 6463.
......@@ -358,7 +358,7 @@ namespace PcapDotNet.Packets.IpV6
/// RFC 6705.
/// MAG IPv6 Address.
/// </summary>
MagIpV6Address = 0x33,
MobileAccessGatewayIpV6Address = 0x33,
/// <summary>
/// RFC 6757.
......
......@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using PcapDotNet.Base;
using PcapDotNet.Packets.Ip;
using PcapDotNet.Packets.IpV4;
......@@ -120,7 +121,7 @@ namespace PcapDotNet.Packets.IpV6
}
}
/// <summary>
/// RFC 6275.
/// <pre>
......@@ -252,7 +253,10 @@ namespace PcapDotNet.Packets.IpV6
/// <summary>
/// Contains an address to use as the care-of address for the binding, rather than using the Source Address of the packet as the care-of address.
/// </summary>
public IpV6Address AlternateCareOfAddress { get { return Address; } }
public IpV6Address AlternateCareOfAddress
{
get { return Address; }
}
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
......@@ -963,7 +967,10 @@ namespace PcapDotNet.Packets.IpV6
/// <summary>
/// 64 bit timestamp.
/// </summary>
public ulong Timestamp { get { return Value; } }
public ulong Timestamp
{
get { return Value; }
}
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
......@@ -1227,7 +1234,10 @@ namespace PcapDotNet.Packets.IpV6
/// <summary>
/// Contains the care-of keygen token generated by the correspondent node.
/// </summary>
public ulong CareOfKeygenToken { get { return Value; } }
public ulong CareOfKeygenToken
{
get { return Value; }
}
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
......@@ -1248,12 +1258,12 @@ namespace PcapDotNet.Packets.IpV6
/// DNS update performed.
/// </summary>
DnsUpdatePerformed = 0,
/// <summary>
/// Reason unspecified.
/// </summary>
ReasonUnspecified = 128,
/// <summary>
/// Administratively prohibited.
/// </summary>
......@@ -1693,7 +1703,10 @@ namespace PcapDotNet.Packets.IpV6
/// <summary>
/// Specifies the type of handoff.
/// </summary>
public IpV6HandoffIndicator HandoffIndicator { get { return (IpV6HandoffIndicator)Value; } }
public IpV6HandoffIndicator HandoffIndicator
{
get { return (IpV6HandoffIndicator)Value; }
}
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
......@@ -1759,7 +1772,10 @@ namespace PcapDotNet.Packets.IpV6
/// <summary>
/// Specifies the access technology through which the mobile node is connected to the access link on the mobile access gateway.
/// </summary>
public IpV6AccessTechnologyType AccessTechnologyType { get { return (IpV6AccessTechnologyType)Value; } }
public IpV6AccessTechnologyType AccessTechnologyType
{
get { return (IpV6AccessTechnologyType)Value; }
}
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
......@@ -1898,7 +1914,10 @@ namespace PcapDotNet.Packets.IpV6
/// <summary>
/// Contains the link-local address.
/// </summary>
public IpV6Address LinkLocalAddress { get { return Address; } }
public IpV6Address LinkLocalAddress
{
get { return Address; }
}
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
......@@ -1938,7 +1957,10 @@ namespace PcapDotNet.Packets.IpV6
/// The value indicates the number of seconds since January 1, 1970, 00:00 UTC, by using a fixed point format.
/// In this format, the integer number of seconds is contained in the first 48 bits of the field, and the remaining 16 bits indicate the number of 1/65536 fractions of a second.
/// </summary>
public ulong Timestamp { get { return Value; } }
public ulong Timestamp
{
get { return Value; }
}
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
......@@ -2559,7 +2581,7 @@ namespace PcapDotNet.Packets.IpV6
}
/// <summary>
/// RFC 5648.
/// RFCs 5648, 6089.
/// <pre>
/// +-----+-------------+---+-----------+
/// | Bit | 0-7 | 8 | 9-15 |
......@@ -2568,7 +2590,7 @@ namespace PcapDotNet.Packets.IpV6
/// +-----+-------------+---------------+
/// | 16 | Binding ID (BID) |
/// +-----+-------------+---+-----------+
/// | 32 | Status | H | Reserved |
/// | 32 | Status | H | BID-PRI |
/// +-----+-------------+---+-----------+
/// | 48 | IPv4 or IPv6 |
/// | ... | care-of address (CoA) |
......@@ -2578,12 +2600,15 @@ namespace PcapDotNet.Packets.IpV6
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.BindingIdentifier)]
public class IpV6MobilityOptionBindingIdentifier : IpV6MobilityOptionComplex
{
public const byte MaxPriority = 0x7F;
private static class Offset
{
public const int BindingId = 0;
public const int Status = BindingId + sizeof(ushort);
public const int SimultaneousHomeAndForeignBinding = Status + sizeof(byte);
public const int CareOfAddress = SimultaneousHomeAndForeignBinding + sizeof(byte);
public const int Priority = SimultaneousHomeAndForeignBinding;
public const int CareOfAddress = Priority + sizeof(byte);
}
public const int OptionDataMinimumLength = Offset.CareOfAddress;
......@@ -2591,22 +2616,24 @@ namespace PcapDotNet.Packets.IpV6
private static class Mask
{
public const byte SimultaneousHomeAndForeignBinding = 0x80;
public const byte Priority = 0x7F;
}
public IpV6MobilityOptionBindingIdentifier(ushort bindingId, IpV6BindingAcknowledgementStatus status, bool simultaneousHomeAndForeignBinding,
IpV4Address careOfAddress)
: this(bindingId, status, simultaneousHomeAndForeignBinding, careOfAddress, null)
byte priority, IpV4Address careOfAddress)
: this(bindingId, status, simultaneousHomeAndForeignBinding, priority, careOfAddress, null)
{
}
public IpV6MobilityOptionBindingIdentifier(ushort bindingId, IpV6BindingAcknowledgementStatus status, bool simultaneousHomeAndForeignBinding,
IpV6Address careOfAddress)
: this(bindingId, status, simultaneousHomeAndForeignBinding, null, careOfAddress)
byte priority, IpV6Address careOfAddress)
: this(bindingId, status, simultaneousHomeAndForeignBinding, priority, null, careOfAddress)
{
}
public IpV6MobilityOptionBindingIdentifier(ushort bindingId, IpV6BindingAcknowledgementStatus status, bool simultaneousHomeAndForeignBinding)
: this(bindingId, status, simultaneousHomeAndForeignBinding, null, null)
public IpV6MobilityOptionBindingIdentifier(ushort bindingId, IpV6BindingAcknowledgementStatus status, bool simultaneousHomeAndForeignBinding,
byte priority)
: this(bindingId, status, simultaneousHomeAndForeignBinding, priority, null, null)
{
}
......@@ -2633,6 +2660,15 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public bool SimultaneousHomeAndForeignBinding { get; private set; }
/// <summary>
/// Places each BID to a relative priority (PRI) with other registered BIDs.
/// Value '0' is reserved and must not be used.
/// A lower number in this field indicates a higher priority, while BIDs with the same BID-PRI value have equal priority meaning that,
/// the BID used is an implementation issue.
/// This is consistent with current practice in packet classifiers.
/// </summary>
public byte Priority { get; private set; }
/// <summary>
/// The IPv4 care-of address for the corresponding BID, or null if no IPv4 care-of address is stored.
/// </summary>
......@@ -2670,17 +2706,18 @@ namespace PcapDotNet.Packets.IpV6
ushort bindingId = data.ReadUShort(Offset.BindingId, Endianity.Big);
IpV6BindingAcknowledgementStatus status = (IpV6BindingAcknowledgementStatus)data[Offset.Status];
bool simultaneousHomeAndForeignBinding = data.ReadBool(Offset.SimultaneousHomeAndForeignBinding, Mask.SimultaneousHomeAndForeignBinding);
byte priority = (byte)(data[Offset.Priority] & Mask.Priority);
if (data.Length == OptionDataMinimumLength)
return new IpV6MobilityOptionBindingIdentifier(bindingId, status, simultaneousHomeAndForeignBinding);
return new IpV6MobilityOptionBindingIdentifier(bindingId, status, simultaneousHomeAndForeignBinding, priority);
if (data.Length == OptionDataMinimumLength + IpV4Address.SizeOf)
{
IpV4Address careOfAddress = data.ReadIpV4Address(Offset.CareOfAddress, Endianity.Big);
return new IpV6MobilityOptionBindingIdentifier(bindingId, status, simultaneousHomeAndForeignBinding, careOfAddress);
return new IpV6MobilityOptionBindingIdentifier(bindingId, status, simultaneousHomeAndForeignBinding, priority, careOfAddress);
}
if (data.Length == OptionDataMinimumLength + IpV6Address.SizeOf)
{
IpV6Address careOfAddress = data.ReadIpV6Address(Offset.CareOfAddress, Endianity.Big);
return new IpV6MobilityOptionBindingIdentifier(bindingId, status, simultaneousHomeAndForeignBinding, careOfAddress);
return new IpV6MobilityOptionBindingIdentifier(bindingId, status, simultaneousHomeAndForeignBinding, priority, careOfAddress);
}
return null;
}
......@@ -2694,10 +2731,10 @@ namespace PcapDotNet.Packets.IpV6
{
buffer.Write(offset + Offset.BindingId, BindingId, Endianity.Big);
buffer.Write(offset + Offset.Status, (byte)Status);
byte simultaneousHomeAndForeignBinding = 0;
byte simultaneousHomeAndForeignBindingAndPriority = (byte)(Priority & Mask.Priority);
if (SimultaneousHomeAndForeignBinding)
simultaneousHomeAndForeignBinding |= Mask.SimultaneousHomeAndForeignBinding;
buffer.Write(offset + Offset.SimultaneousHomeAndForeignBinding, simultaneousHomeAndForeignBinding);
simultaneousHomeAndForeignBindingAndPriority |= Mask.SimultaneousHomeAndForeignBinding;
buffer.Write(offset + Offset.SimultaneousHomeAndForeignBinding, simultaneousHomeAndForeignBindingAndPriority);
if (IpV4CareOfAddress.HasValue)
{
buffer.Write(offset + Offset.CareOfAddress, IpV4CareOfAddress.Value, Endianity.Big);
......@@ -2714,12 +2751,15 @@ namespace PcapDotNet.Packets.IpV6
}
private IpV6MobilityOptionBindingIdentifier(ushort bindingId, IpV6BindingAcknowledgementStatus status, bool simultaneousHomeAndForeignBinding,
IpV4Address? ipV4CareOfAddress, IpV6Address? ipV6CareOfAddress)
byte priority, IpV4Address? ipV4CareOfAddress, IpV6Address? ipV6CareOfAddress)
: base(IpV6MobilityOptionType.BindingIdentifier)
{
if (priority > MaxPriority)
throw new ArgumentOutOfRangeException("priority", priority, string.Format("Must not exceed {0}", MaxPriority));
BindingId = bindingId;
Status = status;
SimultaneousHomeAndForeignBinding = simultaneousHomeAndForeignBinding;
Priority = priority;
IpV4CareOfAddress = ipV4CareOfAddress;
IpV6CareOfAddress = ipV6CareOfAddress;
}
......@@ -2783,7 +2823,7 @@ namespace PcapDotNet.Packets.IpV6
/// The value of 0.0.0.0 is used to request that the local mobility anchor perform the address allocation.
/// </summary>
public IpV4Address HomeAddress { get; private set; }
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
if (data.Length != OptionDataLength)
......@@ -2815,7 +2855,7 @@ namespace PcapDotNet.Packets.IpV6
/// <summary>
/// Success.
/// </summary>
Success = 0,
Success = 0,
/// <summary>
/// Failure, reason unspecified.
......@@ -3093,7 +3133,10 @@ namespace PcapDotNet.Packets.IpV6
/// <summary>
/// The length of the requested option, excluding the Request Type and Request Length fields.
/// </summary>
public byte OptionLength { get { return (byte)Option.Length; } }
public byte OptionLength
{
get { return (byte)Option.Length; }
}
/// <summary>
/// The optional data to uniquely identify the requested context for the requested option.
......@@ -3155,7 +3198,7 @@ namespace PcapDotNet.Packets.IpV6
while (data.Length > offset)
{
byte requestType = data[offset++];
if (offset >= data.Length)
return null;
byte requestLength = data[offset++];
......@@ -3310,9 +3353,11 @@ namespace PcapDotNet.Packets.IpV6
buffer.Write(offset + Offset.LocalMobilityAnchorAddress, LocalMobilityAnchorAddressIpV4.Value, Endianity.Big);
else if (LocalMobilityAnchorAddressIpV6.HasValue)
buffer.Write(offset + Offset.LocalMobilityAnchorAddress, LocalMobilityAnchorAddressIpV6.Value, Endianity.Big);
offset += DataLength;
}
private IpV6MobilityOptionLocalMobilityAnchorAddress(IpV6LocalMobilityAnchorAddressCode code, IpV4Address? localMobilityAnchorAddressIpV4, IpV6Address? localMobilityAnchorAddressIpV6)
private IpV6MobilityOptionLocalMobilityAnchorAddress(IpV6LocalMobilityAnchorAddressCode code, IpV4Address? localMobilityAnchorAddressIpV4,
IpV6Address? localMobilityAnchorAddressIpV6)
: base(IpV6MobilityOptionType.LocalMobilityAnchorAddress)
{
Code = code;
......@@ -3320,4 +3365,1872 @@ namespace PcapDotNet.Packets.IpV6
LocalMobilityAnchorAddressIpV4 = localMobilityAnchorAddressIpV4;
}
}
/// <summary>
/// RFC 5949.
/// <pre>
/// +-----+-------------+--------------+
/// | Bit | 0-7 | 8-15 |
/// +-----+-------------+--------------+
/// | 0 | Option Type | Opt Data Len |
/// +-----+-------------+--------------+
/// | 16 | Reserved |
/// +-----+----------------------------+
/// | 32 | Interface Identifier |
/// | | |
/// | | |
/// | | |
/// +-----+----------------------------+
/// </pre>
/// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.MobileNodeLinkLocalAddressInterfaceIdentifier)]
public class IpV6MobilityOptionMobileNodeLinkLocalAddressInterfaceIdentifier : IpV6MobilityOptionComplex
{
private static class Offset
{
public const int InterfaceIdentifier = sizeof(ushort);
}
public const int OptionDataLength = Offset.InterfaceIdentifier + sizeof(ulong);
public IpV6MobilityOptionMobileNodeLinkLocalAddressInterfaceIdentifier(ulong interfaceIdentifier)
: base(IpV6MobilityOptionType.MobileNodeLinkLocalAddressInterfaceIdentifier)
{
InterfaceIdentifier = interfaceIdentifier;
}
/// <summary>
/// The Interface Identifier value used for the mobile node's IPv6 Link-local address in the P-AN.
/// </summary>
public ulong InterfaceIdentifier { get; private set; }
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
if (data.Length != OptionDataLength)
return null;
ulong interfaceIdentifier = data.ReadULong(Offset.InterfaceIdentifier, Endianity.Big);
return new IpV6MobilityOptionMobileNodeLinkLocalAddressInterfaceIdentifier(interfaceIdentifier);
}
internal override int DataLength
{
get { return OptionDataLength; }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
buffer.Write(offset + Offset.InterfaceIdentifier, InterfaceIdentifier, Endianity.Big);
offset += DataLength;
}
}
/// <summary>
/// RFC 6058.
/// <pre>
/// +-----+----------+---+--------------+
/// | Bit | 0-6 | 7 | 8-15 |
/// +-----+----------+---+--------------+
/// | 0 | Option Type | Opt Data Len |
/// +-----+----------+---+--------------+
/// | 16 | Reserved | L | Lifetime |
/// +-----+----------+---+--------------+
/// </pre>
/// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.TransientBinding)]
public class IpV6MobilityOptionTransientBinding : IpV6MobilityOptionComplex
{
private static class Offset
{
public const int LatePathSwitch = 0;
public const int Lifetime = LatePathSwitch + sizeof(byte);
}
private static class Mask
{
public const int LatePathSwitch = 0x01;
}
public const int OptionDataLength = Offset.Lifetime + sizeof(byte);
public IpV6MobilityOptionTransientBinding(bool latePathSwitch, byte lifetime)
: base(IpV6MobilityOptionType.TransientBinding)
{
LatePathSwitch = latePathSwitch;
Lifetime = lifetime;
}
/// <summary>
/// Indicates that the Local Mobility Anchor (LMA) applies late path switch according to the transient BCE state.
/// If true, the LMA continues to forward downlink packets towards the pMAG.
/// Different setting of this flag may be for future use.
/// </summary>
public bool LatePathSwitch { get; private set; }
/// <summary>
/// Maximum lifetime of a Transient-L state in multiple of 100 ms.
/// </summary>
public byte Lifetime { get; private set; }
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
if (data.Length != OptionDataLength)
return null;
bool latePathSwitch = data.ReadBool(Offset.LatePathSwitch, Mask.LatePathSwitch);
byte lifetime = data[Offset.Lifetime];
return new IpV6MobilityOptionTransientBinding(latePathSwitch, lifetime);
}
internal override int DataLength
{
get { return OptionDataLength; }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
if (LatePathSwitch)
buffer.Write(offset + Offset.LatePathSwitch, Mask.LatePathSwitch);
buffer.Write(offset + Offset.Lifetime, Lifetime);
offset += DataLength;
}
}
/// <summary>
/// RFC 6089.
/// <pre>
/// +-----+-------------+--------------+
/// | Bit | 0-7 | 8-15 |
/// +-----+-------------+--------------+
/// | 0 | Option Type | Opt Data Len |
/// +-----+-------------+--------------+
/// | 16 | FID ... |
/// | ... | |
/// +-----+----------------------------+
/// </pre>
/// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.FlowSummary)]
public class IpV6MobilityOptionFlowSummary : IpV6MobilityOptionComplex
{
public const int OptionDataMinimumLength = sizeof(ushort);
public IpV6MobilityOptionFlowSummary(params ushort[] flowIdentifiers)
: this(flowIdentifiers.AsReadOnly())
{
}
public IpV6MobilityOptionFlowSummary(IEnumerable<ushort> flowIdentifiers)
: this(flowIdentifiers.ToList())
{
}
public IpV6MobilityOptionFlowSummary(IList<ushort> flowIdentifiers)
: this(flowIdentifiers.AsReadOnly())
{
}
public IpV6MobilityOptionFlowSummary(ReadOnlyCollection<ushort> flowIdentifiers)
: base(IpV6MobilityOptionType.FlowSummary)
{
if (!flowIdentifiers.Any())
throw new ArgumentOutOfRangeException("flowIdentifiers", flowIdentifiers, "Must not be empty.");
FlowIdentifiers = flowIdentifiers;
}
/// <summary>
/// Indicating a registered FID.
/// One or more FID fields can be included in this option.
/// </summary>
public ReadOnlyCollection<ushort> FlowIdentifiers { get; private set; }
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
if (data.Length < OptionDataMinimumLength || data.Length % sizeof(ushort) != 0)
return null;
ushort[] flowIdentifiers = new ushort[data.Length / sizeof(ushort)];
for (int i = 0; i != flowIdentifiers.Length; ++i)
flowIdentifiers[i] = data.ReadUShort(i * sizeof(ushort), Endianity.Big);
return new IpV6MobilityOptionFlowSummary(flowIdentifiers);
}
internal override int DataLength
{
get { return FlowIdentifiers.Count * sizeof(ushort); }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
foreach (ushort flowIdentifier in FlowIdentifiers)
buffer.Write(ref offset, flowIdentifier, Endianity.Big);
}
}
/// <summary>
/// RFC 6089.
/// </summary>
public enum IpV6FlowIdentificationStatus : byte
{
/// <summary>
/// Flow binding successful.
/// </summary>
FlowBindingSuccessful = 0,
/// <summary>
/// Administratively prohibited
/// </summary>
AdministrativelyProhibited = 128,
/// <summary>
/// Flow binding rejected, reason unspecified
/// </summary>
FlowBindingRejectedReasonUnspecified = 129,
/// <summary>
/// Flow identification mobility option malformed.
/// </summary>
FlowIdentificationMobilityOptionMalformed = 130,
/// <summary>
/// BID not found.
/// </summary>
BindingIdNotFound = 131,
/// <summary>
/// FID not found.
/// </summary>
FlowIdentifierNotFound = 132,
/// <summary>
/// Traffic selector format not supported.
/// </summary>
TrafficSelectorFormatNotSupported = 133,
}
/// <summary>
/// RFC 6089.
/// </summary>
public abstract class IpV6FlowIdentificationSubOption : Option
{
/// <summary>
/// The type of the option.
/// </summary>
public IpV6FlowIdentificationSubOptionType OptionType { get; private set; }
internal abstract IpV6FlowIdentificationSubOption CreateInstance(DataSegment data);
protected IpV6FlowIdentificationSubOption(IpV6FlowIdentificationSubOptionType type)
{
OptionType = type;
}
internal override void Write(byte[] buffer, ref int offset)
{
buffer[offset++] = (byte)OptionType;
}
public override int Length
{
get { return sizeof(byte); }
}
}
/// <summary>
/// RFC 6089.
/// <pre>
/// +-----+--------------+
/// | Bit | 0-7 |
/// +-----+--------------+
/// | 0 | Sub-Opt Type |
/// +-----+--------------+
/// </pre>
/// </summary>
public abstract class IpV6FlowIdentificationSubOptionSimple : IpV6FlowIdentificationSubOption
{
protected IpV6FlowIdentificationSubOptionSimple(IpV6FlowIdentificationSubOptionType type)
: base(type)
{
}
public override sealed int Length
{
get { return base.Length; }
}
internal override sealed void Write(byte[] buffer, ref int offset)
{
base.Write(buffer, ref offset);
}
internal override sealed IpV6FlowIdentificationSubOption CreateInstance(DataSegment data)
{
throw new InvalidOperationException("Simple options shouldn't be registered.");
}
}
/// <summary>
/// RFC 6089.
/// <pre>
/// +-----+--------------+-------------+
/// | Bit | 0-7 | 8-15 |
/// +-----+--------------+-------------+
/// | 0 | Sub-Opt Type | Sub-Opt Len |
/// +-----+--------------+-------------+
/// | 16 | Option Data |
/// | ... | |
/// +-----+----------------------------+
/// </pre>
/// </summary>
public abstract class IpV6FlowIdentificationSubOptionComplex : IpV6FlowIdentificationSubOption
{
protected IpV6FlowIdentificationSubOptionComplex(IpV6FlowIdentificationSubOptionType type)
: base(type)
{
}
public override sealed int Length
{
get { return base.Length + sizeof(byte) + DataLength; }
}
internal abstract int DataLength { get; }
internal override sealed void Write(byte[] buffer, ref int offset)
{
base.Write(buffer, ref offset);
buffer[offset++] = (byte)DataLength;
WriteData(buffer, ref offset);
}
internal abstract void WriteData(byte[] buffer, ref int offset);
}
/// <summary>
/// RFC 6089.
/// </summary>
public enum IpV6FlowIdentificationSubOptionType : byte
{
/// <summary>
/// RFC 6089.
/// </summary>
Pad1 = 0,
/// <summary>
/// RFC 6089.
/// </summary>
PadN = 1,
/// <summary>
/// RFC 6089.
/// </summary>
BindingReference = 2,
/// <summary>
/// RFC 6089.
/// </summary>
TrafficSelector = 3,
}
/// <summary>
/// RFC 6089.
/// </summary>
public class IpV6FlowIdentificationSubOptions : Options<IpV6FlowIdentificationSubOption>
{
/// <summary>
/// Creates options from a list of options.
/// </summary>
/// <param name="options">The list of options.</param>
public IpV6FlowIdentificationSubOptions(IList<IpV6FlowIdentificationSubOption> options)
: base(options, true, null)
{
}
/// <summary>
/// Creates options from a list of options.
/// </summary>
/// <param name="options">The list of options.</param>
public IpV6FlowIdentificationSubOptions(params IpV6FlowIdentificationSubOption[] options)
: this((IList<IpV6FlowIdentificationSubOption>)options)
{
}
internal IpV6FlowIdentificationSubOptions(DataSegment data)
: this(Read(data))
{
}
private IpV6FlowIdentificationSubOptions(Tuple<IList<IpV6FlowIdentificationSubOption>, bool> optionsAndIsValid)
: base(optionsAndIsValid.Item1, optionsAndIsValid.Item2, null)
{
}
/// <summary>
/// No options instance.
/// </summary>
public static IpV6FlowIdentificationSubOptions None
{
get { return _none; }
}
internal static Tuple<IList<IpV6FlowIdentificationSubOption>, bool> Read(DataSegment data)
{
int offset = 0;
List<IpV6FlowIdentificationSubOption> options = new List<IpV6FlowIdentificationSubOption>();
bool isValid = true;
while (offset < data.Length)
{
IpV6FlowIdentificationSubOptionType optionType = (IpV6FlowIdentificationSubOptionType)data[offset++];
if (optionType == IpV6FlowIdentificationSubOptionType.Pad1)
{
options.Add(new IpV6FlowIdentificationSubOptionPad1());
continue;
}
if (offset >= data.Length)
{
isValid = false;
break;
}
byte optionDataLength = data[offset++];
if (offset + optionDataLength > data.Length)
{
isValid = false;
break;
}
IpV6FlowIdentificationSubOption option = CreateOption(optionType, data.Subsegment(ref offset, optionDataLength));
if (option == null)
{
isValid = false;
break;
}
options.Add(option);
}
return new Tuple<IList<IpV6FlowIdentificationSubOption>, bool>(options, isValid);
}
private static IpV6FlowIdentificationSubOption CreateOption(IpV6FlowIdentificationSubOptionType optionType, DataSegment data)
{
IpV6FlowIdentificationSubOption prototype;
if (!_prototypes.TryGetValue(optionType, out prototype))
return new IpV6FlowIdentificationSubOptionUnknown(optionType, data);
return prototype.CreateInstance(data);
}
private static readonly Dictionary<IpV6FlowIdentificationSubOptionType, IpV6FlowIdentificationSubOption> _prototypes = InitializePrototypes();
private static Dictionary<IpV6FlowIdentificationSubOptionType, IpV6FlowIdentificationSubOption> InitializePrototypes()
{
var prototypes =
from type in Assembly.GetExecutingAssembly().GetTypes()
where typeof (IpV6FlowIdentificationSubOption).IsAssignableFrom(type) &&
GetRegistrationAttribute(type) != null
select new
{
GetRegistrationAttribute(type).OptionType,
Option = (IpV6FlowIdentificationSubOption)Activator.CreateInstance(type)
};
return prototypes.ToDictionary(option => option.OptionType, option => option.Option);
}
private static IpV6FlowIdentificationSubOptionTypeRegistrationAttribute GetRegistrationAttribute(Type type)
{
var registraionAttributes = type.GetCustomAttributes<IpV6FlowIdentificationSubOptionTypeRegistrationAttribute>(false);
if (!registraionAttributes.Any())
return null;
return registraionAttributes.First();
}
private static readonly IpV6FlowIdentificationSubOptions _none = new IpV6FlowIdentificationSubOptions();
}
internal sealed class IpV6FlowIdentificationSubOptionTypeRegistrationAttribute : Attribute
{
public IpV6FlowIdentificationSubOptionTypeRegistrationAttribute(IpV6FlowIdentificationSubOptionType optionType)
{
OptionType = optionType;
}
public IpV6FlowIdentificationSubOptionType OptionType { get; private set; }
}
public class IpV6FlowIdentificationSubOptionPad1 : IpV6FlowIdentificationSubOptionSimple
{
public const int OptionLength = sizeof(byte);
public IpV6FlowIdentificationSubOptionPad1()
: base(IpV6FlowIdentificationSubOptionType.Pad1)
{
}
}
/// <summary>
/// RFC 6089.
/// <pre>
/// +-----+--------------+
/// | Bit | 0-7 |
/// +-----+--------------+
/// | 0 | Sub-Opt Type |
/// +-----+--------------+
/// | 8 | N |
/// +-----+--------------+
/// | 16 | 0 |
/// | ... | |
/// +-----+--------------+
/// </pre>
/// </summary>
[IpV6FlowIdentificationSubOptionTypeRegistration(IpV6FlowIdentificationSubOptionType.PadN)]
public class IpV6FlowIdentificationSubOptionPadN : IpV6FlowIdentificationSubOptionComplex
{
public IpV6FlowIdentificationSubOptionPadN(int paddingDataLength)
: base(IpV6FlowIdentificationSubOptionType.PadN)
{
PaddingDataLength = paddingDataLength;
}
public int PaddingDataLength { get; private set; }
internal override IpV6FlowIdentificationSubOption CreateInstance(DataSegment data)
{
return new IpV6FlowIdentificationSubOptionPadN(data.Length);
}
internal override int DataLength
{
get { return PaddingDataLength; }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
offset += PaddingDataLength;
}
}
/// <summary>
/// RFC 6089.
/// <pre>
/// +-----+--------------+-------------+
/// | Bit | 0-7 | 8-15 |
/// +-----+--------------+-------------+
/// | 0 | Sub-Opt Type | Sub-Opt Len |
/// +-----+--------------+-------------+
/// | 16 | Option Data |
/// | ... | |
/// +-----+----------------------------+
/// </pre>
/// </summary>
public class IpV6FlowIdentificationSubOptionUnknown : IpV6FlowIdentificationSubOptionComplex
{
public IpV6FlowIdentificationSubOptionUnknown(IpV6FlowIdentificationSubOptionType type, DataSegment data)
: base(type)
{
Data = data;
}
public DataSegment Data { get; private set; }
internal override IpV6FlowIdentificationSubOption CreateInstance(DataSegment data)
{
throw new InvalidOperationException("IpV6FlowIdentificationSubOptionUnknown shouldn't be registered.");
}
internal override int DataLength
{
get { return Data.Length; }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
buffer.Write(ref offset, Data);
}
}
/// <summary>
/// RFC 6089.
/// <pre>
/// +-----+--------------+-------------+
/// | Bit | 0-7 | 8-15 |
/// +-----+--------------+-------------+
/// | 0 | Sub-Opt Type | Sub-Opt Len |
/// +-----+--------------+-------------+
/// | 16 | BIDs |
/// | ... | |
/// +-----+----------------------------+
/// </pre>
/// </summary>
[IpV6FlowIdentificationSubOptionTypeRegistration(IpV6FlowIdentificationSubOptionType.BindingReference)]
public class IpV6FlowIdentificationSubOptionBindingReference : IpV6FlowIdentificationSubOptionComplex
{
public IpV6FlowIdentificationSubOptionBindingReference(IList<ushort> bindingIds)
: this(bindingIds.AsReadOnly())
{
}
public IpV6FlowIdentificationSubOptionBindingReference(params ushort[] bindingIds)
: this(bindingIds.AsReadOnly())
{
}
public IpV6FlowIdentificationSubOptionBindingReference(IEnumerable<ushort> bindingIds)
: this(bindingIds.ToList())
{
}
public IpV6FlowIdentificationSubOptionBindingReference(ReadOnlyCollection<ushort> bindingIds)
: base(IpV6FlowIdentificationSubOptionType.BindingReference)
{
BindingIds = bindingIds;
}
/// <summary>
/// Indicates the BIDs that the mobile node wants to associate with the flow identification option.
/// One or more BID fields can be included in this sub-option.
/// </summary>
public ReadOnlyCollection<ushort> BindingIds { get; private set; }
internal override IpV6FlowIdentificationSubOption CreateInstance(DataSegment data)
{
if (data.Length % sizeof(ushort) != 0)
return null;
ushort[] bindingIds = new ushort[data.Length / sizeof(ushort)];
for (int i = 0; i != bindingIds.Length; ++i)
bindingIds[i] = data.ReadUShort(i * sizeof(ushort), Endianity.Big);
return new IpV6FlowIdentificationSubOptionBindingReference(bindingIds);
}
internal override int DataLength
{
get { return BindingIds.Count * sizeof(ushort); }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
foreach (ushort bindingId in BindingIds)
buffer.Write(ref offset, bindingId, Endianity.Big);
}
}
/// <summary>
/// RFCs 6088, 6089.
/// </summary>
public enum IpV6FlowIdentificationTrafficSelectorFormat : byte
{
/// <summary>
/// IPv4 binary traffic selector.
/// </summary>
IpV4Binary = 1,
/// <summary>
/// IPv6 binary traffic selector.
/// </summary>
IpV6Binary = 2,
}
/// <summary>
/// RFC 6089.
/// <pre>
/// +-----+--------------+-------------+
/// | Bit | 0-7 | 8-15 |
/// +-----+--------------+-------------+
/// | 0 | Sub-Opt Type | Sub-Opt Len |
/// +-----+--------------+-------------+
/// | 16 | TS Format | Reserved |
/// +-----+--------------+-------------+
/// | 32 | Traffic Selector |
/// | ... | |
/// +-----+----------------------------+
/// </pre>
/// </summary>
[IpV6FlowIdentificationSubOptionTypeRegistration(IpV6FlowIdentificationSubOptionType.TrafficSelector)]
public class IpV6FlowIdentificationSubOptionTrafficSelector : IpV6FlowIdentificationSubOptionComplex
{
private static class Offset
{
public const int TrafficSelectorFormat = 0;
public const int TrafficSelector = TrafficSelectorFormat + sizeof(byte) + sizeof(byte);
}
public const int OptionDataMinimumLength = Offset.TrafficSelector;
public IpV6FlowIdentificationSubOptionTrafficSelector(IpV6FlowIdentificationTrafficSelectorFormat trafficSelectorFormat, DataSegment trafficSelector)
: base(IpV6FlowIdentificationSubOptionType.TrafficSelector)
{
TrafficSelectorFormat = trafficSelectorFormat;
TrafficSelector = trafficSelector;
}
/// <summary>
/// Indicates the Traffic Selector Format.
/// </summary>
public IpV6FlowIdentificationTrafficSelectorFormat TrafficSelectorFormat { get; private set; }
/// <summary>
/// The traffic selector formatted according to TrafficSelectorFormat.
/// </summary>
public DataSegment TrafficSelector { get; private set; }
internal override IpV6FlowIdentificationSubOption CreateInstance(DataSegment data)
{
if (data.Length < OptionDataMinimumLength)
return null;
IpV6FlowIdentificationTrafficSelectorFormat trafficSelectorFormat = (IpV6FlowIdentificationTrafficSelectorFormat)data[Offset.TrafficSelectorFormat];
DataSegment trafficSelector = data.Subsegment(Offset.TrafficSelector, data.Length - Offset.TrafficSelector);
return new IpV6FlowIdentificationSubOptionTrafficSelector(trafficSelectorFormat, trafficSelector);
}
internal override int DataLength
{
get { return OptionDataMinimumLength + TrafficSelector.Length; }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
buffer.Write(offset + Offset.TrafficSelectorFormat, (byte)TrafficSelectorFormat);
buffer.Write(offset + Offset.TrafficSelector, TrafficSelector);
offset += DataLength;
}
}
/// <summary>
/// RFC 6089.
/// <pre>
/// +-----+-------------+--------------+
/// | Bit | 0-7 | 8-15 |
/// +-----+-------------+--------------+
/// | 0 | Option Type | Opt Data Len |
/// +-----+-------------+--------------+
/// | 16 | FID |
/// +-----+----------------------------+
/// | 32 | FID-PRI |
/// +-----+-------------+--------------+
/// | 48 | Reserved | Status |
/// +-----+-------------+--------------+
/// | 64 | Sub-options (optional) |
/// | ... | |
/// +-----+----------------------------+
/// </pre>
/// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.FlowIdentification)]
public class IpV6MobilityOptionFlowIdentification : IpV6MobilityOptionComplex
{
private static class Offset
{
public const int FlowIdentifier = 0;
public const int Priority = FlowIdentifier + sizeof(ushort);
public const int Status = Priority + sizeof(ushort) + sizeof(byte);
public const int SubOptions = Status + sizeof(byte);
}
public const int OptionDataMinimumLength = Offset.SubOptions;
public IpV6MobilityOptionFlowIdentification(ushort flowIdentifier, ushort priority, IpV6FlowIdentificationStatus status,
IpV6FlowIdentificationSubOptions subOptions)
: base(IpV6MobilityOptionType.FlowIdentification)
{
FlowIdentifier = flowIdentifier;
Priority = priority;
Status = status;
SubOptions = subOptions;
}
/// <summary>
/// Includes the unique identifier for the flow binding.
/// This field is used to refer to an existing flow binding or to create a new flow binding.
/// The value of this field is set by the mobile node.
/// FID = 0 is reserved and must not be used.
/// </summary>
public ushort FlowIdentifier { get; private set; }
/// <summary>
/// Indicates the priority of a particular option.
/// This field is needed in cases where two different flow descriptions in two different options overlap.
/// The priority field decides which policy should be executed in those cases.
/// A lower number in this field indicates a higher priority.
/// Value '0' is reserved and must not be used.
/// Must be unique to each of the flows pertaining to a given MN.
/// In other words, two FIDs must not be associated with the same priority value.
/// </summary>
public ushort Priority { get; private set; }
/// <summary>
/// indicates the success or failure of the flow binding operation for the particular flow in the option.
/// This field is not relevant to the binding update message as a whole or to other flow identification options.
/// This field is only relevant when included in the Binding Acknowledgement message and must be ignored in the binding update message.
/// </summary>
public IpV6FlowIdentificationStatus Status { get; private set; }
/// <summary>
/// Zero or more sub-options.
/// </summary>
public IpV6FlowIdentificationSubOptions SubOptions { get; private set; }
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
if (data.Length < OptionDataMinimumLength)
return null;
ushort flowIdentifier = data.ReadUShort(Offset.FlowIdentifier, Endianity.Big);
ushort priority = data.ReadUShort(Offset.Priority, Endianity.Big);
IpV6FlowIdentificationStatus status = (IpV6FlowIdentificationStatus)data[Offset.Status];
IpV6FlowIdentificationSubOptions subOptions =
new IpV6FlowIdentificationSubOptions(data.Subsegment(Offset.SubOptions, data.Length - Offset.SubOptions));
return new IpV6MobilityOptionFlowIdentification(flowIdentifier, priority, status, subOptions);
}
internal override int DataLength
{
get { return OptionDataMinimumLength + SubOptions.BytesLength; }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
buffer.Write(offset + Offset.FlowIdentifier, FlowIdentifier, Endianity.Big);
buffer.Write(offset + Offset.Priority, Priority, Endianity.Big);
buffer.Write(offset + Offset.Status, (byte)Status);
SubOptions.Write(buffer, offset + Offset.SubOptions);
offset += DataLength;
}
}
/// <summary>
/// RFC 6463.
/// <pre>
/// +-----+-------------+--------------+
/// | Bit | 0-7 | 8-15 |
/// +-----+-------------+--------------+
/// | 0 | Option Type | Opt Data Len |
/// +-----+-------------+--------------+
/// | 16 | Reserved |
/// +-----+----------------------------+
/// </pre>
/// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.RedirectCapability)]
public class IpV6MobilityOptionRedirectCapability : IpV6MobilityOptionComplex
{
public const int OptionDataLength = sizeof(ushort);
public IpV6MobilityOptionRedirectCapability()
: base(IpV6MobilityOptionType.RedirectCapability)
{
}
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
if (data.Length != OptionDataLength)
return null;
return new IpV6MobilityOptionRedirectCapability();
}
internal override int DataLength
{
get { return OptionDataLength; }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
offset += DataLength;
}
}
/// <summary>
/// RFC 6463.
/// <pre>
/// +-----+---+---+-----+--------------+
/// | Bit | 0 | 1 | 2-7 | 8-15 |
/// +-----+---+---+-----+--------------+
/// | 0 | Option Type | Opt Data Len |
/// +-----+---+---+-----+--------------+
/// | 16 | K | N | Reserved |
/// +-----+---+---+--------------------+
/// | 32 | r2LMA Address |
/// | | |
/// | ... | |
/// +-----+----------------------------+
/// </pre>
/// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.Redirect)]
public class IpV6MobilityOptionRedirect : IpV6MobilityOptionComplex
{
private static class Offset
{
public const int IsIpV6 = 0;
public const int IsIpV4 = IsIpV6;
public const int LocalMobilityAddress = IsIpV4 + sizeof(byte) + sizeof(byte);
}
private static class Mask
{
public const byte IsIpV6 = 0x80;
public const byte IsIpV4 = 0x40;
}
public const int OptionDataMinimumLength = Offset.LocalMobilityAddress;
public IpV6MobilityOptionRedirect(IpV4Address localMobilityAddress)
: this(localMobilityAddress, null)
{
}
public IpV6MobilityOptionRedirect(IpV6Address localMobilityAddress)
: this(null, localMobilityAddress)
{
}
/// <summary>
/// The IPv4 address of the r2LMA.
/// This value is present when the corresponding PBU was sourced from an IPv4 address.
/// </summary>
public IpV4Address? LocalMobilityAddressIpV4 { get; private set; }
/// <summary>
/// The unicast IPv6 address of the r2LMA.
/// This value is present when the corresponding PBU was sourced from an IPv6 address.
/// </summary>
public IpV6Address? LocalMobilityAddressIpV6 { get; private set; }
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
if (data.Length < OptionDataMinimumLength)
return null;
bool isIpV4 = data.ReadBool(Offset.IsIpV4, Mask.IsIpV4);
bool isIpV6 = data.ReadBool(Offset.IsIpV6, Mask.IsIpV6);
if (isIpV4 && !isIpV6)
{
if (data.Length != OptionDataMinimumLength + IpV4Address.SizeOf)
return null;
IpV4Address localMobilityAddress = data.ReadIpV4Address(Offset.LocalMobilityAddress, Endianity.Big);
return new IpV6MobilityOptionRedirect(localMobilityAddress);
}
if (isIpV6 && !isIpV4)
{
if (data.Length != OptionDataMinimumLength + IpV6Address.SizeOf)
return null;
IpV6Address localMobilityAddress = data.ReadIpV6Address(Offset.LocalMobilityAddress, Endianity.Big);
return new IpV6MobilityOptionRedirect(localMobilityAddress);
}
return null;
}
internal override int DataLength
{
get
{
return OptionDataMinimumLength +
(LocalMobilityAddressIpV4.HasValue ? IpV4Address.SizeOf : 0) +
(LocalMobilityAddressIpV6.HasValue ? IpV6Address.SizeOf : 0);
}
}
internal override void WriteData(byte[] buffer, ref int offset)
{
if (LocalMobilityAddressIpV4.HasValue)
{
buffer.Write(offset + Offset.IsIpV4, Mask.IsIpV4);
buffer.Write(offset + Offset.LocalMobilityAddress, LocalMobilityAddressIpV4.Value, Endianity.Big);
offset += OptionDataMinimumLength + IpV4Address.SizeOf;
return;
}
buffer.Write(offset + Offset.IsIpV6, Mask.IsIpV6);
buffer.Write(offset + Offset.LocalMobilityAddress, LocalMobilityAddressIpV6.Value, Endianity.Big);
offset += OptionDataMinimumLength + IpV6Address.SizeOf;
}
private IpV6MobilityOptionRedirect(IpV4Address? localMobilityAddressIpV4, IpV6Address? localMobilityAddressIpV6)
: base(IpV6MobilityOptionType.Redirect)
{
LocalMobilityAddressIpV4 = localMobilityAddressIpV4;
LocalMobilityAddressIpV6 = localMobilityAddressIpV6;
}
}
/// <summary>
/// RFC 6463.
/// <pre>
/// +-----+-------------+--------------+----------+
/// | Bit | 0-7 | 8-15 | 16-31 |
/// +-----+-------------+--------------+----------+
/// | 0 | Option Type | Opt Data Len | Priority |
/// +-----+-------------+--------------+----------+
/// | 32 | Sessions in Use |
/// +-----+---------------------------------------+
/// | 64 | Maximum Sessions |
/// +-----+---------------------------------------+
/// | 96 | Used Capacity |
/// +-----+---------------------------------------+
/// | 128 | Maximum Capacity |
/// +-----+---------------------------------------+
/// </pre>
/// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.LoadInformation)]
public class IpV6MobilityOptionLoadInformation : IpV6MobilityOptionComplex
{
private static class Offset
{
public const int Priority = 0;
public const int SessionsInUse = Priority + sizeof(ushort);
public const int MaximumSessions = SessionsInUse + sizeof(uint);
public const int UsedCapacity = MaximumSessions + sizeof(uint);
public const int MaximumCapacity = UsedCapacity + sizeof(uint);
}
public const int OptionDataLength = Offset.MaximumCapacity + sizeof(uint);
public IpV6MobilityOptionLoadInformation(ushort priority, uint sessionsInUse, uint maximumSessions, uint usedCapacity, uint maximumCapacity)
: base(IpV6MobilityOptionType.LoadInformation)
{
Priority = priority;
SessionsInUse = sessionsInUse;
MaximumSessions = maximumSessions;
UsedCapacity = usedCapacity;
MaximumCapacity = maximumCapacity;
}
/// <summary>
/// Represents the priority of an LMA.
/// The lower value, the higher the priority.
/// The priority only has meaning among a group of LMAs under the same administration, for example, determined by a common LMA FQDN, a domain name,
/// or a realm.
/// </summary>
public ushort Priority { get; private set; }
/// <summary>
/// Represents the number of parallel mobility sessions the LMA has in use.
/// </summary>
public uint SessionsInUse { get; private set; }
/// <summary>
/// Represents the maximum number of parallel mobility sessions the LMA is willing to accept.
/// </summary>
public uint MaximumSessions { get; private set; }
/// <summary>
/// Represents the used bandwidth/throughput capacity of the LMA in kilobytes per second.
/// </summary>
public uint UsedCapacity { get; private set; }
/// <summary>
/// Represents the maximum bandwidth/throughput capacity in kilobytes per second the LMA is willing to accept.
/// </summary>
public uint MaximumCapacity { get; private set; }
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
if (data.Length != OptionDataLength)
return null;
ushort priority = data.ReadUShort(Offset.Priority, Endianity.Big);
uint sessionsInUse = data.ReadUShort(Offset.SessionsInUse, Endianity.Big);
uint maximumSessions = data.ReadUShort(Offset.MaximumSessions, Endianity.Big);
uint usedCapacity = data.ReadUShort(Offset.UsedCapacity, Endianity.Big);
uint maximumCapacity = data.ReadUShort(Offset.MaximumCapacity, Endianity.Big);
return new IpV6MobilityOptionLoadInformation(priority, sessionsInUse, maximumSessions, usedCapacity, maximumCapacity);
}
internal override int DataLength
{
get { return OptionDataLength; }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
buffer.Write(offset + Offset.Priority, Priority, Endianity.Big);
buffer.Write(offset + Offset.SessionsInUse, SessionsInUse, Endianity.Big);
buffer.Write(offset + Offset.MaximumSessions, MaximumSessions, Endianity.Big);
buffer.Write(offset + Offset.UsedCapacity, UsedCapacity, Endianity.Big);
buffer.Write(offset + Offset.MaximumCapacity, MaximumCapacity, Endianity.Big);
offset += OptionDataLength;
}
}
/// <summary>
/// RFC 6463.
/// <pre>
/// +-----+-------------+------------------+
/// | Bit | 0-7 | 8-15 |
/// +-----+-------------+------------------+
/// | 0 | Option Type | Opt Data Len |
/// +-----+-------------+------------------+
/// | 16 | Alternate IPv4 Care-of Address |
/// | | |
/// +-----+--------------------------------+
/// </pre>
/// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.AlternateIpV4CareOfAddress)]
public class IpV6MobilityOptionAlternateIpV4CareOfAddress : IpV6MobilityOptionComplex
{
public const int OptionDataLength = IpV4Address.SizeOf;
public IpV6MobilityOptionAlternateIpV4CareOfAddress(IpV4Address alternateCareOfAddress)
: base(IpV6MobilityOptionType.AlternateIpV4CareOfAddress)
{
AlternateCareOfAddress = alternateCareOfAddress;
}
/// <summary>
/// An IPv4 equivalent of the RFC 6275 Alternate Care-of Address option for IPv6.
/// In the context of PMIPv6, its semantic is equivalent to the Alternate Care-of Address option for IPv6.
/// </summary>
public IpV4Address AlternateCareOfAddress { get; private set; }
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
if (data.Length != OptionDataLength)
return null;
return new IpV6MobilityOptionAlternateIpV4CareOfAddress(data.ReadIpV4Address(0, Endianity.Big));
}
internal override int DataLength
{
get { return OptionDataLength; }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
buffer.Write(ref offset, AlternateCareOfAddress, Endianity.Big);
}
}
/// <summary>
/// RFC 6602.
/// </summary>
public enum IpV6MobileNodeGroupIdentifierSubType : byte
{
/// <summary>
/// RFC 6602.
/// </summary>
BulkBindingUpdateGroup = 1,
}
/// <summary>
/// RFC 6602.
/// <pre>
/// +-----+-------------+----------------+
/// | Bit | 0-7 | 8-15 |
/// +-----+-------------+----------------+
/// | 0 | Option Type | Opt Data Len |
/// +-----+-------------+----------------+
/// | 16 | Sub-type | Reserved |
/// +-----+-------------+----------------+
/// | 32 | Mobile Node Group Identifier |
/// | | |
/// +-----+------------------------------+
/// </pre>
/// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.MobileNodeGroupIdentifier)]
public class IpV6MobilityOptionMobileNodeGroupIdentifier : IpV6MobilityOptionComplex
{
private static class Offset
{
public const int SubType = 0;
public const int MobileNodeGroupIdentifier = SubType + sizeof(byte) + sizeof(byte);
}
public const int OptionDataLength = Offset.MobileNodeGroupIdentifier + sizeof(uint);
public IpV6MobilityOptionMobileNodeGroupIdentifier(IpV6MobileNodeGroupIdentifierSubType subType, uint mobileNodeGroupIdentifier)
: base(IpV6MobilityOptionType.MobileNodeGroupIdentifier)
{
SubType = subType;
MobileNodeGroupIdentifier = mobileNodeGroupIdentifier;
}
/// <summary>
/// Identifies the specific mobile node's group type.
/// </summary>
public IpV6MobileNodeGroupIdentifierSubType SubType { get; private set; }
/// <summary>
/// Contains the mobile node's group identifier.
/// The value of (0) is reserved and should not be used.
/// The value of (1) ALL-SESSIONS is the default group of all mobility sessions established between a given local mobility anchor and a mobile access
/// gateway.
/// </summary>
public uint MobileNodeGroupIdentifier { get; private set; }
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
if (data.Length != OptionDataLength)
return null;
IpV6MobileNodeGroupIdentifierSubType subType = (IpV6MobileNodeGroupIdentifierSubType)data[Offset.SubType];
uint mobileNodeGroupIdentifier = data.ReadUInt(Offset.MobileNodeGroupIdentifier, Endianity.Big);
return new IpV6MobilityOptionMobileNodeGroupIdentifier(subType, mobileNodeGroupIdentifier);
}
internal override int DataLength
{
get { return OptionDataLength; }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
buffer.Write(offset + Offset.SubType, (byte)SubType);
buffer.Write(offset + Offset.MobileNodeGroupIdentifier, MobileNodeGroupIdentifier, Endianity.Big);
offset += OptionDataLength;
}
}
/// <summary>
/// RFC 6705.
/// <pre>
/// +-----+-------------+----------------+
/// | Bit | 0-7 | 8-15 |
/// +-----+-------------+----------------+
/// | 0 | Option Type | Opt Data Len |
/// +-----+-------------+----------------+
/// | 16 | Reserved | Address Length |
/// +-----+-------------+----------------+
/// | 32 | MAG IPv6 Address |
/// | | |
/// | | |
/// | | |
/// | | |
/// | | |
/// | | |
/// | | |
/// +-----+------------------------------+
/// </pre>
/// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.MobileAccessGatewayIpV6Address)]
public class IpV6MobilityOptionMobileAccessGatewayIpV6Address : IpV6MobilityOptionComplex
{
public const byte AddressLength = 128;
private static class Offset
{
public const int AddressLength = sizeof(byte);
public const int Address = AddressLength + sizeof(byte);
}
public const int OptionDataLength = Offset.Address + IpV6Address.SizeOf;
public IpV6MobilityOptionMobileAccessGatewayIpV6Address(IpV6Address address)
: base(IpV6MobilityOptionType.MobileAccessGatewayIpV6Address)
{
Address = address;
}
/// <summary>
/// Contains the MAG's IPv6 address.
/// </summary>
public IpV6Address Address { get; private set; }
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
if (data.Length != OptionDataLength)
return null;
if (data[Offset.AddressLength] != AddressLength)
return null;
return new IpV6MobilityOptionMobileAccessGatewayIpV6Address(data.ReadIpV6Address(Offset.Address, Endianity.Big));
}
internal override int DataLength
{
get { return OptionDataLength; }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
buffer.Write(offset + Offset.AddressLength, AddressLength);
buffer.Write(offset + Offset.Address, Address, Endianity.Big);
offset += OptionDataLength;
}
}
/// <summary>
/// RFC 6757.
/// <pre>
/// +-----+-------------+--------------+
/// | Bit | 0-7 | 8-15 |
/// +-----+-------------+--------------+
/// | 0 | Option Type | Opt Data Len |
/// +-----+-------------+--------------+
/// | 16 | ANI Sub-option(s) |
/// | ... | |
/// +-----+----------------------------+
/// </pre>
/// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.AccessNetworkIdentifier)]
public class IpV6MobilityOptionAccessNetworkIdentifier : IpV6MobilityOptionComplex
{
public IpV6MobilityOptionAccessNetworkIdentifier(IpV6AccessNetworkIdentifierSubOptions subOptions)
: base(IpV6MobilityOptionType.AccessNetworkIdentifier)
{
SubOptions = subOptions;
}
/// <summary>
/// Sub options.
/// </summary>
public IpV6AccessNetworkIdentifierSubOptions SubOptions { get; private set; }
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
return new IpV6MobilityOptionAccessNetworkIdentifier(new IpV6AccessNetworkIdentifierSubOptions(data));
}
internal override int DataLength
{
get { return SubOptions.BytesLength; }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
SubOptions.Write(buffer, offset);
offset += DataLength;
}
}
/// <summary>
/// RFC 6757.
/// </summary>
public class IpV6AccessNetworkIdentifierSubOptions : Options<IpV6AccessNetworkIdentifierSubOption>
{
/// <summary>
/// Creates options from a list of options.
/// </summary>
/// <param name="options">The list of options.</param>
public IpV6AccessNetworkIdentifierSubOptions(IList<IpV6AccessNetworkIdentifierSubOption> options)
: base(options, true, null)
{
}
/// <summary>
/// Creates options from a list of options.
/// </summary>
/// <param name="options">The list of options.</param>
public IpV6AccessNetworkIdentifierSubOptions(params IpV6AccessNetworkIdentifierSubOption[] options)
: this((IList<IpV6AccessNetworkIdentifierSubOption>)options)
{
}
internal IpV6AccessNetworkIdentifierSubOptions(DataSegment data)
: this(Read(data))
{
}
private IpV6AccessNetworkIdentifierSubOptions(Tuple<IList<IpV6AccessNetworkIdentifierSubOption>, bool> optionsAndIsValid)
: base(optionsAndIsValid.Item1, optionsAndIsValid.Item2, null)
{
}
/// <summary>
/// No options instance.
/// </summary>
public static IpV6AccessNetworkIdentifierSubOptions None
{
get { return _none; }
}
internal static Tuple<IList<IpV6AccessNetworkIdentifierSubOption>, bool> Read(DataSegment data)
{
int offset = 0;
List<IpV6AccessNetworkIdentifierSubOption> options = new List<IpV6AccessNetworkIdentifierSubOption>();
bool isValid = true;
while (offset < data.Length)
{
IpV6AccessNetworkIdentifierSubOptionType optionType = (IpV6AccessNetworkIdentifierSubOptionType)data[offset++];
if (offset >= data.Length)
{
isValid = false;
break;
}
byte optionDataLength = data[offset++];
if (offset + optionDataLength > data.Length)
{
isValid = false;
break;
}
IpV6AccessNetworkIdentifierSubOption option = CreateOption(optionType, data.Subsegment(ref offset, optionDataLength));
if (option == null)
{
isValid = false;
break;
}
options.Add(option);
}
return new Tuple<IList<IpV6AccessNetworkIdentifierSubOption>, bool>(options, isValid);
}
private static IpV6AccessNetworkIdentifierSubOption CreateOption(IpV6AccessNetworkIdentifierSubOptionType optionType, DataSegment data)
{
IpV6AccessNetworkIdentifierSubOption prototype;
if (!_prototypes.TryGetValue(optionType, out prototype))
return new IpV6AccessNetworkIdentifierSubOptionUnknown(optionType, data);
return prototype.CreateInstance(data);
}
private static readonly Dictionary<IpV6AccessNetworkIdentifierSubOptionType, IpV6AccessNetworkIdentifierSubOption> _prototypes = InitializePrototypes();
private static Dictionary<IpV6AccessNetworkIdentifierSubOptionType, IpV6AccessNetworkIdentifierSubOption> InitializePrototypes()
{
var prototypes =
from type in Assembly.GetExecutingAssembly().GetTypes()
where typeof(IpV6AccessNetworkIdentifierSubOption).IsAssignableFrom(type) &&
GetRegistrationAttribute(type) != null
select new
{
GetRegistrationAttribute(type).OptionType,
Option = (IpV6AccessNetworkIdentifierSubOption)Activator.CreateInstance(type)
};
return prototypes.ToDictionary(option => option.OptionType, option => option.Option);
}
private static IpV6AccessNetworkIdentifierSubOptionTypeRegistrationAttribute GetRegistrationAttribute(Type type)
{
var registraionAttributes = type.GetCustomAttributes<IpV6AccessNetworkIdentifierSubOptionTypeRegistrationAttribute>(false);
if (!registraionAttributes.Any())
return null;
return registraionAttributes.First();
}
private static readonly IpV6AccessNetworkIdentifierSubOptions _none = new IpV6AccessNetworkIdentifierSubOptions();
}
/// <summary>
/// RFC 6757.
/// </summary>
internal sealed class IpV6AccessNetworkIdentifierSubOptionTypeRegistrationAttribute : Attribute
{
public IpV6AccessNetworkIdentifierSubOptionTypeRegistrationAttribute(IpV6AccessNetworkIdentifierSubOptionType optionType)
{
OptionType = optionType;
}
public IpV6AccessNetworkIdentifierSubOptionType OptionType { get; private set; }
}
/// <summary>
/// RFC 6757.
/// </summary>
public enum IpV6AccessNetworkIdentifierSubOptionType : byte
{
/// <summary>
/// Network-Identifier sub-option.
/// </summary>
NetworkIdentifier = 1,
/// <summary>
/// Geo-Location sub-option.
/// </summary>
GeoLocation = 2,
/// <summary>
/// Operator-Identifier sub-option.
/// </summary>
OperatorIdentifier = 3,
}
/// <summary>
/// RFC 6757.
/// </summary>
public abstract class IpV6AccessNetworkIdentifierSubOption : Option
{
/// <summary>
/// The type of the option.
/// </summary>
public IpV6AccessNetworkIdentifierSubOptionType OptionType { get; private set; }
internal abstract IpV6AccessNetworkIdentifierSubOption CreateInstance(DataSegment data);
protected IpV6AccessNetworkIdentifierSubOption(IpV6AccessNetworkIdentifierSubOptionType type)
{
OptionType = type;
}
public override sealed int Length
{
get { return sizeof(byte) + sizeof(byte) + DataLength; }
}
internal abstract int DataLength { get; }
internal override void Write(byte[] buffer, ref int offset)
{
buffer[offset++] = (byte)OptionType;
buffer[offset++] = (byte)DataLength;
WriteData(buffer, ref offset);
}
internal abstract void WriteData(byte[] buffer, ref int offset);
}
/// <summary>
/// RFC 6757.
/// <pre>
/// +-----+---+---------------------------------+
/// | Bit | 0 | 6-7 |
/// +-----+---+---------------------------------+
/// | 0 | ANI Type |
/// +-----+-------------------------------------+
/// | 8 | ANI Length |
/// +-----+---+---------------------------------+
/// | 16 | E | Reserved |
/// +-----+---+---------------------------------+
/// | 24 | Net-Name Len |
/// +-----+-------------------------------------+
/// | 32 | Network Name (e.g., SSID or PLMNID) |
/// | ... | |
/// +-----+-------------------------------------+
/// | | AP-Name Len |
/// +-----+-------------------------------------+
/// | | Access-Point Name |
/// | ... | |
/// +-----+-------------------------------------+
/// </pre>
/// </summary>
[IpV6AccessNetworkIdentifierSubOptionTypeRegistration(IpV6AccessNetworkIdentifierSubOptionType.NetworkIdentifier)]
public class IpV6AccessNetworkIdentifierSubOptionNetworkIdentifier : IpV6AccessNetworkIdentifierSubOption
{
private static class Offset
{
public const int IsNetworkNameUtf8 = 0;
public const int NetworkNameLength = IsNetworkNameUtf8 + sizeof(byte);
public const int NetworkName = NetworkNameLength + sizeof(byte);
}
private static class Mask
{
public const byte IsNetworkNameUtf8 = 0x80;
}
public const int OptionDataMinimumLength = Offset.NetworkName + sizeof(byte);
public IpV6AccessNetworkIdentifierSubOptionNetworkIdentifier(bool isNetworkNameUtf8, DataSegment networkName, DataSegment accessPointName)
: base(IpV6AccessNetworkIdentifierSubOptionType.NetworkIdentifier)
{
IsNetworkNameUtf8 = isNetworkNameUtf8;
NetworkName = networkName;
AccessPointName = accessPointName;
}
/// <summary>
/// Indicates whether the Network Name is encoded in UTF-8.
/// If true, then the Network Name is encoded using UTF-8.
/// If false, this indicates that the encoding is undefined and is determined by out-of-band mechanisms.
/// </summary>
public bool IsNetworkNameUtf8 { get; private set; }
/// <summary>
/// The name of the access network to which the mobile node is attached.
/// The type of the Network Name is dependent on the access technology to which the mobile node is attached.
/// If it is 802.11 access, the Network Name must be the SSID of the network.
/// If the access network is 3GPP access, the Network Name is the PLMN Identifier of the network.
/// If the access network is 3GPP2 access, the Network Name is the Access Network Identifier.
///
/// When encoding the PLMN Identifier, both the Mobile Network Code (MNC) and Mobile Country Code (MCC) must be 3 digits.
/// If the MNC in use only has 2 digits, then it must be preceded with a '0'.
/// Encoding must be UTF-8.
/// </summary>
public DataSegment NetworkName { get; private set; }
/// <summary>
/// The name of the access point (physical device name) to which the mobile node is attached.
/// This is the identifier that uniquely identifies the access point.
/// While Network Name (e.g., SSID) identifies the operator's access network,
/// Access-Point Name identifies a specific network device in the network to which the mobile node is attached.
/// In some deployments, the Access-Point Name can be set to the Media Access Control (MAC) address of the device or some unique identifier
/// that can be used by the policy systems in the operator network to unambiguously identify the device.
/// The string is carried in UTF-8 representation.
/// </summary>
public DataSegment AccessPointName { get; private set; }
internal override IpV6AccessNetworkIdentifierSubOption CreateInstance(DataSegment data)
{
if (data.Length < OptionDataMinimumLength)
return null;
bool isNetworkNameUtf8 = data.ReadBool(Offset.IsNetworkNameUtf8, Mask.IsNetworkNameUtf8);
byte networkNameLength = data[Offset.NetworkNameLength];
if (data.Length < OptionDataMinimumLength + networkNameLength)
return null;
DataSegment networkName = data.Subsegment(Offset.NetworkName, networkNameLength);
int accessPointNameLengthOffset = Offset.NetworkName + networkNameLength;
byte accessPointNameLength = data[accessPointNameLengthOffset];
if (data.Length != OptionDataMinimumLength + networkNameLength + accessPointNameLength)
return null;
int accessPointNameOffset = accessPointNameLengthOffset + sizeof(byte);
DataSegment accessPointName = data.Subsegment(accessPointNameOffset, accessPointNameLength);
return new IpV6AccessNetworkIdentifierSubOptionNetworkIdentifier(isNetworkNameUtf8, networkName, accessPointName);
}
internal override int DataLength
{
get { return OptionDataMinimumLength + NetworkName.Length + AccessPointName.Length; }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
if (IsNetworkNameUtf8)
buffer.Write(offset + Offset.IsNetworkNameUtf8, Mask.IsNetworkNameUtf8);
buffer.Write(offset + Offset.NetworkNameLength, (byte)NetworkName.Length);
NetworkName.Write(buffer, offset + Offset.NetworkNameLength);
buffer.Write(offset + AccessPointNameLengthOffset, (byte)AccessPointName.Length);
AccessPointName.Write(buffer, offset + AccessPointNameOffset);
offset += DataLength;
}
private int AccessPointNameLengthOffset { get { return Offset.NetworkName + NetworkName.Length; } }
private int AccessPointNameOffset { get { return AccessPointNameLengthOffset + sizeof(byte); } }
}
/// <summary>
/// RFC 6757.
/// <pre>
/// +-----+----------+------------+
/// | Bit | 0-7 | 8-15 |
/// +-----+----------+------------+
/// | 0 | ANI Type | ANI Length |
/// +-----+----------+------------+
/// | 16 | Option Data |
/// | ... | |
/// +-----+-----------------------+
/// </pre>
/// </summary>
public class IpV6AccessNetworkIdentifierSubOptionUnknown : IpV6AccessNetworkIdentifierSubOption
{
public IpV6AccessNetworkIdentifierSubOptionUnknown(IpV6AccessNetworkIdentifierSubOptionType type, DataSegment data)
: base(type)
{
Data = data;
}
public DataSegment Data { get; private set; }
internal override IpV6AccessNetworkIdentifierSubOption CreateInstance(DataSegment data)
{
throw new InvalidOperationException("IpV6AccessNetworkIdentifierSubOptionUnknown shouldn't be registered.");
}
internal override int DataLength
{
get { return Data.Length; }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
buffer.Write(ref offset, Data);
}
}
/// <summary>
/// RFC 6757.
/// <pre>
/// +-----+-------------------+
/// | Bit | 0-7 |
/// +-----+-------------------+
/// | 0 | ANI Type |
/// +-----+-------------------+
/// | 8 | ANI Length |
/// +-----+-------------------+
/// | 16 | Latitude Degrees |
/// | | |
/// | | |
/// +-----+-------------------+
/// | 40 | Longitude Degrees |
/// | | |
/// | | |
/// +-----+-------------------+
/// </pre>
/// </summary>
[IpV6AccessNetworkIdentifierSubOptionTypeRegistration(IpV6AccessNetworkIdentifierSubOptionType.GeoLocation)]
public class IpV6AccessNetworkIdentifierSubOptionGeoLocation : IpV6AccessNetworkIdentifierSubOption
{
private static class Offset
{
public const int LatitudeDegrees = 0;
public const int LongitudeDegrees = LatitudeDegrees + UInt24.SizeOf;
}
public const int OptionDataLength = Offset.LongitudeDegrees + UInt24.SizeOf;
public IpV6AccessNetworkIdentifierSubOptionGeoLocation(UInt24 latitudeDegrees, UInt24 longitudeDegrees)
: base(IpV6AccessNetworkIdentifierSubOptionType.GeoLocation)
{
LatitudeDegrees = latitudeDegrees;
LongitudeDegrees = longitudeDegrees;
}
/// <summary>
/// A 24-bit latitude degree value encoded as a two's complement, fixed point number with 9 whole bits.
/// Positive degrees correspond to the Northern Hemisphere and negative degrees correspond to the Southern Hemisphere.
/// The value ranges from -90 to +90 degrees.
/// </summary>
public UInt24 LatitudeDegrees { get; private set; }
/// <summary>
/// Positive degrees correspond to the Northern Hemisphere and negative degrees correspond to the Southern Hemisphere.
/// The value ranges from -90 to +90 degrees.
/// </summary>
public double LatitudeDegreesReal
{
get { return ToReal(LatitudeDegrees); }
}
/// <summary>
/// A 24-bit longitude degree value encoded as a two's complement, fixed point number with 9 whole bits.
/// The value ranges from -180 to +180 degrees.
/// </summary>
public UInt24 LongitudeDegrees { get; private set; }
/// <summary>
/// The value ranges from -180 to +180 degrees.
/// </summary>
public double LongitudeDegreesReal
{
get { return ToReal(LatitudeDegrees); }
}
internal override IpV6AccessNetworkIdentifierSubOption CreateInstance(DataSegment data)
{
if (data.Length != OptionDataLength)
return null;
UInt24 latitudeDegrees = data.ReadUInt24(Offset.LatitudeDegrees, Endianity.Big);
UInt24 longitudeDegrees = data.ReadUInt24(Offset.LongitudeDegrees, Endianity.Big);
return new IpV6AccessNetworkIdentifierSubOptionGeoLocation(latitudeDegrees, longitudeDegrees);
}
internal override int DataLength
{
get { return OptionDataLength; }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
buffer.Write(offset + Offset.LatitudeDegrees, LatitudeDegrees, Endianity.Big);
buffer.Write(offset + Offset.LongitudeDegrees, LongitudeDegrees, Endianity.Big);
offset += OptionDataLength;
}
private static double ToReal(UInt24 twosComplementFixedPointWith9WholeBits)
{
bool isPositive = twosComplementFixedPointWith9WholeBits >> 23 == 1;
int integerPart = (twosComplementFixedPointWith9WholeBits & 0x7F8000) >> 15;
int fractionPart = twosComplementFixedPointWith9WholeBits & 0x007FFF;
return (isPositive ? 1 : -1) *
(integerPart + (((double)fractionPart) / (1 << 15)));
}
}
/// <summary>
/// RFC 6757.
/// </summary>
public enum IpV6AccessNetworkIdentifierOperatorIdentifierType : byte
{
/// <summary>
/// Operator-Identifier as a variable-length Private Enterprise Number (PEN) encoded in a network-byte order.
/// The maximum PEN value depends on the ANI Length and is calculated using the formula: maximum PEN = 2^((ANI_length-1)*8)-1.
/// For example, the ANI Length of 4 allows for encoding PENs from 0 to 2^24-1, i.e., from 0 to 16777215,
/// and uses 3 octets of Operator-Identifier space.
/// </summary>
PrivateEnterpriseNumber = 1,
/// <summary>
/// Realm of the operator.
/// Realm names are required to be unique and are piggybacked on the administration of the DNS namespace.
/// Realms meet the syntactic requirements of the "Preferred Name Syntax".
/// They are encoded as US-ASCII.
/// 3GPP specifications also define realm names that can be used to convey PLMN Identifiers.
/// </summary>
RealmOfTheOperator = 2,
}
/// <summary>
/// RFC 6757.
/// <pre>
/// +-----+---------------------+
/// | Bit | 0-7 |
/// +-----+---------------------+
/// | 0 | ANI Type |
/// +-----+---------------------+
/// | 8 | ANI Length |
/// +-----+---------------------+
/// | 16 | Op-ID Type |
/// +-----+---------------------+
/// | 24 | Operator-Identifier |
/// | ... | |
/// +-----+---------------------+
/// </pre>
/// </summary>
[IpV6AccessNetworkIdentifierSubOptionTypeRegistration(IpV6AccessNetworkIdentifierSubOptionType.OperatorIdentifier)]
public class IpV6AccessNetworkIdentifierSubOptionOperatorIdentifier : IpV6AccessNetworkIdentifierSubOption
{
private static class Offset
{
public const int IdentifierType = 0;
public const int Identifier = IdentifierType + sizeof(byte);
}
public const int OptionDataMinimumLength = Offset.Identifier;
public IpV6AccessNetworkIdentifierSubOptionOperatorIdentifier(IpV6AccessNetworkIdentifierOperatorIdentifierType identifierType, DataSegment identifier)
: base(IpV6AccessNetworkIdentifierSubOptionType.OperatorIdentifier)
{
IdentifierType = identifierType;
Identifier = identifier;
}
/// <summary>
/// Indicates the type of the Operator-Identifier.
/// </summary>
public IpV6AccessNetworkIdentifierOperatorIdentifierType IdentifierType { get; private set; }
/// <summary>
/// Up to 253 octets of the Operator-Identifier.
/// The encoding of the identifier depends on the used Operator-Identifier Type.
/// </summary>
public DataSegment Identifier { get; private set; }
internal override IpV6AccessNetworkIdentifierSubOption CreateInstance(DataSegment data)
{
if (data.Length < OptionDataMinimumLength)
return null;
IpV6AccessNetworkIdentifierOperatorIdentifierType identifierType = (IpV6AccessNetworkIdentifierOperatorIdentifierType)data[Offset.IdentifierType];
DataSegment identifier = data.Subsegment(Offset.Identifier, data.Length - Offset.Identifier);
return new IpV6AccessNetworkIdentifierSubOptionOperatorIdentifier(identifierType, identifier);
}
internal override int DataLength
{
get { return OptionDataMinimumLength + Identifier.Length; }
}
internal override void WriteData(byte[] buffer, ref int offset)
{
buffer.Write(offset + Offset.IdentifierType, (byte)IdentifierType);
Identifier.Write(buffer, offset + Offset.Identifier);
offset += DataLength;
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment