This commit is contained in:
Gustavo J. A. M. Carneiro
2009-09-16 11:01:57 +01:00
30 changed files with 578 additions and 49 deletions

View File

@@ -1,6 +1,7 @@
Kirill Andreev (andreev@iitp.ru)
Nicola Baldo (nbaldo@cttc.es)
Mirko Banchi (mk.banchi@gmail.com)
Ramon Bauza (monbauza@gmail.com)
Mehdi Benamor (mehdi.benamor@telecom-bretagne.eu)
Raj Bhattacharjea (raj.b@gatech.edu)
Timo Bingmann (timo.bingmann@student.kit.edu)

View File

@@ -107,6 +107,9 @@ router solicitation, DAD
<ul>
<li> 10MHz and 5MHz channel width supported by 802.11a model (Ramon Bauza and Kirill Andreev).
</ul>
<ul>
<li> Channel switching support. YansWifiPhy can now switch among different channels (Ramon Bauza and Pavel Boyko).
</ul>
</p>
</li>

View File

@@ -30,8 +30,16 @@ http://www.nsnam.org/wiki/index.php/Installation
New user-visible features
-------------------------
a) Add an implementation of the minstrel rate control algorithm
(Duy Nguyen for gsoc)
a) 802.11 models:
- Add an implementation of the minstrel rate control algorithm
(Duy Nguyen for gsoc)
- AthstatsHelper: enables the wifi device to produce periodic
reports similar to the ones generated by madwifi's
athstats tool (Nicola Baldo)
- 10MHz and 5MHz channel width supported by 802.11a model
(Ramon Bauza and Kirill Andreev)
- Channel switching support. YansWifiPhy can now switch among
different channels (Ramon Bauza and Pavel Boyko)
b) IPv6 models:
- IPv6 interface;
@@ -46,17 +54,10 @@ New user-visible features
- Examples (ping6, simple-routing-ping6, radvd, radvd-two-prefix,
icmpv6-redirect).
c) added AthstatsHelper, which enables the wifi device to produce
periodic reports similar to the ones generated by madwifi's
athstats tool (Nicola Baldo)
d) Wireless Mesh Networking models:
c) Wireless Mesh Networking models:
- General multi-interface mesh stack infrastructure (devices/mesh module).
- IEEE 802.11s (Draft 3.0) model including Peering Management Protocol and HWMP.
- Forwarding Layer for Meshing (FLAME) protocol.
e) 802.11 enhancements:
- 10MHz and 5MHz channel width supported by 802.11a model (Ramon Bauza and Kirill Andreev)
API changes from ns-3.5
-----------------------

View File

@@ -267,6 +267,10 @@ implement the specific operator() method,
};
@end verbatim
@emph{N.B. The previous code is not real ns-3 code. It is simplistic example
code used only to illustrate the concepts involved and to help you understand
the system more. Do not expect to find this code anywhere in the ns-3 tree}
Notice that there are two variables defined in the class above. The m_p
variable is the object pointer and m_pmi is the variable containing the
address of the function to execute.

View File

@@ -112,7 +112,7 @@ functions.
It will be useful to go walk a quick example just to reinforce what we've said.
@verbose
@verbatim
#include ``ns3/object.h''
#include ``ns3/uinteger.h''
#include ``ns3/traced-value.h''
@@ -121,7 +121,7 @@ It will be useful to go walk a quick example just to reinforce what we've said.
#include <iostream>
using namespace ns3;
@end verbose
@end verbatim
The first thing to do is include the required files. As mentioned above, the
trace system makes heavy use of the Object and Attribute systems. The first
@@ -167,7 +167,7 @@ the @code{TracedValue} declaration.
The @code{.AddTraceSource} provides the ``hooks'' used for connecting the trace
source to the outside world. The @code{TracedValue} declaration provides the
infrastructure that overloads the operators above and drives the callback
infrastructure that overloads the operators mentioned above and drives the callback
process.
@verbatim
@@ -201,9 +201,11 @@ The next step, the @code{TraceConnectWithoutContext}, forms the connection
between the trace source and the trace sink. Notice the @code{MakeCallback}
template function. Recall from the Callback section that this creates the
specialized functor responsible for providing the overloaded @code{operator()}
used to ``fire'' the callback. The @code{TraceConnectWithoutContext}, takes
a string parameter that provides the name of the Attribute assigned to the
trace source. Let's ignore the bit about context for now.
used to ``fire'' the callback. The overloaded operators (++, --, etc.) will
use this @code{operator()} to actually invoke the callback. The
@code{TraceConnectWithoutContext}, takes a string parameter that provides
the name of the Attribute assigned to the trace source. Let's ignore the bit
about context for now since it is not important yet.
Finally, the line,
@@ -247,27 +249,27 @@ For example, one might find something that looks like the following in the syste
@end verbatim
This should look very familiar. It is the same thing as the previous example,
except that a static member function of @code{Config} is being called instead of
a method on @code{Object}, and instead of an @code{Attribute} name, a path is
except that a static member function of class @code{Config} is being called instead
of a method on @code{Object}; and instead of an @code{Attribute} name, a path is
being provided.
The first thing to do is to read the path backward. The last segment of the path
must be an @code{Attribute} of an @code{Object}. In fact, if you had a pointer to
the @code{Object} that has the @code{Attribute} handy, you could write this just like
the previous example:
the @code{Object} that has the ``CongestionWindow'' @code{Attribute} handy (call it
@code{theObject}), you could write this just like the previous example:
@verbatim
void CwndTracer (uint32_t oldval, uint32_t newval) {}
...
object->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndTracer));
theObject->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndTracer));
@end verbatim
And it turns out that @code{Config::ConnectWithoutContext} does exactly that. This
function takes a path that represents a chain of @code{Object} pointers and follows
It turns out that the code for @code{Config::ConnectWithoutContext} does exactly that.
This function takes a path that represents a chain of @code{Object} pointers and follows
them until it gets to the end of the path and interprets the last segment as an
@code{Attribute} on the last object.
@code{Attribute} on the last object. Let's walk through what happens.
The leading ``/'' character in the path refers to a so-called namespace. One of the
predefined namespaces in the config system is ``NodeList'' which is a list of all of

