merge
This commit is contained in:
1
AUTHORS
1
AUTHORS
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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
|
||||
-----------------------
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -95,6 +95,7 @@ public:
|
||||
Time duration, double rxPower);
|
||||
|
||||
struct InterferenceHelper::SnrPer CalculateSnrPer (Ptr<InterferenceHelper::Event> event);
|
||||
void EraseEvents (void);
|
||||
private:
|
||||
class NiChange {
|
||||
public:
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user