wifi: (fixes #2399) Improve scanning procedure of StaWifiMac
This commit is contained in:
@@ -485,25 +485,27 @@ Infrastructure association
|
||||
Association in infrastructure (IBSS) mode is a high-level MAC function.
|
||||
Either active probing or passive scanning is used (default is passive scan).
|
||||
At the start of the simulation, Wi-Fi network devices configured as
|
||||
STA will listen for beacons on the same SSID and will attempt to associate
|
||||
with the AP that generates the first received beacon that is considered
|
||||
to be good. If active probing is enabled, STA will regularly send probe
|
||||
request until it receive probe response and will similarly attempt to
|
||||
associate with the AP that generates the first received probe response.
|
||||
STA will attempt to scan the channel. Depends on whether passive or active
|
||||
scanning is selected, STA will attempt to gather beacons, or send a probe
|
||||
request and gather probe responses until the respective timeout occurs. The
|
||||
end result will be a list of candidate AP to associate to. STA will then try
|
||||
to associate to the best AP (i.e., best SNR).
|
||||
|
||||
If association is rejected by the AP for some reason, the STA will
|
||||
move to a 'REFUSED' state and the simulation user will need to force a
|
||||
reassociation retry in some way, perhaps by changing configuration
|
||||
(i.e. the STA will not persistently try to associate upon a refusal).
|
||||
If association is rejected by the AP for some reason, the STA will try to
|
||||
associate to the next best AP until the candidate list is exhausted which
|
||||
then sends STA to 'REFUSED' state. If this occurs, the simulation user will
|
||||
need to force reassociation retry in some way, perhaps by changing
|
||||
configuration (i.e. the STA will not persistently try to associate upon a
|
||||
refusal).
|
||||
|
||||
When associated, if the configuration is changed by the simulation user,
|
||||
the STA will try to reassociate with the existing AP.
|
||||
|
||||
If a number of missed beacons exceeds a threshold, the STA will notify
|
||||
the rest of the device that the link is down (association is lost). If
|
||||
configured for passive scanning, the STA will try to associate again with
|
||||
the first good beacon heard. If in active probing, the STA will initiate
|
||||
a new probe request.
|
||||
If the number of missed beacons exceeds the threshold, the STA will notify
|
||||
the rest of the device that the link is down (association is lost) and
|
||||
restart the scanning process. Note that this can also happen when an
|
||||
association request fails without explicit refusal (i.e., the AP fails to
|
||||
respond to association request).
|
||||
|
||||
Roaming
|
||||
#######
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "wifi-phy.h"
|
||||
#include "mac-low.h"
|
||||
#include "mgt-headers.h"
|
||||
#include "snr-tag.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -41,10 +42,14 @@ StaWifiMac::GetTypeId (void)
|
||||
.SetParent<InfrastructureWifiMac> ()
|
||||
.SetGroupName ("Wifi")
|
||||
.AddConstructor<StaWifiMac> ()
|
||||
.AddAttribute ("ProbeRequestTimeout", "The interval between two consecutive probe request attempts.",
|
||||
.AddAttribute ("ProbeRequestTimeout", "The duration to actively probe the channel.",
|
||||
TimeValue (Seconds (0.05)),
|
||||
MakeTimeAccessor (&StaWifiMac::m_probeRequestTimeout),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("WaitBeaconTimeout", "The duration to dwell on a channel while passively scanning for beacon",
|
||||
TimeValue (MilliSeconds (120)),
|
||||
MakeTimeAccessor (&StaWifiMac::m_waitBeaconTimeout),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("AssocRequestTimeout", "The interval between two consecutive association request attempts.",
|
||||
TimeValue (Seconds (0.5)),
|
||||
MakeTimeAccessor (&StaWifiMac::m_assocRequestTimeout),
|
||||
@@ -75,7 +80,8 @@ StaWifiMac::GetTypeId (void)
|
||||
}
|
||||
|
||||
StaWifiMac::StaWifiMac ()
|
||||
: m_state (BEACON_MISSED),
|
||||
: m_state (UNASSOCIATED),
|
||||
m_waitBeaconEvent (),
|
||||
m_probeRequestEvent (),
|
||||
m_assocRequestEvent (),
|
||||
m_beaconWatchdogEnd (Seconds (0))
|
||||
@@ -87,6 +93,13 @@ StaWifiMac::StaWifiMac ()
|
||||
SetTypeOfStation (STA);
|
||||
}
|
||||
|
||||
void
|
||||
StaWifiMac::DoInitialize (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
StartScanning ();
|
||||
}
|
||||
|
||||
StaWifiMac::~StaWifiMac ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
@@ -96,15 +109,12 @@ void
|
||||
StaWifiMac::SetActiveProbing (bool enable)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << enable);
|
||||
if (enable)
|
||||
{
|
||||
Simulator::ScheduleNow (&StaWifiMac::TryToEnsureAssociated, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_probeRequestEvent.Cancel ();
|
||||
}
|
||||
m_activeProbing = enable;
|
||||
if (m_state == WAIT_PROBE_RESP || m_state == WAIT_BEACON)
|
||||
{
|
||||
NS_LOG_DEBUG ("STA is still scanning, reset scanning process");
|
||||
StartScanning ();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -165,13 +175,6 @@ StaWifiMac::SendProbeRequest (void)
|
||||
//use the non-QoS for these regardless of whether we have a QoS
|
||||
//association or not.
|
||||
m_txop->Queue (packet, hdr);
|
||||
|
||||
if (m_probeRequestEvent.IsRunning ())
|
||||
{
|
||||
m_probeRequestEvent.Cancel ();
|
||||
}
|
||||
m_probeRequestEvent = Simulator::Schedule (m_probeRequestTimeout,
|
||||
&StaWifiMac::ProbeRequestTimeout, this);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -271,17 +274,18 @@ StaWifiMac::TryToEnsureAssociated (void)
|
||||
or until we get a probe response
|
||||
*/
|
||||
break;
|
||||
case BEACON_MISSED:
|
||||
case WAIT_BEACON:
|
||||
/* we have initiated passive scanning, continue to wait
|
||||
and gather beacons
|
||||
*/
|
||||
break;
|
||||
case UNASSOCIATED:
|
||||
/* we were associated but we missed a bunch of beacons
|
||||
* so we should assume we are not associated anymore.
|
||||
* We try to initiate a probe request now.
|
||||
* We try to initiate a scan now.
|
||||
*/
|
||||
m_linkDown ();
|
||||
if (GetActiveProbing ())
|
||||
{
|
||||
SetState (WAIT_PROBE_RESP);
|
||||
SendProbeRequest ();
|
||||
}
|
||||
StartScanning ();
|
||||
break;
|
||||
case WAIT_ASSOC_RESP:
|
||||
/* we have sent an association request so we do not need to
|
||||
@@ -299,6 +303,69 @@ StaWifiMac::TryToEnsureAssociated (void)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StaWifiMac::StartScanning (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_candidateAps.clear ();
|
||||
if (m_probeRequestEvent.IsRunning ())
|
||||
{
|
||||
m_probeRequestEvent.Cancel ();
|
||||
}
|
||||
if (m_waitBeaconEvent.IsRunning ())
|
||||
{
|
||||
m_waitBeaconEvent.Cancel ();
|
||||
}
|
||||
if (GetActiveProbing ())
|
||||
{
|
||||
SetState (WAIT_PROBE_RESP);
|
||||
SendProbeRequest ();
|
||||
m_probeRequestEvent = Simulator::Schedule (m_probeRequestTimeout,
|
||||
&StaWifiMac::ScanningTimeout,
|
||||
this);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetState (WAIT_BEACON);
|
||||
m_waitBeaconEvent = Simulator::Schedule (m_waitBeaconTimeout,
|
||||
&StaWifiMac::ScanningTimeout,
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StaWifiMac::ScanningTimeout (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
if (!m_candidateAps.empty ())
|
||||
{
|
||||
ApInfo bestAp = m_candidateAps.front();
|
||||
m_candidateAps.erase(m_candidateAps.begin ());
|
||||
NS_LOG_DEBUG ("Attempting to associate with BSSID " << bestAp.m_bssid);
|
||||
Time beaconInterval;
|
||||
if (bestAp.m_activeProbing)
|
||||
{
|
||||
UpdateApInfoFromProbeResp (bestAp.m_probeResp, bestAp.m_apAddr, bestAp.m_bssid);
|
||||
beaconInterval = MicroSeconds (bestAp.m_probeResp.GetBeaconIntervalUs ());
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateApInfoFromBeacon (bestAp.m_beacon, bestAp.m_apAddr, bestAp.m_bssid);
|
||||
beaconInterval = MicroSeconds (bestAp.m_beacon.GetBeaconIntervalUs ());
|
||||
}
|
||||
|
||||
Time delay = beaconInterval * m_maxMissedBeacons;
|
||||
RestartBeaconWatchdog (delay);
|
||||
SetState (WAIT_ASSOC_RESP);
|
||||
SendAssociationRequest (false);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_DEBUG ("Exhausted list of candidate AP; restart scanning");
|
||||
StartScanning ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StaWifiMac::AssocRequestTimeout (void)
|
||||
{
|
||||
@@ -307,14 +374,6 @@ StaWifiMac::AssocRequestTimeout (void)
|
||||
SendAssociationRequest (false);
|
||||
}
|
||||
|
||||
void
|
||||
StaWifiMac::ProbeRequestTimeout (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
SetState (WAIT_PROBE_RESP);
|
||||
SendProbeRequest ();
|
||||
}
|
||||
|
||||
void
|
||||
StaWifiMac::MissedBeacons (void)
|
||||
{
|
||||
@@ -330,7 +389,7 @@ StaWifiMac::MissedBeacons (void)
|
||||
return;
|
||||
}
|
||||
NS_LOG_DEBUG ("beacon missed");
|
||||
SetState (BEACON_MISSED);
|
||||
SetState (UNASSOCIATED);
|
||||
TryToEnsureAssociated ();
|
||||
}
|
||||
|
||||
@@ -545,17 +604,25 @@ StaWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
|
||||
NS_LOG_LOGIC ("Beacon is not for us");
|
||||
goodBeacon = false;
|
||||
}
|
||||
if (goodBeacon)
|
||||
if (goodBeacon && m_state == ASSOCIATED)
|
||||
{
|
||||
Time delay = MicroSeconds (beacon.GetBeaconIntervalUs () * m_maxMissedBeacons);
|
||||
RestartBeaconWatchdog (delay);
|
||||
UpdateApInfoFromBeacon (beacon, hdr->GetAddr2 (), hdr->GetAddr3 ());
|
||||
}
|
||||
if (goodBeacon && m_state == BEACON_MISSED)
|
||||
if (goodBeacon && m_state == WAIT_BEACON)
|
||||
{
|
||||
SetState (WAIT_ASSOC_RESP);
|
||||
NS_LOG_DEBUG ("Good beacon received: send association request");
|
||||
SendAssociationRequest (false);
|
||||
NS_LOG_DEBUG ("Beacon received while scanning from " << hdr->GetAddr2 ());
|
||||
SnrTag snrTag;
|
||||
bool removed = packet->RemovePacketTag (snrTag);
|
||||
NS_ASSERT (removed);
|
||||
ApInfo apInfo;
|
||||
apInfo.m_apAddr = hdr->GetAddr2 ();
|
||||
apInfo.m_bssid = hdr->GetAddr3 ();
|
||||
apInfo.m_activeProbing = false;
|
||||
apInfo.m_snr = snrTag.Get ();
|
||||
apInfo.m_beacon = beacon;
|
||||
UpdateCandidateApList (apInfo);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -563,7 +630,7 @@ StaWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
|
||||
{
|
||||
if (m_state == WAIT_PROBE_RESP)
|
||||
{
|
||||
NS_LOG_DEBUG ("Probe response received");
|
||||
NS_LOG_DEBUG ("Probe response received while scanning from " << hdr->GetAddr2 ());
|
||||
MgtProbeResponseHeader probeResp;
|
||||
packet->RemoveHeader (probeResp);
|
||||
if (!probeResp.GetSsid ().IsEqual (GetSsid ()))
|
||||
@@ -571,15 +638,16 @@ StaWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
|
||||
NS_LOG_DEBUG ("Probe response is not for our SSID");
|
||||
return;
|
||||
}
|
||||
UpdateApInfoFromProbeResp (probeResp, hdr->GetAddr2 (), hdr->GetAddr3 ());
|
||||
Time delay = MicroSeconds (probeResp.GetBeaconIntervalUs () * m_maxMissedBeacons);
|
||||
RestartBeaconWatchdog (delay);
|
||||
if (m_probeRequestEvent.IsRunning ())
|
||||
{
|
||||
m_probeRequestEvent.Cancel ();
|
||||
}
|
||||
SetState (WAIT_ASSOC_RESP);
|
||||
SendAssociationRequest (false);
|
||||
SnrTag snrTag;
|
||||
bool removed = packet->RemovePacketTag (snrTag);
|
||||
NS_ASSERT (removed);
|
||||
ApInfo apInfo;
|
||||
apInfo.m_apAddr = hdr->GetAddr2 ();
|
||||
apInfo.m_bssid = hdr->GetAddr3 ();
|
||||
apInfo.m_activeProbing = true;
|
||||
apInfo.m_snr = snrTag.Get ();
|
||||
apInfo.m_probeResp = probeResp;
|
||||
UpdateCandidateApList (apInfo);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -613,7 +681,14 @@ StaWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
|
||||
else
|
||||
{
|
||||
NS_LOG_DEBUG ("association refused");
|
||||
SetState (REFUSED);
|
||||
if (m_candidateAps.empty ())
|
||||
{
|
||||
SetState (REFUSED);
|
||||
}
|
||||
else
|
||||
{
|
||||
ScanningTimeout ();
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -625,6 +700,32 @@ StaWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
|
||||
RegularWifiMac::Receive (packet, hdr);
|
||||
}
|
||||
|
||||
void
|
||||
StaWifiMac::UpdateCandidateApList (ApInfo newApInfo)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << newApInfo.m_bssid << newApInfo.m_apAddr << newApInfo.m_snr << newApInfo.m_activeProbing << newApInfo.m_beacon << newApInfo.m_probeResp);
|
||||
// Remove duplicate ApInfo entry
|
||||
for (std::vector<ApInfo>::iterator i = m_candidateAps.begin(); i != m_candidateAps.end(); ++i)
|
||||
{
|
||||
if (newApInfo.m_bssid == (*i).m_bssid)
|
||||
{
|
||||
m_candidateAps.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Insert before the entry with lower SNR
|
||||
for (std::vector<ApInfo>::iterator i = m_candidateAps.begin(); i != m_candidateAps.end(); ++i)
|
||||
{
|
||||
if (newApInfo.m_snr > (*i).m_snr)
|
||||
{
|
||||
m_candidateAps.insert (i, newApInfo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// If new ApInfo is the lowest, insert at back
|
||||
m_candidateAps.push_back(newApInfo);
|
||||
}
|
||||
|
||||
void
|
||||
StaWifiMac::UpdateApInfoFromBeacon (MgtBeaconHeader beacon, Mac48Address apAddr, Mac48Address bssid)
|
||||
{
|
||||
|
||||
@@ -24,16 +24,29 @@
|
||||
#define STA_WIFI_MAC_H
|
||||
|
||||
#include "infrastructure-wifi-mac.h"
|
||||
#include "mgt-headers.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class MgtAddBaRequestHeader;
|
||||
class MgtBeaconHeader;
|
||||
class MgtProbeResponseHeader;
|
||||
class MgtAssocResponseHeader;
|
||||
class SupportedRates;
|
||||
class CapabilityInformation;
|
||||
|
||||
/**
|
||||
* \ingroup wifi
|
||||
*
|
||||
* Struct to hold information regarding observed AP through
|
||||
* active/passive scanning
|
||||
*/
|
||||
struct ApInfo
|
||||
{
|
||||
Mac48Address m_bssid;
|
||||
Mac48Address m_apAddr;
|
||||
double m_snr;
|
||||
bool m_activeProbing;
|
||||
MgtBeaconHeader m_beacon;
|
||||
MgtProbeResponseHeader m_probeResp;
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup wifi
|
||||
*
|
||||
@@ -41,30 +54,50 @@ class CapabilityInformation;
|
||||
* machine is as follows:
|
||||
*
|
||||
\verbatim
|
||||
--------- -------------- -----------
|
||||
| Start | | Associated | <-------- ------> | Refused |
|
||||
--------- -------------- | / -----------
|
||||
| | | /
|
||||
\ v v /
|
||||
\ ----------------- -----------------------------
|
||||
\-> | Beacon Missed | <--> | Wait Association Response |
|
||||
----------------- -----------------------------
|
||||
\ ^ ^ |
|
||||
\ | | |
|
||||
\ ----------------------- -
|
||||
\-> | Wait Probe Response |
|
||||
-----------------------
|
||||
--------- -------------- -----------
|
||||
| Start | | Associated | <------------------------- ----> | Refused |
|
||||
--------- -------------- | / -----------
|
||||
| | /------------------------------\ | /
|
||||
\ v v | v /
|
||||
\ ---------------- --------------- -----------------------------
|
||||
\-> | Unassociated | --> | Wait Beacon | --> | Wait Association Response |
|
||||
---------------- --------------- -----------------------------
|
||||
\ ^ ^ | ^ ^ |
|
||||
\ | | | | | |
|
||||
\ v - / -
|
||||
\ ----------------------- /
|
||||
\-> | Wait Probe Response | --------/
|
||||
-----------------------
|
||||
^ |
|
||||
| |
|
||||
-
|
||||
\endverbatim
|
||||
*
|
||||
* Notes:
|
||||
* 1. The state 'Start' is not included in #MacState and only used
|
||||
* for illustration purpose.
|
||||
* 2. The transition from Wait Association Response to Beacon Missed
|
||||
* 2. The Unassociated state is a transient state before STA starts the
|
||||
* scanning procedure which moves it into either Wait Beacon or Wait
|
||||
* Probe Response, based on whether passive or active scanning is
|
||||
* selected.
|
||||
* 3. In Wait Beacon and Wait Probe Response, STA is gathering beacon or
|
||||
* probe response packets from APs, resulted in a list of candidate AP.
|
||||
* After the respective timeout, it then tries to associate to the best
|
||||
* AP (i.e., best SNR). STA will switch between the two states and
|
||||
* restart the scanning procedure if SetActiveProbing() called.
|
||||
* 4. In the case when AP responded to STA's association request with a
|
||||
* refusal, STA will try to associate to the next best AP until the list
|
||||
* of candidate AP is exhausted which sends STA to Refused state.
|
||||
* - Note that this behavior is not currently tested since ns-3 does not
|
||||
* implement association refusal at present.
|
||||
* 5. The transition from Wait Association Response to Unassociated
|
||||
* occurs if an association request fails without explicit
|
||||
* refusal (i.e., the AP fails to respond).
|
||||
* 3. The transition from Associated to Wait Association Response
|
||||
* 6. The transition from Associated to Wait Association Response
|
||||
* occurs when STA's PHY capabilities changed. In this state, STA
|
||||
* tries to reassociate with the previously associated AP.
|
||||
* 7. The transition from Associated to Unassociated occurs if the number
|
||||
* of missed beacons exceeds the threshold.
|
||||
*/
|
||||
class StaWifiMac : public InfrastructureWifiMac
|
||||
{
|
||||
@@ -108,9 +141,10 @@ private:
|
||||
enum MacState
|
||||
{
|
||||
ASSOCIATED,
|
||||
WAIT_BEACON,
|
||||
WAIT_PROBE_RESP,
|
||||
WAIT_ASSOC_RESP,
|
||||
BEACON_MISSED,
|
||||
UNASSOCIATED,
|
||||
REFUSED
|
||||
};
|
||||
|
||||
@@ -159,6 +193,13 @@ private:
|
||||
* \param apAddr mac address of the AP
|
||||
*/
|
||||
void UpdateApInfoFromAssocResp (MgtAssocResponseHeader assocResp, Mac48Address apAddr);
|
||||
/**
|
||||
* Update list of candidate AP to associate. The list should contain ApInfo sorted from
|
||||
* best to worst SNR, with no duplicate.
|
||||
*
|
||||
* \param newApInfo the new ApInfo to be inserted
|
||||
*/
|
||||
void UpdateCandidateApList (ApInfo newApInfo);
|
||||
|
||||
/**
|
||||
* Forward a probe request packet to the DCF. The standard is not clear on the correct
|
||||
@@ -189,10 +230,16 @@ private:
|
||||
*/
|
||||
void AssocRequestTimeout (void);
|
||||
/**
|
||||
* This method is called after the probe request timeout occurred. We switch the state to
|
||||
* WAIT_PROBE_RESP and re-send a probe request.
|
||||
* Start the scanning process which trigger active or passive scanning based on the
|
||||
* active probing flag.
|
||||
*/
|
||||
void ProbeRequestTimeout (void);
|
||||
void StartScanning (void);
|
||||
/**
|
||||
* This method is called after wait beacon timeout or wait probe request timeout has
|
||||
* occured. This will trigger association process from beacons or probe responses
|
||||
* gathered while scanning.
|
||||
*/
|
||||
void ScanningTimeout (void);
|
||||
/**
|
||||
* Return whether we are associated with an AP.
|
||||
*
|
||||
@@ -250,15 +297,24 @@ private:
|
||||
*/
|
||||
void PhyCapabilitiesChanged (void);
|
||||
|
||||
void DoInitialize (void);
|
||||
|
||||
MacState m_state; ///< MAC state
|
||||
Time m_waitBeaconTimeout; ///< wait beacon timeout
|
||||
Time m_probeRequestTimeout; ///< probe request timeout
|
||||
Time m_assocRequestTimeout; ///< assoc request timeout
|
||||
EventId m_waitBeaconEvent; ///< wait beacon event
|
||||
EventId m_probeRequestEvent; ///< probe request event
|
||||
EventId m_assocRequestEvent; ///< assoc request event
|
||||
EventId m_beaconWatchdog; ///< beacon watchdog
|
||||
Time m_beaconWatchdogEnd; ///< beacon watchdog end
|
||||
uint32_t m_maxMissedBeacons; ///< maximum missed beacons
|
||||
bool m_activeProbing; ///< active probing
|
||||
std::vector<ApInfo> m_candidateAps; ///< list of candidate APs to associate
|
||||
// Note: std::multiset<ApInfo> might be a candidate container to implement
|
||||
// this sorted list, but we are using a std::vector because we want to sort
|
||||
// based on SNR but find duplicates based on BSSID, and in practice this
|
||||
// candidate vector should not be too large.
|
||||
|
||||
TracedCallback<Mac48Address> m_assocLogger; ///< assoc logger
|
||||
TracedCallback<Mac48Address> m_deAssocLogger; ///< deassoc logger
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "ns3/mobility-helper.h"
|
||||
#include "ns3/wifi-net-device.h"
|
||||
#include "ns3/adhoc-wifi-mac.h"
|
||||
#include "ns3/ap-wifi-mac.h"
|
||||
#include "ns3/propagation-loss-model.h"
|
||||
#include "ns3/yans-error-rate-model.h"
|
||||
#include "ns3/constant-position-mobility-model.h"
|
||||
@@ -1512,6 +1513,182 @@ Bug2831TestCase::DoRun (void)
|
||||
NS_TEST_ASSERT_MSG_EQ (m_countOperationalChannelWidth40, 20, "Incorrect operational channel width after channel change");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
* Make sure that Wifi STA is correctly associating to the best AP (i.e.,
|
||||
* nearest from STA). We consider 3 AP and 1 STA. This test case consisted of
|
||||
* three sub tests:
|
||||
* - The best AP sends its beacon later than the other APs. STA is expected
|
||||
* to associate to the best AP.
|
||||
* - The STA is using active scanning instead of passive, the rest of the
|
||||
* APs works normally. STA is expected to associate to the best AP
|
||||
* - The nearest AP is turned off after sending beacon and while STA is
|
||||
* still scanning. STA is expected to associate to the second best AP.
|
||||
*
|
||||
* See \bugid{2399}
|
||||
* \todo Add explicit association refusal test if ns-3 implemented it.
|
||||
*/
|
||||
|
||||
class StaWifiMacScanningTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
StaWifiMacScanningTestCase ();
|
||||
virtual ~StaWifiMacScanningTestCase ();
|
||||
virtual void DoRun (void);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Callback function on STA assoc event
|
||||
* \param context context string
|
||||
* \param bssid the associated AP's bssid
|
||||
*/
|
||||
void AssocCallback (std::string context, Mac48Address bssid);
|
||||
/**
|
||||
* Turn beacon generation on the AP node
|
||||
* \param apNode the AP node
|
||||
*/
|
||||
void TurnBeaconGenerationOn (Ptr<Node> apNode);
|
||||
/**
|
||||
* Turn the AP node off
|
||||
* \param apNode the AP node
|
||||
*/
|
||||
void TurnApOff (Ptr<Node> apNode);
|
||||
/**
|
||||
* Setup test
|
||||
* \param nearestApBeaconGeneration set BeaconGeneration attribute of the nearest AP
|
||||
* \param staActiveProbe set ActiveProbing attribute of the STA
|
||||
* \return node container containing all nodes
|
||||
*/
|
||||
NodeContainer Setup (bool nearestApBeaconGeneration, bool staActiveProbe);
|
||||
|
||||
Mac48Address m_associatedApBssid; ///< Associated AP's bssid
|
||||
};
|
||||
|
||||
StaWifiMacScanningTestCase::StaWifiMacScanningTestCase ()
|
||||
: TestCase ("Test case for StaWifiMac scanning capability")
|
||||
{
|
||||
}
|
||||
|
||||
StaWifiMacScanningTestCase::~StaWifiMacScanningTestCase ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
StaWifiMacScanningTestCase::AssocCallback (std::string context, Mac48Address bssid)
|
||||
{
|
||||
m_associatedApBssid = bssid;
|
||||
}
|
||||
|
||||
void
|
||||
StaWifiMacScanningTestCase::TurnBeaconGenerationOn (Ptr<Node> apNode)
|
||||
{
|
||||
Ptr<WifiNetDevice> netDevice = DynamicCast<WifiNetDevice> (apNode->GetDevice (0));
|
||||
Ptr<ApWifiMac> mac = DynamicCast<ApWifiMac> (netDevice->GetMac ());
|
||||
mac->SetAttribute ("BeaconGeneration", BooleanValue (true));
|
||||
}
|
||||
|
||||
void
|
||||
StaWifiMacScanningTestCase::TurnApOff (Ptr<Node> apNode)
|
||||
{
|
||||
Ptr<WifiNetDevice> netDevice = DynamicCast<WifiNetDevice> (apNode->GetDevice (0));
|
||||
Ptr<WifiPhy> phy = netDevice->GetPhy ();
|
||||
phy->SetOffMode();
|
||||
}
|
||||
|
||||
NodeContainer
|
||||
StaWifiMacScanningTestCase::Setup (bool nearestApBeaconGeneration, bool staActiveProbe)
|
||||
{
|
||||
NodeContainer apNodes;
|
||||
apNodes.Create (2);
|
||||
|
||||
Ptr<Node> apNodeNearest = CreateObject<Node> ();
|
||||
Ptr<Node> staNode = CreateObject<Node> ();
|
||||
|
||||
YansWifiPhyHelper phy = YansWifiPhyHelper::Default ();
|
||||
YansWifiChannelHelper channel = YansWifiChannelHelper::Default ();
|
||||
phy.SetChannel (channel.Create ());
|
||||
|
||||
WifiHelper wifi;
|
||||
wifi.SetStandard (WIFI_PHY_STANDARD_80211n_2_4GHZ);
|
||||
wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager");
|
||||
|
||||
WifiMacHelper mac;
|
||||
NetDeviceContainer apDevice, apDeviceNearest;
|
||||
mac.SetType ("ns3::ApWifiMac",
|
||||
"BeaconGeneration", BooleanValue (true));
|
||||
apDevice = wifi.Install (phy, mac, apNodes);
|
||||
mac.SetType ("ns3::ApWifiMac",
|
||||
"BeaconGeneration", BooleanValue (nearestApBeaconGeneration));
|
||||
apDeviceNearest = wifi.Install (phy, mac, apNodeNearest);
|
||||
|
||||
NetDeviceContainer staDevice;
|
||||
mac.SetType ("ns3::StaWifiMac",
|
||||
"ActiveProbing", BooleanValue (staActiveProbe));
|
||||
staDevice = wifi.Install (phy, mac, staNode);
|
||||
|
||||
MobilityHelper mobility;
|
||||
Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
|
||||
positionAlloc->Add (Vector (0.0, 0.0, 0.0)); // Furthest AP
|
||||
positionAlloc->Add (Vector (10.0, 0.0, 0.0)); // Second nearest AP
|
||||
positionAlloc->Add (Vector (5.0, 5.0, 0.0)); // Nearest AP
|
||||
positionAlloc->Add (Vector (6.0, 5.0, 0.0)); // STA
|
||||
mobility.SetPositionAllocator (positionAlloc);
|
||||
|
||||
mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
|
||||
mobility.Install (apNodes);
|
||||
mobility.Install (apNodeNearest);
|
||||
mobility.Install (staNode);
|
||||
|
||||
Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Mac/$ns3::StaWifiMac/Assoc", MakeCallback (&StaWifiMacScanningTestCase::AssocCallback, this));
|
||||
|
||||
NodeContainer allNodes = NodeContainer (apNodes, apNodeNearest, staNode);
|
||||
return allNodes;
|
||||
}
|
||||
|
||||
void
|
||||
StaWifiMacScanningTestCase::DoRun (void)
|
||||
{
|
||||
{
|
||||
NodeContainer nodes = Setup (false, false);
|
||||
Ptr<Node> nearestAp = nodes.Get (2);
|
||||
Mac48Address nearestApAddr = DynamicCast<WifiNetDevice> (nearestAp->GetDevice (0))->GetMac ()->GetAddress ();
|
||||
|
||||
Simulator::Schedule (Seconds (0.05), &StaWifiMacScanningTestCase::TurnBeaconGenerationOn, this, nearestAp);
|
||||
|
||||
Simulator::Stop (Seconds (0.2));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (m_associatedApBssid, nearestApAddr, "STA is associated to the wrong AP");
|
||||
}
|
||||
m_associatedApBssid = Mac48Address ();
|
||||
{
|
||||
NodeContainer nodes = Setup (true, true);
|
||||
Ptr<Node> nearestAp = nodes.Get (2);
|
||||
Mac48Address nearestApAddr = DynamicCast<WifiNetDevice> (nearestAp->GetDevice (0))->GetMac ()->GetAddress ();
|
||||
|
||||
Simulator::Stop (Seconds (0.2));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (m_associatedApBssid, nearestApAddr, "STA is associated to the wrong AP");
|
||||
}
|
||||
m_associatedApBssid = Mac48Address ();
|
||||
{
|
||||
NodeContainer nodes = Setup (true, false);
|
||||
Ptr<Node> nearestAp = nodes.Get (2);
|
||||
Mac48Address secondNearestApAddr = DynamicCast<WifiNetDevice> (nodes.Get (1)->GetDevice (0))->GetMac ()->GetAddress ();
|
||||
|
||||
Simulator::Schedule (Seconds (0.1), &StaWifiMacScanningTestCase::TurnApOff, this, nearestAp);
|
||||
|
||||
Simulator::Stop (Seconds (1.5));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (m_associatedApBssid, secondNearestApAddr, "STA is associated to the wrong AP");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup wifi-test
|
||||
* \ingroup tests
|
||||
@@ -1536,6 +1713,7 @@ WifiTestSuite::WifiTestSuite ()
|
||||
AddTestCase (new Bug2222TestCase, TestCase::QUICK); //Bug 2222
|
||||
AddTestCase (new Bug2483TestCase, TestCase::QUICK); //Bug 2483
|
||||
AddTestCase (new Bug2831TestCase, TestCase::QUICK); //Bug 2831
|
||||
AddTestCase (new StaWifiMacScanningTestCase, TestCase::QUICK); //Bug 2399
|
||||
}
|
||||
|
||||
static WifiTestSuite g_wifiTestSuite; ///< the test suite
|
||||
|
||||
Reference in New Issue
Block a user