View File

@@ -62,6 +62,9 @@ PhyStateTrace (std::string context, Time start, Time duration, enum WifiPhy::Sta
{
std::cout << " state=";
switch (state) {
case WifiPhy::SWITCHING:
std::cout << "switchng";
break;
case WifiPhy::TX:
std::cout << "tx ";
break;

View File

@@ -32,7 +32,7 @@ int main (int argc, char *argv[])
mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
mobility.Install (c);
Config::Connect ("/NodeList/*/$ns3::MobilityModelNotifier/CourseChange",
Config::Connect ("/NodeList/*/$ns3::MobilityModel/CourseChange",
MakeCallback (&CourseChange));
Simulator::Stop (Seconds (100.0));

View File

@@ -252,6 +252,7 @@ WifiMeshActionHeader::GetAction ()
return retval;
default:
NS_FATAL_ERROR ("Unknown mesh peering management action code");
retval.peerLink = PEER_LINK_OPEN; /* quiet compiler */
return retval;
}
case MESH_PATH_SELECTION:
@@ -262,6 +263,7 @@ WifiMeshActionHeader::GetAction ()
return retval;
default:
NS_FATAL_ERROR ("Unknown mesh path selection action code");
retval.peerLink = PEER_LINK_OPEN; /* quiet compiler */
return retval;
}
case MESH_LINK_METRIC:
@@ -272,6 +274,7 @@ WifiMeshActionHeader::GetAction ()
// not yet supported
default:
NS_FATAL_ERROR ("Unsupported mesh action");
retval.peerLink = PEER_LINK_OPEN; /* quiet compiler */
return retval;
}
}

View File

