2025-12-01 15:56:02 +01:00
# include "tsn-net-device.h"
# include "ns3/log.h"
# include "ns3/packet.h"
# include "ns3/queue.h"
# include "ns3/ethernet-trailer.h"
# include "ns3/names.h"
# include "ns3/timestamp-tag.h"
# include "ns3/simulator.h"
# include "ns3/callback.h"
# include "ns3/error-model.h"
# include "ns3/ethernet-net-device.h"
# include "ns3/ethernet-channel.h"
# include "ns3/ethernet-header2.h"
# include "ns3/tsn-transmission-selection-algo.h"
# include "ns3/tas.h"
# include "ns3/transmission-gate.h"
# include "psfp-stream-filter-instance.h"
# include "psfp-flow-meter-instance.h"
namespace ns3
{
NS_LOG_COMPONENT_DEFINE ( " TsnNetDevice " ) ;
NS_OBJECT_ENSURE_REGISTERED ( TsnNetDevice ) ;
TypeId
TsnNetDevice : : GetTypeId ( )
{
static TypeId tid =
TypeId ( " ns3::TsnNetDevice " )
. SetParent < EthernetNetDevice > ( )
. SetGroupName ( " Tsn " )
. AddConstructor < TsnNetDevice > ( )
. AddTraceSource ( " FrerDrop " ,
" Trace source indicating a packet was drop "
" by FRER recovery function " ,
MakeTraceSourceAccessor ( & TsnNetDevice : : m_frerDropTrace ) ,
" ns3::Packet::TracedCallback " )
. AddTraceSource ( " MaxSDUSizeFilterDrop " ,
" Trace source indicating a packet was drop "
" by the maxSDUSize filter " ,
MakeTraceSourceAccessor ( & TsnNetDevice : : m_maxSDUSizeFilterDropTrace ) ,
" ns3::Packet::TracedCallback " )
. AddTraceSource ( " REDFrameDrop " ,
" Trace source indicating a packet was drop "
" by the flow meter " ,
MakeTraceSourceAccessor ( & TsnNetDevice : : m_REDFrameDropTrace ) ,
" ns3::Packet::TracedCallback " ) ;
return tid ;
}
TsnNetDevice : : TsnNetDevice ( ) : EthernetNetDevice ( )
{
NS_LOG_FUNCTION ( this ) ;
m_tas = CreateObject < Tas > ( ) ;
m_tas - > SetTsnNetDevice ( this ) ;
}
TsnNetDevice : : ~ TsnNetDevice ( )
{
NS_LOG_FUNCTION ( this ) ;
}
void
TsnNetDevice : : SetNode ( Ptr < TsnNode > node )
{
m_node = node ;
}
void
TsnNetDevice : : SetQueue ( Ptr < Queue < Packet > > q )
{
NS_LOG_FUNCTION ( this < < q ) ;
Ptr < TsnTransmissionSelectionAlgo > tsa = CreateObject < TsnTransmissionSelectionAlgo > ( ) ;
tsa - > SetQueue ( q ) ;
tsa - > SetTsnNetDevice ( this ) ;
SetQueue ( q , tsa ) ;
}
void
TsnNetDevice : : SetQueue ( Ptr < Queue < Packet > > q , Ptr < TsnTransmissionSelectionAlgo > tsa )
{
NS_LOG_FUNCTION ( this < < q ) ;
tsa - > SetQueue ( q ) ;
m_queues . insert ( m_queues . end ( ) , q ) ;
m_tas - > AddTransmissionGate ( ) ;
m_tas - > AddTsa ( tsa ) ;
m_transmissionSelectionAlgos . insert ( m_transmissionSelectionAlgos . end ( ) , tsa ) ;
}
void
TsnNetDevice : : UpdateQueue ( uint32_t queue_id , Ptr < Queue < Packet > > q , Ptr < TsnTransmissionSelectionAlgo > tsa )
{
NS_LOG_FUNCTION ( this < < q ) ;
NS_ASSERT ( queue_id < m_queues . size ( ) ) ;
NS_ASSERT ( queue_id < m_transmissionSelectionAlgos . size ( ) ) ;
tsa - > SetQueue ( q ) ;
m_tas - > AddTransmissionGate ( ) ;
m_tas - > AddTsa ( tsa ) ;
m_queues [ queue_id ] = q ;
m_transmissionSelectionAlgos [ queue_id ] = tsa ;
}
int
TsnNetDevice : : TransmitSelection ( )
{
NS_LOG_FUNCTION ( this ) ;
2025-12-02 11:43:04 +01:00
//Udpate Transmission selection algo states (e.g update cbs credit)
for ( int i = m_queues . size ( ) ; i - - > 0 ; )
{
m_transmissionSelectionAlgos [ i ] - > Update ( ) ;
}
2025-12-01 15:56:02 +01:00
for ( int i = m_queues . size ( ) ; i - - > 0 ; )
{
if ( ! m_queues [ i ] - > IsEmpty ( ) & & m_tas - > IsGateOpen ( i ) )
{
if ( m_transmissionSelectionAlgos [ i ] - > IsReadyToTransmit ( ) )
{
if ( m_tas - > IsEnable ( ) )
{
Ptr < const Packet > p = m_queues [ i ] - > Peek ( ) ;
if ( m_tas - > IsSendable ( p , m_bps , m_preambleAndSFDGap , m_interframeGap , m_mtu ) )
{
return ( i ) ;
}
}
else
{
return ( i ) ;
}
}
}
}
return ( - 1 ) ;
}
bool
TsnNetDevice : : SendFrom ( Ptr < Packet > packet ,
const Address & source ,
const Address & dest ,
uint16_t ethertype )
{
NS_LOG_FUNCTION ( this ) ;
Time hardwareLatency = Time ( 0 ) ;
// Stream identification in-facing output
std : : vector < Ptr < StreamIdEntry > > streamIdentityTable = GetNode ( ) - > GetStreamIdentityTable ( ) ;
for ( uint16_t i = 0 ; i < streamIdentityTable . size ( ) ; i + + ) {
if ( streamIdentityTable [ i ] - > Match ( this , true , false , packet ) ) {
uint32_t streamHandle = streamIdentityTable [ i ] - > GetStreamHandle ( ) ;
hardwareLatency + = streamIdentityTable [ i ] - > GetHardwareLatency ( ) ;
//FRER
// NS_LOG_INFO( "Stream handle of Pkt #"<<packet->GetUid() << " on output : " << streamHandle);
bool isSeqNumber = false ;
uint16_t seqNumber = 0 ;
//Sequence decode => extract RTAG if this function is enable for this stream handle
std : : vector < Ptr < SequenceEncodeDecodeFunction > > seqEncTable = GetNode ( ) - > GetSequenceEncodeDecodeTable ( ) ;
for ( uint32_t i = 0 ; i < seqEncTable . size ( ) ; i + + )
{
if ( seqEncTable [ i ] - > IsApplicable ( streamHandle , this , false ) )
{
isSeqNumber = true ;
seqNumber = seqEncTable [ i ] - > Decode ( packet ) ;
break ;
}
}
//Individual Recovery if this function is enable for this stream handle
//TODO
//Sequence Recovery if this function is enable for this stream handle
std : : vector < Ptr < SequenceRecoveryFunction > > seqRcvyTable = GetNode ( ) - > GetSequenceRecoveryTable ( ) ;
for ( uint32_t i = 0 ; i < seqRcvyTable . size ( ) ; i + + )
{
bool IsApplicable ( uint32_t streamHandle , Ptr < TsnNetDevice > port , bool direction , bool hasSeqNumber , bool individualRecovery ) ;
if ( seqRcvyTable [ i ] - > IsApplicable ( streamHandle , this , false , isSeqNumber , false ) )
{
if ( ! seqRcvyTable [ i ] - > Recovery ( seqNumber ) )
{
//Duplicate FRER packet detected ! ==> Drop
m_frerDropTrace ( packet ) ;
return false ;
}
hardwareLatency + = seqRcvyTable [ i ] - > GetHardwareLatency ( ) ;
break ;
}
}
//Stream Transfert Function
//Nothing to implement in the simulator
//Sequence Generation if this function is enable for this stream handle
//TODO
//Stream splitting if this function is enable for this stream handle
//TODO
//Sequence encode => encode RTAG if this function is enable for this stream handle
//TODO
break ;
}
}
//Stream identification out-facing output (active)
for ( uint16_t i = 0 ; i < streamIdentityTable . size ( ) ; i + + ) {
if ( streamIdentityTable [ i ] - > Match ( this , false , false , packet ) ) {
streamIdentityTable [ i ] - > DoActiveUpdate ( packet ) ;
hardwareLatency + = streamIdentityTable [ i ] - > GetHardwareLatency ( ) ;
break ;
}
}
//
// If IsLinkUp() is false it means there is no channel to send any packet
// over so we just hit the drop trace on the packet and return an error.
//
if ( ! IsLinkUp ( ) )
{
m_macTxDropTrace ( packet ) ;
return false ;
}
//Add timestamp if first emission
TimestampTag tag ( Simulator : : Now ( ) ) ;
if ( ! packet - > FindFirstMatchingByteTag ( tag ) )
{
packet - > AddByteTag ( tag ) ;
}
m_macTxTrace ( packet ) ;
m_macTxAnimationTrace ( packet , this ) ;
Ptr < Packet > pCopy = packet - > Copy ( ) ;
EthernetHeader2 header ;
pCopy - > RemoveHeader ( header ) ;
uint8_t pcp = header . GetPcp ( ) ;
m_FIFOStateSnifferTrace ( m_queues , m_txMachineState = = BUSY , packet ) ;
// NS_LOG_INFO(Names::FindName(this) << " "<< Simulator::Now().GetNanoSeconds()<<" Enqueue pkt #"<<packet->GetUid() << " (Vid : " << header.GetVid() << ") in FIFO #" << unsigned(pcp));
//
// We should enqueue and dequeue the packet to hit the tracing hooks.
//
if ( m_queues [ pcp ] - > Enqueue ( packet ) )
{
//Add the event after all the already present at this exact instant to avoid
//the beginning of a transmission if a packet will be ready at the event just
//after but at the same time instant.
Simulator : : Schedule ( hardwareLatency , & TsnNetDevice : : CheckForReadyPacket , this ) ;
//NS_LOG_INFO(Names::FindName(this) << " Enqueue pkt #"<<packet->GetUid() << " OK !");
return true ;
}
// Enqueue may fail (overflow)
m_macTxDropTrace ( packet ) ;
return false ;
}
bool
TsnNetDevice : : SendWithSpecificFIFO ( Ptr < Packet > packet , const Address & dest , uint16_t ethertype , uint8_t pcp )
{
NS_LOG_FUNCTION ( this ) ;
return SendFrom ( packet , GetAddress ( ) , dest , ethertype , pcp ) ;
}
bool
TsnNetDevice : : SendFrom ( Ptr < Packet > packet ,
const Address & source ,
const Address & dest ,
uint16_t ethertype ,
uint8_t pcp )
{
// This function is use to put GPTP frame in a specific FIFO without using QTAG
NS_LOG_FUNCTION ( this ) ;
NS_ASSERT_MSG ( m_queues . size ( ) > pcp , " Not enough fifos ( 0 to " < < m_queues . size ( ) - 1 < < " ) to handle this pcp priority ( " < < unsigned ( pcp ) < < " ) on Node " < < Names : : FindName ( GetNode ( ) ) ) ;
AddHeader ( packet , Mac48Address : : ConvertFrom ( dest ) , Mac48Address : : ConvertFrom ( source ) , ethertype ) ;
EthernetTrailer trailer ;
trailer . EnableFcs ( true ) ;
trailer . CalcFcs ( packet ) ;
packet - > AddTrailer ( trailer ) ;
//
// If IsLinkUp() is false it means there is no channel to send any packet
// over so we just hit the drop trace on the packet and return an error.
//
if ( ! IsLinkUp ( ) )
{
m_macTxDropTrace ( packet ) ;
return false ;
}
//Add timestamp if first emission
TimestampTag tag ( Simulator : : Now ( ) ) ;
if ( ! packet - > FindFirstMatchingByteTag ( tag ) )
{
packet - > AddByteTag ( tag ) ;
}
m_macTxTrace ( packet ) ;
m_FIFOStateSnifferTrace ( m_queues , m_txMachineState = = BUSY , packet ) ;
// NS_LOG_INFO(Names::FindName(this) << " "<< Simulator::Now().GetNanoSeconds()<<" Enqueue pkt #"<<packet->GetUid() << " in FIFO #" << unsigned(pcp));
//
// We should enqueue and dequeue the packet to hit the tracing hooks.
//
if ( m_queues [ pcp ] - > Enqueue ( packet ) )
{
//NS_LOG_INFO(Names::FindName(this) << " Enqueue pkt #"<<packet->GetUid() << " OK !");
//Add the event after all the already present at this exact instant to avoid
//the beginning of a transmission if a packet will be ready at the event just
//after but at the same time instant.
Simulator : : Schedule ( Time ( 0 ) , & TsnNetDevice : : CheckForReadyPacket , this ) ;
return true ;
}
// Enqueue may fail (overflow)
m_macTxDropTrace ( packet ) ;
return false ;
}
bool
TsnNetDevice : : TransmitStart ( Ptr < Packet > p , int queue_id )
{
NS_LOG_FUNCTION ( this < < p ) ;
NS_LOG_LOGIC ( " UID is " < < p - > GetUid ( ) < < " ) " ) ;
//Timestamping at last bits emission
NS_ASSERT_MSG ( m_node ! = nullptr , " m_node was not set using void TsnNetDevice::SetNode(Ptr<TsnNode> node) " ) ;
Time txTimestamp = m_node - > GetTime ( ) ;
// NS_LOG_INFO("On " << Names::FindName(this)<< " Tx start at " << Simulator::Now().GetNanoSeconds() << " recording : " << txTimestamp.GetNanoSeconds());
//Add a tag to compute delay between reception(or FIFO enter if first
//emission port) and transmission start
TimestampTag tag ( Simulator : : Now ( ) ) ;
p - > AddByteTag ( tag ) ;
//
// This function is called to start the process of transmitting a packet.
// We need to tell the channel that we've started wiggling the wire and
// schedule an event that will be executed when the transmission is complete.
//
NS_ASSERT_MSG ( m_txMachineState = = READY , " Must be READY to transmit " ) ;
m_txMachineState = BUSY ;
m_txHardwareLatencyExperienced = false ;
m_currentPkt = p ;
m_phyTxBeginTrace ( m_currentPkt ) ;
Time preambleAndSFDGapTime = m_bps . CalculateBytesTxTime ( m_preambleAndSFDGap ) ;
Time txTime = m_bps . CalculateBytesTxTime ( p - > GetSize ( ) ) ;
Time interpacketGapTime = m_bps . CalculateBytesTxTime ( m_interframeGap ) ;
Time txCompleteTime = preambleAndSFDGapTime + txTime + interpacketGapTime ;
//NS_LOG_INFO(Names::FindName(this) << " "<< Simulator::Now().GetNanoSeconds()<<" Transmit pkt #"<<p->GetUid());
Simulator : : Schedule ( txCompleteTime , & TsnTransmissionSelectionAlgo : : TransmitComplete , m_transmissionSelectionAlgos [ queue_id ] , p ) ;
m_transmissionSelectionAlgos [ queue_id ] - > TransmitStart ( p , txTime ) ;
NS_LOG_LOGIC ( " Schedule TransmitCompleteEvent in " < < txCompleteTime . As ( Time : : S ) ) ;
Simulator : : Schedule ( txCompleteTime , & TsnNetDevice : : TransmitComplete , this , queue_id ) ;
bool result = m_channel - > TransmitStart ( p , this , txCompleteTime - interpacketGapTime ) ; //Pkt don't need to wait for the end of Interpacket gap to be considered as receive on the other end of the link
if ( ! result )
{
m_phyTxDropTrace ( p ) ;
}
if ( ! m_rxCallbackWithTimestamp . IsNull ( ) ) {
m_txCallbackWithTimestamp ( p , txTimestamp ) ;
}
return result ;
}
void
TsnNetDevice : : TransmitComplete ( int queue_id )
{
NS_LOG_FUNCTION ( this ) ;
// This function is called to when we're all done transmitting a packet.
// We try and pull another packet off of the transmit queue. If the queue
// is empty, we are done, otherwise we need to start transmitting the
// next packet.
//
NS_ASSERT_MSG ( m_txMachineState = = BUSY , " Must be BUSY if transmitting " ) ;
m_txMachineState = READY ;
NS_ASSERT_MSG ( m_currentPkt , " TsnNetDevice::TransmitComplete(): m_currentPkt zero " ) ;
m_phyTxEndTrace ( m_currentPkt ) ;
//m_transmissionSelectionAlgos[queue_id]->TransmitComplete(m_currentPkt);
m_currentPkt = nullptr ;
//Add the event after all the already present at this exact instant to avoid
//the beginning of a transmission if a packet will be ready at the event just
//after but at the same time instant.
Simulator : : Schedule ( Time ( 0 ) , & TsnNetDevice : : CheckForReadyPacket , this ) ;
}
void
TsnNetDevice : : CheckForReadyPacket ( )
{
NS_LOG_FUNCTION ( this ) ;
if ( m_txMachineState ! = READY | | m_txHardwareLatencyExperienced )
{
return ;
}
int next_queue_id = TransmitSelection ( ) ;
if ( next_queue_id = = - 1 )
{
NS_LOG_LOGIC ( " No pending packets in device queue after tx complete " ) ;
return ;
}
//
// Got another packet off of the queue, so start the transmit process again.
//
Ptr < Packet > p = m_queues [ next_queue_id ] - > Dequeue ( ) ;
m_snifferTrace ( p ) ;
m_promiscSnifferTrace ( p ) ;
m_txHardwareLatencyExperienced = true ;
Time hardwareLatency = m_transmissionSelectionAlgos [ next_queue_id ] - > GetHardwareLatency ( ) + m_tas - > GetHardwareLatency ( ) ;
Simulator : : Schedule ( hardwareLatency , & TsnNetDevice : : TransmitStart , this , p , next_queue_id ) ;
}
void
TsnNetDevice : : Receive ( Ptr < Packet > packet )
{
NS_LOG_FUNCTION ( this < < packet ) ;
NS_LOG_LOGIC ( " UID is " < < packet - > GetUid ( ) ) ;
//Timestamping at last bits receiption thus compensate for the duration between first bit and last
NS_ASSERT_MSG ( m_node ! = nullptr , " m_node was not set using void TsnNetDevice::SetNode(Ptr<TsnNode> node) " ) ;
Time rxTimestamp = m_node - > GetTime ( ) - ( m_bps . CalculateBytesTxTime ( m_preambleAndSFDGap ) + m_bps . CalculateBytesTxTime ( packet - > GetSize ( ) ) ) ;
Time hardwareLatency = Time ( 0 ) ;
// NS_LOG_INFO("On " << Names::FindName(this)<< " Rx end at " << (Simulator::Now()- (m_bps.CalculateBytesTxTime(m_preambleAndSFDGap) + m_bps.CalculateBytesTxTime(packet->GetSize()))).GetNanoSeconds() << " recording : " << rxTimestamp.GetNanoSeconds());
if ( m_receiveErrorModel & & m_receiveErrorModel - > IsCorrupt ( packet ) )
{
//
// If we have an error model and it indicates that it is time to lose a
// corrupted packet, don't forward this packet up, let it go.
//
NS_LOG_LOGIC ( " Dropping pkt due to error model " ) ;
m_phyRxDropTrace ( packet ) ;
}
else
{
//Add timestamp to measure delay in the switches
TimestampTag tag ( Simulator : : Now ( ) ) ;
packet - > AddByteTag ( tag ) ;
//
// Hit the trace hooks. All of these hooks are in the same place in this
// device because it is so simple, but this is not usually the case in
// more complicated devices.
m_snifferTrace ( packet ) ;
m_promiscSnifferTrace ( packet ) ;
m_phyRxEndTrace ( packet ) ;
//
// Trace sinks will expect complete packets, not packets without some of the
// headers.
//
Ptr < Packet > originalPacket = packet - > Copy ( ) ;
//Check checksum
EthernetTrailer trailer ;
packet - > RemoveTrailer ( trailer ) ;
if ( Node : : ChecksumEnabled ( ) )
{
trailer . EnableFcs ( true ) ;
}
bool crcGood = trailer . CheckFcs ( packet ) ;
if ( ! crcGood )
{
NS_LOG_INFO ( " CRC error on Packet " < < packet ) ;
m_phyRxDropTrace ( packet ) ;
return ;
}
//
// Strip off the ethernet protocol header and forward this packet
// up the protocol stack. Since this is a simple point-to-point link,
// there is no difference in what the promisc callback sees and what the
// normal receive callback sees.
//
EthernetHeader2 header ;
packet - > RemoveHeader ( header ) ;
uint16_t protocol = header . GetEthertype ( ) ;
uint8_t priority = header . GetPcp ( ) ;
// Stream identification out-facing input
std : : vector < Ptr < StreamIdEntry > > streamIdentityTable = GetNode ( ) - > GetStreamIdentityTable ( ) ;
for ( uint32_t i = 0 ; i < streamIdentityTable . size ( ) ; i + + ) {
if ( streamIdentityTable [ i ] - > Match ( this , false , true , originalPacket ) ) {
uint32_t streamHandle = streamIdentityTable [ i ] - > GetStreamHandle ( ) ;
hardwareLatency + = streamIdentityTable [ i ] - > GetHardwareLatency ( ) ;
//PSFP
std : : vector < Ptr < StreamFilterInstance > > streamFilterInstanceTable = GetNode ( ) - > GetStreamFilterInstanceTable ( ) ;
for ( uint16_t i = 0 ; i < streamFilterInstanceTable . size ( ) ; i + + ) {
if ( streamFilterInstanceTable [ i ] - > Match ( streamHandle , priority ) ) {
//MaxSDUSizeFilter
if ( streamFilterInstanceTable [ i ] - > MaxSDUSizeFilter ( originalPacket ) ) {
m_maxSDUSizeFilterDropTrace ( originalPacket ) ;
return ;
}
//TODO Stream Gate
//Flow Meter
std : : vector < uint16_t > fmids = streamFilterInstanceTable [ i ] - > GetFlowMeterIds ( ) ;
std : : vector < Ptr < FlowMeterInstance > > flowMeterInstanceTable = GetNode ( ) - > GetFlowMeterInstanceTable ( ) ;
bool pass = true ;
for ( uint16_t j = 0 ; j < fmids . size ( ) ; j + + ) {
if ( flowMeterInstanceTable [ fmids [ j ] ] - > Test ( originalPacket ) ) {
pass = false ;
}
}
if ( not pass ) {
streamFilterInstanceTable [ i ] - > increaseRedFrameCount ( ) ;
m_REDFrameDropTrace ( originalPacket ) ;
return ;
}
break ;
}
}
//FRER
// NS_LOG_INFO( "Stream handle of Pkt #"<<packet->GetUid() << " on input : " << streamHandle);
bool isSeqNumber = false ;
uint16_t seqNumber = 0 ;
//Sequence decode => extract RTAG if this function is enable for this stream handle
//TODO
//Individual Recovery if this function is enable for this stream handle
//TODO
//Sequence Recovery if this function is enable for this stream handle
//TODO
//Stream Transfert Function
//Nothing to implement in the simulator
//Sequence Generation if this function is enable for this stream handle
std : : vector < Ptr < SequenceGenerationFunction > > seqGenTable = GetNode ( ) - > GetSequenceGenerationTable ( ) ;
for ( uint32_t i = 0 ; i < seqGenTable . size ( ) ; i + + )
{
if ( seqGenTable [ i ] - > IsApplicable ( streamHandle ) )
{
isSeqNumber = true ;
seqNumber = seqGenTable [ i ] - > GetSequenceNumber ( ) ;
break ;
}
}
//Stream splitting if this function is enable for this stream handle
//TODO
//Sequence encode => encode RTAG if this function is enable for this stream handle
if ( isSeqNumber )
{
std : : vector < Ptr < SequenceEncodeDecodeFunction > > seqEncTable = GetNode ( ) - > GetSequenceEncodeDecodeTable ( ) ;
for ( uint32_t i = 0 ; i < seqEncTable . size ( ) ; i + + )
{
if ( seqEncTable [ i ] - > IsApplicable ( streamHandle , this , false ) )
{
seqEncTable [ i ] - > Encode ( originalPacket , seqNumber ) ;
break ;
}
}
}
break ;
}
}
//
// Classify the packet based on its destination.
//
PacketType packetType ;
if ( header . GetDest ( ) = = m_address )
{
packetType = PACKET_HOST ;
}
else if ( header . GetDest ( ) . IsBroadcast ( ) )
{
packetType = PACKET_BROADCAST ;
}
else if ( header . GetDest ( ) . IsGroup ( ) )
{
packetType = PACKET_MULTICAST ;
}
else
{
packetType = PACKET_OTHERHOST ;
}
if ( ! m_promiscCallback . IsNull ( ) )
{
Simulator : : Schedule ( hardwareLatency ,
& TsnNetDevice : : m_macPromiscRxTrace ,
this ,
originalPacket - > Copy ( ) ) ;
Simulator : : Schedule ( hardwareLatency ,
& TsnNetDevice : : m_promiscCallback ,
this ,
this ,
originalPacket ,
protocol ,
header . GetSrc ( ) ,
header . GetDest ( ) ,
packetType ) ;
}
//
// If this packet is not destined for some other host, it must be for us
// as either a broadcast, multicast or unicast. We need to hit the mac
// packet received trace hook and forward the packet up the stack.
//
if ( packetType ! = PACKET_OTHERHOST )
{
//NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << Names::FindName(m_node) << "/" << Names::FindName(this) <<" : Pkt #" << originalPacket->GetUid() <<" received by the netDevice ! " << originalPacket->ToString());
m_macRxTrace ( originalPacket ) ;
m_rxCallback ( this , packet , protocol , header . GetSrc ( ) ) ;
if ( ! m_rxCallbackWithTimestamp . IsNull ( ) )
{
m_rxCallbackWithTimestamp ( this , packet , protocol , header . GetSrc ( ) , rxTimestamp ) ;
}
m_latencyTrace ( originalPacket ) ;
}
}
}
Ptr < TsnNode >
TsnNetDevice : : GetNode ( )
{
return m_node ;
}
void
TsnNetDevice : : SetReceiveCallbackWithTimestamp ( ReceiveCallbackWithTimestamp cb )
{
m_rxCallbackWithTimestamp = cb ;
}
void
TsnNetDevice : : SetTransmitCallbackWithTimestamp ( TransmitCallbackWithTimestamp cb )
{
m_txCallbackWithTimestamp = cb ;
}
void
TsnNetDevice : : AddGclEntry ( Time duration , uint8_t states )
{
NS_LOG_FUNCTION ( this ) ;
m_tas - > AddGclEntry ( duration , states ) ;
}
void
TsnNetDevice : : StartTas ( )
{
NS_LOG_FUNCTION ( this ) ;
StartTas ( Time ( 0 ) ) ;
}
void
TsnNetDevice : : StartTas ( Time startTime )
{
NS_LOG_FUNCTION ( this ) ;
Simulator : : Schedule ( startTime , & Tas : : Start , m_tas ) ;
}
Ptr < Tas >
TsnNetDevice : : GetTas ( )
{
NS_LOG_FUNCTION ( this ) ;
return m_tas ;
}
}