@@ -241,7 +241,7 @@ PeerManagementProtocol::ReceivePeerLinkFrame (uint32_t interface, Mac48Address p
Ptr<PeerLink> peerLink = FindPeerLink (interface, peerAddress);
if (peerManagementElement.SubtypeIsOpen ())
{
PmpReasonCode reasonCode;
PmpReasonCode reasonCode (REASON11S_RESERVED);
bool reject = !(ShouldAcceptOpen (interface, peerAddress, reasonCode));
if (peerLink == 0)
{

View File

@@ -58,6 +58,9 @@ private:
virtual void DoNotifyCollision (void) {
m_txop->NotifyCollision ();
}
virtual void DoNotifyChannelSwitching (void) {
m_txop->NotifyChannelSwitching ();
}
DcaTxop *m_txop;
};
@@ -446,6 +449,13 @@ DcaTxop::NotifyCollision (void)
RestartAccessIfNeeded ();
}
void
DcaTxop::NotifyChannelSwitching (void)
{
m_queue->Flush();
m_currentPacket = 0;
}
void
DcaTxop::GotCts (double snr, WifiMode txMode)
{

View File

@@ -127,6 +127,10 @@ private:
void NotifyAccessGranted (void);
void NotifyInternalCollision (void);
void NotifyCollision (void);
/**
* When a channel switching occurs, enqueued packets are removed.
*/
void NotifyChannelSwitching (void);
/* event handlers */
void GotCts (double snr, WifiMode txMode);
void MissedCts (void);

View File

@@ -38,6 +38,7 @@ private:
virtual void DoNotifyAccessGranted (void);
virtual void DoNotifyInternalCollision (void);
virtual void DoNotifyCollision (void);
virtual void DoNotifyChannelSwitching (void);
typedef std::pair<uint64_t,uint64_t> ExpectedGrant;
typedef std::list<ExpectedGrant> ExpectedGrants;
@@ -65,6 +66,7 @@ public:
void NotifyAccessGranted (uint32_t i);
void NotifyInternalCollision (uint32_t i);
void NotifyCollision (uint32_t i);
void NotifyChannelSwitching (uint32_t i);
private:
@@ -88,6 +90,9 @@ private:
void AddAccessRequestWithSuccessfullAck (uint64_t at, uint64_t txTime,
uint64_t expectedGrantTime, uint32_t ackDelay, uint32_t from);
void DoAccessRequest (uint64_t txTime, uint64_t expectedGrantTime, DcfStateTest *state);
void AddCcaBusyEvt (uint64_t at, uint64_t duration);
void AddSwitchingEvt (uint64_t at, uint64_t duration);
void AddRxStartEvt (uint64_t at, uint64_t duration);
typedef std::vector<DcfStateTest *> DcfStates;
@@ -122,7 +127,11 @@ DcfStateTest::DoNotifyCollision (void)
{
m_test->NotifyCollision (m_i);
}
void
DcfStateTest::DoNotifyChannelSwitching (void)
{
m_test->NotifyChannelSwitching (m_i);
}
DcfManagerTest::DcfManagerTest ()
@@ -182,7 +191,22 @@ DcfManagerTest::NotifyCollision (uint32_t i)
m_result = result;
}
}
void
DcfManagerTest::NotifyChannelSwitching (uint32_t i)
{
DcfStateTest *state = m_dcfStates[i];
bool result = true;
if (!state->m_expectedGrants.empty ())
{
std::pair<uint64_t, uint64_t> expected = state->m_expectedGrants.front ();
state->m_expectedGrants.pop_front ();
NS_TEST_ASSERT_EQUAL (Simulator::Now (), MicroSeconds (expected.second));
}
if (!result)
{
m_result = result;
}
}
void
DcfManagerTest::ExpectInternalCollision (uint64_t time, uint32_t nSlots, uint32_t from)
@@ -320,7 +344,27 @@ DcfManagerTest::DoAccessRequest (uint64_t txTime, uint64_t expectedGrantTime, Dc
state->QueueTx (txTime, expectedGrantTime);
m_dcfManager->RequestAccess (state);
}
void
DcfManagerTest::AddCcaBusyEvt (uint64_t at, uint64_t duration)
{
Simulator::Schedule (MicroSeconds (at) - Now (),
&DcfManager::NotifyMaybeCcaBusyStartNow, m_dcfManager,
MicroSeconds (duration));
}
void
DcfManagerTest::AddSwitchingEvt (uint64_t at, uint64_t duration)
{
Simulator::Schedule (MicroSeconds (at) - Now (),
&DcfManager::NotifySwitchingStartNow, m_dcfManager,
MicroSeconds (duration));
}
void
DcfManagerTest::AddRxStartEvt (uint64_t at, uint64_t duration)
{
Simulator::Schedule (MicroSeconds (at) - Now (),
&DcfManager::NotifyRxStartNow, m_dcfManager,
MicroSeconds (duration));
}
@@ -559,7 +603,95 @@ DcfManagerTest::RunTests (void)
AddAccessRequest (30, 50, 108, 0);
ExpectCollision (30, 3, 0); // backoff: 3 slots
EndTest ();
// Channel switching tests
// 0 20 23 24 25
// | switching | sifs | aifsn | tx |
// |
// 21 access request.
StartTest (1, 3, 10);
AddDcfState (1);
AddSwitchingEvt(0,20);
AddAccessRequest (21, 1, 24, 0);
EndTest ();
// 20 40 50 53 54 55
// | switching | busy | sifs | aifsn | tx |
// | |
// 30 busy. 45 access request.
//
StartTest (1, 3, 10);
AddDcfState (1);
AddSwitchingEvt(20,20);
AddCcaBusyEvt(30,20);
AddAccessRequest (45, 1, 54, 0);
EndTest ();
// 20 30 50 53 54 55
// | rx | switching | sifs | aifsn | tx |
// |
// 51 access request.
//
StartTest (1, 3, 10);
AddDcfState (1);
AddRxStartEvt (20,40);
AddSwitchingEvt(30,20);
AddAccessRequest (51, 1, 54, 0);
EndTest ();
// 20 30 50 53 54 55
// | busy | switching | sifs | aifsn | tx |
// |
// 51 access request.
//
StartTest (1, 3, 10);
AddDcfState (1);
AddCcaBusyEvt (20,40);
AddSwitchingEvt(30,20);
AddAccessRequest (51, 1, 54, 0);
EndTest ();
// 20 30 50 53 54 55
// | nav | switching | sifs | aifsn | tx |
// |
// 51 access request.
//
StartTest (1, 3, 10);
AddDcfState (1);
AddNavStart (20,40);
AddSwitchingEvt(30,20);
AddAccessRequest (51, 1, 54, 0);
EndTest ();
// 20 40 50 55 58 59 60
// | tx | ack timeout | switching | sifs | aifsn | tx |
// | |
// 45 access request. 56 access request.
//
StartTest (1, 3, 10);
AddDcfState (1);
AddAccessRequestWithAckTimeout (20, 20, 20, 0);
AddAccessRequest (45, 1, 50, 0);
AddSwitchingEvt(50,5);
AddAccessRequest (56, 1, 59, 0);
EndTest ();
// 20 60 66 70 74 78 80 100 106 110 112
// | rx | sifs | aifsn | bslot0 | bslot1 | | switching | sifs | aifsn | tx |
// | |
// 30 access request. 101 access request.
//
StartTest (4, 6, 10);
AddDcfState (1);
AddRxOkEvt(20,40);
AddAccessRequest (30, 2, 80, 0);
ExpectCollision(30, 4, 0); // backoff: 4 slots
AddSwitchingEvt(80,20);
AddAccessRequest (101, 2, 110, 0);
EndTest ();
return m_result;
}

View File

@@ -154,6 +154,11 @@ DcfState::NotifyInternalCollision (void)
{
DoNotifyInternalCollision ();
}
void
DcfState::NotifyChannelSwitching (void)
{
DoNotifyChannelSwitching ();
}
/***************************************************************
@@ -211,6 +216,9 @@ public:
virtual void NotifyMaybeCcaBusyStart (Time duration) {
m_dcf->NotifyMaybeCcaBusyStartNow (duration);
}
virtual void NotifySwitchingStart (Time duration) {
m_dcf->NotifySwitchingStartNow (duration);
}
private:
ns3::DcfManager *m_dcf;
};
@@ -232,6 +240,8 @@ DcfManager::DcfManager ()
m_lastTxDuration (MicroSeconds (0)),
m_lastBusyStart (MicroSeconds (0)),
m_lastBusyDuration (MicroSeconds (0)),
m_lastSwitchingStart (MicroSeconds (0)),
m_lastSwitchingDuration (MicroSeconds (0)),
m_rxing (false),
m_slotTime (Seconds (0.0)),
m_sifs (Seconds (0.0)),
@@ -319,6 +329,18 @@ DcfManager::MostRecent (Time a, Time b, Time c, Time d, Time e, Time f) const
return retval;
}
Time
DcfManager::MostRecent (Time a, Time b, Time c, Time d, Time e, Time f, Time g) const
{
Time h = Max (a, b);
Time i = Max (c, d);
Time j = Max (e, f);
Time k = Max (h, i);
Time l = Max (j, g);
Time retval = Max (k, l);
return retval;
}
bool
DcfManager::IsBusy (void) const
{
@@ -454,12 +476,14 @@ DcfManager::GetAccessGrantStart (void) const
Time navAccessStart = m_lastNavStart + m_lastNavDuration + m_sifs;
Time ackTimeoutAccessStart = m_lastAckTimeoutEnd + m_sifs;
Time ctsTimeoutAccessStart = m_lastCtsTimeoutEnd + m_sifs;
Time switchingAccessStart = m_lastSwitchingStart + m_lastSwitchingDuration + m_sifs;
Time accessGrantedStart = MostRecent (rxAccessStart,
busyAccessStart,
txAccessStart,
navAccessStart,
ackTimeoutAccessStart,
ctsTimeoutAccessStart
ctsTimeoutAccessStart,
switchingAccessStart
);
NS_LOG_INFO ("access grant start=" << accessGrantedStart <<
", rx access start=" << rxAccessStart <<
@@ -596,6 +620,67 @@ DcfManager::NotifyMaybeCcaBusyStartNow (Time duration)
m_lastBusyStart = Simulator::Now ();
m_lastBusyDuration = duration;
}
void
DcfManager::NotifySwitchingStartNow (Time duration)
{
Time now = Simulator::Now ();
NS_ASSERT (m_lastTxStart + m_lastTxDuration <= now);
NS_ASSERT (m_lastSwitchingStart + m_lastSwitchingDuration <= now);
if (m_rxing)
{
// channel switching during packet reception
m_lastRxEnd = Simulator::Now ();
m_lastRxDuration = m_lastRxEnd - m_lastRxStart;
m_lastRxReceivedOk = true;
m_rxing = false;
}
if (m_lastNavStart + m_lastNavDuration > now)
{
m_lastNavDuration = now - m_lastNavStart;
}
if (m_lastBusyStart + m_lastBusyDuration > now)
{
m_lastBusyDuration = now - m_lastBusyStart;
}
if (m_lastAckTimeoutEnd > now)
{
m_lastAckTimeoutEnd = now;
}
if (m_lastCtsTimeoutEnd > now)
{
m_lastCtsTimeoutEnd = now;
}
// Cancel timeout
if (m_accessTimeout.IsRunning ())
{
m_accessTimeout.Cancel ();
}
// Reset backoffs
for (States::iterator i = m_states.begin (); i != m_states.end (); i++)
{
DcfState *state = *i;
uint32_t remainingSlots = state->GetBackoffSlots ();
if (remainingSlots > 0)
{
state->UpdateBackoffSlotsNow (remainingSlots, now);
NS_ASSERT(state->GetBackoffSlots()==0);
}
state->ResetCw();
state->m_accessRequested = false;
state->NotifyChannelSwitching();
}
MY_DEBUG ("switching start for "<<duration);
m_lastSwitchingStart = Simulator::Now ();
m_lastSwitchingDuration = duration;
}
void
DcfManager::NotifyNavResetNow (Time duration)
{

View File

@@ -100,6 +100,7 @@ private:
void NotifyAccessGranted (void);
void NotifyCollision (void);
void NotifyInternalCollision (void);
void NotifyChannelSwitching (void);
/**
@@ -130,6 +131,14 @@ private:
* is access is still needed.
*/
virtual void DoNotifyCollision (void) = 0;
/**
* Called by DcfManager to notify a DcfState subclass
* that a channel switching occured.
*
* The subclass is expected to flush the queue of
* packets.
*/
virtual void DoNotifyChannelSwitching () = 0;
uint32_t m_aifsn;
uint32_t m_backoffSlots;
@@ -247,6 +256,14 @@ public:
* Notify the DCF that a CCA busy period has just started.
*/
void NotifyMaybeCcaBusyStartNow (Time duration);
/**
* \param duration expected duration of channel switching period
*
* Notify the DCF that a channel switching period has just started.
* During swtiching state, new packets can be enqueued in DcaTxop/EdcaTxop
* but they won't access to the medium until the end of the channel switching.
*/
void NotifySwitchingStartNow (Time duration);
/**
* \param duration the value of the received NAV.
*
@@ -269,6 +286,7 @@ private:
Time MostRecent (Time a, Time b, Time c) const;
Time MostRecent (Time a, Time b, Time c, Time d) const;
Time MostRecent (Time a, Time b, Time c, Time d, Time e, Time f) const;
Time MostRecent (Time a, Time b, Time c, Time d, Time e, Time f, Time g) const;
/**
* Access will never be granted to the medium _before_
* the time returned by this method.
@@ -299,6 +317,8 @@ private:
Time m_lastTxDuration;
Time m_lastBusyStart;
Time m_lastBusyDuration;
Time m_lastSwitchingStart;
Time m_lastSwitchingDuration;
bool m_rxing;
bool m_sleeping;
Time m_eifsNoDifs;

View File

@@ -55,6 +55,9 @@ private:
virtual void DoNotifyCollision (void) {
m_txop->NotifyCollision ();
}
virtual void DoNotifyChannelSwitching (void) {
m_txop->NotifyChannelSwitching ();
}
EdcaTxopN *m_txop;
};
@@ -427,6 +430,13 @@ EdcaTxopN::MissedCts (void)
RestartAccessIfNeeded ();
}
void
EdcaTxopN::NotifyChannelSwitching (void)
{
m_queue->Flush();
m_currentPacket = 0;
}
void
EdcaTxopN::Queue (Ptr<const Packet> packet, WifiMacHeader const &hdr)
{

View File

@@ -101,6 +101,10 @@ public:
void NotifyAccessGranted (void);
void NotifyInternalCollision (void);
void NotifyCollision (void);
/**
* When a channel switching occurs, enqueued packets are removed.
*/
void NotifyChannelSwitching (void);
/*event handlers*/
void GotCts (double snr, WifiMode txMode);

View File

@@ -603,6 +603,10 @@ InterferenceHelper::CalculateSnrPer (Ptr<InterferenceHelper::Event> event)
return snrPer;
}
void
InterferenceHelper::EraseEvents (void)
{
m_events.erase (m_events.begin (), m_events.end ());
}
} // namespace ns3

View File

@@ -95,6 +95,7 @@ public:
Time duration, double rxPower);
struct InterferenceHelper::SnrPer CalculateSnrPer (Ptr<InterferenceHelper::Event> event);
void EraseEvents (void);
private:
class NiChange {
public:

View File

@@ -244,6 +244,30 @@ std::ostream &operator << (std::ostream &os, const MacLowTransmissionParameters
return os;
}
/***************************************************************
* Listener for PHY events. Forwards to MacLow
***************************************************************/
class PhyMacLowListener : public ns3::WifiPhyListener {
public:
PhyMacLowListener (ns3::MacLow *macLow)
: m_macLow (macLow) {}
virtual ~PhyMacLowListener () {}
virtual void NotifyRxStart (Time duration) {}
virtual void NotifyRxEndOk (void) {}
virtual void NotifyRxEndError (void) {}
virtual void NotifyTxStart (Time duration) {}
virtual void NotifyMaybeCcaBusyStart (Time duration) {}
virtual void NotifySwitchingStart (Time duration) {
m_macLow->NotifySwitchingStartNow (duration);
}
private:
ns3::MacLow *m_macLow;
};
MacLow::MacLow ()
: m_normalAckTimeoutEvent (),
m_fastAckTimeoutEvent (),
@@ -267,6 +291,14 @@ MacLow::~MacLow ()
NS_LOG_FUNCTION (this);
}
void
MacLow::SetupPhyMacLowListener (Ptr<WifiPhy> phy)
{
m_phyMacLowListener = new PhyMacLowListener (this);
phy->RegisterListener (m_phyMacLowListener);
}
void
MacLow::DoDispose (void)
{
@@ -274,6 +306,8 @@ MacLow::DoDispose (void)
CancelAllEvents ();
m_phy = 0;
m_stationManager = 0;
delete m_phyMacLowListener;
m_phyMacLowListener = 0;
}
void
@@ -339,6 +373,7 @@ MacLow::SetPhy (Ptr<WifiPhy> phy)
m_phy = phy;
m_phy->SetReceiveOkCallback (MakeCallback (&MacLow::ReceiveOk, this));
m_phy->SetReceiveErrorCallback (MakeCallback (&MacLow::ReceiveError, this));
SetupPhyMacLowListener(phy);
}
void
MacLow::SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> manager)
@@ -488,6 +523,22 @@ MacLow::ReceiveError (Ptr<const Packet> packet, double rxSnr)
return;
}
void
MacLow::NotifySwitchingStartNow (Time duration)
{
NS_LOG_DEBUG ("switching channel. Cancelling MAC pending events");
m_stationManager->Reset();
CancelAllEvents();
if (m_navCounterResetCtsMissed.IsRunning ())
{
m_navCounterResetCtsMissed.Cancel();
}
m_lastNavStart = Simulator::Now ();
m_lastNavDuration = Seconds (0);
m_currentPacket = 0;
m_listener = 0;
}
void
MacLow::ReceiveOk (Ptr<Packet> packet, double rxSnr, WifiMode txMode, WifiPreamble preamble)
{

View File

@@ -356,6 +356,14 @@ public:
* the MAC layer that a packet was unsuccessfully received.
*/
void ReceiveError (Ptr<const Packet> packet, double rxSnr);
/**
* \param duration switching delay duration.
*
* This method is typically invoked by the PhyMacLowListener to notify
* the MAC layer that a channel switching occured. When a channel switching
* occurs, pending MAC transmissions (RTS, CTS, DATA and ACK) are cancelled.
*/
void NotifySwitchingStartNow (Time duration);
private:
void CancelAllEvents (void);
uint32_t GetAckSize (void) const;
@@ -402,6 +410,8 @@ private:
void StartDataTxTimers (void);
virtual void DoDispose (void);
void SetupPhyMacLowListener (Ptr<WifiPhy> phy);
Ptr<WifiPhy> m_phy;
Ptr<WifiRemoteStationManager> m_stationManager;
MacLowRxCallback m_rxCallback;
@@ -434,6 +444,9 @@ private:
Time m_lastNavStart;
Time m_lastNavDuration;
// Listerner needed to monitor when a channel switching occurs.
class PhyMacLowListener *m_phyMacLowListener;
};
} // namespace ns3

View File

@@ -54,9 +54,11 @@ WifiPhyStateHelper::WifiPhyStateHelper ()
m_endTx (Seconds (0)),
m_endSync (Seconds (0)),
m_endCcaBusy (Seconds (0)),
m_endSwitching (Seconds (0)),
m_startTx (Seconds (0)),
m_startSync (Seconds (0)),
m_startCcaBusy (Seconds (0)),
m_startSwitching (Seconds (0)),
m_previousStateChangeTime (Seconds (0))
{
NS_LOG_FUNCTION (this);
@@ -104,6 +106,11 @@ WifiPhyStateHelper::IsStateTx (void)
{
return (GetState () == WifiPhy::TX)?true:false;
}
bool
WifiPhyStateHelper::IsStateSwitching (void)
{
return (GetState () == WifiPhy::SWITCHING)?true:false;
}
@@ -128,6 +135,9 @@ WifiPhyStateHelper::GetDelayUntilIdle (void)
case WifiPhy::CCA_BUSY:
retval = m_endCcaBusy - Simulator::Now ();
break;
case WifiPhy::SWITCHING:
retval = m_endSwitching - Simulator::Now ();
break;
case WifiPhy::IDLE:
retval = Seconds (0);
break;
@@ -163,6 +173,9 @@ WifiPhyStateHelper::StateToString (enum WifiPhy::State state)
case WifiPhy::SYNC:
return "SYNC";
break;
case WifiPhy::SWITCHING:
return "SWITCHING";
break;
default:
NS_ASSERT (false);
// quiet compiler
@@ -182,6 +195,10 @@ WifiPhyStateHelper::GetState (void)
{
return WifiPhy::SYNC;
}
else if (m_endSwitching > Simulator::Now ())
{
return WifiPhy::SWITCHING;
}
else if (m_endCcaBusy > Simulator::Now ())
{
return WifiPhy::CCA_BUSY;
@@ -228,6 +245,13 @@ WifiPhyStateHelper::NotifyMaybeCcaBusyStart (Time duration)
(*i)->NotifyMaybeCcaBusyStart (duration);
}
}
void
WifiPhyStateHelper::NotifySwitchingStart (Time duration)
{
for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++) {
(*i)->NotifySwitchingStart (duration);
}
}
void
WifiPhyStateHelper::LogPreviousIdleAndCcaBusyStates (void)
@@ -235,11 +259,14 @@ WifiPhyStateHelper::LogPreviousIdleAndCcaBusyStates (void)
Time now = Simulator::Now ();
Time idleStart = Max (m_endCcaBusy, m_endSync);
idleStart = Max (idleStart, m_endTx);
idleStart = Max (idleStart, m_endSwitching);
NS_ASSERT (idleStart <= now);
if (m_endCcaBusy > m_endSync &&
m_endCcaBusy > m_endSwitching &&
m_endCcaBusy > m_endTx) {
Time ccaBusyStart = Max (m_endTx, m_endSync);
ccaBusyStart = Max (ccaBusyStart, m_startCcaBusy);
ccaBusyStart = Max (ccaBusyStart, m_endSwitching);
m_stateLogger (ccaBusyStart, idleStart - ccaBusyStart, WifiPhy::CCA_BUSY);
}
m_stateLogger (idleStart, now - idleStart, WifiPhy::IDLE);
@@ -264,11 +291,13 @@ WifiPhyStateHelper::SwitchToTx (Time txDuration, Ptr<const Packet> packet, WifiM
case WifiPhy::CCA_BUSY: {
Time ccaStart = Max (m_endSync, m_endTx);
ccaStart = Max (ccaStart, m_startCcaBusy);
ccaStart = Max (ccaStart, m_endSwitching);
m_stateLogger (ccaStart, now - ccaStart, WifiPhy::CCA_BUSY);
} break;
case WifiPhy::IDLE:
LogPreviousIdleAndCcaBusyStates ();
break;
case WifiPhy::SWITCHING:
default:
NS_ASSERT (false);
break;
@@ -292,8 +321,10 @@ WifiPhyStateHelper::SwitchToSync (Time rxDuration)
case WifiPhy::CCA_BUSY: {
Time ccaStart = Max (m_endSync, m_endTx);
ccaStart = Max (ccaStart, m_startCcaBusy);
ccaStart = Max (ccaStart, m_endSwitching);
m_stateLogger (ccaStart, now - ccaStart, WifiPhy::CCA_BUSY);
} break;
case WifiPhy::SWITCHING:
case WifiPhy::SYNC:
case WifiPhy::TX:
NS_ASSERT (false);
@@ -305,6 +336,49 @@ WifiPhyStateHelper::SwitchToSync (Time rxDuration)
m_endSync = now + rxDuration;
NS_ASSERT (IsStateSync ());
}
void
WifiPhyStateHelper::SwitchToChannelSwitching (Time switchingDuration)
{
NotifySwitchingStart (switchingDuration);
Time now = Simulator::Now ();
switch (GetState ()) {
case WifiPhy::SYNC:
/* The packet which is being received as well
* as its endSync event are cancelled by the caller.
*/
m_syncing = false;
m_stateLogger (m_startSync, now - m_startSync, WifiPhy::SYNC);
m_endSync = now;
break;
case WifiPhy::CCA_BUSY: {
Time ccaStart = Max (m_endSync, m_endTx);
ccaStart = Max (ccaStart, m_startCcaBusy);
ccaStart = Max (ccaStart, m_endSwitching);
m_stateLogger (ccaStart, now - ccaStart, WifiPhy::CCA_BUSY);
} break;
case WifiPhy::IDLE:
LogPreviousIdleAndCcaBusyStates ();
break;
case WifiPhy::TX:
case WifiPhy::SWITCHING:
default:
NS_ASSERT (false);
break;
}
if (now < m_endCcaBusy)
{
m_endCcaBusy = now;
}
m_stateLogger (now, switchingDuration, WifiPhy::SWITCHING);
m_previousStateChangeTime = now;
m_startSwitching = now;
m_endSwitching = now + switchingDuration;
NS_ASSERT (IsStateSwitching ());
}
void
WifiPhyStateHelper::SwitchFromSyncEndOk (Ptr<Packet> packet, double snr, WifiMode mode, enum WifiPreamble preamble)
{
@@ -348,6 +422,8 @@ WifiPhyStateHelper::SwitchMaybeToCcaBusy (Time duration)
NotifyMaybeCcaBusyStart (duration);
Time now = Simulator::Now ();
switch (GetState ()) {
case WifiPhy::SWITCHING:
break;
case WifiPhy::IDLE:
LogPreviousIdleAndCcaBusyStates ();
break;

View File

@@ -43,12 +43,14 @@ public:
bool IsStateBusy (void);
bool IsStateSync (void);
bool IsStateTx (void);
bool IsStateSwitching (void);
Time GetStateDuration (void);
Time GetDelayUntilIdle (void);
Time GetLastRxStartTime (void) const;
void SwitchToTx (Time txDuration, Ptr<const Packet> packet, WifiMode txMode, WifiPreamble preamble, uint8_t txPower);
void SwitchToSync (Time syncDuration);
void SwitchToChannelSwitching (Time switchingDuration);
void SwitchFromSyncEndOk (Ptr<Packet> packet, double snr, WifiMode mode, enum WifiPreamble preamble);
void SwitchFromSyncEndError (Ptr<const Packet> packet, double snr);
void SwitchMaybeToCcaBusy (Time duration);
@@ -66,15 +68,18 @@ private:
void NotifySyncEndOk (void);
void NotifySyncEndError (void);
void NotifyMaybeCcaBusyStart (Time duration);
void NotifySwitchingStart (Time duration);
void DoSwitchFromSync (void);
bool m_syncing;
Time m_endTx;
Time m_endSync;
Time m_endCcaBusy;
Time m_endSwitching;
Time m_startTx;
Time m_startSync;
Time m_startCcaBusy;
Time m_startSwitching;
Time m_previousStateChangeTime;
Listeners m_listeners;

View File

@@ -97,6 +97,14 @@ public:
* what duration it reported.
*/
virtual void NotifyMaybeCcaBusyStart (Time duration) = 0;
/**
* \param duration the expected channel switching duration.
*
* We do not send any event to notify the end of
* channel switching. Listeners should assume that the
* channel implicitely reverts to the idle or busy states.
*/
virtual void NotifySwitchingStart (Time duration) = 0;
};
@@ -127,7 +135,11 @@ public:
/**
* The PHY layer is IDLE.
*/
IDLE
IDLE,
/**
* The PHY layer is switching to other channel.
*/
SWITCHING
};
/**
* arg1: packet received successfully

View File

@@ -76,7 +76,9 @@ public:
* \param preamble the preamble associated to the packet
*
* This method should not be invoked by normal users. It is
* currently invoked only from WifiPhy::Send.
* currently invoked only from WifiPhy::Send. YansWifiChannel
* delivers packets only between PHYs with the same m_channelNumber,
* e.g. PHYs that are operating on the same channel.
*/
void Send (Ptr<YansWifiPhy> sender, Ptr<const Packet> packet, double txPowerDbm,
WifiMode wifiMode, WifiPreamble preamble) const;

View File

@@ -302,27 +302,53 @@ YansWifiPhy::SetChannel (Ptr<YansWifiChannel> channel)
{
m_channel = channel;
m_channel->Add (this);
m_channelId = 1; // always start on channel starting frequency (channel 1)
m_channelNumber = 1; // always start on channel starting frequency (channel 1)
}
void
YansWifiPhy::SetChannelNumber (uint16_t nch)
{
// TODO implement channel switching state machine here
DoSetChannelNumber (nch);
}
NS_ASSERT(!IsStateSwitching());
switch (m_state->GetState ()) {
case YansWifiPhy::SYNC:
NS_LOG_DEBUG ("drop packet because of channel switching while reception");
m_endSyncEvent.Cancel();
goto switchChannel;
break;
case YansWifiPhy::TX:
NS_LOG_DEBUG ("channel switching postponed until end of current transmission");
Simulator::Schedule (GetDelayUntilIdle(), &YansWifiPhy::SetChannelNumber, this, nch);
break;
case YansWifiPhy::CCA_BUSY:
case YansWifiPhy::IDLE:
goto switchChannel;
break;
default:
NS_ASSERT (false);
break;
}
void
YansWifiPhy::DoSetChannelNumber (uint16_t nch)
{
NS_LOG_DEBUG("switching channel " << m_channelId << " -> " << nch);
m_channelId = nch;
return;
switchChannel:
NS_LOG_DEBUG("switching channel " << m_channelNumber << " -> " << nch);
m_state->SwitchToChannelSwitching(m_channelSwitchDelay);
m_interference.EraseEvents();
/*
* Needed here to be able to correctly sensed the medium for the first
* time after the switching. The actual switching is not performed until
* after m_channelSwitchDelay. Packets received during the switching
* state are added to the event list and are employed later to figure
* out the state of the medium after the switching.
*/
m_channelNumber = nch;
}
uint16_t
YansWifiPhy::GetChannelNumber() const
{
return m_channelId;
return m_channelNumber;
}
double
@@ -361,6 +387,24 @@ YansWifiPhy::StartReceivePacket (Ptr<Packet> packet,
rxPowerW);
switch (m_state->GetState ()) {
case YansWifiPhy::SWITCHING:
NS_LOG_DEBUG ("drop packet because of channel switching");
NotifyRxDrop (packet);
/*
* Packets received on the upcoming channel are added to the event list
* during the switching state. This way the medium can be correctly sensed
* when the device listens to the channel for the first time after the
* switching e.g. after channel switching, the channel may be sensed as
* busy due to other devices' tramissions started before the end of
* the switching.
*/
if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ())
{
// that packet will be noise _after_ the completion of the
// channel switching.
goto maybeCcaBusy;
}
break;
case YansWifiPhy::SYNC:
NS_LOG_DEBUG ("drop packet because already in Sync (power="<<
rxPowerW<<"W)");
@@ -431,7 +475,7 @@ YansWifiPhy::SendPacket (Ptr<const Packet> packet, WifiMode txMode, WifiPreamble
* prevent it.
* - we are idle
*/
NS_ASSERT (!m_state->IsStateTx ());
NS_ASSERT (!m_state->IsStateTx () && !m_state->IsStateSwitching ());
Time txDuration = CalculateTxDuration (packet->GetSize (), txMode, preamble);
if (m_state->IsStateSync ())
@@ -563,6 +607,11 @@ YansWifiPhy::IsStateTx (void)
{
return m_state->IsStateTx ();
}
bool
YansWifiPhy::IsStateSwitching (void)
{
return m_state->IsStateSwitching ();
}
Time
YansWifiPhy::GetStateDuration (void)

View File

@@ -77,6 +77,13 @@ public:
*
* where Starting channel frequency is standard-dependent, see SetStandard()
* as defined in IEEE 802.11-2007 17.3.8.3.2.
*
* YansWifiPhy can switch among different channels. Basically, YansWifiPhy
* has a private attribute m_channelNumber that identifies the channel the
* PHY operates on. Channel switching cannot interrupt an ongoing transmission.
* When PHY is in TX state, the channel switching is postponed until the end
* of the current transmission. When the PHY is in SYNC state, the channel
* switching causes the drop of the sync packet.
*/
void SetChannelNumber (uint16_t id);
/// Return current channel number, see SetChannelNumber()
@@ -124,6 +131,7 @@ public:
virtual bool IsStateBusy (void);
virtual bool IsStateSync (void);
virtual bool IsStateTx (void);
virtual bool IsStateSwitching (void);
virtual Time GetStateDuration (void);
virtual Time GetDelayUntilIdle (void);
virtual Time GetLastRxStartTime (void) const;
@@ -152,7 +160,6 @@ private:
double RatioToDb (double ratio) const;
double GetPowerDbm (uint8_t power) const;
void EndSync (Ptr<Packet> packet, Ptr<InterferenceHelper::Event> event);
void DoSetChannelNumber(uint16_t id);
private:
double m_edThresholdW;
@@ -164,7 +171,7 @@ private:
uint32_t m_nTxPower;
Ptr<YansWifiChannel> m_channel;
uint16_t m_channelId;
uint16_t m_channelNumber;
Ptr<Object> m_device;
Ptr<Object> m_mobility;
Modes m_modes;

View File

@@ -69,6 +69,10 @@ TypeId Icmpv6L4Protocol::GetTypeId ()
static TypeId tid = TypeId ("ns3::Icmpv6L4Protocol")
.SetParent<Ipv6L4Protocol> ()
.AddConstructor<Icmpv6L4Protocol> ()
.AddAttribute ("DAD", "Always do DAD check.",
BooleanValue (true),
MakeBooleanAccessor (&Icmpv6L4Protocol::m_alwaysDad),
MakeBooleanChecker ())
;
return tid;
}
@@ -144,14 +148,24 @@ int Icmpv6L4Protocol::GetVersion () const
return 1;
}
bool Icmpv6L4Protocol::IsAlwaysDad () const
{
return m_alwaysDad;
}
void Icmpv6L4Protocol::DoDAD (Ipv6Address target, Ptr<Ipv6Interface> interface)
{
NS_LOG_FUNCTION (this << target << interface);
Ipv6Address addr;
Ptr<Ipv6L3Protocol> ipv6 = m_node->GetObject<Ipv6L3Protocol> ();
NS_ASSERT (ipv6);
if(!m_alwaysDad)
{
return;
}
/* TODO : disable multicast loopback to prevent NS probing to be received by the sender */
Ptr<Packet> p = ForgeNS ("::" ,Ipv6Address::MakeSolicitedAddress (target), target, interface->GetDevice ()->GetAddress ());

View File

@@ -28,6 +28,7 @@
#include "ns3/ptr.h"
#include "ns3/socket.h"
#include "ns3/buffer.h"
#include "ns3/boolean.h"
#include "icmpv6-header.h"
#include "ipv6-l4-protocol.h"
#include "ndisc-cache.h"
@@ -387,6 +388,12 @@ class Icmpv6L4Protocol : public Ipv6L4Protocol
*/
Ptr<NdiscCache> CreateCache (Ptr<NetDevice> device, Ptr<Ipv6Interface> interface);
/**
* \brief Is the node must do DAD.
* \return true if node has to do DAD.
*/
bool IsAlwaysDad () const;
protected:
/**
* \brief Dispose this object.
@@ -407,6 +414,11 @@ class Icmpv6L4Protocol : public Ipv6L4Protocol
*/
CacheList m_cacheList;
/**
* \brief Always do DAD ?
*/
bool m_alwaysDad;
/**
* \brief Receive Neighbor Solicitation method.
* \param p the packet

View File

@@ -196,7 +196,7 @@ bool Ipv6Interface::AddAddress (Ipv6InterfaceAddress iface)
/* DAD handling */
Ptr<Icmpv6L4Protocol> icmpv6 = m_node->GetObject<Ipv6L3Protocol> ()->GetIcmpv6 ();
if (icmpv6)
if (icmpv6 && icmpv6->IsAlwaysDad ())
{
Simulator::Schedule (Seconds (0.), &Icmpv6L4Protocol::DoDAD, icmpv6, addr, this);
Simulator::Schedule (Seconds (1.), &Icmpv6L4Protocol::FunctionDadTimeout, icmpv6, this, addr);

View File

@@ -78,6 +78,7 @@ bool Ipv6L3ProtocolTest::RunTests ()
uint32_t index = 0;
/* init */
icmpv6->SetAttribute ("DAD", BooleanValue (false));
node->AggregateObject (ipv6);
node->AggregateObject (icmpv6);
ipv6->Insert (icmpv6);