branch merge
This commit is contained in:
@@ -15,7 +15,7 @@ import Build
|
||||
import Utils
|
||||
|
||||
## https://launchpad.net/pybindgen/
|
||||
REQUIRED_PYBINDGEN_VERSION = (0, 13, 0, 744)
|
||||
REQUIRED_PYBINDGEN_VERSION = (0, 13, 0, 745)
|
||||
REQUIRED_PYGCCXML_VERSION = (0, 9, 5)
|
||||
|
||||
|
||||
|
||||
@@ -496,6 +496,7 @@ WARN_LOGFILE =
|
||||
INPUT = doc/modules \
|
||||
doc/main.h \
|
||||
doc/introspected-doxygen.h \
|
||||
utils \
|
||||
src
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files that
|
||||
|
||||
@@ -60,5 +60,9 @@
|
||||
* @defgroup constants Constants
|
||||
* @brief Constants you can change
|
||||
*
|
||||
* @defgroup utils Utils
|
||||
* @brief The utils directory is for various programs and scripts related
|
||||
* to code coverage, test suites, style checking, and benchmarking.
|
||||
*
|
||||
* @defgroup contrib Contrib
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 MIRKO BANCHI
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mirko Banchi <mk.banchi@gmail.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is a simple example in order to show how 802.11n compressed block ack mechanism could be used.
|
||||
*
|
||||
* Network topology:
|
||||
*
|
||||
* Wifi 192.168.1.0
|
||||
*
|
||||
* AP
|
||||
* * *
|
||||
* | |
|
||||
* n1 n2
|
||||
*
|
||||
* In this example a QoS sta sends UDP datagram packets to access point. On the access point
|
||||
* there is no application installed so it replies to every packet with an ICMP frame. However
|
||||
* our attention is on originator sta n1. We have set blockAckThreshold (mininum number of packets to use
|
||||
* block ack) to 2 so if there are in the BestEffort queue more than 2 packets a block ack will be
|
||||
* negotiated. We also set a timeout for block ack inactivity to 3 blocks of 1024 microseconds. This timer is
|
||||
* reset when:
|
||||
* - the originator receives a block ack frame.
|
||||
* - the recipient receives a block ack request or a MPDU with ack policy Block Ack.
|
||||
*/
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
#include "ns3/global-routing-module.h"
|
||||
#include "ns3/wifi-module.h"
|
||||
#include "ns3/mobility-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("Test-block-ack");
|
||||
|
||||
int main (int argc, char const* argv[])
|
||||
{
|
||||
LogComponentEnable ("EdcaTxopN", LOG_LEVEL_DEBUG);
|
||||
LogComponentEnable ("BlockAckManager", LOG_LEVEL_INFO);
|
||||
|
||||
Ptr<Node> sta = CreateObject<Node> ();
|
||||
Ptr<Node> ap = CreateObject<Node> ();
|
||||
|
||||
YansWifiChannelHelper channel = YansWifiChannelHelper::Default ();
|
||||
YansWifiPhyHelper phy = YansWifiPhyHelper::Default ();
|
||||
phy.SetChannel (channel.Create ());
|
||||
|
||||
WifiHelper wifi = WifiHelper::Default ();
|
||||
QosWifiMacHelper mac = QosWifiMacHelper::Default ();
|
||||
/* disable fragmentation */
|
||||
wifi.SetRemoteStationManager ("ns3::AarfWifiManager", "FragmentationThreshold", UintegerValue (2500));
|
||||
|
||||
Ssid ssid ("My-network");
|
||||
|
||||
mac.SetType ("ns3::QstaWifiMac", "Ssid" , SsidValue (ssid), "ActiveProbing", BooleanValue (false));
|
||||
NetDeviceContainer staDevice = wifi.Install (phy, mac, sta);
|
||||
|
||||
mac.SetType ("ns3::QapWifiMac", "Ssid", SsidValue (ssid), "BeaconGeneration", BooleanValue (true),
|
||||
"BeaconInterval", TimeValue (Seconds (2.5)));
|
||||
NetDeviceContainer apDevice = wifi.Install (phy, mac, ap);
|
||||
|
||||
/* setting blockack threshold for sta's BE queue */
|
||||
Config::Set ("/NodeList/0/DeviceList/0/Mac/BE_EdcaTxopN/BlockAckThreshold", UintegerValue (2));
|
||||
/* setting block inactivity timeout to 3*1024 = 3072 microseconds */
|
||||
//Config::Set ("/NodeList/0/DeviceList/0/Mac/BE_EdcaTxopN/BlockAckInactivityTimeout", UintegerValue (3));
|
||||
|
||||
/* Setting mobility model */
|
||||
MobilityHelper mobility;
|
||||
|
||||
mobility.SetPositionAllocator ("ns3::GridPositionAllocator",
|
||||
"MinX", DoubleValue (0.0),
|
||||
"MinY", DoubleValue (0.0),
|
||||
"DeltaX", DoubleValue (5.0),
|
||||
"DeltaY", DoubleValue (10.0),
|
||||
"GridWidth", UintegerValue (3),
|
||||
"LayoutType", StringValue ("RowFirst"));
|
||||
|
||||
mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel",
|
||||
"Bounds", RectangleValue (Rectangle (-50, 50, -50, 50)));
|
||||
mobility.Install (sta);
|
||||
|
||||
mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
|
||||
mobility.Install (ap);
|
||||
|
||||
/* Internet stack*/
|
||||
InternetStackHelper stack;
|
||||
stack.Install (sta);
|
||||
stack.Install (ap);
|
||||
|
||||
Ipv4AddressHelper address;
|
||||
|
||||
address.SetBase ("192.168.1.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer staIf;
|
||||
Ipv4InterfaceContainer apIf;
|
||||
staIf = address.Assign (staDevice);
|
||||
apIf = address.Assign (apDevice);
|
||||
|
||||
/* Setting applications */
|
||||
|
||||
uint16_t port = 9;
|
||||
|
||||
DataRate dataRate ("1Mb/s");
|
||||
OnOffHelper onOff ("ns3::UdpSocketFactory", Address (InetSocketAddress (apIf.GetAddress (0), port)));
|
||||
onOff.SetAttribute ("DataRate", DataRateValue (dataRate));
|
||||
onOff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (0.01)));
|
||||
onOff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (8)));
|
||||
onOff.SetAttribute ("PacketSize", UintegerValue (50));
|
||||
|
||||
ApplicationContainer staApps = onOff.Install (sta);
|
||||
|
||||
staApps.Start (Seconds (1.0));
|
||||
staApps.Stop (Seconds (10.0));
|
||||
|
||||
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
|
||||
|
||||
Simulator::Stop (Seconds (10.0));
|
||||
|
||||
phy.EnablePcap ("test-blockack-2", ap->GetId (), 0);
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -34,3 +34,6 @@ def build(bld):
|
||||
|
||||
obj = bld.create_ns3_program('wifi-simple-interference', ['core', 'simulator', 'mobility', 'wifi'])
|
||||
obj.source = 'wifi-simple-interference.cc'
|
||||
|
||||
obj = bld.create_ns3_program('wifi-blockack', ['core', 'simulator', 'mobility', 'wifi'])
|
||||
obj.source = 'wifi-blockack.cc'
|
||||
|
||||
@@ -23,6 +23,10 @@ def build(bld):
|
||||
'pcap-file-test-suite.cc',
|
||||
'pcap-file-object.cc',
|
||||
'output-stream-object.cc',
|
||||
'propagation-delay-model.cc',
|
||||
'propagation-loss-model.cc',
|
||||
'propagation-loss-model-test-suite.cc',
|
||||
'jakes-propagation-loss-model.cc',
|
||||
]
|
||||
|
||||
headers = bld.new_task_gen('ns3header')
|
||||
@@ -47,4 +51,7 @@ def build(bld):
|
||||
'pcap-file.h',
|
||||
'pcap-file-object.h',
|
||||
'output-stream-object.h',
|
||||
'propagation-delay-model.h',
|
||||
'propagation-loss-model.h',
|
||||
'jakes-propagation-loss-model.h',
|
||||
]
|
||||
|
||||
+831
-538
File diff suppressed because it is too large
Load Diff
+175
-135
@@ -43,7 +43,6 @@ class RandomVariableBase;
|
||||
class SeedManager
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief set the seed
|
||||
* it will duplicate the seed value 6 times
|
||||
@@ -57,45 +56,45 @@ public:
|
||||
* Note, while the underlying RNG takes six integer values as a seed;
|
||||
* it is sufficient to set these all to the same integer, so we provide
|
||||
* a simpler interface here that just takes one integer.
|
||||
*/
|
||||
*/
|
||||
static void SetSeed (uint32_t seed);
|
||||
|
||||
|
||||
/**
|
||||
* \brief Get the seed value
|
||||
* \return the seed value
|
||||
*
|
||||
* Note: returns the first of the six seed values used in the underlying RNG
|
||||
*/
|
||||
static uint32_t GetSeed ();
|
||||
|
||||
/**
|
||||
* \brief Set the run number of simulation
|
||||
*
|
||||
* \code
|
||||
* SeedManager::SetSeed(12);
|
||||
* int N = atol(argv[1]); //read in run number from command line
|
||||
* SeedManager::SetRun(N);
|
||||
* UniformVariable x(0,10);
|
||||
* ExponentialVariable y(2902);
|
||||
* \endcode
|
||||
* In this example, N could successivly be equal to 1,2,3, etc. and the user
|
||||
* would continue to get independent runs out of the single simulation. For
|
||||
* this simple example, the following might work:
|
||||
* \code
|
||||
* ./simulation 0
|
||||
* ...Results for run 0:...
|
||||
*
|
||||
* ./simulation 1
|
||||
* ...Results for run 1:...
|
||||
* \endcode
|
||||
*/
|
||||
static uint32_t GetSeed ();
|
||||
|
||||
/**
|
||||
* \brief Set the run number of simulation
|
||||
*
|
||||
* \code
|
||||
* SeedManager::SetSeed(12);
|
||||
* int N = atol(argv[1]); //read in run number from command line
|
||||
* SeedManager::SetRun(N);
|
||||
* UniformVariable x(0,10);
|
||||
* ExponentialVariable y(2902);
|
||||
* \endcode
|
||||
* In this example, N could successivly be equal to 1,2,3, etc. and the user
|
||||
* would continue to get independent runs out of the single simulation. For
|
||||
* this simple example, the following might work:
|
||||
* \code
|
||||
* ./simulation 0
|
||||
* ...Results for run 0:...
|
||||
*
|
||||
* ./simulation 1
|
||||
* ...Results for run 1:...
|
||||
* \endcode
|
||||
*/
|
||||
static void SetRun (uint32_t run);
|
||||
/**
|
||||
* \returns the current run number
|
||||
* @sa SetRun
|
||||
*/
|
||||
static uint32_t GetRun (void);
|
||||
|
||||
|
||||
/**
|
||||
* \brief Check if seed value is valid if wanted to be used as seed
|
||||
* \return true if valid and false if invalid
|
||||
@@ -111,7 +110,7 @@ public:
|
||||
* Note: The underlying random number generation method used
|
||||
* by NS-3 is the RngStream code by Pierre L'Ecuyer at
|
||||
* the University of Montreal.
|
||||
*
|
||||
*
|
||||
* NS-3 has a rich set of random number generators.
|
||||
* Class RandomVariable defines the base class functionalty
|
||||
* required for all random number generators. By default, the underlying
|
||||
@@ -119,13 +118,13 @@ public:
|
||||
* coming from the ns3::GlobalValue \ref GlobalValueRngSeed "RngSeed" and \ref GlobalValueRngRun "RngRun".
|
||||
*/
|
||||
class RandomVariable
|
||||
{
|
||||
{
|
||||
public:
|
||||
RandomVariable();
|
||||
RandomVariable(const RandomVariable&o);
|
||||
RandomVariable ();
|
||||
RandomVariable (const RandomVariable&o);
|
||||
RandomVariable &operator = (const RandomVariable &o);
|
||||
~RandomVariable();
|
||||
|
||||
~RandomVariable ();
|
||||
|
||||
/**
|
||||
* \brief Returns a random double from the underlying distribution
|
||||
* \return A floating point random value
|
||||
@@ -139,13 +138,13 @@ public:
|
||||
uint32_t GetInteger (void) const;
|
||||
|
||||
private:
|
||||
friend std::ostream &operator << (std::ostream &os, const RandomVariable &var);
|
||||
friend std::istream &operator >> (std::istream &os, RandomVariable &var);
|
||||
friend std::ostream & operator << (std::ostream &os, const RandomVariable &var);
|
||||
friend std::istream & operator >> (std::istream &os, RandomVariable &var);
|
||||
|
||||
RandomVariableBase *m_variable;
|
||||
protected:
|
||||
RandomVariable (const RandomVariableBase &variable);
|
||||
RandomVariableBase *Peek (void) const;
|
||||
RandomVariableBase * Peek (void) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -153,7 +152,7 @@ protected:
|
||||
* \ingroup randomvariable
|
||||
*
|
||||
* This class supports the creation of objects that return random numbers
|
||||
* from a fixed uniform distribution. It also supports the generation of
|
||||
* from a fixed uniform distribution. It also supports the generation of
|
||||
* single random numbers from various uniform distributions.
|
||||
*
|
||||
* The low end of the range is always included and the high end
|
||||
@@ -164,40 +163,40 @@ protected:
|
||||
* UniformVariable::GetSingleValue(100,1000); //returns a value [100,1000)
|
||||
* \endcode
|
||||
*/
|
||||
class UniformVariable : public RandomVariable
|
||||
class UniformVariable : public RandomVariable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates a uniform random number generator in the
|
||||
* range [0.0 .. 1.0).
|
||||
*/
|
||||
UniformVariable();
|
||||
UniformVariable ();
|
||||
|
||||
/**
|
||||
* Creates a uniform random number generator with the specified range
|
||||
* \param s Low end of the range
|
||||
* \param l High end of the range
|
||||
*/
|
||||
UniformVariable(double s, double l);
|
||||
UniformVariable (double s, double l);
|
||||
|
||||
/**
|
||||
* \brief call RandomVariable::GetValue
|
||||
* \return A floating point random value
|
||||
*
|
||||
* Note: we have to re-implement this method here because the method is
|
||||
* Note: we have to re-implement this method here because the method is
|
||||
* overloaded below for the two-argument variant and the c++ name resolution
|
||||
* rules don't work well with overloads split between parent and child
|
||||
* rules don't work well with overloads split between parent and child
|
||||
* classes.
|
||||
*/
|
||||
double GetValue (void) const;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Returns a random double with the specified range
|
||||
* \param s Low end of the range
|
||||
* \param l High end of the range
|
||||
* \return A floating point random value
|
||||
*/
|
||||
double GetValue(double s, double l);
|
||||
double GetValue (double s, double l);
|
||||
|
||||
/**
|
||||
* \brief Returns a random unsigned integer from the interval [s,l] including both ends.
|
||||
@@ -215,26 +214,27 @@ public:
|
||||
* Class ConstantVariable defines a random number generator that
|
||||
* returns the same value every sample.
|
||||
*/
|
||||
class ConstantVariable : public RandomVariable {
|
||||
class ConstantVariable : public RandomVariable
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a ConstantVariable RNG that returns zero every sample
|
||||
*/
|
||||
ConstantVariable();
|
||||
|
||||
ConstantVariable ();
|
||||
|
||||
/**
|
||||
* Construct a ConstantVariable RNG that returns the specified value
|
||||
* every sample.
|
||||
* \param c Unchanging value for this RNG.
|
||||
*/
|
||||
ConstantVariable(double c);
|
||||
ConstantVariable (double c);
|
||||
|
||||
/**
|
||||
* \brief Specify a new constant RNG for this generator.
|
||||
* \param c New constant value for this RNG.
|
||||
*/
|
||||
void SetConstant(double c);
|
||||
void SetConstant (double c);
|
||||
|
||||
};
|
||||
|
||||
@@ -244,10 +244,10 @@ public:
|
||||
*
|
||||
* Class SequentialVariable defines a random number generator that
|
||||
* returns a sequential sequence. The sequence monotonically
|
||||
* increases for a period, then wraps around to the low value
|
||||
* increases for a period, then wraps around to the low value
|
||||
* and begins monotonicaly increasing again.
|
||||
*/
|
||||
class SequentialVariable : public RandomVariable
|
||||
class SequentialVariable : public RandomVariable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -261,7 +261,7 @@ public:
|
||||
* \param i Increment between sequence values
|
||||
* \param c Number of times each member of the sequence is repeated
|
||||
*/
|
||||
SequentialVariable(double f, double l, double i = 1, uint32_t c = 1);
|
||||
SequentialVariable (double f, double l, double i = 1, uint32_t c = 1);
|
||||
|
||||
/**
|
||||
* \brief Constructor for the SequentialVariable RNG.
|
||||
@@ -273,7 +273,7 @@ public:
|
||||
* \param i Reference to a RandomVariable for the sequence increment
|
||||
* \param c Number of times each member of the sequence is repeated
|
||||
*/
|
||||
SequentialVariable(double f, double l, const RandomVariable& i, uint32_t c = 1);
|
||||
SequentialVariable (double f, double l, const RandomVariable& i, uint32_t c = 1);
|
||||
|
||||
};
|
||||
|
||||
@@ -282,17 +282,18 @@ public:
|
||||
* \ingroup randomvariable
|
||||
*
|
||||
* This class supports the creation of objects that return random numbers
|
||||
* from a fixed exponential distribution. It also supports the generation of
|
||||
* from a fixed exponential distribution. It also supports the generation of
|
||||
* single random numbers from various exponential distributions.
|
||||
*
|
||||
* The probability density function of an exponential variable
|
||||
* The probability density function of an exponential variable
|
||||
* is defined over the interval [0, +inf) as:
|
||||
* \f$ \alpha e^{-\alpha x} \f$
|
||||
* where \f$ \alpha = \frac{1}{mean} \f$
|
||||
* where \f$ \alpha = \frac{1}{mean} \f$
|
||||
*
|
||||
* The bounded version is defined over the interval [0,b] as:
|
||||
* \f$ \alpha e^{-\alpha x} \quad x \in [0,b] \f$.
|
||||
* Note that in this case the true mean is \f$ 1/\alpha - b/(e^{\alpha \, b}-1) \f$
|
||||
*
|
||||
* The bounded version is defined over the internal [0,+inf) as:
|
||||
* \f$ \left\{ \begin{array}{cl} \alpha e^{-\alpha x} & x < bound \\ bound & x > bound \end{array}\right. \f$
|
||||
*
|
||||
* \code
|
||||
* ExponentialVariable x(3.14);
|
||||
* x.GetValue(); //will always return with mean 3.14
|
||||
@@ -301,33 +302,33 @@ public:
|
||||
* \endcode
|
||||
*
|
||||
*/
|
||||
class ExponentialVariable : public RandomVariable
|
||||
{
|
||||
class ExponentialVariable : public RandomVariable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs an exponential random variable with a mean
|
||||
* value of 1.0.
|
||||
*/
|
||||
ExponentialVariable();
|
||||
ExponentialVariable ();
|
||||
|
||||
/**
|
||||
* \brief Constructs an exponential random variable with a specified mean
|
||||
* \param m Mean value for the random variable
|
||||
*/
|
||||
explicit ExponentialVariable(double m);
|
||||
explicit ExponentialVariable (double m);
|
||||
|
||||
/**
|
||||
* \brief Constructs an exponential random variable with spefified
|
||||
* \brief mean and upper limit.
|
||||
* \brief Constructs an exponential random variable with specified
|
||||
* mean and upper limit.
|
||||
*
|
||||
* Since exponential distributions can theoretically return unbounded values,
|
||||
* it is sometimes useful to specify a fixed upper limit. Note however when
|
||||
* the upper limit is specified, the true mean of the distribution is
|
||||
* slightly smaller than the mean value specified.
|
||||
* the upper limit is specified, the true mean of the distribution is
|
||||
* slightly smaller than the mean value specified: \f$ m - b/(e^{b/m}-1) \f$.
|
||||
* \param m Mean value of the random variable
|
||||
* \param b Upper bound on returned values
|
||||
*/
|
||||
ExponentialVariable(double m, double b);
|
||||
ExponentialVariable (double m, double b);
|
||||
|
||||
};
|
||||
|
||||
@@ -336,13 +337,13 @@ public:
|
||||
* \ingroup randomvariable
|
||||
*
|
||||
* This class supports the creation of objects that return random numbers
|
||||
* from a fixed pareto distribution. It also supports the generation of
|
||||
* from a fixed pareto distribution. It also supports the generation of
|
||||
* single random numbers from various pareto distributions.
|
||||
*
|
||||
* The probability density function is defined over the range [\f$x_m\f$,+inf) as:
|
||||
* \f$ k \frac{x_m^k}{x^{k+1}}\f$ where \f$x_m > 0\f$ is called the location
|
||||
* \f$ k \frac{x_m^k}{x^{k+1}}\f$ where \f$x_m > 0\f$ is called the location
|
||||
* parameter and \f$ k > 0\f$ is called the pareto index or shape.
|
||||
*
|
||||
*
|
||||
* The parameter \f$ x_m \f$ can be infered from the mean and the parameter \f$ k \f$
|
||||
* with the equation \f$ x_m = mean \frac{k-1}{k}, k > 1\f$.
|
||||
*
|
||||
@@ -367,7 +368,7 @@ public:
|
||||
* parameter of 1.5
|
||||
* \param m Mean value of the distribution
|
||||
*/
|
||||
explicit ParetoVariable(double m);
|
||||
explicit ParetoVariable (double m);
|
||||
|
||||
/**
|
||||
* Constructs a pareto random variable with the specified mean value and
|
||||
@@ -375,7 +376,7 @@ public:
|
||||
* \param m Mean value of the distribution
|
||||
* \param s Shape parameter for the distribution
|
||||
*/
|
||||
ParetoVariable(double m, double s);
|
||||
ParetoVariable (double m, double s);
|
||||
|
||||
/**
|
||||
* \brief Constructs a pareto random variable with the specified mean
|
||||
@@ -389,7 +390,7 @@ public:
|
||||
* \param s Shape parameter
|
||||
* \param b Upper limit on returned values
|
||||
*/
|
||||
ParetoVariable(double m, double s, double b);
|
||||
ParetoVariable (double m, double s, double b);
|
||||
|
||||
};
|
||||
|
||||
@@ -398,7 +399,7 @@ public:
|
||||
* \ingroup randomvariable
|
||||
*
|
||||
* This class supports the creation of objects that return random numbers
|
||||
* from a fixed weibull distribution. It also supports the generation of
|
||||
* from a fixed weibull distribution. It also supports the generation of
|
||||
* single random numbers from various weibull distributions.
|
||||
*
|
||||
* The probability density function is defined over the interval [0, +inf]
|
||||
@@ -407,13 +408,14 @@ public:
|
||||
* specified mean is related to the scale and shape parameters by the following relation:
|
||||
* \f$ mean = \lambda\Gamma\left(1+\frac{1}{k}\right) \f$ where \f$ \Gamma \f$ is the Gamma function.
|
||||
*/
|
||||
class WeibullVariable : public RandomVariable {
|
||||
class WeibullVariable : public RandomVariable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a weibull random variable with a mean
|
||||
* value of 1.0 and a shape (alpha) parameter of 1
|
||||
*/
|
||||
WeibullVariable();
|
||||
WeibullVariable ();
|
||||
|
||||
|
||||
/**
|
||||
@@ -421,7 +423,7 @@ public:
|
||||
* value and a shape (alpha) parameter of 1.5.
|
||||
* \param m mean value of the distribution
|
||||
*/
|
||||
WeibullVariable(double m) ;
|
||||
WeibullVariable (double m);
|
||||
|
||||
/**
|
||||
* Constructs a weibull random variable with the specified mean
|
||||
@@ -429,20 +431,20 @@ public:
|
||||
* \param m Mean value for the distribution.
|
||||
* \param s Shape (alpha) parameter for the distribution.
|
||||
*/
|
||||
WeibullVariable(double m, double s);
|
||||
WeibullVariable (double m, double s);
|
||||
|
||||
/**
|
||||
* \brief Constructs a weibull random variable with the specified mean
|
||||
* \brief value, shape (alpha), and upper bound.
|
||||
* Since WeibullVariable distributions can theoretically return unbounded values,
|
||||
* it is sometimes usefull to specify a fixed upper limit. Note however
|
||||
* that when the upper limit is specified, the true mean of the distribution
|
||||
* is slightly smaller than the mean value specified.
|
||||
* \param m Mean value for the distribution.
|
||||
* \param s Shape (alpha) parameter for the distribution.
|
||||
* \param b Upper limit on returned values
|
||||
*/
|
||||
WeibullVariable(double m, double s, double b);
|
||||
/**
|
||||
* \brief Constructs a weibull random variable with the specified mean
|
||||
* \brief value, shape (alpha), and upper bound.
|
||||
* Since WeibullVariable distributions can theoretically return unbounded values,
|
||||
* it is sometimes usefull to specify a fixed upper limit. Note however
|
||||
* that when the upper limit is specified, the true mean of the distribution
|
||||
* is slightly smaller than the mean value specified.
|
||||
* \param m Mean value for the distribution.
|
||||
* \param s Shape (alpha) parameter for the distribution.
|
||||
* \param b Upper limit on returned values
|
||||
*/
|
||||
WeibullVariable (double m, double s, double b);
|
||||
|
||||
};
|
||||
|
||||
@@ -450,9 +452,9 @@ public:
|
||||
* \brief Class NormalVariable defines a random variable with a
|
||||
* normal (Gaussian) distribution.
|
||||
* \ingroup randomvariable
|
||||
*
|
||||
*
|
||||
* This class supports the creation of objects that return random numbers
|
||||
* from a fixed normal distribution. It also supports the generation of
|
||||
* from a fixed normal distribution. It also supports the generation of
|
||||
* single random numbers from various normal distributions.
|
||||
*
|
||||
* The density probability function is defined over the interval (-inf,+inf)
|
||||
@@ -466,15 +468,15 @@ public:
|
||||
/**
|
||||
* Constructs an normal random variable with a mean
|
||||
* value of 0 and variance of 1.
|
||||
*/
|
||||
NormalVariable();
|
||||
*/
|
||||
NormalVariable ();
|
||||
|
||||
/**
|
||||
* \brief Construct a normal random variable with specified mean and variance.
|
||||
* \param m Mean value
|
||||
* \param v Variance
|
||||
*/
|
||||
NormalVariable(double m, double v);
|
||||
*/
|
||||
NormalVariable (double m, double v);
|
||||
|
||||
/**
|
||||
* \brief Construct a normal random variable with specified mean and variance
|
||||
@@ -482,15 +484,15 @@ public:
|
||||
* \param v Variance
|
||||
* \param b Bound. The NormalVariable is bounded symetrically about the mean
|
||||
* [mean-bound,mean+bound]
|
||||
*/
|
||||
NormalVariable(double m, double v, double b);
|
||||
*/
|
||||
NormalVariable (double m, double v, double b);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief EmpiricalVariable distribution random var
|
||||
* \ingroup randomvariable
|
||||
*
|
||||
* Defines a random variable that has a specified, empirical
|
||||
* Defines a random variable that has a specified, empirical
|
||||
* distribution. The distribution is specified by a
|
||||
* series of calls to the CDF member function, specifying a
|
||||
* value and the probability that the function value is less than
|
||||
@@ -501,19 +503,20 @@ public:
|
||||
* as inverse transform sampling:
|
||||
* (http://en.wikipedia.org/wiki/Inverse_transform_sampling).
|
||||
*/
|
||||
class EmpiricalVariable : public RandomVariable {
|
||||
class EmpiricalVariable : public RandomVariable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor for the EmpiricalVariable random variables.
|
||||
*/
|
||||
explicit EmpiricalVariable();
|
||||
explicit EmpiricalVariable ();
|
||||
|
||||
/**
|
||||
* \brief Specifies a point in the empirical distribution
|
||||
* \param v The function value for this point
|
||||
* \param c Probability that the function is less than or equal to v
|
||||
*/
|
||||
void CDF(double v, double c); // Value, prob <= Value
|
||||
void CDF (double v, double c); // Value, prob <= Value
|
||||
protected:
|
||||
EmpiricalVariable (const RandomVariableBase &variable);
|
||||
};
|
||||
@@ -527,10 +530,10 @@ protected:
|
||||
* sampling interpolation described in the EmpiricalVariable documentation
|
||||
* is modified to only return integers.
|
||||
*/
|
||||
class IntEmpiricalVariable : public EmpiricalVariable
|
||||
class IntEmpiricalVariable : public EmpiricalVariable
|
||||
{
|
||||
public:
|
||||
IntEmpiricalVariable();
|
||||
IntEmpiricalVariable ();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -550,13 +553,13 @@ public:
|
||||
*
|
||||
* Creates a generator that returns successive elements of the d array
|
||||
* on successive calls to ::Value(). Note that the d pointer is copied
|
||||
* for use by the generator (shallow-copy), not its contents, so the
|
||||
* contents of the array d points to have to remain unchanged for the use
|
||||
* for use by the generator (shallow-copy), not its contents, so the
|
||||
* contents of the array d points to have to remain unchanged for the use
|
||||
* of DeterministicVariable to be meaningful.
|
||||
* \param d Pointer to array of random values to return in sequence
|
||||
* \param c Number of values in the array
|
||||
*/
|
||||
explicit DeterministicVariable(double* d, uint32_t c);
|
||||
explicit DeterministicVariable (double* d, uint32_t c);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -573,7 +576,7 @@ public:
|
||||
*
|
||||
* The probability density function is defined over the interval [0,+inf) as:
|
||||
* \f$ \frac{1}{x\sigma\sqrt{2\pi}} e^{-\frac{(ln(x) - \mu)^2}{2\sigma^2}}\f$
|
||||
* where \f$ mean = e^{\mu+\frac{\sigma^2}{2}} \f$ and
|
||||
* where \f$ mean = e^{\mu+\frac{\sigma^2}{2}} \f$ and
|
||||
* \f$ variance = (e^{\sigma^2}-1)e^{2\mu+\sigma^2}\f$
|
||||
*
|
||||
* The \f$ \mu \f$ and \f$ \sigma \f$ parameters can be calculated from the mean
|
||||
@@ -581,7 +584,7 @@ public:
|
||||
* \f$ \mu = ln(mean) - \frac{1}{2}ln\left(1+\frac{stddev}{mean^2}\right)\f$, and,
|
||||
* \f$ \sigma = \sqrt{ln\left(1+\frac{stddev}{mean^2}\right)}\f$
|
||||
*/
|
||||
class LogNormalVariable : public RandomVariable
|
||||
class LogNormalVariable : public RandomVariable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -595,18 +598,18 @@ public:
|
||||
* \brief Gamma Distributed Random Variable
|
||||
* \ingroup randomvariable
|
||||
*
|
||||
* GammaVariable defines a random variable with gamma distribution.
|
||||
* GammaVariable defines a random variable with gamma distribution.
|
||||
*
|
||||
* This class supports the creation of objects that return random numbers
|
||||
* from a fixed gamma distribution. It also supports the generation of
|
||||
* from a fixed gamma distribution. It also supports the generation of
|
||||
* single random numbers from various gamma distributions.
|
||||
*
|
||||
* The probability density function is defined over the interval [0,+inf) as:
|
||||
* \f$ x^{\alpha-1} \frac{e^{-\frac{x}{\beta}}}{\beta^\alpha \Gamma(\alpha)}\f$
|
||||
* where \f$ mean = \alpha\beta \f$ and
|
||||
* where \f$ mean = \alpha\beta \f$ and
|
||||
* \f$ variance = \alpha \beta^2\f$
|
||||
*/
|
||||
class GammaVariable : public RandomVariable
|
||||
class GammaVariable : public RandomVariable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -622,7 +625,7 @@ public:
|
||||
|
||||
/**
|
||||
* \brief call RandomVariable::GetValue
|
||||
* \return A floating point random value
|
||||
* \return A floating point random value
|
||||
*
|
||||
* Note: we have to re-implement this method here because the method is
|
||||
* overloaded below for the two-argument variant and the c++ name resolution
|
||||
@@ -630,14 +633,14 @@ public:
|
||||
* classes.
|
||||
*/
|
||||
double GetValue (void) const;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Returns a gamma random distributed double with parameters alpha and beta.
|
||||
* \param alpha alpha parameter of the gamma distribution
|
||||
* \param beta beta parameter of the gamma distribution
|
||||
* \return A floating point random value
|
||||
*/
|
||||
double GetValue(double alpha, double beta) const;
|
||||
double GetValue (double alpha, double beta) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -656,10 +659,10 @@ public:
|
||||
*
|
||||
* The probability density function is defined over the interval [0,+inf) as:
|
||||
* \f$ \frac{x^{k-1} e^{-\frac{x}{\lambda}}}{\lambda^k (k-1)!}\f$
|
||||
* where \f$ mean = k \lambda \f$ and
|
||||
* where \f$ mean = k \lambda \f$ and
|
||||
* \f$ variance = k \lambda^2\f$
|
||||
*/
|
||||
class ErlangVariable : public RandomVariable
|
||||
class ErlangVariable : public RandomVariable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -675,7 +678,7 @@ public:
|
||||
|
||||
/**
|
||||
* \brief call RandomVariable::GetValue
|
||||
* \return A floating point random value
|
||||
* \return A floating point random value
|
||||
*
|
||||
* Note: we have to re-implement this method here because the method is
|
||||
* overloaded below for the two-argument variant and the c++ name resolution
|
||||
@@ -683,50 +686,87 @@ public:
|
||||
* classes.
|
||||
*/
|
||||
double GetValue (void) const;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Returns an Erlang random distributed double with parameters k and lambda.
|
||||
* \param k k parameter of the Erlang distribution. Must be a non-negative integer.
|
||||
* \param lambda lambda parameter of the Erlang distribution
|
||||
* \return A floating point random value
|
||||
*/
|
||||
double GetValue(unsigned int k, double lambda) const;
|
||||
double GetValue (unsigned int k, double lambda) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Zipf Distributed random var (between 1 and n included)
|
||||
* \brief Zipf Distributed Random Variable
|
||||
* \ingroup randomvariable
|
||||
*
|
||||
* ZipfVariable defines a discrete random variable with Zipf distribution.
|
||||
*
|
||||
* The Zipf's law states that given some corpus of natural language
|
||||
* utterances, the frequency of any word is inversely proportional
|
||||
* to its rank in the frequency table.
|
||||
*
|
||||
* Zipf's distribution have two parameters, alpha and N, where:
|
||||
* \f$ \alpha > 0 \f$ (real) and \f$ N \in \{1,2,3 \dots\}\f$ (integer).
|
||||
* Probability Mass Function is \f$ f(k; \alpha, N) = k^{-\alpha}/ H_{N,\alpha} \f$
|
||||
* where \f$ H_{N,\alpha} = \sum_{n=1}^N n^{-\alpha} \f$
|
||||
*/
|
||||
class ZipfVariable : public RandomVariable
|
||||
class ZipfVariable : public RandomVariable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \param n the number of possible items
|
||||
* \param alpha the alpha parameter
|
||||
* \brief Returns a Zipf random variable with parameters N and alpha.
|
||||
* \param N the number of possible items. Must be a positive integer.
|
||||
* \param alpha the alpha parameter. Must be a strictly positive real.
|
||||
*/
|
||||
ZipfVariable (long n, double alpha);
|
||||
ZipfVariable (long N, double alpha);
|
||||
/**
|
||||
* A zipf variable with N=1 and alpha=0
|
||||
* Constructs a Zipf random variable with N=1 and alpha=0.
|
||||
*/
|
||||
ZipfVariable ();
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Zeta Distributed Distributed Random Variable
|
||||
* \ingroup randomvariable
|
||||
*
|
||||
* ZetaVariable defines a discrete random variable with Zeta distribution.
|
||||
*
|
||||
* The Zeta distribution is closely related to Zipf distribution when N goes to infinity.
|
||||
*
|
||||
* Zeta distribution has one parameter, alpha, \f$ \alpha > 1 \f$ (real).
|
||||
* Probability Mass Function is \f$ f(k; \alpha) = k^{-\alpha}/\zeta(\alpha) \f$
|
||||
* where \f$ \zeta(\alpha) \f$ is the Riemann zeta function ( \f$ \sum_{n=1}^\infty n^{-\alpha} ) \f$
|
||||
*/
|
||||
class ZetaVariable : public RandomVariable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Returns a Zeta random variable with parameter alpha.
|
||||
* \param alpha the alpha parameter. Must be a strictly greater than 1, real.
|
||||
*/
|
||||
ZetaVariable (double alpha);
|
||||
/**
|
||||
* Constructs a Zeta random variable with alpha=3.14
|
||||
*/
|
||||
ZetaVariable ();
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Triangularly Distributed random var
|
||||
* \ingroup randomvariable
|
||||
*
|
||||
*
|
||||
* This distribution is a triangular distribution. The probablility density
|
||||
* is in the shape of a triangle.
|
||||
*/
|
||||
class TriangularVariable : public RandomVariable
|
||||
class TriangularVariable : public RandomVariable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates a triangle distribution random number generator in the
|
||||
* range [0.0 .. 1.0), with mean of 0.5
|
||||
*/
|
||||
TriangularVariable();
|
||||
TriangularVariable ();
|
||||
|
||||
/**
|
||||
* Creates a triangle distribution random number generator with the specified
|
||||
@@ -735,12 +775,12 @@ public:
|
||||
* \param l High end of the range
|
||||
* \param mean mean of the distribution
|
||||
*/
|
||||
TriangularVariable(double s, double l, double mean);
|
||||
TriangularVariable (double s, double l, double mean);
|
||||
|
||||
};
|
||||
|
||||
std::ostream &operator << (std::ostream &os, const RandomVariable &var);
|
||||
std::istream &operator >> (std::istream &os, RandomVariable &var);
|
||||
std::ostream & operator << (std::ostream &os, const RandomVariable &var);
|
||||
std::istream & operator >> (std::istream &os, RandomVariable &var);
|
||||
|
||||
/**
|
||||
* \class ns3::RandomVariableValue
|
||||
@@ -751,7 +791,7 @@ ATTRIBUTE_VALUE_DEFINE (RandomVariable);
|
||||
ATTRIBUTE_CHECKER_DEFINE (RandomVariable);
|
||||
ATTRIBUTE_ACCESSOR_DEFINE (RandomVariable);
|
||||
|
||||
}//namespace ns3
|
||||
} // namespace ns3
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 MIRKO BANCHI
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mirko Banchi <mk.banchi@gmail.com>
|
||||
*/
|
||||
#include "block-ack-agreement.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
BlockAckAgreement::BlockAckAgreement ()
|
||||
: m_amsduSupported (0),
|
||||
m_blockAckPolicy (1),
|
||||
m_inactivityEvent ()
|
||||
{}
|
||||
|
||||
BlockAckAgreement::BlockAckAgreement (Mac48Address peer, uint8_t tid)
|
||||
: m_amsduSupported (0),
|
||||
m_blockAckPolicy (1),
|
||||
m_inactivityEvent ()
|
||||
{
|
||||
m_tid = tid;
|
||||
m_peer = peer;
|
||||
}
|
||||
|
||||
BlockAckAgreement::~BlockAckAgreement ()
|
||||
{
|
||||
m_inactivityEvent.Cancel ();
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckAgreement::SetBufferSize (uint16_t bufferSize)
|
||||
{
|
||||
NS_ASSERT (bufferSize <= 1024);
|
||||
m_bufferSize = bufferSize;
|
||||
}
|
||||
void
|
||||
BlockAckAgreement::SetTimeout (uint16_t timeout)
|
||||
{
|
||||
m_timeout = timeout;
|
||||
}
|
||||
void
|
||||
BlockAckAgreement::SetStartingSequence (uint16_t seq)
|
||||
{
|
||||
NS_ASSERT (seq < 4096);
|
||||
m_startingSeq = seq;
|
||||
}
|
||||
void
|
||||
BlockAckAgreement::SetImmediateBlockAck (void)
|
||||
{
|
||||
m_blockAckPolicy = 1;
|
||||
}
|
||||
void
|
||||
BlockAckAgreement::SetDelayedBlockAck (void)
|
||||
{
|
||||
m_blockAckPolicy = 0;
|
||||
}
|
||||
void
|
||||
BlockAckAgreement::SetAmsduSupport (bool supported)
|
||||
{
|
||||
m_amsduSupported = supported;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
BlockAckAgreement::GetTid (void) const
|
||||
{
|
||||
return m_tid;
|
||||
}
|
||||
Mac48Address
|
||||
BlockAckAgreement::GetPeer (void) const
|
||||
{
|
||||
return m_peer;
|
||||
}
|
||||
uint16_t
|
||||
BlockAckAgreement::GetBufferSize (void) const
|
||||
{
|
||||
return m_bufferSize;
|
||||
}
|
||||
uint16_t
|
||||
BlockAckAgreement::GetTimeout (void) const
|
||||
{
|
||||
return m_timeout;
|
||||
}
|
||||
uint16_t
|
||||
BlockAckAgreement::GetStartingSequence (void) const
|
||||
{
|
||||
return m_startingSeq;
|
||||
}
|
||||
uint16_t
|
||||
BlockAckAgreement::GetStartingSequenceControl (void) const
|
||||
{
|
||||
uint16_t seqControl = (m_startingSeq<<4) | 0xfff0;
|
||||
return seqControl;
|
||||
}
|
||||
bool
|
||||
BlockAckAgreement::IsImmediateBlockAck (void) const
|
||||
{
|
||||
return (m_blockAckPolicy == 1);
|
||||
}
|
||||
bool
|
||||
BlockAckAgreement::IsAmsduSupported (void) const
|
||||
{
|
||||
return (m_amsduSupported == 1)?true:false;
|
||||
}
|
||||
|
||||
} //namespace ns3
|
||||
@@ -0,0 +1,68 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 MIRKO BANCHI
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mirko Banchi <mk.banchi@gmail.com>
|
||||
*/
|
||||
#ifndef BLOCK_ACK_AGREEMENT_H
|
||||
#define BLOCK_ACK_AGREEMENT_H
|
||||
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/event-id.h"
|
||||
|
||||
namespace ns3 {
|
||||
/**
|
||||
* \brief Maintains information for a block ack agreement.
|
||||
*/
|
||||
class BlockAckAgreement
|
||||
{
|
||||
friend class MacLow;
|
||||
public:
|
||||
BlockAckAgreement ();
|
||||
BlockAckAgreement (Mac48Address peer, uint8_t tid);
|
||||
~BlockAckAgreement ();
|
||||
void SetBufferSize (uint16_t bufferSize);
|
||||
void SetTimeout (uint16_t timeout);
|
||||
void SetStartingSequence (uint16_t seq);
|
||||
void SetImmediateBlockAck (void);
|
||||
void SetDelayedBlockAck (void);
|
||||
void SetAmsduSupport (bool supported);
|
||||
|
||||
uint8_t GetTid (void) const;
|
||||
Mac48Address GetPeer (void) const;
|
||||
uint16_t GetBufferSize (void) const;
|
||||
uint16_t GetTimeout (void) const;
|
||||
uint16_t GetStartingSequence (void) const;
|
||||
uint16_t GetStartingSequenceControl (void) const;
|
||||
bool IsImmediateBlockAck (void) const;
|
||||
bool IsAmsduSupported (void) const;
|
||||
|
||||
protected:
|
||||
|
||||
Mac48Address m_peer;
|
||||
uint8_t m_amsduSupported;
|
||||
uint8_t m_blockAckPolicy; /* represents type of block ack: immediate or delayed */
|
||||
uint8_t m_tid;
|
||||
uint16_t m_bufferSize;
|
||||
uint16_t m_timeout;
|
||||
uint16_t m_startingSeq;
|
||||
|
||||
EventId m_inactivityEvent;
|
||||
};
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
#endif /* BLOCK_ACK_AGREEMENT_H */
|
||||
@@ -0,0 +1,617 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 MIRKO BANCHI
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mirko Banchi <mk.banchi@gmail.com>
|
||||
*/
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/assert.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/fatal-error.h"
|
||||
|
||||
#include "block-ack-manager.h"
|
||||
#include "mgt-headers.h"
|
||||
#include "ctrl-headers.h"
|
||||
#include "wifi-mac-header.h"
|
||||
#include "edca-txop-n.h"
|
||||
#include "mac-low.h"
|
||||
#include "wifi-mac-queue.h"
|
||||
#include "mac-tx-middle.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("BlockAckManager");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
BlockAckManager::Item::Item ()
|
||||
{}
|
||||
|
||||
BlockAckManager::Item::Item (Ptr<const Packet> packet, const WifiMacHeader &hdr, Time tStamp)
|
||||
: packet (packet), hdr (hdr), timestamp (tStamp)
|
||||
{}
|
||||
|
||||
Bar::Bar ()
|
||||
{}
|
||||
|
||||
Bar::Bar (Ptr<const Packet> bar, Mac48Address recipient, uint8_t tid, bool immediate)
|
||||
: bar (bar), recipient (recipient), tid (tid), immediate (immediate)
|
||||
{}
|
||||
|
||||
BlockAckManager::BlockAckManager ()
|
||||
{}
|
||||
|
||||
BlockAckManager::~BlockAckManager ()
|
||||
{
|
||||
m_queue = 0;
|
||||
m_agreements.clear ();
|
||||
m_retryPackets.clear ();
|
||||
}
|
||||
|
||||
bool
|
||||
BlockAckManager::ExistsAgreement (Mac48Address recipient, uint8_t tid) const
|
||||
{
|
||||
return (m_agreements.find (std::make_pair (recipient, tid)) != m_agreements.end ());
|
||||
}
|
||||
|
||||
bool
|
||||
BlockAckManager::ExistsAgreementInState (Mac48Address recipient, uint8_t tid,
|
||||
enum OriginatorBlockAckAgreement::State state) const
|
||||
{
|
||||
AgreementsCI it;
|
||||
it = m_agreements.find (std::make_pair (recipient, tid));
|
||||
if (it != m_agreements.end ())
|
||||
{
|
||||
switch (state) {
|
||||
case OriginatorBlockAckAgreement::INACTIVE:
|
||||
return it->second.first.IsInactive ();
|
||||
case OriginatorBlockAckAgreement::ESTABLISHED:
|
||||
return it->second.first.IsEstablished ();
|
||||
case OriginatorBlockAckAgreement::PENDING:
|
||||
return it->second.first.IsPending ();
|
||||
case OriginatorBlockAckAgreement::UNSUCCESSFUL:
|
||||
return it->second.first.IsUnsuccessful ();
|
||||
default:
|
||||
NS_FATAL_ERROR ("Invalid state for block ack agreement");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::CreateAgreement (const MgtAddBaRequestHeader *reqHdr, Mac48Address recipient)
|
||||
{
|
||||
pair<Mac48Address, uint8_t> key (recipient, reqHdr->GetTid ());
|
||||
OriginatorBlockAckAgreement agreement (recipient, reqHdr->GetTid ());
|
||||
agreement.SetStartingSequence (reqHdr->GetStartingSequence ());
|
||||
/* for now we assume that originator doesn't use this field. Use of this field
|
||||
is mandatory only for recipient */
|
||||
agreement.SetBufferSize (0);
|
||||
agreement.SetTimeout (reqHdr->GetTimeout ());
|
||||
agreement.SetAmsduSupport (reqHdr->IsAmsduSupported ());
|
||||
if (reqHdr->IsImmediateBlockAck ())
|
||||
{
|
||||
agreement.SetImmediateBlockAck ();
|
||||
}
|
||||
else
|
||||
{
|
||||
agreement.SetDelayedBlockAck ();
|
||||
}
|
||||
agreement.SetState (OriginatorBlockAckAgreement::PENDING);
|
||||
PacketQueue queue(0);
|
||||
pair<OriginatorBlockAckAgreement, PacketQueue> value (agreement, queue);
|
||||
m_agreements.insert (make_pair (key, value));
|
||||
m_blockPackets (recipient, reqHdr->GetTid ());
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::DestroyAgreement (Mac48Address recipient, uint8_t tid)
|
||||
{
|
||||
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
|
||||
if (it != m_agreements.end ())
|
||||
{
|
||||
for (list<PacketQueueI>::iterator i = m_retryPackets.begin (); i != m_retryPackets.end ();)
|
||||
{
|
||||
if ((*i)->hdr.GetAddr1 () == recipient && (*i)->hdr.GetQosTid () == tid)
|
||||
{
|
||||
i = m_retryPackets.erase (i);
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
m_agreements.erase (it);
|
||||
//remove scheduled bar
|
||||
for (list<Bar>::iterator i = m_bars.begin (); i != m_bars.end ();)
|
||||
{
|
||||
if (i->recipient == recipient && i->tid == tid)
|
||||
{
|
||||
i = m_bars.erase (i);
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::UpdateAgreement (const MgtAddBaResponseHeader *respHdr, Mac48Address recipient)
|
||||
{
|
||||
uint8_t tid = respHdr->GetTid ();
|
||||
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
|
||||
if (it != m_agreements.end ())
|
||||
{
|
||||
OriginatorBlockAckAgreement& agreement = it->second.first;
|
||||
agreement.SetBufferSize (respHdr->GetBufferSize () + 1);
|
||||
agreement.SetTimeout (respHdr->GetTimeout ());
|
||||
agreement.SetAmsduSupport (respHdr->IsAmsduSupported ());
|
||||
if (respHdr->IsImmediateBlockAck ())
|
||||
{
|
||||
agreement.SetImmediateBlockAck ();
|
||||
}
|
||||
else
|
||||
{
|
||||
agreement.SetDelayedBlockAck ();
|
||||
}
|
||||
agreement.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
|
||||
if (agreement.GetTimeout () != 0)
|
||||
{
|
||||
Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
|
||||
agreement.m_inactivityEvent = Simulator::Schedule (timeout,
|
||||
&BlockAckManager::InactivityTimeout,
|
||||
this,
|
||||
recipient, tid);
|
||||
}
|
||||
}
|
||||
m_unblockPackets (recipient, tid);
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::StorePacket (Ptr<const Packet> packet, const WifiMacHeader &hdr, Time tStamp)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_ASSERT (hdr.IsQosData ());
|
||||
|
||||
uint8_t tid = hdr.GetQosTid ();
|
||||
Mac48Address recipient = hdr.GetAddr1 ();
|
||||
|
||||
Item item (packet, hdr, tStamp);
|
||||
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
|
||||
NS_ASSERT (it != m_agreements.end ());
|
||||
it->second.second.push_back (item);
|
||||
}
|
||||
|
||||
Ptr<const Packet>
|
||||
BlockAckManager::GetNextPacket (WifiMacHeader &hdr)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
Ptr<const Packet> packet = 0;
|
||||
if (m_retryPackets.size () > 0)
|
||||
{
|
||||
CleanupBuffers ();
|
||||
PacketQueueI queueIt = m_retryPackets.front ();
|
||||
m_retryPackets.pop_front ();
|
||||
packet = queueIt->packet;
|
||||
hdr = queueIt->hdr;
|
||||
hdr.SetRetry ();
|
||||
NS_LOG_INFO ("Retry packet seq="<<hdr.GetSequenceNumber ());
|
||||
uint8_t tid = hdr.GetQosTid ();
|
||||
Mac48Address recipient = hdr.GetAddr1 ();
|
||||
|
||||
if (ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED) ||
|
||||
SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ()))
|
||||
{
|
||||
hdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* From section 9.10.3 in IEEE802.11e standard:
|
||||
* In order to improve efficiency, originators using the Block Ack facility
|
||||
* may send MPDU frames with the Ack Policy subfield in QoS control frames
|
||||
* set to Normal Ack if only a few MPDUs are available for transmission.[...]
|
||||
* When there are sufficient number of MPDUs, the originator may switch back to
|
||||
* the use of Block Ack.
|
||||
*/
|
||||
hdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK);
|
||||
AgreementsI i = m_agreements.find (std::make_pair (recipient, tid));
|
||||
i->second.second.erase (queueIt);
|
||||
}
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
bool
|
||||
BlockAckManager::HasBar (struct Bar &bar)
|
||||
{
|
||||
if (m_bars.size () > 0)
|
||||
{
|
||||
bar = m_bars.front ();
|
||||
m_bars.pop_front ();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
BlockAckManager::HasPackets (void) const
|
||||
{
|
||||
return (m_retryPackets.size () > 0 || m_bars.size () > 0);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
BlockAckManager::GetNBufferedPackets (Mac48Address recipient, uint8_t tid) const
|
||||
{
|
||||
uint32_t nPackets = 0;
|
||||
if (ExistsAgreement (recipient, tid))
|
||||
{
|
||||
AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
|
||||
PacketQueueCI queueIt = (*it).second.second.begin ();
|
||||
uint16_t currentSeq = 0;
|
||||
while (queueIt != (*it).second.second.end ())
|
||||
{
|
||||
currentSeq = (*queueIt).hdr.GetSequenceNumber ();
|
||||
nPackets++;
|
||||
/* a fragmented packet must be counted as one packet */
|
||||
while (queueIt != (*it).second.second.end () && (*queueIt).hdr.GetSequenceNumber () == currentSeq)
|
||||
{
|
||||
queueIt++;
|
||||
}
|
||||
}
|
||||
return nPackets;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
BlockAckManager::GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const
|
||||
{
|
||||
uint32_t nPackets = 0;
|
||||
uint16_t currentSeq = 0;
|
||||
if (ExistsAgreement (recipient, tid))
|
||||
{
|
||||
list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
|
||||
while (it != m_retryPackets.end ())
|
||||
{
|
||||
if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
|
||||
{
|
||||
currentSeq = (*it)->hdr.GetSequenceNumber ();
|
||||
nPackets++;
|
||||
/* a fragmented packet must be counted as one packet */
|
||||
while (it != m_retryPackets.end () && (*it)->hdr.GetSequenceNumber () == currentSeq)
|
||||
{
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nPackets;
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::SetBlockAckThreshold (uint8_t nPackets)
|
||||
{
|
||||
m_blockAckThreshold = nPackets;
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
uint16_t sequenceFirstLost = 0;
|
||||
if (!blockAck->IsMultiTid ())
|
||||
{
|
||||
uint8_t tid = blockAck->GetTidInfo ();
|
||||
if (ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED))
|
||||
{
|
||||
bool foundFirstLost = false;
|
||||
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
|
||||
PacketQueueI queueEnd = it->second.second.end ();
|
||||
|
||||
if (it->second.first.m_inactivityEvent.IsRunning ())
|
||||
{
|
||||
/* Upon reception of a block ack frame, the inactivity timer at the
|
||||
originator must be reset.
|
||||
For more details see section 11.5.3 in IEEE802.11e standard */
|
||||
it->second.first.m_inactivityEvent.Cancel ();
|
||||
Time timeout = MicroSeconds (1024 * it->second.first.GetTimeout ());
|
||||
it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
|
||||
&BlockAckManager::InactivityTimeout,
|
||||
this,
|
||||
recipient, tid);
|
||||
}
|
||||
if (blockAck->IsBasic ())
|
||||
{
|
||||
for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd;)
|
||||
{
|
||||
if (blockAck->IsFragmentReceived ((*queueIt).hdr.GetSequenceNumber (),
|
||||
(*queueIt).hdr.GetFragmentNumber ()))
|
||||
{
|
||||
queueIt = it->second.second.erase (queueIt);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!foundFirstLost)
|
||||
{
|
||||
foundFirstLost = true;
|
||||
sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber ();
|
||||
(*it).second.first.SetStartingSequence (sequenceFirstLost);
|
||||
}
|
||||
m_retryPackets.push_back (queueIt);
|
||||
queueIt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (blockAck->IsCompressed ())
|
||||
{
|
||||
for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd;)
|
||||
{
|
||||
if (blockAck->IsPacketReceived ((*queueIt).hdr.GetSequenceNumber ()))
|
||||
{
|
||||
uint16_t currentSeq = (*queueIt).hdr.GetSequenceNumber ();
|
||||
while (queueIt != queueEnd &&
|
||||
(*queueIt).hdr.GetSequenceNumber () == currentSeq)
|
||||
{
|
||||
queueIt = it->second.second.erase (queueIt);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!foundFirstLost)
|
||||
{
|
||||
foundFirstLost = true;
|
||||
sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber ();
|
||||
(*it).second.first.SetStartingSequence (sequenceFirstLost);
|
||||
}
|
||||
m_retryPackets.push_back (queueIt);
|
||||
queueIt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint16_t newSeq = m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, recipient);
|
||||
if ((foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, sequenceFirstLost)) ||
|
||||
(!foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, newSeq)))
|
||||
{
|
||||
it->second.first.SetState (OriginatorBlockAckAgreement::INACTIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//NOT SUPPORTED FOR NOW
|
||||
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::SetBlockAckType (enum BlockAckType bAckType)
|
||||
{
|
||||
m_blockAckType = bAckType;
|
||||
}
|
||||
|
||||
Ptr<Packet>
|
||||
BlockAckManager::ScheduleBlockAckReqIfNeeded (Mac48Address recipient, uint8_t tid)
|
||||
{
|
||||
/* This method checks if a BlockAckRequest frame should be send to the recipient station.
|
||||
Number of packets under block ack is specified in OriginatorBlockAckAgreement object but sometimes
|
||||
this number could be incorrect. In fact is possible that a block ack agreement exists for n
|
||||
packets but some of these packets are dropped due to MSDU lifetime expiration.
|
||||
*/
|
||||
NS_LOG_FUNCTION (this);
|
||||
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
|
||||
NS_ASSERT (it != m_agreements.end ());
|
||||
|
||||
if ((*it).second.first.NeedBlockAckRequest () ||
|
||||
(GetNRetryNeededPackets (recipient, tid) == 0 &&
|
||||
m_queue->GetNPacketsByTidAndAddress (tid, WifiMacHeader::ADDR1, recipient) == 0))
|
||||
{
|
||||
OriginatorBlockAckAgreement &agreement = (*it).second.first;
|
||||
agreement.CompleteExchange ();
|
||||
|
||||
CtrlBAckRequestHeader reqHdr;
|
||||
if (m_blockAckType == BASIC_BLOCK_ACK || m_blockAckType == COMPRESSED_BLOCK_ACK)
|
||||
{
|
||||
reqHdr.SetType (m_blockAckType);
|
||||
reqHdr.SetTidInfo (agreement.GetTid ());
|
||||
reqHdr.SetStartingSequence (agreement.GetStartingSequence ());
|
||||
}
|
||||
else if (m_blockAckType == MULTI_TID_BLOCK_ACK)
|
||||
{
|
||||
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Invalid block ack type.");
|
||||
}
|
||||
Ptr<Packet> bar = Create<Packet> ();
|
||||
bar->AddHeader (reqHdr);
|
||||
return bar;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::InactivityTimeout (Mac48Address recipient, uint8_t tid)
|
||||
{
|
||||
m_blockAckInactivityTimeout (recipient, tid, true);
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
|
||||
NS_ASSERT (it != m_agreements.end ());
|
||||
|
||||
it->second.first.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
|
||||
it->second.first.SetStartingSequence (startingSeq);
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::NotifyAgreementUnsuccessful (Mac48Address recipient, uint8_t tid)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
|
||||
NS_ASSERT (it != m_agreements.end ());
|
||||
if (it != m_agreements.end ())
|
||||
{
|
||||
it->second.first.SetState (OriginatorBlockAckAgreement::UNSUCCESSFUL);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::NotifyMpduTransmission (Mac48Address recipient, uint8_t tid)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
Ptr<Packet> bar = 0;
|
||||
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
|
||||
NS_ASSERT (it != m_agreements.end ());
|
||||
it->second.first.NotifyMpduTransmission ();
|
||||
bar = ScheduleBlockAckReqIfNeeded (recipient, tid);
|
||||
if (bar != 0)
|
||||
{
|
||||
Bar request (bar, recipient, tid, it->second.first.IsImmediateBlockAck ());
|
||||
m_bars.push_back (request);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::SetQueue (Ptr<WifiMacQueue> queue)
|
||||
{
|
||||
m_queue = queue;
|
||||
}
|
||||
|
||||
bool
|
||||
BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_ASSERT (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::PENDING));
|
||||
if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::UNSUCCESSFUL) && ExistsAgreement (recipient, tid))
|
||||
{
|
||||
uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, WifiMacHeader::ADDR1, recipient) +
|
||||
GetNBufferedPackets (recipient, tid);
|
||||
if (packets >= m_blockAckThreshold)
|
||||
{
|
||||
NotifyAgreementEstablished (recipient, tid, startingSeq);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::TearDownBlockAck (Mac48Address recipient, uint8_t tid)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
DestroyAgreement (recipient, tid);
|
||||
}
|
||||
|
||||
bool
|
||||
BlockAckManager::HasOtherFragments (uint16_t sequenceNumber) const
|
||||
{
|
||||
bool retVal = false;
|
||||
if (m_retryPackets.size () > 0)
|
||||
{
|
||||
Item next = *(m_retryPackets.front ());
|
||||
if (next.hdr.GetSequenceNumber () == sequenceNumber)
|
||||
{
|
||||
retVal = true;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
BlockAckManager::GetNextPacketSize (void) const
|
||||
{
|
||||
uint32_t size = 0;
|
||||
if (m_retryPackets.size () > 0)
|
||||
{
|
||||
Item next = *(m_retryPackets.front ());
|
||||
size = next.packet->GetSize ();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::CleanupBuffers (void)
|
||||
{
|
||||
for (AgreementsI j = m_agreements.begin(); j != m_agreements.end (); j++)
|
||||
{
|
||||
if (j->second.second.empty ())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Time now = Simulator::Now ();
|
||||
PacketQueueI end = j->second.second.begin ();
|
||||
for (PacketQueueI i = j->second.second.begin (); i != j->second.second.end (); i++)
|
||||
{
|
||||
if (i->timestamp + m_maxDelay > now)
|
||||
{
|
||||
end = i;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* remove retry packet iterator if it's present in retry queue */
|
||||
for (list<PacketQueueI>::iterator it = m_retryPackets.begin (); it != m_retryPackets.end (); it++)
|
||||
{
|
||||
if ((*it)->hdr.GetAddr1 () == j->second.first.GetPeer () &&
|
||||
(*it)->hdr.GetQosTid () == j->second.first.GetTid () &&
|
||||
(*it)->hdr.GetSequenceNumber () == i->hdr.GetSequenceNumber ())
|
||||
{
|
||||
m_retryPackets.erase (it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
j->second.second.erase (j->second.second.begin (), end);
|
||||
j->second.first.SetStartingSequence (end->hdr.GetSequenceNumber ());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::SetMaxPacketDelay (Time maxDelay)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_maxDelay = maxDelay;
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::SetBlockAckInactivityCallback (Callback<void, Mac48Address, uint8_t, bool> callback)
|
||||
{
|
||||
m_blockAckInactivityTimeout = callback;
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::SetBlockDestinationCallback (Callback<void, Mac48Address, uint8_t> callback)
|
||||
{
|
||||
m_blockPackets = callback;
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::SetUnblockDestinationCallback (Callback<void, Mac48Address, uint8_t> callback)
|
||||
{
|
||||
m_unblockPackets = callback;
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::SetTxMiddle (MacTxMiddle* txMiddle)
|
||||
{
|
||||
m_txMiddle = txMiddle;
|
||||
}
|
||||
|
||||
} //namespace ns3
|
||||
@@ -0,0 +1,297 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 MIRKO BANCHI
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mirko Banchi <mk.banchi@gmail.com>
|
||||
*/
|
||||
#ifndef BLOCK_ACK_MANAGER_H
|
||||
#define BLOCK_ACK_MANAGER_H
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
|
||||
#include "ns3/packet.h"
|
||||
|
||||
#include "wifi-mac-header.h"
|
||||
#include "originator-block-ack-agreement.h"
|
||||
#include "ctrl-headers.h"
|
||||
#include "qos-utils.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class MgtAddBaResponseHeader;
|
||||
class MgtAddBaRequestHeader;
|
||||
class MgtDelBaHeader;
|
||||
class MacTxMiddle;
|
||||
class WifiMacQueue;
|
||||
|
||||
struct Bar {
|
||||
Bar ();
|
||||
Bar (Ptr<const Packet> packet,
|
||||
Mac48Address recipient,
|
||||
uint8_t tid,
|
||||
bool immediate);
|
||||
Ptr<const Packet> bar;
|
||||
Mac48Address recipient;
|
||||
uint8_t tid;
|
||||
bool immediate;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Manages all block ack agreements for an originator station.
|
||||
*/
|
||||
class BlockAckManager
|
||||
{
|
||||
public:
|
||||
BlockAckManager ();
|
||||
~BlockAckManager ();
|
||||
/**
|
||||
* \param recipient Address of peer station involved in block ack mechanism.
|
||||
* \param tid Traffic ID.
|
||||
*
|
||||
* Checks if a block ack agreement exists with station addressed by
|
||||
* <i>recipient</i> for tid <i>tid</i>.
|
||||
*/
|
||||
bool ExistsAgreement (Mac48Address recipient, uint8_t tid) const;
|
||||
/**
|
||||
* \param recipient Address of peer station involved in block ack mechanism.
|
||||
* \param tid Traffic ID.
|
||||
* \param state The state for block ack agreement
|
||||
|
||||
* Checks if a block ack agreement with a state equals to <i>state</i> exists with
|
||||
* station addressed by <i>recipient</i> for tid <i>tid</i>.
|
||||
*/
|
||||
bool ExistsAgreementInState (Mac48Address recipient, uint8_t tid,
|
||||
enum OriginatorBlockAckAgreement::State state) const;
|
||||
/**
|
||||
* \param reqHdr Relative Add block ack request (action frame).
|
||||
* \param recipient Address of peer station involved in block ack mechanism.
|
||||
*
|
||||
* Creates a new block ack agreement in pending state. When a ADDBA response
|
||||
* with a successful status code is received, the relative agreement becomes established.
|
||||
*/
|
||||
void CreateAgreement (const MgtAddBaRequestHeader *reqHdr, Mac48Address recipient);
|
||||
/**
|
||||
* \param recipient Address of peer station involved in block ack mechanism.
|
||||
* \param tid Tid Traffic id of transmitted packet.
|
||||
*
|
||||
* Invoked when a recipient reject a block ack agreement or when a Delba frame
|
||||
* is Received/Trasmitted.
|
||||
*/
|
||||
void DestroyAgreement (Mac48Address recipient, uint8_t tid);
|
||||
/**
|
||||
* \param respHdr Relative Add block ack response (action frame).
|
||||
* \param recipient Address of peer station involved in block ack mechanism.
|
||||
*
|
||||
* Invoked upon receipt of a ADDBA response frame from <i>recipient</i>.
|
||||
*/
|
||||
void UpdateAgreement (const MgtAddBaResponseHeader *respHdr, Mac48Address recipient);
|
||||
/**
|
||||
* \param packet Packet to store.
|
||||
* \param hdr 802.11 header for packet.
|
||||
*
|
||||
* Stores <i>packet</i> for a possible future retransmission. Retransmission occurs
|
||||
* if the packet, in a block ack frame, is indicated by recipient as not received.
|
||||
*/
|
||||
void StorePacket (Ptr<const Packet> packet, const WifiMacHeader &hdr, Time tStamp);
|
||||
/**
|
||||
* \param hdr 802.11 header of returned packet (if exists).
|
||||
*
|
||||
* This methods returns a packet (if exists) indicated as not received in
|
||||
* corresponding block ack bitmap.
|
||||
*/
|
||||
Ptr<const Packet> GetNextPacket (WifiMacHeader &hdr);
|
||||
bool HasBar (struct Bar &bar);
|
||||
/**
|
||||
* Returns true if there are packets that need of retransmission or at least a
|
||||
* BAR is sheduled. Returns false othewise.
|
||||
*/
|
||||
bool HasPackets (void) const;
|
||||
/**
|
||||
* \param blockAck The received block ack frame.
|
||||
* \param recipient Sender of block ack frame.
|
||||
*
|
||||
* Invoked upon receipt of a block ack frame. Typically, this function, is called
|
||||
* by ns3::EdcaTxopN object. Performs a check on which MPDUs, previously sent
|
||||
* with ack policy set to Block Ack, were correctly received by the recipient.
|
||||
* An acknowldeged MPDU is removed from the buffer, retransmitted otherwise.
|
||||
*/
|
||||
void NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient);
|
||||
/**
|
||||
* \param recipient Address of peer station involved in block ack mechanism.
|
||||
* \param tid Traffic ID.
|
||||
*
|
||||
* Returns number of packets buffered for a specified agreement. This methods doesn't return
|
||||
* number of buffered MPDUs but number of buffered MSDUs.
|
||||
*/
|
||||
uint32_t GetNBufferedPackets (Mac48Address recipient, uint8_t tid) const;
|
||||
/**
|
||||
* \param recipient Address of peer station involved in block ack mechanism.
|
||||
* \param tid Traffic ID.
|
||||
*
|
||||
* Returns number of packets for a specific agreeemnt that need retransmission.
|
||||
* This methods doesn't return number of MPDUs that need retransmission but number MSDUs.
|
||||
*/
|
||||
uint32_t GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const;
|
||||
/**
|
||||
* \param recipient Address of peer station involved in block ack mechanism.
|
||||
* \param tid Traffic ID of transmitted packet.
|
||||
*
|
||||
* Puts corresponding agreement in established state and updates number of packets
|
||||
* and starting sequence field. Invoked typically after a block ack refresh.
|
||||
*/
|
||||
void NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq);
|
||||
/**
|
||||
* \param recipient Address of peer station involved in block ack mechanism.
|
||||
* \param tid Traffic ID of transmitted packet.
|
||||
*
|
||||
* Marks an agreement as unsuccessful. This happens if <i>recipient</i> station reject block ack setup
|
||||
* by an ADDBAResponse frame with a failure status code. FOr now we assume that every QoS station accepts
|
||||
* a block ack setup.
|
||||
*/
|
||||
void NotifyAgreementUnsuccessful (Mac48Address recipient, uint8_t tid);
|
||||
/**
|
||||
* \param recipient Address of peer station involved in block ack mechanism.
|
||||
* \param tid Traffic ID of transmitted packet.
|
||||
*
|
||||
* This methods is typically invoked by ns3::EdcaTxopN object every time that a MPDU
|
||||
* with ack policy subfield in Qos Control field set to Block Ack is transmitted.
|
||||
*/
|
||||
void NotifyMpduTransmission (Mac48Address recipient, uint8_t tid);
|
||||
/**
|
||||
* \param nPackets Minimum number of packets for use of block ack.
|
||||
*
|
||||
* Upon receipt of a block ack frame, if total number of packets (packets in WifiMacQueue
|
||||
* and buffered packets) is greater of <i>nPackets</i>, they are transmitted using block ack mechanism.
|
||||
*/
|
||||
void SetBlockAckThreshold (uint8_t nPackets);
|
||||
/**
|
||||
* \param queue The WifiMacQueue object.
|
||||
*/
|
||||
void SetQueue (Ptr<WifiMacQueue> queue);
|
||||
void SetTxMiddle (MacTxMiddle* txMiddle);
|
||||
/**
|
||||
* \param bAckType Type of block ack
|
||||
*
|
||||
* See ctrl-headers.h for more details.
|
||||
*/
|
||||
void SetBlockAckType (enum BlockAckType bAckType);
|
||||
/**
|
||||
* \param recipient Address of station involved in block ack mechanism.
|
||||
* \param tid Traffic ID.
|
||||
*
|
||||
* This method is invoked by EdcaTxopN object upon receipt of a DELBA frame
|
||||
* from recipient. The relative block ack agreement is destroied.
|
||||
*/
|
||||
void TearDownBlockAck (Mac48Address recipient, uint8_t tid);
|
||||
/**
|
||||
* \param Sequence number of the packet which fragment is part of.
|
||||
*
|
||||
* Returns true if another fragment with sequence number <i>sequenceNumber</i> is scheduled
|
||||
* for retransmission.
|
||||
*/
|
||||
bool HasOtherFragments (uint16_t sequenceNumber) const;
|
||||
/**
|
||||
* Returns size of the next packet that needs retransmission.
|
||||
*/
|
||||
uint32_t GetNextPacketSize (void) const;
|
||||
/**
|
||||
* \param maxDelay Max delay for a buffered packet.
|
||||
*
|
||||
* This method is always called by ns3::WifiMacQueue object and sets max delay equals
|
||||
* to ns3:WifiMacQueue delay value.
|
||||
*/
|
||||
void SetMaxPacketDelay (Time maxDelay);
|
||||
/**
|
||||
*/
|
||||
void SetBlockAckInactivityCallback (Callback<void, Mac48Address, uint8_t, bool> callback);
|
||||
void SetBlockDestinationCallback (Callback<void, Mac48Address, uint8_t> callback);
|
||||
void SetUnblockDestinationCallback (Callback<void, Mac48Address, uint8_t> callback);
|
||||
/**
|
||||
* Checks if there are in the queue other packets that could be send under block ack.
|
||||
* If yes adds these packets in current block ack exchange.
|
||||
* However, number of packets exchanged in the current block ack, will not exceed
|
||||
* the value of BufferSize in the corresponding OriginatorBlockAckAgreement object.
|
||||
*/
|
||||
bool SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq);
|
||||
private:
|
||||
/**
|
||||
* Checks if all packets, for which a block ack agreement was established or refreshed,
|
||||
* have been transmitted. If yes, adds a pair in m_bAckReqs to indicate that
|
||||
* at next channel access a block ack request (for established agreement
|
||||
* <i>recipient</i>,<i>tid</i>) is needed.
|
||||
*/
|
||||
Ptr<Packet> ScheduleBlockAckReqIfNeeded (Mac48Address recipient, uint8_t tid);
|
||||
/**
|
||||
* This method removes packets whose lifetime was exceded.
|
||||
*/
|
||||
void CleanupBuffers (void);
|
||||
void InactivityTimeout (Mac48Address, uint8_t);
|
||||
|
||||
struct Item;
|
||||
typedef std::list<Item> PacketQueue;
|
||||
typedef std::list<Item>::iterator PacketQueueI;
|
||||
typedef std::list<Item>::const_iterator PacketQueueCI;
|
||||
|
||||
typedef std::map<std::pair<Mac48Address, uint8_t>,
|
||||
std::pair<OriginatorBlockAckAgreement, PacketQueue> > Agreements;
|
||||
typedef std::map<std::pair<Mac48Address, uint8_t>,
|
||||
std::pair<OriginatorBlockAckAgreement, PacketQueue> >::iterator AgreementsI;
|
||||
typedef std::map<std::pair<Mac48Address, uint8_t>,
|
||||
std::pair<OriginatorBlockAckAgreement, PacketQueue> >::const_iterator AgreementsCI;
|
||||
|
||||
struct Item {
|
||||
Item ();
|
||||
Item (Ptr<const Packet> packet,
|
||||
const WifiMacHeader &hdr,
|
||||
Time tStamp);
|
||||
Ptr<const Packet> packet;
|
||||
WifiMacHeader hdr;
|
||||
Time timestamp;
|
||||
};
|
||||
|
||||
/**
|
||||
* This data structure contains, for each block ack agreement (recipient, tid), a set of packets
|
||||
* for which an ack by block ack is requested.
|
||||
* Every packet or fragment indicated as correctly received in block ack frame is
|
||||
* erased from this data structure. Pushed back in retransmission queue otherwise.
|
||||
*/
|
||||
Agreements m_agreements;
|
||||
/**
|
||||
* This list contains all iterators to stored packets that need to be retransmitted.
|
||||
* A packet needs retransmission if it's indicated as not correctly recevied in a block ack
|
||||
* frame.
|
||||
*/
|
||||
std::list<PacketQueueI> m_retryPackets;
|
||||
std::list<Bar> m_bars;
|
||||
|
||||
uint8_t m_blockAckThreshold;
|
||||
enum BlockAckType m_blockAckType;
|
||||
Time m_maxDelay;
|
||||
MacTxMiddle* m_txMiddle;
|
||||
Mac48Address m_address;
|
||||
Ptr<WifiMacQueue> m_queue;
|
||||
Callback<void, Mac48Address, uint8_t, bool> m_blockAckInactivityTimeout;
|
||||
Callback<void, Mac48Address, uint8_t> m_blockPackets;
|
||||
Callback<void, Mac48Address, uint8_t> m_unblockPackets;
|
||||
};
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
#endif /* BLOCK_ACK_MANAGER_H */
|
||||
@@ -0,0 +1,214 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 MIRKO BANCHI
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mirko Banchi <mk.banchi@gmail.com>
|
||||
*/
|
||||
#include "ns3/test.h"
|
||||
#include "ns3/log.h"
|
||||
#include "qos-utils.h"
|
||||
#include <list>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("BlockAckTest");
|
||||
/**
|
||||
* This simple test verifies the correctness of buffering for packets received
|
||||
* under block ack. In order to completely understand this example is important to cite
|
||||
* section 9.10.3 in IEEE802.11 standard:
|
||||
*
|
||||
* "[...] The sequence number space is considered divided into two parts, one of which
|
||||
* is “old” and one of which is “new” by means of a boundary created by adding half the
|
||||
* sequence number range to the current start of receive window (modulo 2^12)."
|
||||
*/
|
||||
//-------------------------------------------------------------------------------------
|
||||
|
||||
/* ----- = old packets
|
||||
* +++++ = new packets
|
||||
*
|
||||
* CASE A: startSeq < endSeq
|
||||
* - - +
|
||||
* initial buffer state: 0 16 56000
|
||||
*
|
||||
*
|
||||
* 0 4095
|
||||
* |------|++++++++++++++++|-----|
|
||||
* ^ ^
|
||||
* | startSeq | endSeq = 4000
|
||||
*
|
||||
* first received packet's sequence control = 64016 (seqNum = 4001, fragNum = 0) -
|
||||
* second received packet's sequence control = 63984 (seqNum = 3999, fragNum = 0) +
|
||||
* 4001 is older seq number so this packet should be inserted at the buffer's begin.
|
||||
* 3999 is previous element of older of new packets: it should be inserted at the end of buffer.
|
||||
*
|
||||
* expected buffer state: 64016 0 16 56000 63984
|
||||
*
|
||||
*/
|
||||
class PacketBufferingCaseA : public TestCase
|
||||
{
|
||||
public:
|
||||
PacketBufferingCaseA ();
|
||||
virtual ~PacketBufferingCaseA ();
|
||||
private:
|
||||
virtual bool DoRun (void);
|
||||
std::list<uint16_t> m_expectedBuffer;
|
||||
};
|
||||
|
||||
PacketBufferingCaseA::PacketBufferingCaseA ()
|
||||
: TestCase ("Check correct order of buffering when startSequence < endSeq")
|
||||
{
|
||||
m_expectedBuffer.push_back (64016);
|
||||
m_expectedBuffer.push_back (0);
|
||||
m_expectedBuffer.push_back (16);
|
||||
m_expectedBuffer.push_back (56000);
|
||||
m_expectedBuffer.push_back (63984);
|
||||
}
|
||||
|
||||
PacketBufferingCaseA::~PacketBufferingCaseA ()
|
||||
{}
|
||||
|
||||
bool
|
||||
PacketBufferingCaseA::DoRun (void)
|
||||
{
|
||||
std::list<uint16_t> m_buffer;
|
||||
std::list<uint16_t>::iterator i,j;
|
||||
m_buffer.push_back (0);
|
||||
m_buffer.push_back (16);
|
||||
m_buffer.push_back (56000);
|
||||
|
||||
uint16_t endSeq = 4000;
|
||||
|
||||
uint16_t receivedSeq = 4001 * 16;
|
||||
uint32_t mappedSeq = QosUtilsMapSeqControlToUniqueInteger (receivedSeq, endSeq);
|
||||
for (i = m_buffer.begin (); i != m_buffer.end () && QosUtilsMapSeqControlToUniqueInteger ((*i), endSeq) < mappedSeq; i++);
|
||||
{
|
||||
m_buffer.insert (i, receivedSeq);
|
||||
}
|
||||
|
||||
receivedSeq = 3999 * 16;
|
||||
mappedSeq = QosUtilsMapSeqControlToUniqueInteger (receivedSeq, endSeq);
|
||||
for (i = m_buffer.begin (); i != m_buffer.end () && QosUtilsMapSeqControlToUniqueInteger ((*i), endSeq) < mappedSeq; i++);
|
||||
{
|
||||
m_buffer.insert (i, receivedSeq);
|
||||
}
|
||||
|
||||
for (i = m_buffer.begin (), j = m_expectedBuffer.begin (); i != m_buffer.end (); i++, j++)
|
||||
{
|
||||
NS_TEST_EXPECT_MSG_EQ (*i, *j, "error in buffer order");
|
||||
}
|
||||
return GetErrorStatus ();
|
||||
}
|
||||
|
||||
/* ----- = old packets
|
||||
* +++++ = new packets
|
||||
*
|
||||
* CASE B: startSeq > endSeq
|
||||
* - + +
|
||||
* initial buffer state: 256 64000 16
|
||||
*
|
||||
*
|
||||
* 0 4095
|
||||
* |++++++|----------------|++++++|
|
||||
* ^ ^
|
||||
* | endSeq = 10 | startSeq
|
||||
*
|
||||
* first received packet's sequence control = 240 (seqNum = 15, fragNum = 0) -
|
||||
* second received packet's sequence control = 241 (seqNum = 15, fragNum = 1) -
|
||||
* third received packet's sequence control = 64800 (seqNum = 4050, fragNum = 0) +
|
||||
* 240 is an old packet should be inserted at the buffer's begin.
|
||||
* 241 is an old packet: second segment of the above packet.
|
||||
* 4050 is a new packet: it should be inserted between 64000 and 16.
|
||||
*
|
||||
* expected buffer state: 240 241 256 64000 64800 16
|
||||
*
|
||||
*/
|
||||
class PacketBufferingCaseB : public TestCase
|
||||
{
|
||||
public:
|
||||
PacketBufferingCaseB ();
|
||||
virtual ~PacketBufferingCaseB ();
|
||||
private:
|
||||
virtual bool DoRun (void);
|
||||
std::list<uint16_t> m_expectedBuffer;
|
||||
};
|
||||
|
||||
PacketBufferingCaseB::PacketBufferingCaseB ()
|
||||
: TestCase ("Check correct order of buffering when startSequence > endSeq")
|
||||
{
|
||||
m_expectedBuffer.push_back (240);
|
||||
m_expectedBuffer.push_back (241);
|
||||
m_expectedBuffer.push_back (256);
|
||||
m_expectedBuffer.push_back (64000);
|
||||
m_expectedBuffer.push_back (64800);
|
||||
m_expectedBuffer.push_back (16);
|
||||
}
|
||||
|
||||
PacketBufferingCaseB::~PacketBufferingCaseB ()
|
||||
{}
|
||||
|
||||
bool
|
||||
PacketBufferingCaseB::DoRun (void)
|
||||
{
|
||||
std::list<uint16_t> m_buffer;
|
||||
std::list<uint16_t>::iterator i,j;
|
||||
m_buffer.push_back (256);
|
||||
m_buffer.push_back (64000);
|
||||
m_buffer.push_back (16);
|
||||
|
||||
uint16_t endSeq = 10;
|
||||
|
||||
uint16_t receivedSeq = 15 * 16;
|
||||
uint32_t mappedSeq = QosUtilsMapSeqControlToUniqueInteger (receivedSeq, endSeq);
|
||||
for (i = m_buffer.begin (); i != m_buffer.end () && QosUtilsMapSeqControlToUniqueInteger ((*i), endSeq) < mappedSeq; i++);
|
||||
{
|
||||
m_buffer.insert (i, receivedSeq);
|
||||
}
|
||||
|
||||
receivedSeq = 15 * 16 + 1;
|
||||
mappedSeq = QosUtilsMapSeqControlToUniqueInteger (receivedSeq, endSeq);
|
||||
for (i = m_buffer.begin (); i != m_buffer.end () && QosUtilsMapSeqControlToUniqueInteger ((*i), endSeq) < mappedSeq; i++);
|
||||
{
|
||||
m_buffer.insert (i, receivedSeq);
|
||||
}
|
||||
|
||||
receivedSeq = 4050 * 16;
|
||||
mappedSeq = QosUtilsMapSeqControlToUniqueInteger (receivedSeq, endSeq);
|
||||
for (i = m_buffer.begin (); i != m_buffer.end () && QosUtilsMapSeqControlToUniqueInteger ((*i), endSeq) < mappedSeq; i++);
|
||||
{
|
||||
m_buffer.insert (i, receivedSeq);
|
||||
}
|
||||
|
||||
for (i = m_buffer.begin (), j = m_expectedBuffer.begin (); i != m_buffer.end (); i++, j++)
|
||||
{
|
||||
NS_TEST_EXPECT_MSG_EQ (*i, *j, "error in buffer order");
|
||||
}
|
||||
return GetErrorStatus ();
|
||||
}
|
||||
|
||||
class BlockAckTestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
BlockAckTestSuite ();
|
||||
};
|
||||
|
||||
BlockAckTestSuite::BlockAckTestSuite ()
|
||||
: TestSuite ("wifi-block-ack", UNIT)
|
||||
{
|
||||
AddTestCase (new PacketBufferingCaseA);
|
||||
AddTestCase (new PacketBufferingCaseB);
|
||||
}
|
||||
|
||||
BlockAckTestSuite g_blockAckTestSuite;
|
||||
@@ -0,0 +1,681 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 MIRKO BANCHI
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mirko Banchi <mk.banchi@gmail.com>
|
||||
*/
|
||||
#include "ns3/fatal-error.h"
|
||||
|
||||
#include "ctrl-headers.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/***********************************
|
||||
* Block ack request
|
||||
***********************************/
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (CtrlBAckRequestHeader);
|
||||
|
||||
CtrlBAckRequestHeader::CtrlBAckRequestHeader ()
|
||||
: m_barAckPolicy (false),
|
||||
m_multiTid (false),
|
||||
m_compressed (false)
|
||||
{}
|
||||
|
||||
CtrlBAckRequestHeader::~CtrlBAckRequestHeader ()
|
||||
{}
|
||||
|
||||
TypeId
|
||||
CtrlBAckRequestHeader::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::CtrlBAckRequestHeader")
|
||||
.SetParent<Header> ()
|
||||
.AddConstructor<CtrlBAckRequestHeader> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
TypeId
|
||||
CtrlBAckRequestHeader::GetInstanceTypeId (void) const
|
||||
{
|
||||
return GetTypeId ();
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckRequestHeader::Print (std::ostream &os) const
|
||||
{
|
||||
os << "TID_INFO=" << m_tidInfo << ", StartingSeq=" << std::hex << m_startingSeq;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CtrlBAckRequestHeader::GetSerializedSize () const
|
||||
{
|
||||
uint32_t size = 0;
|
||||
size += 2; //Bar control
|
||||
if (!m_multiTid)
|
||||
{
|
||||
size += 2; //Starting sequence control
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_compressed)
|
||||
{
|
||||
size += (2 + 2) * (m_tidInfo + 1); //Multi-tid block ack
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Reserved configuration.");
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckRequestHeader::Serialize (Buffer::Iterator start) const
|
||||
{
|
||||
Buffer::Iterator i = start;
|
||||
i.WriteHtolsbU16 (GetBarControl ());
|
||||
if (!m_multiTid)
|
||||
{
|
||||
i.WriteHtolsbU16 (GetStartingSequenceControl ());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_compressed)
|
||||
{
|
||||
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Reserved configuration.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CtrlBAckRequestHeader::Deserialize (Buffer::Iterator start)
|
||||
{
|
||||
Buffer::Iterator i = start;
|
||||
SetBarControl (i.ReadLsbtohU16 ());
|
||||
if (!m_multiTid)
|
||||
{
|
||||
SetStartingSequenceControl (i.ReadLsbtohU16 ());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_compressed)
|
||||
{
|
||||
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Reserved configuration.");
|
||||
}
|
||||
}
|
||||
return i.GetDistanceFrom (start);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
CtrlBAckRequestHeader::GetBarControl (void) const
|
||||
{
|
||||
uint16_t res = 0;
|
||||
if (m_barAckPolicy)
|
||||
{
|
||||
res |= 0x1;
|
||||
}
|
||||
if (m_multiTid)
|
||||
{
|
||||
res |= (0x1<<1);
|
||||
}
|
||||
if (m_compressed)
|
||||
{
|
||||
res |= (0x1<<2);
|
||||
}
|
||||
res |= (m_tidInfo << 12) & (0xf<<12);
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckRequestHeader::SetBarControl (uint16_t bar)
|
||||
{
|
||||
m_barAckPolicy = ((bar & 0x01) == 1)?true:false;
|
||||
m_multiTid = (((bar >> 1) & 0x01) == 1)?true:false;
|
||||
m_compressed = (((bar >> 2) & 0x01) == 1)?true:false;
|
||||
m_tidInfo = (bar >> 12) & 0x0f;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
CtrlBAckRequestHeader::GetStartingSequenceControl (void) const
|
||||
{
|
||||
return (m_startingSeq << 4) & 0xfff0;
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckRequestHeader::SetStartingSequenceControl (uint16_t seqControl)
|
||||
{
|
||||
m_startingSeq = (seqControl >> 4) & 0x0fff;
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckRequestHeader::SetHtImmediateAck (bool immediateAck)
|
||||
{
|
||||
m_barAckPolicy = immediateAck;
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckRequestHeader::SetType (enum BlockAckType type)
|
||||
{
|
||||
switch (type) {
|
||||
case BASIC_BLOCK_ACK:
|
||||
m_multiTid = false;
|
||||
m_compressed = false;
|
||||
break;
|
||||
case COMPRESSED_BLOCK_ACK:
|
||||
m_multiTid = false;
|
||||
m_compressed = true;
|
||||
break;
|
||||
case MULTI_TID_BLOCK_ACK:
|
||||
m_multiTid = true;
|
||||
m_compressed = true;
|
||||
break;
|
||||
default:
|
||||
NS_FATAL_ERROR ("Invalid variant type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckRequestHeader::SetTidInfo (uint8_t tid)
|
||||
{
|
||||
m_tidInfo = static_cast<uint16_t> (tid);
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckRequestHeader::SetStartingSequence (uint16_t seq)
|
||||
{
|
||||
m_startingSeq = seq;
|
||||
}
|
||||
|
||||
bool
|
||||
CtrlBAckRequestHeader::MustSendHtImmediateAck (void) const
|
||||
{
|
||||
return m_barAckPolicy;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
CtrlBAckRequestHeader::GetTidInfo (void) const
|
||||
{
|
||||
uint8_t tid = static_cast<uint8_t> (m_tidInfo);
|
||||
return tid;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
CtrlBAckRequestHeader::GetStartingSequence (void) const
|
||||
{
|
||||
return m_startingSeq;
|
||||
}
|
||||
|
||||
bool
|
||||
CtrlBAckRequestHeader::IsBasic (void) const
|
||||
{
|
||||
return (!m_multiTid && !m_compressed)?true:false;
|
||||
}
|
||||
|
||||
bool
|
||||
CtrlBAckRequestHeader::IsCompressed (void) const
|
||||
{
|
||||
return (!m_multiTid && m_compressed)?true:false;
|
||||
}
|
||||
|
||||
bool
|
||||
CtrlBAckRequestHeader::IsMultiTid (void) const
|
||||
{
|
||||
return (m_multiTid && m_compressed)?true:false;
|
||||
}
|
||||
|
||||
/***********************************
|
||||
* Block ack response
|
||||
***********************************/
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (CtrlBAckResponseHeader);
|
||||
|
||||
CtrlBAckResponseHeader::CtrlBAckResponseHeader ()
|
||||
: m_baAckPolicy (false),
|
||||
m_multiTid (false),
|
||||
m_compressed (false)
|
||||
{
|
||||
memset (&bitmap, 0, sizeof (bitmap));
|
||||
}
|
||||
|
||||
CtrlBAckResponseHeader::~CtrlBAckResponseHeader ()
|
||||
{}
|
||||
|
||||
TypeId
|
||||
CtrlBAckResponseHeader::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::CtrlBAckResponseHeader")
|
||||
.SetParent<Header> ()
|
||||
.AddConstructor<CtrlBAckResponseHeader> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
TypeId
|
||||
CtrlBAckResponseHeader::GetInstanceTypeId (void) const
|
||||
{
|
||||
return GetTypeId ();
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckResponseHeader::Print (std::ostream &os) const
|
||||
{
|
||||
os << "TID_INFO=" << m_tidInfo << ", StartingSeq=" << std::hex << m_startingSeq;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CtrlBAckResponseHeader::GetSerializedSize (void) const
|
||||
{
|
||||
uint32_t size = 0;
|
||||
size += 2; //Bar control
|
||||
if (!m_multiTid)
|
||||
{
|
||||
if (!m_compressed)
|
||||
{
|
||||
size += (2 + 128); //Basic block ack
|
||||
}
|
||||
else
|
||||
{
|
||||
size += (2 + 8); //Compressed block ack
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_compressed)
|
||||
{
|
||||
size += (2 + 2 + 8) * (m_tidInfo + 1); //Multi-tid block ack
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Reserved configuration.");
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckResponseHeader::Serialize (Buffer::Iterator start) const
|
||||
{
|
||||
Buffer::Iterator i = start;
|
||||
i.WriteHtolsbU16 (GetBaControl ());
|
||||
if (!m_multiTid)
|
||||
{
|
||||
i.WriteHtolsbU16 (GetStartingSequenceControl ());
|
||||
i = SerializeBitmap (i);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_compressed)
|
||||
{
|
||||
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Reserved configuration.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CtrlBAckResponseHeader::Deserialize (Buffer::Iterator start)
|
||||
{
|
||||
Buffer::Iterator i = start;
|
||||
SetBaControl (i.ReadLsbtohU16 ());
|
||||
if (!m_multiTid)
|
||||
{
|
||||
SetStartingSequenceControl (i.ReadLsbtohU16 ());
|
||||
i = DeserializeBitmap (i);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_compressed)
|
||||
{
|
||||
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Reserved configuration.");
|
||||
}
|
||||
}
|
||||
return i.GetDistanceFrom (start);
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckResponseHeader::SetHtImmediateAck (bool immediateAck)
|
||||
{
|
||||
m_baAckPolicy = immediateAck;
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckResponseHeader::SetType (enum BlockAckType type)
|
||||
{
|
||||
switch (type) {
|
||||
case BASIC_BLOCK_ACK:
|
||||
m_multiTid = false;
|
||||
m_compressed = false;
|
||||
break;
|
||||
case COMPRESSED_BLOCK_ACK:
|
||||
m_multiTid = false;
|
||||
m_compressed = true;
|
||||
break;
|
||||
case MULTI_TID_BLOCK_ACK:
|
||||
m_multiTid = true;
|
||||
m_compressed = true;
|
||||
break;
|
||||
default:
|
||||
NS_FATAL_ERROR ("Invalid variant type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckResponseHeader::SetTidInfo (uint8_t tid)
|
||||
{
|
||||
m_tidInfo = static_cast<uint16_t> (tid);
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckResponseHeader::SetStartingSequence (uint16_t seq)
|
||||
{
|
||||
m_startingSeq = seq;
|
||||
}
|
||||
|
||||
bool
|
||||
CtrlBAckResponseHeader::MustSendHtImmediateAck (void) const
|
||||
{
|
||||
return (m_baAckPolicy)?true:false;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
CtrlBAckResponseHeader::GetTidInfo (void) const
|
||||
{
|
||||
uint8_t tid = static_cast<uint8_t> (m_tidInfo);
|
||||
return tid;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
CtrlBAckResponseHeader::GetStartingSequence (void) const
|
||||
{
|
||||
return m_startingSeq;
|
||||
}
|
||||
|
||||
bool
|
||||
CtrlBAckResponseHeader::IsBasic (void) const
|
||||
{
|
||||
return (!m_multiTid && !m_compressed)?true:false;
|
||||
}
|
||||
|
||||
bool
|
||||
CtrlBAckResponseHeader::IsCompressed (void) const
|
||||
{
|
||||
return (!m_multiTid && m_compressed)?true:false;
|
||||
}
|
||||
|
||||
bool
|
||||
CtrlBAckResponseHeader::IsMultiTid (void) const
|
||||
{
|
||||
return (m_multiTid && m_compressed)?true:false;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
CtrlBAckResponseHeader::GetBaControl (void) const
|
||||
{
|
||||
uint16_t res = 0;
|
||||
if (m_baAckPolicy)
|
||||
{
|
||||
res |= 0x1;
|
||||
}
|
||||
if (m_multiTid)
|
||||
{
|
||||
res |= (0x1<<1);
|
||||
}
|
||||
if (m_compressed)
|
||||
{
|
||||
res |= (0x1<<2);
|
||||
}
|
||||
res |= (m_tidInfo << 12) & (0xf<<12);
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckResponseHeader::SetBaControl (uint16_t ba)
|
||||
{
|
||||
m_baAckPolicy = ((ba & 0x01) == 1)?true:false;
|
||||
m_multiTid = (((ba >> 1) & 0x01) == 1)?true:false;
|
||||
m_compressed = (((ba >> 2) & 0x01) == 1)?true:false;
|
||||
m_tidInfo = (ba >> 12) & 0x0f;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
CtrlBAckResponseHeader::GetStartingSequenceControl (void) const
|
||||
{
|
||||
return (m_startingSeq << 4) & 0xfff0;
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckResponseHeader::SetStartingSequenceControl (uint16_t seqControl)
|
||||
{
|
||||
m_startingSeq = (seqControl >> 4) & 0x0fff;
|
||||
}
|
||||
|
||||
Buffer::Iterator
|
||||
CtrlBAckResponseHeader::SerializeBitmap (Buffer::Iterator start) const
|
||||
{
|
||||
Buffer::Iterator i = start;
|
||||
if (!m_multiTid)
|
||||
{
|
||||
if (!m_compressed)
|
||||
{
|
||||
for (uint32_t j = 0; j < 64; j++)
|
||||
{
|
||||
i.WriteHtolsbU16 (bitmap.m_bitmap[j]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i.WriteHtolsbU64 (bitmap.m_compressedBitmap);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_compressed)
|
||||
{
|
||||
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Reserved configuration.");
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
Buffer::Iterator
|
||||
CtrlBAckResponseHeader::DeserializeBitmap (Buffer::Iterator start)
|
||||
{
|
||||
Buffer::Iterator i = start;
|
||||
if (!m_multiTid)
|
||||
{
|
||||
if (!m_compressed)
|
||||
{
|
||||
for (uint32_t j = 0; j < 64; j++)
|
||||
{
|
||||
bitmap.m_bitmap[j] = i.ReadLsbtohU16 ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bitmap.m_compressedBitmap = i.ReadLsbtohU64 ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_compressed)
|
||||
{
|
||||
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Reserved configuration.");
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckResponseHeader::SetReceivedPacket (uint16_t seq)
|
||||
{
|
||||
if (!m_multiTid)
|
||||
{
|
||||
if (!m_compressed)
|
||||
{
|
||||
/* To set correctly basic block ack bitmap we need fragment number too.
|
||||
So if it's not specified, we consider packet not fragmented. */
|
||||
bitmap.m_bitmap[IndexInBitmap (seq)] |= 0x0001;
|
||||
}
|
||||
else
|
||||
{
|
||||
bitmap.m_compressedBitmap |= (0x0000000000000001 << IndexInBitmap (seq));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_compressed)
|
||||
{
|
||||
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Reserved configuration.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CtrlBAckResponseHeader::SetReceivedFragment (uint16_t seq, uint8_t frag)
|
||||
{
|
||||
NS_ASSERT (frag < 16);
|
||||
if (!m_multiTid)
|
||||
{
|
||||
if (!m_compressed)
|
||||
{
|
||||
bitmap.m_bitmap[IndexInBitmap (seq)] |= (0x0001<<frag);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We can ignore this...compressed block ack doesn't support
|
||||
acknowledgement of single fragments */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_compressed)
|
||||
{
|
||||
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Reserved configuration.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CtrlBAckResponseHeader::IsPacketReceived (uint16_t seq) const
|
||||
{
|
||||
if (!m_multiTid)
|
||||
{
|
||||
if (!m_compressed)
|
||||
{
|
||||
/*It's impossible to say if an entire packet was correctly received. */
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t mask = 0x0000000000000001;
|
||||
return (((bitmap.m_compressedBitmap >> IndexInBitmap (seq)) & mask) == 1)?true:false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_compressed)
|
||||
{
|
||||
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Reserved configuration.");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CtrlBAckResponseHeader::IsFragmentReceived (uint16_t seq, uint8_t frag) const
|
||||
{
|
||||
NS_ASSERT (frag < 16);
|
||||
if (!m_multiTid)
|
||||
{
|
||||
if (!m_compressed)
|
||||
{
|
||||
return ((bitmap.m_bitmap[IndexInBitmap (seq)] & (0x0001<<frag)) != 0x0000)?true:false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Although this could make no sense, if packet with sequence number
|
||||
equal to <i>seq</i> was correctly received, also all of its fragments
|
||||
were correctly received. */
|
||||
uint64_t mask = 0x0000000000000001;
|
||||
return (((bitmap.m_compressedBitmap >> IndexInBitmap (seq)) & mask) == 1)?true:false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_compressed)
|
||||
{
|
||||
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Reserved configuration.");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
CtrlBAckResponseHeader::IndexInBitmap (uint16_t seq) const
|
||||
{
|
||||
if (seq >= m_startingSeq)
|
||||
{
|
||||
return (seq - m_startingSeq);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (4096 - m_startingSeq + seq);
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace ns3
|
||||
@@ -0,0 +1,159 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 MIRKO BANCHI
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mirko Banchi <mk.banchi@gmail.com>
|
||||
*/
|
||||
#ifndef CTRL_HEADERS_H
|
||||
#define CTRL_HEADERS_H
|
||||
|
||||
#include "ns3/header.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/** Headers for Block ack request and response.
|
||||
* 802.11n standard includes three types of block ack:
|
||||
* - Basic block ack (unique type in 802.11e)
|
||||
* - Compressed block ack
|
||||
* - Multi-TID block ack
|
||||
* For now only basic block ack and compressed block ack
|
||||
* are supported.
|
||||
* Basic block ack is also default variant.
|
||||
*/
|
||||
enum BlockAckType
|
||||
{
|
||||
BASIC_BLOCK_ACK,
|
||||
COMPRESSED_BLOCK_ACK,
|
||||
MULTI_TID_BLOCK_ACK
|
||||
};
|
||||
|
||||
class CtrlBAckRequestHeader : public Header {
|
||||
public:
|
||||
CtrlBAckRequestHeader ();
|
||||
~CtrlBAckRequestHeader ();
|
||||
static TypeId GetTypeId (void);
|
||||
virtual TypeId GetInstanceTypeId (void) const;
|
||||
virtual void Print (std::ostream &os) const;
|
||||
virtual uint32_t GetSerializedSize (void) const;
|
||||
virtual void Serialize (Buffer::Iterator start) const;
|
||||
virtual uint32_t Deserialize (Buffer::Iterator start);
|
||||
|
||||
void SetHtImmediateAck (bool immediateAck);
|
||||
void SetType (enum BlockAckType type);
|
||||
void SetTidInfo (uint8_t tid);
|
||||
void SetStartingSequence (uint16_t seq);
|
||||
|
||||
bool MustSendHtImmediateAck (void) const;
|
||||
uint8_t GetTidInfo (void) const;
|
||||
uint16_t GetStartingSequence (void) const;
|
||||
bool IsBasic (void) const;
|
||||
bool IsCompressed (void) const;
|
||||
bool IsMultiTid (void) const;
|
||||
|
||||
uint16_t GetStartingSequenceControl (void) const;
|
||||
|
||||
private:
|
||||
|
||||
void SetStartingSequenceControl (uint16_t seqControl);
|
||||
uint16_t GetBarControl (void) const;
|
||||
void SetBarControl (uint16_t bar);
|
||||
|
||||
/**
|
||||
* The lsb bit of the BAR control field is used only for the
|
||||
* HT (High Throughput) delayed block ack configuration.
|
||||
* For now only non HT immediate block ack is implemented so this field
|
||||
* is here only for a future implementation of HT delayed variant.
|
||||
*/
|
||||
bool m_barAckPolicy;
|
||||
bool m_multiTid;
|
||||
bool m_compressed;
|
||||
uint16_t m_tidInfo;
|
||||
uint16_t m_startingSeq;
|
||||
};
|
||||
|
||||
class CtrlBAckResponseHeader : public Header {
|
||||
public:
|
||||
CtrlBAckResponseHeader ();
|
||||
~CtrlBAckResponseHeader ();
|
||||
static TypeId GetTypeId (void);
|
||||
virtual TypeId GetInstanceTypeId (void) const;
|
||||
virtual void Print (std::ostream &os) const;
|
||||
virtual uint32_t GetSerializedSize (void) const;
|
||||
virtual void Serialize (Buffer::Iterator start) const;
|
||||
virtual uint32_t Deserialize (Buffer::Iterator start);
|
||||
|
||||
void SetHtImmediateAck (bool immeadiateAck);
|
||||
void SetType (enum BlockAckType type);
|
||||
void SetTidInfo (uint8_t tid);
|
||||
void SetStartingSequence (uint16_t seq);
|
||||
|
||||
bool MustSendHtImmediateAck (void) const;
|
||||
uint8_t GetTidInfo (void) const;
|
||||
uint16_t GetStartingSequence (void) const;
|
||||
bool IsBasic (void) const;
|
||||
bool IsCompressed (void) const;
|
||||
bool IsMultiTid (void) const;
|
||||
|
||||
void SetReceivedPacket (uint16_t seq);
|
||||
void SetReceivedFragment (uint16_t seq, uint8_t frag);
|
||||
bool IsPacketReceived (uint16_t seq) const;
|
||||
bool IsFragmentReceived (uint16_t seq, uint8_t frag) const;
|
||||
|
||||
uint16_t GetStartingSequenceControl (void) const;
|
||||
void SetStartingSequenceControl (uint16_t seqControl);
|
||||
|
||||
private:
|
||||
|
||||
uint16_t GetBaControl (void) const;
|
||||
void SetBaControl (uint16_t bar);
|
||||
|
||||
Buffer::Iterator SerializeBitmap (Buffer::Iterator start) const;
|
||||
Buffer::Iterator DeserializeBitmap (Buffer::Iterator start);
|
||||
|
||||
/**
|
||||
* This function is used to correctly index in both bitmap
|
||||
* and compressed bitmap, one bit or one block of 16 bits respectly.
|
||||
* If we are using basic block ack, return value represents index of
|
||||
* block of 16 bits for packet having sequence number equals to <i>seq</i>.
|
||||
* If we are using compressed block ack, return value represents bit
|
||||
* to set to 1 in the compressed bitmap to indicate that packet having
|
||||
* sequence number equals to <i>seq</i> was correctly received.
|
||||
*
|
||||
* for more details see 7.2.1.8 in IEEE 802.11n/D4.00
|
||||
*/
|
||||
uint8_t IndexInBitmap (uint16_t seq) const;
|
||||
|
||||
/**
|
||||
* The lsb bit of the BA control field is used only for the
|
||||
* HT (High Throughput) delayed block ack configuration.
|
||||
* For now only non HT immediate block ack is implemented so this field
|
||||
* is here only for a future implementation of HT delayed variant.
|
||||
*/
|
||||
bool m_baAckPolicy;
|
||||
bool m_multiTid;
|
||||
bool m_compressed;
|
||||
uint16_t m_tidInfo;
|
||||
uint16_t m_startingSeq;
|
||||
|
||||
union {
|
||||
uint16_t m_bitmap[64];
|
||||
uint64_t m_compressedBitmap;
|
||||
} bitmap;
|
||||
};
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
#endif /* CTRL_HEADERS_H */
|
||||
+429
-28
@@ -31,6 +31,9 @@
|
||||
#include "random-stream.h"
|
||||
#include "wifi-mac-queue.h"
|
||||
#include "msdu-aggregator.h"
|
||||
#include "mgt-headers.h"
|
||||
#include "qos-blocked-destinations.h"
|
||||
#include "block-ack-manager.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("EdcaTxopN");
|
||||
|
||||
@@ -82,6 +85,12 @@ public:
|
||||
virtual void MissedAck (void) {
|
||||
m_txop->MissedAck ();
|
||||
}
|
||||
virtual void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source) {
|
||||
m_txop->GotBlockAck (blockAck, source);
|
||||
}
|
||||
virtual void MissedBlockAck (void) {
|
||||
m_txop->MissedBlockAck ();
|
||||
}
|
||||
virtual void StartNext (void) {
|
||||
m_txop->StartNext ();
|
||||
}
|
||||
@@ -93,6 +102,22 @@ private:
|
||||
EdcaTxopN *m_txop;
|
||||
};
|
||||
|
||||
class EdcaTxopN::BlockAckEventListener : public MacLowBlockAckEventListener
|
||||
{
|
||||
public:
|
||||
BlockAckEventListener (EdcaTxopN *txop)
|
||||
: MacLowBlockAckEventListener (),
|
||||
m_txop (txop) {}
|
||||
virtual ~BlockAckEventListener () {}
|
||||
|
||||
virtual void BlockAckInactivityTimeout (Mac48Address address, uint8_t tid) {
|
||||
m_txop->SendDelbaFrame (address, tid, false);
|
||||
}
|
||||
|
||||
private:
|
||||
EdcaTxopN *m_txop;
|
||||
};
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (EdcaTxopN);
|
||||
|
||||
TypeId
|
||||
@@ -101,6 +126,19 @@ EdcaTxopN::GetTypeId (void)
|
||||
static TypeId tid = TypeId ("ns3::EdcaTxopN")
|
||||
.SetParent<Object> ()
|
||||
.AddConstructor<EdcaTxopN> ()
|
||||
.AddAttribute ("BlockAckThreshold", "If number of packets in this queue reaches this value,\
|
||||
block ack mechanism is used. If this value is 0, block ack is never used.",
|
||||
UintegerValue(0),
|
||||
MakeUintegerAccessor (&EdcaTxopN::SetBlockAckThreshold,
|
||||
&EdcaTxopN::GetBlockAckThreshold),
|
||||
MakeUintegerChecker<uint8_t> (0, 64))
|
||||
.AddAttribute ("BlockAckInactivityTimeout", "Represents max time (blocks of 1024 micro seconds) allowed for block ack\
|
||||
inactivity. If this value isn't equal to 0 a timer start after that a\
|
||||
block ack setup is completed and will be reset every time that a block\
|
||||
ack frame is received. If this value is 0, block ack inactivity timeout won't be used.",
|
||||
UintegerValue(0),
|
||||
MakeUintegerAccessor (&EdcaTxopN::m_blockAckInactivityTimeout),
|
||||
MakeUintegerChecker<uint16_t> ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
@@ -108,13 +146,22 @@ EdcaTxopN::GetTypeId (void)
|
||||
EdcaTxopN::EdcaTxopN ()
|
||||
: m_manager (0),
|
||||
m_currentPacket(0),
|
||||
m_aggregator (0)
|
||||
m_aggregator (0),
|
||||
m_blockAckType (COMPRESSED_BLOCK_ACK)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_transmissionListener = new EdcaTxopN::TransmissionListener (this);
|
||||
m_blockAckListener = new EdcaTxopN::BlockAckEventListener (this);
|
||||
m_dcf = new EdcaTxopN::Dcf (this);
|
||||
m_queue = CreateObject<WifiMacQueue> ();
|
||||
m_rng = new RealRandomStream ();
|
||||
m_qosBlockedDestinations = new QosBlockedDestinations ();
|
||||
m_baManager = new BlockAckManager ();
|
||||
m_baManager->SetQueue (m_queue);
|
||||
m_baManager->SetBlockAckType (m_blockAckType);
|
||||
m_baManager->SetBlockDestinationCallback (MakeCallback (&QosBlockedDestinations::Block, m_qosBlockedDestinations));
|
||||
m_baManager->SetUnblockDestinationCallback (MakeCallback (&QosBlockedDestinations::Unblock, m_qosBlockedDestinations));
|
||||
m_baManager->SetMaxPacketDelay (m_queue->GetMaxDelay ());
|
||||
}
|
||||
|
||||
EdcaTxopN::~EdcaTxopN ()
|
||||
@@ -132,9 +179,15 @@ EdcaTxopN::DoDispose (void)
|
||||
delete m_transmissionListener;
|
||||
delete m_dcf;
|
||||
delete m_rng;
|
||||
delete m_qosBlockedDestinations;
|
||||
delete m_baManager;
|
||||
delete m_blockAckListener;
|
||||
m_transmissionListener = 0;
|
||||
m_dcf = 0;
|
||||
m_rng = 0;
|
||||
m_qosBlockedDestinations = 0;
|
||||
m_baManager = 0;
|
||||
m_blockAckListener = 0;
|
||||
m_txMiddle = 0;
|
||||
m_aggregator = 0;
|
||||
}
|
||||
@@ -253,7 +306,7 @@ EdcaTxopN::SetLow(Ptr<MacLow> low)
|
||||
bool
|
||||
EdcaTxopN::NeedsAccess (void) const
|
||||
{
|
||||
return !m_queue->IsEmpty () || m_currentPacket != 0;
|
||||
return !m_queue->IsEmpty () || m_currentPacket != 0 || m_baManager->HasPackets ();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -262,23 +315,50 @@ EdcaTxopN::NotifyAccessGranted (void)
|
||||
NS_LOG_FUNCTION (this);
|
||||
if (m_currentPacket == 0)
|
||||
{
|
||||
if (m_queue->IsEmpty ())
|
||||
if (m_queue->IsEmpty () && !m_baManager->HasPackets ())
|
||||
{
|
||||
MY_DEBUG ("queue is empty");
|
||||
return;
|
||||
}
|
||||
m_currentPacket = m_queue->Dequeue (&m_currentHdr);
|
||||
NS_ASSERT (m_currentPacket != 0);
|
||||
|
||||
uint16_t sequence = m_txMiddle->GetNextSequenceNumberfor (&m_currentHdr);
|
||||
m_currentHdr.SetSequenceNumber (sequence);
|
||||
m_currentHdr.SetFragmentNumber (0);
|
||||
m_currentHdr.SetNoMoreFragments ();
|
||||
m_currentHdr.SetNoRetry ();
|
||||
m_fragmentNumber = 0;
|
||||
MY_DEBUG ("dequeued size="<<m_currentPacket->GetSize ()<<
|
||||
", to="<<m_currentHdr.GetAddr1 ()<<
|
||||
", seq="<<m_currentHdr.GetSequenceControl ());
|
||||
struct Bar bar;
|
||||
if (m_baManager->HasBar (bar))
|
||||
{
|
||||
SendBlockAckRequest (bar);
|
||||
return;
|
||||
}
|
||||
/* check if packets need retransmission are stored in BlockAckManager */
|
||||
m_currentPacket = m_baManager->GetNextPacket (m_currentHdr);
|
||||
if (m_currentPacket == 0)
|
||||
{
|
||||
if (m_queue->PeekFirstAvailable (&m_currentHdr, m_currentPacketTimestamp, m_qosBlockedDestinations) == 0)
|
||||
{
|
||||
MY_DEBUG ("no available packets in the queue");
|
||||
return;
|
||||
}
|
||||
if (m_currentHdr.IsQosData () && !m_currentHdr.GetAddr1 ().IsBroadcast () &&
|
||||
m_blockAckThreshold > 0 &&
|
||||
!m_baManager->ExistsAgreement (m_currentHdr.GetAddr1 (), m_currentHdr.GetQosTid ()) &&
|
||||
SetupBlockAckIfNeeded ())
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_currentPacket = m_queue->DequeueFirstAvailable (&m_currentHdr, m_currentPacketTimestamp, m_qosBlockedDestinations);
|
||||
NS_ASSERT (m_currentPacket != 0);
|
||||
|
||||
uint16_t sequence = m_txMiddle->GetNextSequenceNumberfor (&m_currentHdr);
|
||||
m_currentHdr.SetSequenceNumber (sequence);
|
||||
m_currentHdr.SetFragmentNumber (0);
|
||||
m_currentHdr.SetNoMoreFragments ();
|
||||
m_currentHdr.SetNoRetry ();
|
||||
m_fragmentNumber = 0;
|
||||
MY_DEBUG ("dequeued size="<<m_currentPacket->GetSize ()<<
|
||||
", to="<<m_currentHdr.GetAddr1 ()<<
|
||||
", seq="<<m_currentHdr.GetSequenceControl ());
|
||||
if (m_currentHdr.IsQosData () && !m_currentHdr.GetAddr1 ().IsBroadcast ())
|
||||
{
|
||||
VerifyBlockAck ();
|
||||
}
|
||||
}
|
||||
}
|
||||
MacLowTransmissionParameters params;
|
||||
params.DisableOverrideDurationId ();
|
||||
@@ -288,9 +368,9 @@ EdcaTxopN::NotifyAccessGranted (void)
|
||||
params.DisableAck ();
|
||||
params.DisableNextData ();
|
||||
m_low->StartTransmission (m_currentPacket,
|
||||
&m_currentHdr,
|
||||
params,
|
||||
m_transmissionListener);
|
||||
&m_currentHdr,
|
||||
params,
|
||||
m_transmissionListener);
|
||||
|
||||
m_currentPacket = 0;
|
||||
m_dcf->ResetCw ();
|
||||
@@ -300,11 +380,21 @@ EdcaTxopN::NotifyAccessGranted (void)
|
||||
}
|
||||
else
|
||||
{
|
||||
params.EnableAck ();
|
||||
if (NeedFragmentation () && ((m_currentHdr.IsQosData () &&
|
||||
!m_currentHdr.IsQosAmsdu ()) ||
|
||||
m_currentHdr.IsData ()))
|
||||
if (m_currentHdr.IsQosData () && m_currentHdr.IsQosBlockAck ())
|
||||
{
|
||||
params.DisableAck ();
|
||||
}
|
||||
else
|
||||
{
|
||||
params.EnableAck ();
|
||||
}
|
||||
if (NeedFragmentation () && ((m_currentHdr.IsQosData () &&
|
||||
!m_currentHdr.IsQosAmsdu ()) ||
|
||||
m_currentHdr.IsData ()) &&
|
||||
(m_blockAckThreshold == 0 ||
|
||||
m_blockAckType == BASIC_BLOCK_ACK))
|
||||
{
|
||||
//With COMPRESSED_BLOCK_ACK fragmentation must be avoided.
|
||||
params.DisableRts ();
|
||||
WifiMacHeader hdr;
|
||||
Ptr<Packet> fragment = GetFragmentPacket (&hdr);
|
||||
@@ -319,7 +409,7 @@ EdcaTxopN::NotifyAccessGranted (void)
|
||||
params.EnableNextData (GetNextFragmentSize ());
|
||||
}
|
||||
m_low->StartTransmission (fragment, &hdr, params,
|
||||
m_transmissionListener);
|
||||
m_transmissionListener);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -328,7 +418,7 @@ EdcaTxopN::NotifyAccessGranted (void)
|
||||
m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (),
|
||||
WifiMacHeader::ADDR1, m_currentHdr.GetAddr1 ()) &&
|
||||
!m_currentHdr.GetAddr1 ().IsBroadcast () &&
|
||||
m_aggregator != 0)
|
||||
m_aggregator != 0 && !m_currentHdr.IsRetry ())
|
||||
{
|
||||
/* here is performed aggregation */
|
||||
Ptr<Packet> currentAggregatedPacket = Create<Packet> ();
|
||||
@@ -338,8 +428,8 @@ EdcaTxopN::NotifyAccessGranted (void)
|
||||
bool aggregated = false;
|
||||
bool isAmsdu = false;
|
||||
Ptr<const Packet> peekedPacket = m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (),
|
||||
WifiMacHeader::ADDR1,
|
||||
m_currentHdr.GetAddr1 ());
|
||||
WifiMacHeader::ADDR1,
|
||||
m_currentHdr.GetAddr1 ());
|
||||
while (peekedPacket != 0)
|
||||
{
|
||||
aggregated = m_aggregator->Aggregate (peekedPacket, currentAggregatedPacket,
|
||||
@@ -379,6 +469,7 @@ EdcaTxopN::NotifyAccessGranted (void)
|
||||
params.DisableNextData ();
|
||||
m_low->StartTransmission (m_currentPacket, &m_currentHdr,
|
||||
params, m_transmissionListener);
|
||||
CompleteTx ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -462,6 +553,27 @@ EdcaTxopN::GotAck (double snr, WifiMode txMode)
|
||||
{
|
||||
m_txOkCallback (m_currentHdr);
|
||||
}
|
||||
|
||||
if (m_currentHdr.IsAction ())
|
||||
{
|
||||
WifiActionHeader actionHdr;
|
||||
Ptr<Packet> p = m_currentPacket->Copy ();
|
||||
p->RemoveHeader (actionHdr);
|
||||
if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK &&
|
||||
actionHdr.GetAction ().blockAck == WifiActionHeader::BLOCK_ACK_DELBA)
|
||||
{
|
||||
MgtDelBaHeader delBa;
|
||||
p->PeekHeader (delBa);
|
||||
if (delBa.IsByOriginator ())
|
||||
{
|
||||
m_baManager->TearDownBlockAck (m_currentHdr.GetAddr1 (), delBa.GetTid ());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_low->DestroyBlockAckAgreement (m_currentHdr.GetAddr1 (), delBa.GetTid ());
|
||||
}
|
||||
}
|
||||
}
|
||||
m_currentPacket = 0;
|
||||
|
||||
m_dcf->ResetCw ();
|
||||
@@ -502,6 +614,20 @@ EdcaTxopN::MissedAck (void)
|
||||
RestartAccessIfNeeded ();
|
||||
}
|
||||
|
||||
void
|
||||
EdcaTxopN::MissedBlockAck (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
MY_DEBUG ("missed block ack");
|
||||
//should i report this to station addressed by ADDR1?
|
||||
MY_DEBUG ("Retransmit block ack request");
|
||||
m_currentHdr.SetRetry ();
|
||||
m_dcf->UpdateFailedCw ();
|
||||
|
||||
m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
|
||||
RestartAccessIfNeeded ();
|
||||
}
|
||||
|
||||
Ptr<MsduAggregator>
|
||||
EdcaTxopN::GetMsduAggregator (void) const
|
||||
{
|
||||
@@ -513,7 +639,7 @@ EdcaTxopN::RestartAccessIfNeeded (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
if ((m_currentPacket != 0 ||
|
||||
!m_queue->IsEmpty ()) &&
|
||||
!m_queue->IsEmpty () || m_baManager->HasPackets ()) &&
|
||||
!m_dcf->IsAccessRequested ())
|
||||
{
|
||||
m_manager->RequestAccess (m_dcf);
|
||||
@@ -525,7 +651,7 @@ EdcaTxopN::StartAccessIfNeeded (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
if (m_currentPacket == 0 &&
|
||||
!m_queue->IsEmpty () &&
|
||||
(!m_queue->IsEmpty () || m_baManager->HasPackets ()) &&
|
||||
!m_dcf->IsAccessRequested ())
|
||||
{
|
||||
m_manager->RequestAccess (m_dcf);
|
||||
@@ -651,6 +777,12 @@ EdcaTxopN::GetFragmentPacket (WifiMacHeader *hdr)
|
||||
return fragment;
|
||||
}
|
||||
|
||||
void
|
||||
EdcaTxopN::SetAccessClass (enum AccessClass ac)
|
||||
{
|
||||
m_ac = ac;
|
||||
}
|
||||
|
||||
Mac48Address
|
||||
EdcaTxopN::MapSrcAddressForAggregation (const WifiMacHeader &hdr)
|
||||
{
|
||||
@@ -687,4 +819,273 @@ EdcaTxopN::SetMsduAggregator (Ptr<MsduAggregator> aggr)
|
||||
m_aggregator = aggr;
|
||||
}
|
||||
|
||||
void
|
||||
EdcaTxopN::PushFront (Ptr<const Packet> packet, const WifiMacHeader &hdr)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << packet << &hdr);
|
||||
WifiMacTrailer fcs;
|
||||
uint32_t fullPacketSize = hdr.GetSerializedSize () + packet->GetSize () + fcs.GetSerializedSize ();
|
||||
WifiRemoteStation *station = GetStation (hdr.GetAddr1 ());
|
||||
station->PrepareForQueue (packet, fullPacketSize);
|
||||
m_queue->PushFront (packet, hdr);
|
||||
StartAccessIfNeeded ();
|
||||
}
|
||||
|
||||
void
|
||||
EdcaTxopN::GotAddBaResponse (const MgtAddBaResponseHeader *respHdr, Mac48Address recipient)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
MY_DEBUG ("received ADDBA response from "<<recipient);
|
||||
uint8_t tid = respHdr->GetTid ();
|
||||
if (m_baManager->ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::PENDING))
|
||||
{
|
||||
if (respHdr->GetStatusCode ().IsSuccess ())
|
||||
{
|
||||
MY_DEBUG ("block ack agreement established with "<<recipient);
|
||||
m_baManager->UpdateAgreement (respHdr, recipient);
|
||||
}
|
||||
else
|
||||
{
|
||||
MY_DEBUG ("discard ADDBA response"<<recipient);
|
||||
m_baManager->NotifyAgreementUnsuccessful (recipient, tid);
|
||||
}
|
||||
}
|
||||
RestartAccessIfNeeded ();
|
||||
}
|
||||
|
||||
void
|
||||
EdcaTxopN::GotDelBaFrame (const MgtDelBaHeader *delBaHdr, Mac48Address recipient)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
MY_DEBUG ("received DELBA frame from="<<recipient);
|
||||
m_baManager->TearDownBlockAck (recipient, delBaHdr->GetTid ());
|
||||
}
|
||||
|
||||
void
|
||||
EdcaTxopN::GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient)
|
||||
{
|
||||
MY_DEBUG ("got block ack from="<<recipient);
|
||||
m_baManager->NotifyGotBlockAck (blockAck, recipient);
|
||||
m_currentPacket = 0;
|
||||
m_dcf->ResetCw ();
|
||||
m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
|
||||
RestartAccessIfNeeded ();
|
||||
}
|
||||
|
||||
void
|
||||
EdcaTxopN::VerifyBlockAck (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
uint8_t tid = m_currentHdr.GetQosTid ();
|
||||
Mac48Address recipient = m_currentHdr.GetAddr1 ();
|
||||
uint16_t sequence = m_currentHdr.GetSequenceNumber ();
|
||||
if (m_baManager->ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::INACTIVE))
|
||||
{
|
||||
m_baManager->SwitchToBlockAckIfNeeded (recipient, tid, sequence);
|
||||
}
|
||||
if (m_baManager->ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED))
|
||||
{
|
||||
m_currentHdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EdcaTxopN::CompleteTx (void)
|
||||
{
|
||||
if (m_currentHdr.IsQosData () && m_currentHdr.IsQosBlockAck ())
|
||||
{
|
||||
if (!m_currentHdr.IsRetry ())
|
||||
{
|
||||
m_baManager->StorePacket (m_currentPacket, m_currentHdr, m_currentPacketTimestamp);
|
||||
}
|
||||
m_baManager->NotifyMpduTransmission (m_currentHdr.GetAddr1 (), m_currentHdr.GetQosTid ());
|
||||
//we are not waiting for an ack: transmission is completed
|
||||
m_currentPacket = 0;
|
||||
m_dcf->ResetCw ();
|
||||
m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
|
||||
StartAccessIfNeeded ();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
EdcaTxopN::SetupBlockAckIfNeeded ()
|
||||
{
|
||||
uint8_t tid = m_currentHdr.GetQosTid ();
|
||||
Mac48Address recipient = m_currentHdr.GetAddr1 ();
|
||||
|
||||
uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, WifiMacHeader::ADDR1, recipient);
|
||||
|
||||
if (packets >= m_blockAckThreshold)
|
||||
{
|
||||
/* Block ack setup */
|
||||
uint16_t startingSequence = m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, recipient);
|
||||
SendAddBaRequest (recipient, tid, startingSequence, m_blockAckInactivityTimeout, true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
EdcaTxopN::SendBlockAckRequest (const struct Bar &bar)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
WifiMacHeader hdr;
|
||||
hdr.SetType (WIFI_MAC_CTL_BACKREQ);
|
||||
hdr.SetAddr1 (bar.recipient);
|
||||
hdr.SetAddr2 (m_low->GetAddress ());
|
||||
hdr.SetAddr3 (m_low->GetBssid ());
|
||||
hdr.SetDsNotTo ();
|
||||
hdr.SetDsNotFrom ();
|
||||
hdr.SetNoRetry ();
|
||||
hdr.SetNoMoreFragments ();
|
||||
|
||||
m_currentPacket = bar.bar;
|
||||
m_currentHdr = hdr;
|
||||
|
||||
MacLowTransmissionParameters params;
|
||||
params.DisableRts ();
|
||||
params.DisableNextData ();
|
||||
params.DisableOverrideDurationId ();
|
||||
if (bar.immediate)
|
||||
{
|
||||
if (m_blockAckType == BASIC_BLOCK_ACK)
|
||||
{
|
||||
params.EnableBasicBlockAck ();
|
||||
}
|
||||
else if (m_blockAckType == COMPRESSED_BLOCK_ACK)
|
||||
{
|
||||
params.EnableCompressedBlockAck ();
|
||||
}
|
||||
else if (m_blockAckType == MULTI_TID_BLOCK_ACK)
|
||||
{
|
||||
NS_FATAL_ERROR ("Multi-tid block ack is not supported");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Delayed block ack
|
||||
params.EnableAck ();
|
||||
}
|
||||
m_low->StartTransmission (m_currentPacket, &m_currentHdr, params, m_transmissionListener);
|
||||
}
|
||||
|
||||
void
|
||||
EdcaTxopN::CompleteConfig (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_baManager->SetTxMiddle (m_txMiddle);
|
||||
m_low->RegisterBlockAckListenerForAc (m_ac, m_blockAckListener);
|
||||
m_baManager->SetBlockAckInactivityCallback (MakeCallback (&EdcaTxopN::SendDelbaFrame, this));
|
||||
}
|
||||
|
||||
void
|
||||
EdcaTxopN::SetBlockAckThreshold (uint8_t threshold)
|
||||
{
|
||||
m_blockAckThreshold = threshold;
|
||||
m_baManager->SetBlockAckThreshold (threshold);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
EdcaTxopN::GetBlockAckThreshold (void) const
|
||||
{
|
||||
return m_blockAckThreshold;
|
||||
}
|
||||
|
||||
void
|
||||
EdcaTxopN::SendAddBaRequest (Mac48Address dest, uint8_t tid, uint16_t startSeq,
|
||||
uint16_t timeout, bool immediateBAck)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
MY_DEBUG ("sent ADDBA request to "<<dest);
|
||||
WifiMacHeader hdr;
|
||||
hdr.SetAction ();
|
||||
hdr.SetAddr1 (dest);
|
||||
hdr.SetAddr2 (m_low->GetAddress ());
|
||||
hdr.SetAddr3 (m_low->GetAddress ());
|
||||
hdr.SetDsNotTo ();
|
||||
hdr.SetDsNotFrom ();
|
||||
|
||||
WifiActionHeader actionHdr;
|
||||
WifiActionHeader::ActionValue action;
|
||||
action.blockAck = WifiActionHeader::BLOCK_ACK_ADDBA_REQUEST;
|
||||
actionHdr.SetAction (WifiActionHeader::BLOCK_ACK, action);
|
||||
|
||||
Ptr<Packet> packet = Create<Packet> ();
|
||||
/*Setting ADDBARequest header*/
|
||||
MgtAddBaRequestHeader reqHdr;
|
||||
reqHdr.SetAmsduSupport (true);
|
||||
if (immediateBAck)
|
||||
{
|
||||
reqHdr.SetImmediateBlockAck ();
|
||||
}
|
||||
else
|
||||
{
|
||||
reqHdr.SetDelayedBlockAck ();
|
||||
}
|
||||
reqHdr.SetTid (tid);
|
||||
/* For now we don't use buffer size field in the ADDBA request frame. The recipient
|
||||
* will choose how many packets it can receive under block ack.
|
||||
*/
|
||||
reqHdr.SetBufferSize (0);
|
||||
reqHdr.SetTimeout (timeout);
|
||||
reqHdr.SetStartingSequence (startSeq);
|
||||
|
||||
m_baManager->CreateAgreement (&reqHdr, dest);
|
||||
|
||||
packet->AddHeader (reqHdr);
|
||||
packet->AddHeader (actionHdr);
|
||||
|
||||
m_currentPacket = packet;
|
||||
m_currentHdr = hdr;
|
||||
|
||||
uint16_t sequence = m_txMiddle->GetNextSequenceNumberfor (&m_currentHdr);
|
||||
m_currentHdr.SetSequenceNumber (sequence);
|
||||
m_currentHdr.SetFragmentNumber (0);
|
||||
m_currentHdr.SetNoMoreFragments ();
|
||||
m_currentHdr.SetNoRetry ();
|
||||
|
||||
MacLowTransmissionParameters params;
|
||||
params.EnableAck ();
|
||||
params.DisableRts ();
|
||||
params.DisableNextData ();
|
||||
params.DisableOverrideDurationId ();
|
||||
|
||||
m_low->StartTransmission (m_currentPacket, &m_currentHdr, params,
|
||||
m_transmissionListener);
|
||||
}
|
||||
|
||||
void
|
||||
EdcaTxopN::SendDelbaFrame (Mac48Address addr, uint8_t tid, bool byOriginator)
|
||||
{
|
||||
WifiMacHeader hdr;
|
||||
hdr.SetAction ();
|
||||
hdr.SetAddr1 (addr);
|
||||
hdr.SetAddr2 (m_low->GetAddress ());
|
||||
hdr.SetAddr3 (m_low->GetAddress ());
|
||||
hdr.SetDsNotTo ();
|
||||
hdr.SetDsNotFrom ();
|
||||
|
||||
MgtDelBaHeader delbaHdr;
|
||||
delbaHdr.SetTid (tid);
|
||||
if (byOriginator)
|
||||
{
|
||||
delbaHdr.SetByOriginator ();
|
||||
}
|
||||
else
|
||||
{
|
||||
delbaHdr.SetByRecipient ();
|
||||
}
|
||||
|
||||
WifiActionHeader actionHdr;
|
||||
WifiActionHeader::ActionValue action;
|
||||
action.blockAck = WifiActionHeader::BLOCK_ACK_DELBA;
|
||||
actionHdr.SetAction (WifiActionHeader::BLOCK_ACK, action);
|
||||
|
||||
Ptr<Packet> packet = Create<Packet> ();
|
||||
packet->AddHeader (delbaHdr);
|
||||
packet->AddHeader (actionHdr);
|
||||
|
||||
PushFront (packet, hdr);
|
||||
}
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "wifi-mac-header.h"
|
||||
#include "qos-utils.h"
|
||||
#include "dcf.h"
|
||||
#include "ctrl-headers.h"
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
@@ -44,7 +45,12 @@ class MacTxMiddle;
|
||||
class WifiMacParameters;
|
||||
class WifiMacQueue;
|
||||
class RandomStream;
|
||||
class QosBlockedDestinations;
|
||||
class MsduAggregator;
|
||||
class MgtAddBaResponseHeader;
|
||||
class BlockAckManager;
|
||||
class MgtDelBaHeader;
|
||||
|
||||
|
||||
/* This queue contains packets for a particular access class.
|
||||
* possibles access classes are:
|
||||
@@ -110,6 +116,10 @@ public:
|
||||
void GotCts (double snr, WifiMode txMode);
|
||||
void MissedCts (void);
|
||||
void GotAck (double snr, WifiMode txMode);
|
||||
void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient);
|
||||
void MissedBlockAck (void);
|
||||
void GotAddBaResponse (const MgtAddBaResponseHeader *respHdr, Mac48Address recipient);
|
||||
void GotDelBaFrame (const MgtDelBaHeader *delBaHdr, Mac48Address recipient);
|
||||
void MissedAck (void);
|
||||
void StartNext (void);
|
||||
void Cancel (void);
|
||||
@@ -128,8 +138,14 @@ public:
|
||||
void NextFragment (void);
|
||||
Ptr<Packet> GetFragmentPacket (WifiMacHeader *hdr);
|
||||
|
||||
void SetAccessClass (enum AccessClass ac);
|
||||
void Queue (Ptr<const Packet> packet, const WifiMacHeader &hdr);
|
||||
void SetMsduAggregator (Ptr<MsduAggregator> aggr);
|
||||
void PushFront (Ptr<const Packet> packet, const WifiMacHeader &hdr);
|
||||
void CompleteConfig (void);
|
||||
void SetBlockAckThreshold (uint8_t threshold);
|
||||
uint8_t GetBlockAckThreshold (void) const;
|
||||
void SendDelbaFrame (Mac48Address addr, uint8_t tid, bool byOriginator);
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -145,9 +161,33 @@ private:
|
||||
Mac48Address MapDestAddressForAggregation (const WifiMacHeader &hdr);
|
||||
EdcaTxopN &operator = (const EdcaTxopN &);
|
||||
EdcaTxopN (const EdcaTxopN &);
|
||||
|
||||
/* If number of packets in the queue reaches m_blockAckThreshold value, an ADDBARequest frame
|
||||
* is sent to destination in order to setup a block ack.
|
||||
*/
|
||||
bool SetupBlockAckIfNeeded ();
|
||||
/* Sends an ADDBARequest to establish a block ack agreement with sta
|
||||
* addressed by <i>recipient</i> for tid <i>tid</i>.
|
||||
*/
|
||||
void SendAddBaRequest (Mac48Address recipient, uint8_t tid, uint16_t startSeq,
|
||||
uint16_t timeout, bool immediateBAck);
|
||||
/* After that all packets, for which a block ack agreement was established, have been
|
||||
* transmitted, we have to send a block ack request.
|
||||
*/
|
||||
void SendBlockAckRequest (const struct Bar &bar);
|
||||
/* For now is typically invoked to complete transmission of a packets sent with ack policy
|
||||
* Block Ack: the packet is buffered and dcf is reset.
|
||||
*/
|
||||
void CompleteTx (void);
|
||||
/* Verifies if dequeued packet has to be transmitted with ack policy Block Ack. This happens
|
||||
* if an established block ack agreement exists with the receiver.
|
||||
*/
|
||||
void VerifyBlockAck (void);
|
||||
|
||||
AccessClass m_ac;
|
||||
class Dcf;
|
||||
class TransmissionListener;
|
||||
class BlockAckEventListener;
|
||||
friend class Dcf;
|
||||
friend class TransmissionListener;
|
||||
Dcf *m_dcf;
|
||||
@@ -158,6 +198,7 @@ private:
|
||||
Ptr<MacLow> m_low;
|
||||
MacTxMiddle *m_txMiddle;
|
||||
TransmissionListener *m_transmissionListener;
|
||||
BlockAckEventListener *m_blockAckListener;
|
||||
RandomStream *m_rng;
|
||||
Ptr<WifiRemoteStationManager> m_stationManager;
|
||||
uint8_t m_fragmentNumber;
|
||||
@@ -170,6 +211,15 @@ private:
|
||||
WifiMacHeader m_currentHdr;
|
||||
Ptr<MsduAggregator> m_aggregator;
|
||||
TypeOfStation m_typeOfStation;
|
||||
QosBlockedDestinations *m_qosBlockedDestinations;
|
||||
BlockAckManager *m_baManager;
|
||||
/*
|
||||
* Represents the minimun number of packets for use of block ack.
|
||||
*/
|
||||
uint8_t m_blockAckThreshold;
|
||||
enum BlockAckType m_blockAckType;
|
||||
Time m_currentPacketTimestamp;
|
||||
uint16_t m_blockAckInactivityTimeout;
|
||||
};
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
+604
-3
@@ -1,6 +1,7 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005,2006 INRIA
|
||||
* Copyright (c) 2009 MIRKO BANCHI
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,6 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
* Author: Mirko Banchi <mk.banchi@gmail.com>
|
||||
*/
|
||||
|
||||
#include "ns3/assert.h"
|
||||
@@ -28,6 +30,8 @@
|
||||
#include "mac-low.h"
|
||||
#include "wifi-phy.h"
|
||||
#include "wifi-mac-trailer.h"
|
||||
#include "qos-utils.h"
|
||||
#include "edca-txop-n.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("MacLow");
|
||||
|
||||
@@ -110,11 +114,23 @@ MacLowTransmissionListener::MacLowTransmissionListener ()
|
||||
{}
|
||||
MacLowTransmissionListener::~MacLowTransmissionListener ()
|
||||
{}
|
||||
void
|
||||
MacLowTransmissionListener::GotBlockAck (const CtrlBAckResponseHeader *blockAck,
|
||||
Mac48Address source)
|
||||
{}
|
||||
void
|
||||
MacLowTransmissionListener::MissedBlockAck (void)
|
||||
{}
|
||||
MacLowDcfListener::MacLowDcfListener ()
|
||||
{}
|
||||
MacLowDcfListener::~MacLowDcfListener ()
|
||||
{}
|
||||
|
||||
MacLowBlockAckEventListener::MacLowBlockAckEventListener ()
|
||||
{}
|
||||
MacLowBlockAckEventListener::~MacLowBlockAckEventListener ()
|
||||
{}
|
||||
|
||||
MacLowTransmissionParameters::MacLowTransmissionParameters ()
|
||||
: m_nextSize (0),
|
||||
m_waitAck (ACK_NONE),
|
||||
@@ -146,6 +162,21 @@ MacLowTransmissionParameters::EnableSuperFastAck (void)
|
||||
{
|
||||
m_waitAck = ACK_SUPER_FAST;
|
||||
}
|
||||
void
|
||||
MacLowTransmissionParameters::EnableBasicBlockAck (void)
|
||||
{
|
||||
m_waitAck = BLOCK_ACK_BASIC;
|
||||
}
|
||||
void
|
||||
MacLowTransmissionParameters::EnableCompressedBlockAck (void)
|
||||
{
|
||||
m_waitAck = BLOCK_ACK_COMPRESSED;
|
||||
}
|
||||
void
|
||||
MacLowTransmissionParameters::EnableMultiTidBlockAck (void)
|
||||
{
|
||||
m_waitAck = BLOCK_ACK_MULTI_TID;
|
||||
}
|
||||
void
|
||||
MacLowTransmissionParameters::EnableFastAck (void)
|
||||
{
|
||||
@@ -191,6 +222,21 @@ MacLowTransmissionParameters::MustWaitSuperFastAck (void) const
|
||||
{
|
||||
return (m_waitAck == ACK_SUPER_FAST);
|
||||
}
|
||||
bool
|
||||
MacLowTransmissionParameters::MustWaitBasicBlockAck (void) const
|
||||
{
|
||||
return (m_waitAck == BLOCK_ACK_BASIC)?true:false;
|
||||
}
|
||||
bool
|
||||
MacLowTransmissionParameters::MustWaitCompressedBlockAck (void) const
|
||||
{
|
||||
return (m_waitAck == BLOCK_ACK_COMPRESSED)?true:false;
|
||||
}
|
||||
bool
|
||||
MacLowTransmissionParameters::MustWaitMultiTidBlockAck (void) const
|
||||
{
|
||||
return (m_waitAck == BLOCK_ACK_MULTI_TID)?true:false;
|
||||
}
|
||||
bool
|
||||
MacLowTransmissionParameters::MustSendRts (void) const
|
||||
{
|
||||
@@ -239,6 +285,15 @@ std::ostream &operator << (std::ostream &os, const MacLowTransmissionParameters
|
||||
case MacLowTransmissionParameters::ACK_SUPER_FAST:
|
||||
os << "super-fast";
|
||||
break;
|
||||
case MacLowTransmissionParameters::BLOCK_ACK_BASIC:
|
||||
os << "basic-block-ack";
|
||||
break;
|
||||
case MacLowTransmissionParameters::BLOCK_ACK_COMPRESSED:
|
||||
os << "compressed-block-ack";
|
||||
break;
|
||||
case MacLowTransmissionParameters::BLOCK_ACK_MULTI_TID:
|
||||
os << "multi-tid-block-ack";
|
||||
break;
|
||||
}
|
||||
os << "]";
|
||||
return os;
|
||||
@@ -273,6 +328,7 @@ MacLow::MacLow ()
|
||||
m_fastAckTimeoutEvent (),
|
||||
m_superFastAckTimeoutEvent (),
|
||||
m_fastAckFailedTimeoutEvent (),
|
||||
m_blockAckTimeoutEvent (),
|
||||
m_ctsTimeoutEvent (),
|
||||
m_sendCtsEvent (),
|
||||
m_sendAckEvent (),
|
||||
@@ -307,6 +363,7 @@ MacLow::DoDispose (void)
|
||||
m_fastAckTimeoutEvent.Cancel ();
|
||||
m_superFastAckTimeoutEvent.Cancel ();
|
||||
m_fastAckFailedTimeoutEvent.Cancel ();
|
||||
m_blockAckTimeoutEvent.Cancel ();
|
||||
m_ctsTimeoutEvent.Cancel ();
|
||||
m_sendCtsEvent.Cancel ();
|
||||
m_sendAckEvent.Cancel ();
|
||||
@@ -343,6 +400,11 @@ MacLow::CancelAllEvents (void)
|
||||
m_fastAckFailedTimeoutEvent.Cancel ();
|
||||
oneRunning = true;
|
||||
}
|
||||
if (m_blockAckTimeoutEvent.IsRunning ())
|
||||
{
|
||||
m_blockAckTimeoutEvent.Cancel ();
|
||||
oneRunning = true;
|
||||
}
|
||||
if (m_ctsTimeoutEvent.IsRunning ())
|
||||
{
|
||||
m_ctsTimeoutEvent.Cancel ();
|
||||
@@ -399,6 +461,16 @@ MacLow::SetAckTimeout (Time ackTimeout)
|
||||
{
|
||||
m_ackTimeout = ackTimeout;
|
||||
}
|
||||
void
|
||||
MacLow::SetBasicBlockAckTimeout (Time blockAckTimeout)
|
||||
{
|
||||
m_basicBlockAckTimeout = blockAckTimeout;
|
||||
}
|
||||
void
|
||||
MacLow::SetCompressedBlockAckTimeout (Time blockAckTimeout)
|
||||
{
|
||||
m_compressedBlockAckTimeout = blockAckTimeout;
|
||||
}
|
||||
void
|
||||
MacLow::SetCtsTimeout (Time ctsTimeout)
|
||||
{
|
||||
@@ -434,6 +506,16 @@ MacLow::GetAckTimeout (void) const
|
||||
{
|
||||
return m_ackTimeout;
|
||||
}
|
||||
Time
|
||||
MacLow::GetBasicBlockAckTimeout () const
|
||||
{
|
||||
return m_basicBlockAckTimeout;
|
||||
}
|
||||
Time
|
||||
MacLow::GetCompressedBlockAckTimeout () const
|
||||
{
|
||||
return m_compressedBlockAckTimeout;
|
||||
}
|
||||
Time
|
||||
MacLow::GetCtsTimeout (void) const
|
||||
{
|
||||
@@ -649,6 +731,53 @@ MacLow::ReceiveOk (Ptr<Packet> packet, double rxSnr, WifiMode txMode, WifiPreamb
|
||||
&MacLow::WaitSifsAfterEndTx, this);
|
||||
}
|
||||
}
|
||||
else if (hdr.IsBlockAck () && hdr.GetAddr1 () == m_self &&
|
||||
(m_txParams.MustWaitBasicBlockAck () || m_txParams.MustWaitCompressedBlockAck ()) &&
|
||||
m_blockAckTimeoutEvent.IsRunning ())
|
||||
{
|
||||
NS_LOG_DEBUG ("got block ack from "<<hdr.GetAddr2 ());
|
||||
CtrlBAckResponseHeader blockAck;
|
||||
packet->RemoveHeader (blockAck);
|
||||
m_blockAckTimeoutEvent.Cancel ();
|
||||
m_listener->GotBlockAck (&blockAck, hdr.GetAddr2 ());
|
||||
}
|
||||
else if (hdr.IsBlockAckReq () && hdr.GetAddr1 () == m_self)
|
||||
{
|
||||
CtrlBAckRequestHeader blockAckReq;
|
||||
packet->RemoveHeader (blockAckReq);
|
||||
if (!blockAckReq.IsMultiTid ())
|
||||
{
|
||||
AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), blockAckReq.GetTidInfo ()));
|
||||
if (it != m_bAckAgreements.end ())
|
||||
{
|
||||
NS_ASSERT (m_sendAckEvent.IsExpired ());
|
||||
/* See section 11.5.3 in IEEE802.11 for mean of this timer */
|
||||
ResetBlockAckInactivityTimerIfNeeded (it->second.first);
|
||||
if ((*it).second.first.IsImmediateBlockAck ())
|
||||
{
|
||||
NS_LOG_DEBUG ("rx blockAckRequest/sendImmediateBlockAck from="<< hdr.GetAddr2 ());
|
||||
m_sendAckEvent = Simulator::Schedule (GetSifs (),
|
||||
&MacLow::SendBlockAckAfterBlockAckRequest, this,
|
||||
blockAckReq,
|
||||
hdr.GetAddr2 (),
|
||||
hdr.GetDuration (),
|
||||
txMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Delayed block ack not supported.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_DEBUG ("There's not a valid agreement for this block ack request.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
|
||||
}
|
||||
}
|
||||
else if (hdr.IsCtl ())
|
||||
{
|
||||
NS_LOG_DEBUG ("rx drop " << hdr.GetTypeString ());
|
||||
@@ -658,7 +787,50 @@ MacLow::ReceiveOk (Ptr<Packet> packet, double rxSnr, WifiMode txMode, WifiPreamb
|
||||
WifiRemoteStation *station = GetStation (hdr.GetAddr2 ());
|
||||
station->ReportRxOk (rxSnr, txMode);
|
||||
|
||||
if (hdr.IsQosData () && hdr.IsQosNoAck ())
|
||||
if (hdr.IsQosData () && StoreMpduIfNeeded (packet, hdr))
|
||||
{
|
||||
/* From section 9.10.4 in IEEE802.11:
|
||||
Upon the receipt of a QoS data frame from the originator for which
|
||||
the Block Ack agreement exists, the recipient shall buffer the MSDU
|
||||
regardless of the value of the Ack Policy subfield within the
|
||||
QoS Control field of the QoS data frame. */
|
||||
if (hdr.IsQosAck ())
|
||||
{
|
||||
AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), hdr.GetQosTid ()));
|
||||
RxCompleteBufferedPacketsWithSmallerSequence (it->second.first.GetStartingSequence (),
|
||||
hdr.GetAddr2 (), hdr.GetQosTid ());
|
||||
RxCompleteBufferedPackets (hdr.GetAddr2 (), hdr.GetQosTid ());
|
||||
NS_ASSERT (m_sendAckEvent.IsExpired ());
|
||||
m_sendAckEvent = Simulator::Schedule (GetSifs (),
|
||||
&MacLow::SendAckAfterData, this,
|
||||
hdr.GetAddr2 (),
|
||||
hdr.GetDuration (),
|
||||
txMode,
|
||||
rxSnr);
|
||||
}
|
||||
else if (hdr.IsQosBlockAck ())
|
||||
{
|
||||
AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), hdr.GetQosTid ()));
|
||||
/* See section 11.5.3 in IEEE802.11 for mean of this timer */
|
||||
ResetBlockAckInactivityTimerIfNeeded (it->second.first);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (hdr.IsQosData () && hdr.IsQosBlockAck ())
|
||||
{
|
||||
/* This happens if a packet with ack policy Block Ack is received and a block ack
|
||||
agreement for that packet doesn't exist.
|
||||
|
||||
From section 11.5.3 in IEEE802.11e:
|
||||
When a recipient does not have an active Block ack for a TID, but receives
|
||||
data MPDUs with the Ack Policy subfield set to Block Ack, it shall discard
|
||||
them and shall send a DELBA frame using the normal access
|
||||
mechanisms. */
|
||||
AccessClass ac = QosUtilsMapTidToAc (hdr.GetQosTid ());
|
||||
m_edcaListeners[ac]->BlockAckInactivityTimeout (hdr.GetAddr2 (), hdr.GetQosTid ());
|
||||
return;
|
||||
}
|
||||
else if (hdr.IsQosData () && hdr.IsQosNoAck ())
|
||||
{
|
||||
NS_LOG_DEBUG ("rx unicast/noAck from="<<hdr.GetAddr2 ());
|
||||
}
|
||||
@@ -706,6 +878,27 @@ MacLow::GetAckSize (void) const
|
||||
ack.SetType (WIFI_MAC_CTL_ACK);
|
||||
return ack.GetSize () + 4;
|
||||
}
|
||||
uint32_t
|
||||
MacLow::GetBlockAckSize (enum BlockAckType type) const
|
||||
{
|
||||
WifiMacHeader hdr;
|
||||
hdr.SetType (WIFI_MAC_CTL_BACKRESP);
|
||||
CtrlBAckResponseHeader blockAck;
|
||||
if (type == BASIC_BLOCK_ACK)
|
||||
{
|
||||
blockAck.SetType (BASIC_BLOCK_ACK);
|
||||
}
|
||||
else if (type == COMPRESSED_BLOCK_ACK)
|
||||
{
|
||||
blockAck.SetType (COMPRESSED_BLOCK_ACK);
|
||||
}
|
||||
else if (type == MULTI_TID_BLOCK_ACK)
|
||||
{
|
||||
//Not implemented
|
||||
NS_ASSERT (false);
|
||||
}
|
||||
return hdr.GetSize () + blockAck.GetSerializedSize () + 4;
|
||||
}
|
||||
uint32_t
|
||||
MacLow::GetRtsSize (void) const
|
||||
{
|
||||
@@ -720,6 +913,19 @@ MacLow::GetAckDuration (Mac48Address to, WifiMode dataTxMode) const
|
||||
return m_phy->CalculateTxDuration (GetAckSize (), ackMode, WIFI_PREAMBLE_LONG);
|
||||
}
|
||||
Time
|
||||
MacLow::GetBlockAckDuration (Mac48Address to, WifiMode blockAckReqTxMode, enum BlockAckType type) const
|
||||
{
|
||||
/*
|
||||
* For immediate BlockAck we should transmit the frame with the same WifiMode
|
||||
* as the BlockAckReq.
|
||||
*
|
||||
* from section 9.6 in IEEE802.11e:
|
||||
* The BlockAck control frame shall be sent at the same rate and modulation class as
|
||||
* the BlockAckReq frame if it is sent in response to a BlockAckReq frame.
|
||||
*/
|
||||
return m_phy->CalculateTxDuration (GetBlockAckSize (type), blockAckReqTxMode, WIFI_PREAMBLE_LONG);
|
||||
}
|
||||
Time
|
||||
MacLow::GetCtsDuration (Mac48Address to, WifiMode rtsTxMode) const
|
||||
{
|
||||
WifiMode ctsMode = GetCtsTxModeForRts (to, rtsTxMode);
|
||||
@@ -977,6 +1183,18 @@ MacLow::FastAckTimeout (void)
|
||||
}
|
||||
}
|
||||
void
|
||||
MacLow::BlockAckTimeout (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_DEBUG ("block ack timeout");
|
||||
|
||||
WifiRemoteStation *station = GetStation (m_currentHdr.GetAddr1 ());
|
||||
station->ReportDataFailed ();
|
||||
MacLowTransmissionListener *listener = m_listener;
|
||||
m_listener = 0;
|
||||
listener->MissedBlockAck ();
|
||||
}
|
||||
void
|
||||
MacLow::SuperFastAckTimeout ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
@@ -1069,7 +1287,19 @@ MacLow::StartDataTxTimers (void)
|
||||
NotifyAckTimeoutStartNow (timerDelay);
|
||||
m_superFastAckTimeoutEvent = Simulator::Schedule (timerDelay,
|
||||
&MacLow::SuperFastAckTimeout, this);
|
||||
}
|
||||
}
|
||||
else if (m_txParams.MustWaitBasicBlockAck ())
|
||||
{
|
||||
Time timerDelay = txDuration + GetBasicBlockAckTimeout ();
|
||||
NS_ASSERT (m_blockAckTimeoutEvent.IsExpired ());
|
||||
m_blockAckTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::BlockAckTimeout, this);
|
||||
}
|
||||
else if (m_txParams.MustWaitCompressedBlockAck ())
|
||||
{
|
||||
Time timerDelay = txDuration + GetCompressedBlockAckTimeout ();
|
||||
NS_ASSERT (m_blockAckTimeoutEvent.IsExpired ());
|
||||
m_blockAckTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::BlockAckTimeout, this);
|
||||
}
|
||||
else if (m_txParams.HasNextPacket ())
|
||||
{
|
||||
Time delay = txDuration + GetSifs ();
|
||||
@@ -1098,7 +1328,17 @@ MacLow::SendDataPacket (void)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_txParams.MustWaitAck ())
|
||||
if (m_txParams.MustWaitBasicBlockAck ())
|
||||
{
|
||||
duration += GetSifs ();
|
||||
duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), dataTxMode, BASIC_BLOCK_ACK);
|
||||
}
|
||||
else if (m_txParams.MustWaitCompressedBlockAck ())
|
||||
{
|
||||
duration += GetSifs ();
|
||||
duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), dataTxMode, COMPRESSED_BLOCK_ACK);
|
||||
}
|
||||
else if (m_txParams.MustWaitAck ())
|
||||
{
|
||||
duration += GetSifs ();
|
||||
duration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxMode);
|
||||
@@ -1255,4 +1495,365 @@ MacLow::SendAckAfterData (Mac48Address source, Time duration, WifiMode dataTxMod
|
||||
ForwardDown (packet, &ack, ackTxMode);
|
||||
}
|
||||
|
||||
bool
|
||||
MacLow::StoreMpduIfNeeded (Ptr<Packet> packet, WifiMacHeader hdr)
|
||||
{
|
||||
AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), hdr.GetQosTid ()));
|
||||
if (it != m_bAckAgreements.end ())
|
||||
{
|
||||
WifiMacTrailer fcs;
|
||||
packet->RemoveTrailer (fcs);
|
||||
BufferedPacket bufferedPacket (packet, hdr);
|
||||
|
||||
uint16_t endSequence = ((*it).second.first.GetStartingSequence () + 2047) % 4096;
|
||||
uint16_t mappedSeqControl = QosUtilsMapSeqControlToUniqueInteger (hdr.GetSequenceControl () ,endSequence);
|
||||
|
||||
BufferedPacketI i = (*it).second.second.begin ();
|
||||
for (; i != (*it).second.second.end () &&
|
||||
QosUtilsMapSeqControlToUniqueInteger ((*i).second.GetSequenceControl (), endSequence) < mappedSeqControl; i++);
|
||||
(*it).second.second.insert (i, bufferedPacket);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
MacLow::CreateBlockAckAgreement (const MgtAddBaResponseHeader *respHdr, Mac48Address originator,
|
||||
uint16_t startingSeq)
|
||||
{
|
||||
uint8_t tid = respHdr->GetTid ();
|
||||
BlockAckAgreement agreement (originator, tid);
|
||||
if (respHdr->IsImmediateBlockAck ())
|
||||
{
|
||||
agreement.SetImmediateBlockAck ();
|
||||
}
|
||||
else
|
||||
{
|
||||
agreement.SetDelayedBlockAck ();
|
||||
}
|
||||
agreement.SetAmsduSupport (respHdr->IsAmsduSupported ());
|
||||
agreement.SetBufferSize (respHdr->GetBufferSize ());
|
||||
agreement.SetTimeout (respHdr->GetTimeout ());
|
||||
agreement.SetStartingSequence (startingSeq);
|
||||
|
||||
std::list<BufferedPacket> buffer (0);
|
||||
AgreementKey key (originator, respHdr->GetTid ());
|
||||
AgreementValue value (agreement, buffer);
|
||||
m_bAckAgreements.insert (std::make_pair (key, value));
|
||||
|
||||
if (respHdr->GetTimeout () != 0)
|
||||
{
|
||||
AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, respHdr->GetTid ()));
|
||||
Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
|
||||
|
||||
AccessClass ac = QosUtilsMapTidToAc (agreement.GetTid ());
|
||||
|
||||
it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
|
||||
&MacLowBlockAckEventListener::BlockAckInactivityTimeout,
|
||||
m_edcaListeners[ac],
|
||||
originator, tid);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacLow::DestroyBlockAckAgreement (Mac48Address originator, uint8_t tid)
|
||||
{
|
||||
AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid));
|
||||
if (it != m_bAckAgreements.end ())
|
||||
{
|
||||
RxCompleteBufferedPacketsWithSmallerSequence (it->second.first.GetStartingSequence (), originator, tid);
|
||||
RxCompleteBufferedPackets (originator, tid);
|
||||
m_bAckAgreements.erase (it);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacLow::RxCompleteBufferedPacketsWithSmallerSequence (uint16_t seq, Mac48Address originator, uint8_t tid)
|
||||
{
|
||||
AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid));
|
||||
if (it != m_bAckAgreements.end ())
|
||||
{
|
||||
BufferedPacketI i = (*it).second.second.begin ();
|
||||
uint16_t endSequence = ((*it).second.first.GetStartingSequence () + 2047) % 4096;
|
||||
uint16_t mappedStart = QosUtilsMapSeqControlToUniqueInteger (seq, endSequence);
|
||||
uint16_t guard = (*it).second.first.GetStartingSequence ();
|
||||
BufferedPacketI last = (*it).second.second.begin ();
|
||||
|
||||
for (; i != (*it).second.second.end () &&
|
||||
QosUtilsMapSeqControlToUniqueInteger ((*i).second.GetSequenceNumber (), endSequence) < mappedStart;)
|
||||
{
|
||||
while (i != (*it).second.second.end () && guard == (*i).second.GetSequenceControl ())
|
||||
{
|
||||
if (!(*i).second.IsMoreFragments ())
|
||||
{
|
||||
while (last != i)
|
||||
{
|
||||
m_rxCallback ((*last).first, &(*last).second);
|
||||
last++;
|
||||
}
|
||||
m_rxCallback ((*last).first, &(*last).second);
|
||||
last++;
|
||||
}
|
||||
guard = (*i).second.IsMoreFragments () ? (guard + 1) : ((guard + 16) & 0xfff0);
|
||||
}
|
||||
/* go to next packet */
|
||||
while (i != (*it).second.second.end () && ((guard >> 4) & 0x0fff) == (*i).second.GetSequenceNumber ())
|
||||
{
|
||||
i++;
|
||||
}
|
||||
if (i != (*it).second.second.end ())
|
||||
{
|
||||
guard = (*i).second.GetSequenceControl () & 0xfff0;
|
||||
last = i;
|
||||
}
|
||||
}
|
||||
(*it).second.second.erase ((*it).second.second.begin (), i);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacLow::RxCompleteBufferedPackets (Mac48Address originator, uint8_t tid)
|
||||
{
|
||||
AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid));
|
||||
if (it != m_bAckAgreements.end ())
|
||||
{
|
||||
uint16_t startingSeqCtrl = ((*it).second.first.GetStartingSequence ()<<4) & 0xfff0;
|
||||
uint16_t guard = startingSeqCtrl;
|
||||
|
||||
BufferedPacketI lastComplete = (*it).second.second.begin ();
|
||||
BufferedPacketI i = (*it).second.second.begin ();
|
||||
for (;i != (*it).second.second.end() && guard == (*i).second.GetSequenceControl (); i++)
|
||||
{
|
||||
if (!(*i).second.IsMoreFragments ())
|
||||
{
|
||||
while (lastComplete != i)
|
||||
{
|
||||
m_rxCallback ((*lastComplete).first, &(*lastComplete).second);
|
||||
lastComplete++;
|
||||
}
|
||||
m_rxCallback ((*lastComplete).first, &(*lastComplete).second);
|
||||
lastComplete++;
|
||||
}
|
||||
guard = (*i).second.IsMoreFragments () ? (guard + 1) : ((guard + 16) & 0xfff0);
|
||||
}
|
||||
(*it).second.first.SetStartingSequence ((guard>>4)&0x0fff);
|
||||
/* All packets already forwarded to WifiMac must be removed from buffer:
|
||||
[begin (), lastComplete) */
|
||||
(*it).second.second.erase ((*it).second.second.begin (), lastComplete);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacLow::SendBlockAckResponse (const CtrlBAckResponseHeader* blockAck, Mac48Address originator, bool immediate,
|
||||
Time duration, WifiMode blockAckReqTxMode)
|
||||
{
|
||||
Ptr<Packet> packet = Create<Packet> ();
|
||||
packet->AddHeader (*blockAck);
|
||||
|
||||
WifiMacHeader hdr;
|
||||
hdr.SetType (WIFI_MAC_CTL_BACKRESP);
|
||||
hdr.SetAddr1 (originator);
|
||||
hdr.SetAddr2 (GetAddress ());
|
||||
hdr.SetDsNotFrom ();
|
||||
hdr.SetDsNotTo ();
|
||||
hdr.SetNoRetry ();
|
||||
hdr.SetNoMoreFragments ();
|
||||
|
||||
m_currentPacket = packet;
|
||||
m_currentHdr = hdr;
|
||||
if (immediate)
|
||||
{
|
||||
m_txParams.DisableAck ();
|
||||
duration -= GetSifs ();
|
||||
if (blockAck->IsBasic ())
|
||||
{
|
||||
duration -= GetBlockAckDuration (originator, blockAckReqTxMode, BASIC_BLOCK_ACK);
|
||||
}
|
||||
else if (blockAck->IsCompressed ())
|
||||
{
|
||||
duration -= GetBlockAckDuration (originator, blockAckReqTxMode, COMPRESSED_BLOCK_ACK);
|
||||
}
|
||||
else if (blockAck->IsMultiTid ())
|
||||
{
|
||||
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_txParams.EnableAck ();
|
||||
duration += GetSifs ();
|
||||
duration += GetAckDuration (originator, blockAckReqTxMode);
|
||||
}
|
||||
m_txParams.DisableNextData ();
|
||||
|
||||
StartDataTxTimers ();
|
||||
|
||||
NS_ASSERT (duration >= MicroSeconds (0));
|
||||
hdr.SetDuration (duration);
|
||||
//here should be present a control about immediate or delayed block ack
|
||||
//for now we assume immediate
|
||||
packet->AddHeader (hdr);
|
||||
WifiMacTrailer fcs;
|
||||
packet->AddTrailer (fcs);
|
||||
ForwardDown (packet, &hdr, blockAckReqTxMode);
|
||||
m_currentPacket = 0;
|
||||
}
|
||||
|
||||
void
|
||||
MacLow::SendBlockAckAfterBlockAckRequest (const CtrlBAckRequestHeader reqHdr, Mac48Address originator,
|
||||
Time duration, WifiMode blockAckReqTxMode)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
CtrlBAckResponseHeader blockAck;
|
||||
uint8_t tid;
|
||||
bool immediate = false;
|
||||
if (!reqHdr.IsMultiTid ())
|
||||
{
|
||||
blockAck.SetStartingSequence (reqHdr.GetStartingSequence ());
|
||||
blockAck.SetTidInfo (reqHdr.GetTidInfo ());
|
||||
|
||||
tid = reqHdr.GetTidInfo ();
|
||||
AgreementsI it;
|
||||
it = m_bAckAgreements.find (std::make_pair (originator, tid));
|
||||
if (it != m_bAckAgreements.end ())
|
||||
{
|
||||
immediate = (*it).second.first.IsImmediateBlockAck ();
|
||||
uint16_t startingSeqCtrl = reqHdr.GetStartingSequenceControl ();
|
||||
|
||||
/* All packets with smaller sequence than starting sequence control must be passed up to Wifimac
|
||||
* See 9.10.3 in IEEE8022.11e standard.
|
||||
*/
|
||||
RxCompleteBufferedPacketsWithSmallerSequence ((startingSeqCtrl>>4)&0xfff0, originator, tid);
|
||||
|
||||
std::list<BufferedPacket>::iterator i = (*it).second.second.begin ();
|
||||
|
||||
/* For more details about next operations see section 9.10.4 of IEEE802.11e standard */
|
||||
if (reqHdr.IsBasic ())
|
||||
{
|
||||
blockAck.SetType (BASIC_BLOCK_ACK);
|
||||
uint16_t guard = startingSeqCtrl;
|
||||
std::list<BufferedPacket>::iterator lastComplete = (*it).second.second.begin ();
|
||||
for (; i != (*it).second.second.end () && guard == (*i).second.GetSequenceControl (); i++)
|
||||
{
|
||||
blockAck.SetReceivedFragment ((*i).second.GetSequenceNumber (),
|
||||
(*i).second.GetFragmentNumber ());
|
||||
/* Section 9.10.4 in IEEE802.11n: the recipient shall pass up to WifiMac the
|
||||
* MSDUs and A-MSDUs starting with the starting sequence number
|
||||
* sequentially until there is an incomplete MSDU or A-MSDU in the buffer */
|
||||
if (!(*i).second.IsMoreFragments ())
|
||||
{
|
||||
while (lastComplete != i)
|
||||
{
|
||||
m_rxCallback ((*lastComplete).first, &(*lastComplete).second);
|
||||
lastComplete++;
|
||||
}
|
||||
m_rxCallback ((*lastComplete).first, &(*lastComplete).second);
|
||||
lastComplete++;
|
||||
}
|
||||
guard = (*i).second.IsMoreFragments () ? (guard + 1) : (guard + 16) & 0xfff0;
|
||||
}
|
||||
(*it).second.first.SetStartingSequence ((guard>>4)&0x0fff);
|
||||
/* All packets already forwarded to WifiMac must be removed from buffer:
|
||||
[begin (), lastComplete) */
|
||||
(*it).second.second.erase ((*it).second.second.begin (), lastComplete);
|
||||
for (i = lastComplete; i != (*it).second.second.end (); i++)
|
||||
{
|
||||
blockAck.SetReceivedFragment ((*i).second.GetSequenceNumber (),
|
||||
(*i).second.GetFragmentNumber ());
|
||||
}
|
||||
}
|
||||
else if (reqHdr.IsCompressed ())
|
||||
{
|
||||
blockAck.SetType (COMPRESSED_BLOCK_ACK);
|
||||
uint16_t guard = startingSeqCtrl;
|
||||
std::list<BufferedPacket>::iterator lastComplete = (*it).second.second.begin ();
|
||||
for (; i != (*it).second.second.end () && guard == (*i).second.GetSequenceControl (); i++)
|
||||
{
|
||||
if (!(*i).second.IsMoreFragments ())
|
||||
{
|
||||
blockAck.SetReceivedPacket ((*i).second.GetSequenceNumber ());
|
||||
while (lastComplete != i)
|
||||
{
|
||||
m_rxCallback ((*lastComplete).first, &(*lastComplete).second);
|
||||
lastComplete++;
|
||||
}
|
||||
m_rxCallback ((*lastComplete).first, &(*lastComplete).second);
|
||||
lastComplete++;
|
||||
}
|
||||
guard = (*i).second.IsMoreFragments () ? (guard + 1) : (guard + 16) & 0xfff0;
|
||||
}
|
||||
(*it).second.first.SetStartingSequence ((guard>>4)&0x0fff);
|
||||
/* All packets already forwarded to WifiMac must be removed from buffer:
|
||||
[begin (), lastcomplete) */
|
||||
(*it).second.second.erase ((*it).second.second.begin (), lastComplete);
|
||||
i = lastComplete;
|
||||
if (i != (*it).second.second.end ())
|
||||
{
|
||||
guard = (*i).second.GetSequenceControl () & 0xfff0;
|
||||
}
|
||||
for (; i != (*it).second.second.end ();)
|
||||
{
|
||||
for (; i != (*it).second.second.end () && guard == (*i).second.GetSequenceControl (); i++)
|
||||
{
|
||||
if (!(*i).second.IsMoreFragments ())
|
||||
{
|
||||
guard = (guard + 16) & 0xfff0;
|
||||
blockAck.SetReceivedPacket ((*i).second.GetSequenceNumber ());
|
||||
}
|
||||
else
|
||||
{
|
||||
guard += 1;
|
||||
}
|
||||
}
|
||||
while (i != (*it).second.second.end () && ((guard >> 4) & 0x0fff) == (*i).second.GetSequenceNumber ())
|
||||
{
|
||||
i++;
|
||||
}
|
||||
if (i != (*it).second.second.end ())
|
||||
{
|
||||
guard = (*i).second.GetSequenceControl () & 0xfff0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_DEBUG ("there's not a valid block ack agreement with "<<originator);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
|
||||
}
|
||||
|
||||
SendBlockAckResponse (&blockAck, originator, immediate, duration, blockAckReqTxMode);
|
||||
}
|
||||
|
||||
void
|
||||
MacLow::ResetBlockAckInactivityTimerIfNeeded (BlockAckAgreement &agreement)
|
||||
{
|
||||
if (agreement.GetTimeout () != 0)
|
||||
{
|
||||
NS_ASSERT (agreement.m_inactivityEvent.IsRunning ());
|
||||
agreement.m_inactivityEvent.Cancel ();
|
||||
Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
|
||||
|
||||
AccessClass ac = QosUtilsMapTidToAc (agreement.GetTid ());
|
||||
//std::map<AccessClass, MacLowTransmissionListener*>::iterator it = m_edcaListeners.find (ac);
|
||||
//NS_ASSERT (it != m_edcaListeners.end ());
|
||||
|
||||
agreement.m_inactivityEvent = Simulator::Schedule (timeout,
|
||||
&MacLowBlockAckEventListener::BlockAckInactivityTimeout,
|
||||
m_edcaListeners[ac],
|
||||
agreement.GetPeer (),
|
||||
agreement.GetTid ());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacLow::RegisterBlockAckListenerForAc (enum AccessClass ac, MacLowBlockAckEventListener *listener)
|
||||
{
|
||||
m_edcaListeners.insert (std::make_pair (ac, listener));
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
+188
-1
@@ -1,6 +1,7 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005, 2006 INRIA
|
||||
* Copyright (c) 2009 MIRKO BANCHI
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,6 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
* Author: Mirko Banchi <mk.banchi@gmail.com>
|
||||
*/
|
||||
#ifndef MAC_LOW_H
|
||||
#define MAC_LOW_H
|
||||
@@ -23,21 +25,27 @@
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include <ostream>
|
||||
#include <map>
|
||||
|
||||
#include "wifi-mac-header.h"
|
||||
#include "wifi-mode.h"
|
||||
#include "wifi-preamble.h"
|
||||
#include "wifi-remote-station-manager.h"
|
||||
#include "ctrl-headers.h"
|
||||
#include "mgt-headers.h"
|
||||
#include "block-ack-agreement.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/event-id.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "qos-utils.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class WifiPhy;
|
||||
class WifiMac;
|
||||
class EdcaTxopN;
|
||||
|
||||
/**
|
||||
* \brief listen to events coming from ns3::MacLow.
|
||||
@@ -75,6 +83,29 @@ public:
|
||||
* AckTimeout.
|
||||
*/
|
||||
virtual void MissedAck (void) = 0;
|
||||
/**
|
||||
* \param blockAck Block ack response header
|
||||
* \param source Address of block ack sender
|
||||
*
|
||||
* Invoked when ns3::MacLow receives a block ack frame.
|
||||
* Block ack frame is received after a block ack request
|
||||
* and contains information about the correct reception
|
||||
* of a set of packet for which a normal ack wasn't send.
|
||||
* Default implementation for this method is empty. Every
|
||||
* queue that intends to be notified by MacLow of reception
|
||||
* of a block ack must redefine this function.
|
||||
*/
|
||||
virtual void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source);
|
||||
/**
|
||||
* ns3::MacLow did not receive an expected BLOCK_ACK within
|
||||
* BlockAckTimeout. This method is used only for immediate
|
||||
* block ack variant. With delayed block ack, the MissedAck method will be
|
||||
* called instead: upon receipt of a block ack request, the rx station will
|
||||
* reply with a normal ack frame. Later, when the rx station gets a txop, it
|
||||
* will send the block ack back to the tx station which will reply with a
|
||||
* normal ack to the rx station.
|
||||
*/
|
||||
virtual void MissedBlockAck (void);
|
||||
/**
|
||||
* Invoked when ns3::MacLow wants to start a new transmission
|
||||
* as configured by MacLowTransmissionParameters::EnableNextData.
|
||||
@@ -118,6 +149,25 @@ public:
|
||||
virtual void CtsTimeoutReset () = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief listen for block ack events.
|
||||
*/
|
||||
class MacLowBlockAckEventListener {
|
||||
public:
|
||||
MacLowBlockAckEventListener ();
|
||||
virtual ~MacLowBlockAckEventListener ();
|
||||
/**
|
||||
* Typically is called in order to notify EdcaTxopN that a block ack inactivity
|
||||
* timeout occurs for the block ack agreement identified by the pair <i>originator</i>, <i>tid</i>.
|
||||
*
|
||||
* Rx station maintains an inactivity timer for each block ack
|
||||
* agreement. Timer is reset when a frame with ack policy block ack
|
||||
* or a block ack request are received. When this timer reaches zero
|
||||
* this method is called and a delba frame is scheduled for transmission.
|
||||
*/
|
||||
virtual void BlockAckInactivityTimeout (Mac48Address originator, uint8_t tid) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief control how a packet is transmitted.
|
||||
*
|
||||
@@ -156,6 +206,18 @@ public:
|
||||
* MacLowTransmissionListener::MissedAck
|
||||
*/
|
||||
void EnableSuperFastAck (void);
|
||||
/**
|
||||
* Wait BASICBLOCKACKTimeout for a Basic Block Ack Response frame.
|
||||
*/
|
||||
void EnableBasicBlockAck (void);
|
||||
/**
|
||||
* Wait COMPRESSEDBLOCKACKTimeout for a Compressed Block Ack Response frame.
|
||||
*/
|
||||
void EnableCompressedBlockAck (void);
|
||||
/**
|
||||
* NOT IMPLEMENTED FOR NOW
|
||||
*/
|
||||
void EnableMultiTidBlockAck (void);
|
||||
/**
|
||||
* Send a RTS, and wait CTSTimeout for a CTS. If we get a
|
||||
* CTS on time, call MacLowTransmissionListener::GotCts
|
||||
@@ -232,6 +294,24 @@ public:
|
||||
* \sa EnableSuperFastAck
|
||||
*/
|
||||
bool MustWaitSuperFastAck (void) const;
|
||||
/**
|
||||
* \returns true if block ack mechanism is used, false otherwise.
|
||||
*
|
||||
* \sa EnableBlockAck
|
||||
*/
|
||||
bool MustWaitBasicBlockAck (void) const;
|
||||
/**
|
||||
* \returns true if compressed block ack mechanism is used, false otherwise.
|
||||
*
|
||||
* \sa EnableCompressedBlockAck
|
||||
*/
|
||||
bool MustWaitCompressedBlockAck (void) const;
|
||||
/**
|
||||
* \returns true if multi-tid block ack mechanism is used, false otherwise.
|
||||
*
|
||||
* \sa EnableMultiTidBlockAck
|
||||
*/
|
||||
bool MustWaitMultiTidBlockAck (void) const;
|
||||
/**
|
||||
* \returns true if RTS should be sent and CTS waited for before
|
||||
* sending data, false otherwise.
|
||||
@@ -262,7 +342,10 @@ private:
|
||||
ACK_NONE,
|
||||
ACK_NORMAL,
|
||||
ACK_FAST,
|
||||
ACK_SUPER_FAST
|
||||
ACK_SUPER_FAST,
|
||||
BLOCK_ACK_BASIC,
|
||||
BLOCK_ACK_COMPRESSED,
|
||||
BLOCK_ACK_MULTI_TID
|
||||
} m_waitAck;
|
||||
bool m_sendRts;
|
||||
Time m_overrideDurationId;
|
||||
@@ -286,6 +369,8 @@ public:
|
||||
|
||||
void SetAddress (Mac48Address ad);
|
||||
void SetAckTimeout (Time ackTimeout);
|
||||
void SetBasicBlockAckTimeout (Time blockAckTimeout);
|
||||
void SetCompressedBlockAckTimeout (Time blockAckTimeout);
|
||||
void SetCtsTimeout (Time ctsTimeout);
|
||||
void SetSifs (Time sifs);
|
||||
void SetSlotTime (Time slotTime);
|
||||
@@ -293,6 +378,8 @@ public:
|
||||
void SetBssid (Mac48Address ad);
|
||||
Mac48Address GetAddress (void) const;
|
||||
Time GetAckTimeout (void) const;
|
||||
Time GetBasicBlockAckTimeout () const;
|
||||
Time GetCompressedBlockAckTimeout () const;
|
||||
Time GetCtsTimeout (void) const;
|
||||
Time GetSifs (void) const;
|
||||
Time GetSlotTime (void) const;
|
||||
@@ -364,9 +451,39 @@ public:
|
||||
* occurs, pending MAC transmissions (RTS, CTS, DATA and ACK) are cancelled.
|
||||
*/
|
||||
void NotifySwitchingStartNow (Time duration);
|
||||
/**
|
||||
* \param respHdr Add block ack response from originator (action frame).
|
||||
* \param originator Address of peer station involved in block ack mechanism.
|
||||
* \param startingSeq Sequence number of the first MPDU of all packets for which block ack was negotiated.
|
||||
*
|
||||
* This function is typically invoked only by ns3::QapWifiMac and ns3::QstaWifiMac.
|
||||
* If we are transmitting an Add block ack response, MacLow must allocate buffers to collect
|
||||
* all correctly received packets belonging to category for which block ack was negotiated.
|
||||
* It's needed in order to send a Block ack after corresponding originator's Block ack request.
|
||||
*/
|
||||
void CreateBlockAckAgreement (const MgtAddBaResponseHeader *respHdr, Mac48Address originator,
|
||||
uint16_t startingSeq);
|
||||
/**
|
||||
* \param originator Address of peer partecipating in Block Ack mechanism.
|
||||
* \param tid TID for which Block Ack was created.
|
||||
*
|
||||
* Checks if exists an established block ack agreement with <i>originator</i>
|
||||
* for tid <i>tid</i>. If the agreement exists, tears down it. This function is typically
|
||||
* invoked when a DELBA frame is received from <i>originator</i>.
|
||||
*/
|
||||
void DestroyBlockAckAgreement (Mac48Address originator, uint8_t tid);
|
||||
/**
|
||||
* \param ac Access class managed by the queue.
|
||||
* \param listener The listener for the queue.
|
||||
*
|
||||
* The lifetime of the registered listener is typically equal to the lifetime of the queue
|
||||
* associated to this AC.
|
||||
*/
|
||||
void RegisterBlockAckListenerForAc (enum AccessClass ac, MacLowBlockAckEventListener *listener);
|
||||
private:
|
||||
void CancelAllEvents (void);
|
||||
uint32_t GetAckSize (void) const;
|
||||
uint32_t GetBlockAckSize (enum BlockAckType type) const;
|
||||
uint32_t GetRtsSize (void) const;
|
||||
uint32_t GetCtsSize (void) const;
|
||||
uint32_t GetSize (Ptr<const Packet> packet, const WifiMacHeader *hdr) const;
|
||||
@@ -381,8 +498,10 @@ private:
|
||||
WifiMode GetDataTxMode (Ptr<const Packet> packet, const WifiMacHeader *hdr) const;
|
||||
WifiMode GetCtsTxModeForRts (Mac48Address to, WifiMode rtsTxMode) const;
|
||||
WifiMode GetAckTxModeForData (Mac48Address to, WifiMode dataTxMode) const;
|
||||
|
||||
Time GetCtsDuration (Mac48Address to, WifiMode rtsTxMode) const;
|
||||
Time GetAckDuration (Mac48Address to, WifiMode dataTxMode) const;
|
||||
Time GetBlockAckDuration (Mac48Address to, WifiMode blockAckReqTxMode, enum BlockAckType type) const;
|
||||
void NotifyNav (const WifiMacHeader &hdr, WifiMode txMode, WifiPreamble preamble);
|
||||
void DoNavResetNow (Time duration);
|
||||
bool DoNavStartNow (Time duration);
|
||||
@@ -398,6 +517,7 @@ private:
|
||||
void FastAckTimeout (void);
|
||||
void SuperFastAckTimeout (void);
|
||||
void FastAckFailedTimeout (void);
|
||||
void BlockAckTimeout (void);
|
||||
void CtsTimeout (void);
|
||||
void SendCtsAfterRts (Mac48Address source, Time duration, WifiMode txMode, double rtsSnr);
|
||||
void SendAckAfterData (Mac48Address source, Time duration, WifiMode txMode, double rtsSnr);
|
||||
@@ -409,6 +529,53 @@ private:
|
||||
void SendCurrentTxPacket (void);
|
||||
void StartDataTxTimers (void);
|
||||
virtual void DoDispose (void);
|
||||
/**
|
||||
* \param originator Address of peer partecipating in Block Ack mechanism.
|
||||
* \param tid TID for which Block Ack was created.
|
||||
* \param seq Starting sequence
|
||||
*
|
||||
* This function forward up all completed "old" packets with sequence number
|
||||
* smaller than <i>seq</i>. All comparison are performed circularly mod 4096.
|
||||
*/
|
||||
void RxCompleteBufferedPacketsWithSmallerSequence (uint16_t seq, Mac48Address originator, uint8_t tid);
|
||||
/**
|
||||
* \param originator Address of peer partecipating in Block Ack mechanism.
|
||||
* \param tid TID for which Block Ack was created.
|
||||
*
|
||||
* This method is typically invoked when a MPDU with ack policy
|
||||
* subfield set to Normal Ack is received and a block ack agreement
|
||||
* for that packet exists.
|
||||
* This happens when the originator of block ack has only few MPDUs to send.
|
||||
* All completed MSDUs starting with starting sequence number of block ack
|
||||
* agreement are forward up to WifiMac until there is an incomplete MSDU.
|
||||
* See section 9.10.4 in IEEE802.11 standard for more details.
|
||||
*/
|
||||
void RxCompleteBufferedPackets (Mac48Address originator, uint8_t tid);
|
||||
/*
|
||||
* This method checks if exists a valid established block ack agreement.
|
||||
* If there is, store the packet without pass it up to WifiMac. The packet is buffered
|
||||
* in order of increasing sequence control field. All comparison are performed
|
||||
* circularly modulo 2^12.
|
||||
*/
|
||||
bool StoreMpduIfNeeded (Ptr<Packet> packet, WifiMacHeader hdr);
|
||||
/*
|
||||
* Invoked after that a block ack request has been received. Looks for corresponding
|
||||
* block ack agreement and creates block ack bitmap on a received packets basis.
|
||||
*/
|
||||
void SendBlockAckAfterBlockAckRequest (const CtrlBAckRequestHeader reqHdr, Mac48Address originator,
|
||||
Time duration, WifiMode blockAckReqTxMode);
|
||||
/*
|
||||
* This method creates block ack frame with header equals to <i>blockAck</i> and start its transmission.
|
||||
*/
|
||||
void SendBlockAckResponse (const CtrlBAckResponseHeader* blockAck, Mac48Address originator, bool immediate,
|
||||
Time duration, WifiMode blockAckReqTxMode);
|
||||
/*
|
||||
* Every time that a block ack request or a packet with ack policy equals to <i>block ack</i>
|
||||
* are received, if a relative block ack agreement exists and the value of inactivity timeout
|
||||
* is not 0, the timer is reset.
|
||||
* see section 11.5.3 in IEEE802.11e for more details.
|
||||
*/
|
||||
void ResetBlockAckInactivityTimerIfNeeded (BlockAckAgreement &agreement);
|
||||
|
||||
void SetupPhyMacLowListener (Ptr<WifiPhy> phy);
|
||||
|
||||
@@ -423,6 +590,7 @@ private:
|
||||
EventId m_fastAckTimeoutEvent;
|
||||
EventId m_superFastAckTimeoutEvent;
|
||||
EventId m_fastAckFailedTimeoutEvent;
|
||||
EventId m_blockAckTimeoutEvent;
|
||||
EventId m_ctsTimeoutEvent;
|
||||
EventId m_sendCtsEvent;
|
||||
EventId m_sendAckEvent;
|
||||
@@ -437,6 +605,8 @@ private:
|
||||
Mac48Address m_self;
|
||||
Mac48Address m_bssid;
|
||||
Time m_ackTimeout;
|
||||
Time m_basicBlockAckTimeout;
|
||||
Time m_compressedBlockAckTimeout;
|
||||
Time m_ctsTimeout;
|
||||
Time m_sifs;
|
||||
Time m_slotTime;
|
||||
@@ -447,6 +617,23 @@ private:
|
||||
|
||||
// Listerner needed to monitor when a channel switching occurs.
|
||||
class PhyMacLowListener *m_phyMacLowListener;
|
||||
|
||||
/*
|
||||
* BlockAck data structures.
|
||||
*/
|
||||
typedef std::pair<Ptr<Packet>, WifiMacHeader> BufferedPacket;
|
||||
typedef std::list<BufferedPacket>::iterator BufferedPacketI;
|
||||
|
||||
typedef std::pair<Mac48Address, uint8_t> AgreementKey;
|
||||
typedef std::pair<BlockAckAgreement, std::list<BufferedPacket> > AgreementValue;
|
||||
|
||||
typedef std::map<AgreementKey, AgreementValue> Agreements;
|
||||
typedef std::map<AgreementKey, AgreementValue>::iterator AgreementsI;
|
||||
|
||||
Agreements m_bAckAgreements;
|
||||
|
||||
typedef std::map<AccessClass, MacLowBlockAckEventListener*> QueueListeners;
|
||||
QueueListeners m_edcaListeners;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -77,4 +77,17 @@ MacTxMiddle::GetNextSequenceNumberfor (const WifiMacHeader *hdr)
|
||||
return retval;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
MacTxMiddle::GetNextSeqNumberByTidAndAddress (uint8_t tid, Mac48Address addr) const
|
||||
{
|
||||
NS_ASSERT (tid < 16);
|
||||
uint16_t seq = 0;
|
||||
std::map <Mac48Address,uint16_t*>::const_iterator it = m_qosSequences.find (addr);
|
||||
if (it != m_qosSequences.end ())
|
||||
{
|
||||
return it->second[tid];
|
||||
}
|
||||
return seq;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -37,6 +37,7 @@ public:
|
||||
~MacTxMiddle ();
|
||||
|
||||
uint16_t GetNextSequenceNumberfor (const WifiMacHeader *hdr);
|
||||
uint16_t GetNextSeqNumberByTidAndAddress (uint8_t tid, Mac48Address addr) const;
|
||||
|
||||
private:
|
||||
std::map <Mac48Address,uint16_t*> m_qosSequences;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006 INRIA
|
||||
* Copyright (c) 2009 MIRKO BANCHI
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,6 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
* Author: Mirko Banchi <mk.banchi@gmail.com>
|
||||
*/
|
||||
#include "mgt-headers.h"
|
||||
#include "ns3/simulator.h"
|
||||
@@ -405,6 +407,11 @@ WifiActionHeader::SetAction (WifiActionHeader::CategoryValue type,
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case BLOCK_ACK:
|
||||
{
|
||||
m_actionValue = action.blockAck;
|
||||
break;
|
||||
}
|
||||
case MESH_PEERING_MGT:
|
||||
{
|
||||
m_actionValue = action.peerLink;
|
||||
@@ -427,6 +434,8 @@ WifiActionHeader::GetCategory ()
|
||||
{
|
||||
switch (m_category)
|
||||
{
|
||||
case BLOCK_ACK:
|
||||
return BLOCK_ACK;
|
||||
case MESH_PEERING_MGT:
|
||||
return MESH_PEERING_MGT;
|
||||
case MESH_LINK_METRIC:
|
||||
@@ -451,6 +460,19 @@ WifiActionHeader::GetAction ()
|
||||
retval.peerLink = PEER_LINK_OPEN; // Needs to be initialized to something to quiet valgrind in default cases
|
||||
switch (m_category)
|
||||
{
|
||||
case BLOCK_ACK:
|
||||
switch (m_actionValue)
|
||||
{
|
||||
case BLOCK_ACK_ADDBA_REQUEST:
|
||||
retval.blockAck = BLOCK_ACK_ADDBA_REQUEST;
|
||||
return retval;
|
||||
case BLOCK_ACK_ADDBA_RESPONSE:
|
||||
retval.blockAck = BLOCK_ACK_ADDBA_RESPONSE;
|
||||
return retval;
|
||||
case BLOCK_ACK_DELBA:
|
||||
retval.blockAck = BLOCK_ACK_DELBA;
|
||||
return retval;
|
||||
}
|
||||
case MESH_PEERING_MGT:
|
||||
switch (m_actionValue)
|
||||
{
|
||||
@@ -528,4 +550,449 @@ WifiActionHeader::Deserialize (Buffer::Iterator start)
|
||||
return i.GetDistanceFrom (start);
|
||||
}
|
||||
|
||||
/***************************************************
|
||||
* ADDBARequest
|
||||
****************************************************/
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (MgtAddBaRequestHeader);
|
||||
|
||||
MgtAddBaRequestHeader::MgtAddBaRequestHeader ()
|
||||
: m_dialogToken (1),
|
||||
m_amsduSupport (1),
|
||||
m_bufferSize (0)
|
||||
{}
|
||||
|
||||
TypeId
|
||||
MgtAddBaRequestHeader::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::MgtAddBaRequestHeader")
|
||||
.SetParent<Header> ()
|
||||
.AddConstructor<MgtAddBaRequestHeader> ();
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
TypeId
|
||||
MgtAddBaRequestHeader::GetInstanceTypeId (void) const
|
||||
{
|
||||
return GetTypeId ();
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaRequestHeader::Print (std::ostream &os) const
|
||||
{}
|
||||
|
||||
uint32_t
|
||||
MgtAddBaRequestHeader::GetSerializedSize (void) const
|
||||
{
|
||||
uint32_t size = 0;
|
||||
size += 1; //Dialog token
|
||||
size += 2; //Block ack parameter set
|
||||
size += 2; //Block ack timeout value
|
||||
size += 2; //Starting sequence control
|
||||
return size;
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaRequestHeader::Serialize (Buffer::Iterator start) const
|
||||
{
|
||||
Buffer::Iterator i = start;
|
||||
i.WriteU8 (m_dialogToken);
|
||||
i.WriteHtolsbU16 (GetParameterSet ());
|
||||
i.WriteHtolsbU16 (m_timeoutValue);
|
||||
i.WriteHtolsbU16 (GetStartingSequenceControl ());
|
||||
}
|
||||
|
||||
uint32_t
|
||||
MgtAddBaRequestHeader::Deserialize (Buffer::Iterator start)
|
||||
{
|
||||
Buffer::Iterator i = start;
|
||||
m_dialogToken = i.ReadU8 ();
|
||||
SetParameterSet (i.ReadLsbtohU16 ());
|
||||
m_timeoutValue = i.ReadLsbtohU16 ();
|
||||
SetStartingSequenceControl (i.ReadLsbtohU16 ());
|
||||
return i.GetDistanceFrom (start);
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaRequestHeader::SetDelayedBlockAck ()
|
||||
{
|
||||
m_policy = 0;
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaRequestHeader::SetImmediateBlockAck ()
|
||||
{
|
||||
m_policy = 1;
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaRequestHeader::SetTid (uint8_t tid)
|
||||
{
|
||||
NS_ASSERT (tid < 16);
|
||||
m_tid = tid;
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaRequestHeader::SetTimeout (uint16_t timeout)
|
||||
{
|
||||
m_timeoutValue = timeout;
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaRequestHeader::SetBufferSize (uint16_t size)
|
||||
{
|
||||
m_bufferSize = size;
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaRequestHeader::SetStartingSequence (uint16_t seq)
|
||||
{
|
||||
m_startingSeq = seq;
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaRequestHeader::SetAmsduSupport (bool supported)
|
||||
{
|
||||
m_amsduSupport = supported;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
MgtAddBaRequestHeader::GetTid (void) const
|
||||
{
|
||||
return m_tid;
|
||||
}
|
||||
|
||||
bool
|
||||
MgtAddBaRequestHeader::IsImmediateBlockAck (void) const
|
||||
{
|
||||
return (m_policy == 1)?true:false;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
MgtAddBaRequestHeader::GetTimeout (void) const
|
||||
{
|
||||
return m_timeoutValue;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
MgtAddBaRequestHeader::GetBufferSize (void) const
|
||||
{
|
||||
return m_bufferSize;
|
||||
}
|
||||
|
||||
bool
|
||||
MgtAddBaRequestHeader::IsAmsduSupported (void) const
|
||||
{
|
||||
return (m_amsduSupport == 1)?true:false;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
MgtAddBaRequestHeader::GetStartingSequence (void) const
|
||||
{
|
||||
return m_startingSeq;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
MgtAddBaRequestHeader::GetStartingSequenceControl (void) const
|
||||
{
|
||||
return (m_startingSeq << 4) & 0xfff0;
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaRequestHeader::SetStartingSequenceControl (uint16_t seqControl)
|
||||
{
|
||||
m_startingSeq = (seqControl >> 4) & 0x0fff;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
MgtAddBaRequestHeader::GetParameterSet (void) const
|
||||
{
|
||||
uint16_t res = 0;
|
||||
res |= m_amsduSupport;
|
||||
res |= m_policy << 1;
|
||||
res |= m_tid << 2;
|
||||
res |= m_bufferSize << 6;
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaRequestHeader::SetParameterSet (uint16_t params)
|
||||
{
|
||||
m_amsduSupport = (params) & 0x01;
|
||||
m_policy = (params >> 1) & 0x01;
|
||||
m_tid = (params >> 2) & 0x0f;
|
||||
m_bufferSize = (params >> 6) & 0x03ff;
|
||||
}
|
||||
|
||||
/***************************************************
|
||||
* ADDBAResponse
|
||||
****************************************************/
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (MgtAddBaResponseHeader);
|
||||
|
||||
MgtAddBaResponseHeader::MgtAddBaResponseHeader ()
|
||||
: m_dialogToken (1),
|
||||
m_amsduSupport (1),
|
||||
m_bufferSize (0)
|
||||
{}
|
||||
|
||||
TypeId
|
||||
MgtAddBaResponseHeader::GetTypeId ()
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::MgtAddBaResponseHeader")
|
||||
.SetParent<Header> ()
|
||||
.AddConstructor<MgtAddBaResponseHeader> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
TypeId
|
||||
MgtAddBaResponseHeader::GetInstanceTypeId (void) const
|
||||
{
|
||||
return GetTypeId ();
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaResponseHeader::Print (std::ostream &os) const
|
||||
{
|
||||
os <<"status code="<<m_code;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
MgtAddBaResponseHeader::GetSerializedSize (void) const
|
||||
{
|
||||
uint32_t size = 0;
|
||||
size += 1; //Dialog token
|
||||
size += m_code.GetSerializedSize (); //Status code
|
||||
size += 2; //Block ack parameter set
|
||||
size += 2; //Block ack timeout value
|
||||
return size;
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaResponseHeader::Serialize (Buffer::Iterator start) const
|
||||
{
|
||||
Buffer::Iterator i = start;
|
||||
i.WriteU8 (m_dialogToken);
|
||||
i = m_code.Serialize (i);
|
||||
i.WriteHtolsbU16 (GetParameterSet ());
|
||||
i.WriteHtolsbU16 (m_timeoutValue);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
MgtAddBaResponseHeader::Deserialize (Buffer::Iterator start)
|
||||
{
|
||||
Buffer::Iterator i = start;
|
||||
m_dialogToken = i.ReadU8 ();
|
||||
i = m_code.Deserialize (i);
|
||||
SetParameterSet (i.ReadLsbtohU16 ());
|
||||
m_timeoutValue = i.ReadLsbtohU16 ();
|
||||
return i.GetDistanceFrom (start);
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaResponseHeader::SetDelayedBlockAck ()
|
||||
{
|
||||
m_policy = 0;
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaResponseHeader::SetImmediateBlockAck ()
|
||||
{
|
||||
m_policy = 1;
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaResponseHeader::SetTid (uint8_t tid)
|
||||
{
|
||||
NS_ASSERT (tid < 16);
|
||||
m_tid = tid;
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaResponseHeader::SetTimeout (uint16_t timeout)
|
||||
{
|
||||
m_timeoutValue = timeout;
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaResponseHeader::SetBufferSize (uint16_t size)
|
||||
{
|
||||
m_bufferSize = size;
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaResponseHeader::SetStatusCode (StatusCode code)
|
||||
{
|
||||
m_code = code;
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaResponseHeader::SetAmsduSupport (bool supported)
|
||||
{
|
||||
m_amsduSupport = supported;
|
||||
}
|
||||
|
||||
StatusCode
|
||||
MgtAddBaResponseHeader::GetStatusCode (void) const
|
||||
{
|
||||
return m_code;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
MgtAddBaResponseHeader::GetTid (void) const
|
||||
{
|
||||
return m_tid;
|
||||
}
|
||||
|
||||
bool
|
||||
MgtAddBaResponseHeader::IsImmediateBlockAck (void) const
|
||||
{
|
||||
return (m_policy == 1)?true:false;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
MgtAddBaResponseHeader::GetTimeout (void) const
|
||||
{
|
||||
return m_timeoutValue;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
MgtAddBaResponseHeader::GetBufferSize (void) const
|
||||
{
|
||||
return m_bufferSize;
|
||||
}
|
||||
|
||||
bool
|
||||
MgtAddBaResponseHeader::IsAmsduSupported (void) const
|
||||
{
|
||||
return (m_amsduSupport == 1)?true:false;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
MgtAddBaResponseHeader::GetParameterSet (void) const
|
||||
{
|
||||
uint16_t res = 0;
|
||||
res |= m_amsduSupport;
|
||||
res |= m_policy << 1;
|
||||
res |= m_tid << 2;
|
||||
res |= m_bufferSize << 6;
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
MgtAddBaResponseHeader::SetParameterSet (uint16_t params)
|
||||
{
|
||||
m_amsduSupport = (params) & 0x01;
|
||||
m_policy = (params >> 1) & 0x01;
|
||||
m_tid = (params >> 2) & 0x0f;
|
||||
m_bufferSize = (params >> 6) & 0x03ff;
|
||||
}
|
||||
|
||||
/***************************************************
|
||||
* DelBa
|
||||
****************************************************/
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (MgtDelBaHeader);
|
||||
|
||||
MgtDelBaHeader::MgtDelBaHeader ()
|
||||
: m_reasonCode (1)
|
||||
{}
|
||||
|
||||
TypeId
|
||||
MgtDelBaHeader::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::MgtDelBaHeader")
|
||||
.SetParent<Header> ()
|
||||
.AddConstructor<MgtDelBaHeader> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
TypeId
|
||||
MgtDelBaHeader::GetInstanceTypeId (void) const
|
||||
{
|
||||
return GetTypeId ();
|
||||
}
|
||||
|
||||
void
|
||||
MgtDelBaHeader::Print (std::ostream &os) const
|
||||
{}
|
||||
|
||||
uint32_t
|
||||
MgtDelBaHeader::GetSerializedSize (void) const
|
||||
{
|
||||
uint32_t size = 0;
|
||||
size += 2; //DelBa parameter set
|
||||
size += 2; //Reason code
|
||||
return size;
|
||||
}
|
||||
|
||||
void
|
||||
MgtDelBaHeader::Serialize (Buffer::Iterator start) const
|
||||
{
|
||||
Buffer::Iterator i = start;
|
||||
i.WriteHtolsbU16 (GetParameterSet ());
|
||||
i.WriteHtolsbU16 (m_reasonCode);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
MgtDelBaHeader::Deserialize (Buffer::Iterator start)
|
||||
{
|
||||
Buffer::Iterator i = start;
|
||||
SetParameterSet (i.ReadLsbtohU16 ());
|
||||
m_reasonCode = i.ReadLsbtohU16 ();
|
||||
return i.GetDistanceFrom (start);
|
||||
}
|
||||
|
||||
bool
|
||||
MgtDelBaHeader::IsByOriginator (void) const
|
||||
{
|
||||
return (m_initiator == 1)?true:false;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
MgtDelBaHeader::GetTid (void) const
|
||||
{
|
||||
NS_ASSERT (m_tid < 16);
|
||||
uint8_t tid = static_cast<uint8_t> (m_tid);
|
||||
return tid;
|
||||
}
|
||||
|
||||
void
|
||||
MgtDelBaHeader::SetByOriginator (void)
|
||||
{
|
||||
m_initiator = 1;
|
||||
}
|
||||
|
||||
void
|
||||
MgtDelBaHeader::SetByRecipient (void)
|
||||
{
|
||||
m_initiator = 0;
|
||||
}
|
||||
|
||||
void
|
||||
MgtDelBaHeader::SetTid (uint8_t tid)
|
||||
{
|
||||
NS_ASSERT (tid < 16);
|
||||
m_tid = static_cast<uint16_t> (tid);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
MgtDelBaHeader::GetParameterSet (void) const
|
||||
{
|
||||
uint16_t res = 0;
|
||||
res |= m_initiator << 11;
|
||||
res |= m_tid << 12;
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
MgtDelBaHeader::SetParameterSet (uint16_t params)
|
||||
{
|
||||
m_initiator = (params >> 11) & 0x01;
|
||||
m_tid = (params >> 12) & 0x0f;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006 INRIA
|
||||
* Copyright (c) 2009 MIRKO BANCHI
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,6 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
* Author: Mirko Banchi <mk.banchi@gmail.com>
|
||||
*/
|
||||
#ifndef MGT_HEADERS_H
|
||||
#define MGT_HEADERS_H
|
||||
@@ -134,6 +136,10 @@ private:
|
||||
|
||||
class MgtBeaconHeader : public MgtProbeResponseHeader {};
|
||||
|
||||
/****************************
|
||||
* Action frames
|
||||
*****************************/
|
||||
|
||||
/**
|
||||
* \brief See IEEE 802.11 chapter 7.3.1.11
|
||||
*
|
||||
@@ -148,6 +154,7 @@ public:
|
||||
/* Compatible with open80211s implementation */
|
||||
enum CategoryValue //table 7-24 staring from 4
|
||||
{
|
||||
BLOCK_ACK = 3,
|
||||
MESH_PEERING_MGT = 30,
|
||||
MESH_LINK_METRIC = 31,
|
||||
MESH_PATH_SELECTION = 32,
|
||||
@@ -189,6 +196,12 @@ public:
|
||||
TBTT_ADJUSTMENT_REQUEST,
|
||||
MESH_CHANNEL_SWITCH_ANNOUNCEMENT,
|
||||
};
|
||||
enum BlockAckActionValue
|
||||
{
|
||||
BLOCK_ACK_ADDBA_REQUEST = 0,
|
||||
BLOCK_ACK_ADDBA_RESPONSE = 1,
|
||||
BLOCK_ACK_DELBA = 2
|
||||
};
|
||||
typedef union
|
||||
{
|
||||
enum PeerLinkMgtActionValue peerLink;
|
||||
@@ -196,6 +209,7 @@ public:
|
||||
enum PathSelectionActionValue pathSelection;
|
||||
enum InterworkActionValue interwork;
|
||||
enum ResourceCoordinationActionValue resourceCoordination;
|
||||
enum BlockAckActionValue blockAck;
|
||||
} ActionValue;
|
||||
void SetAction (enum CategoryValue type,ActionValue action);
|
||||
|
||||
@@ -212,6 +226,115 @@ private:
|
||||
uint8_t m_actionValue;
|
||||
};
|
||||
|
||||
class MgtAddBaRequestHeader : public Header {
|
||||
public:
|
||||
|
||||
MgtAddBaRequestHeader ();
|
||||
|
||||
static TypeId GetTypeId (void);
|
||||
virtual TypeId GetInstanceTypeId (void) const;
|
||||
virtual void Print (std::ostream &os) const;
|
||||
virtual uint32_t GetSerializedSize (void) const;
|
||||
virtual void Serialize (Buffer::Iterator start) const;
|
||||
virtual uint32_t Deserialize (Buffer::Iterator start);
|
||||
|
||||
void SetDelayedBlockAck ();
|
||||
void SetImmediateBlockAck ();
|
||||
void SetTid (uint8_t tid);
|
||||
void SetTimeout (uint16_t timeout);
|
||||
void SetBufferSize (uint16_t size);
|
||||
void SetStartingSequence (uint16_t seq);
|
||||
void SetAmsduSupport (bool supported);
|
||||
|
||||
uint16_t GetStartingSequence (void) const;
|
||||
uint8_t GetTid (void) const;
|
||||
bool IsImmediateBlockAck (void) const;
|
||||
uint16_t GetTimeout (void) const;
|
||||
uint16_t GetBufferSize (void) const;
|
||||
bool IsAmsduSupported (void) const;
|
||||
|
||||
private:
|
||||
uint16_t GetParameterSet (void) const;
|
||||
void SetParameterSet (uint16_t params);
|
||||
uint16_t GetStartingSequenceControl (void) const;
|
||||
void SetStartingSequenceControl (uint16_t seqControl);
|
||||
|
||||
uint8_t m_dialogToken; /* Not used for now */
|
||||
uint8_t m_amsduSupport;
|
||||
uint8_t m_policy;
|
||||
uint8_t m_tid;
|
||||
uint16_t m_bufferSize;
|
||||
uint16_t m_timeoutValue;
|
||||
uint16_t m_startingSeq;
|
||||
};
|
||||
|
||||
class MgtAddBaResponseHeader : public Header {
|
||||
public:
|
||||
|
||||
MgtAddBaResponseHeader ();
|
||||
|
||||
static TypeId GetTypeId (void);
|
||||
virtual TypeId GetInstanceTypeId (void) const;
|
||||
virtual void Print (std::ostream &os) const;
|
||||
virtual uint32_t GetSerializedSize (void) const;
|
||||
virtual void Serialize (Buffer::Iterator start) const;
|
||||
virtual uint32_t Deserialize (Buffer::Iterator start);
|
||||
|
||||
void SetDelayedBlockAck ();
|
||||
void SetImmediateBlockAck ();
|
||||
void SetTid (uint8_t tid);
|
||||
void SetTimeout (uint16_t timeout);
|
||||
void SetBufferSize (uint16_t size);
|
||||
void SetStatusCode (StatusCode code);
|
||||
void SetAmsduSupport (bool supported);
|
||||
|
||||
StatusCode GetStatusCode (void) const;
|
||||
uint8_t GetTid (void) const;
|
||||
bool IsImmediateBlockAck (void) const;
|
||||
uint16_t GetTimeout (void) const;
|
||||
uint16_t GetBufferSize (void) const;
|
||||
bool IsAmsduSupported (void) const;
|
||||
|
||||
private:
|
||||
uint16_t GetParameterSet (void) const;
|
||||
void SetParameterSet (uint16_t params);
|
||||
|
||||
uint8_t m_dialogToken; /* Not used for now */
|
||||
StatusCode m_code;
|
||||
uint8_t m_amsduSupport;
|
||||
uint8_t m_policy;
|
||||
uint8_t m_tid;
|
||||
uint16_t m_bufferSize;
|
||||
uint16_t m_timeoutValue;
|
||||
};
|
||||
|
||||
class MgtDelBaHeader : public Header {
|
||||
public:
|
||||
MgtDelBaHeader ();
|
||||
|
||||
static TypeId GetTypeId (void);
|
||||
virtual TypeId GetInstanceTypeId (void) const;
|
||||
virtual void Print (std::ostream &os) const;
|
||||
virtual uint32_t GetSerializedSize (void) const;
|
||||
virtual void Serialize (Buffer::Iterator start) const;
|
||||
virtual uint32_t Deserialize (Buffer::Iterator start);
|
||||
|
||||
bool IsByOriginator (void) const;
|
||||
uint8_t GetTid (void) const;
|
||||
void SetTid (uint8_t);
|
||||
void SetByOriginator (void);
|
||||
void SetByRecipient (void);
|
||||
|
||||
private:
|
||||
uint16_t GetParameterSet (void) const;
|
||||
void SetParameterSet (uint16_t params);
|
||||
|
||||
uint16_t m_initiator;
|
||||
uint16_t m_tid;
|
||||
/* Not used for now.
|
||||
Always set to 1: "Unspecified reason" */
|
||||
uint16_t m_reasonCode;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 MIRKO BANCHI
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mirko Banchi <mk.banchi@gmail.com>
|
||||
*/
|
||||
#include "originator-block-ack-agreement.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
OriginatorBlockAckAgreement::OriginatorBlockAckAgreement ()
|
||||
: BlockAckAgreement (),
|
||||
m_state (PENDING),
|
||||
m_sentMpdus (0)
|
||||
{}
|
||||
OriginatorBlockAckAgreement::OriginatorBlockAckAgreement (Mac48Address recipient, uint8_t tid)
|
||||
: BlockAckAgreement (recipient, tid),
|
||||
m_state (PENDING),
|
||||
m_sentMpdus (0)
|
||||
{}
|
||||
OriginatorBlockAckAgreement::~OriginatorBlockAckAgreement ()
|
||||
{}
|
||||
void
|
||||
OriginatorBlockAckAgreement::SetState (enum State state)
|
||||
{
|
||||
m_state = state;
|
||||
if (state == INACTIVE)
|
||||
{
|
||||
m_sentMpdus = 0;
|
||||
}
|
||||
}
|
||||
bool
|
||||
OriginatorBlockAckAgreement::IsPending (void) const
|
||||
{
|
||||
return (m_state == PENDING)?true:false;
|
||||
}
|
||||
bool
|
||||
OriginatorBlockAckAgreement::IsEstablished (void) const
|
||||
{
|
||||
return (m_state == ESTABLISHED)?true:false;
|
||||
}
|
||||
bool
|
||||
OriginatorBlockAckAgreement::IsInactive (void) const
|
||||
{
|
||||
return (m_state == INACTIVE)?true:false;
|
||||
}
|
||||
bool
|
||||
OriginatorBlockAckAgreement::IsUnsuccessful (void) const
|
||||
{
|
||||
return (m_state == UNSUCCESSFUL)?true:false;
|
||||
}
|
||||
void
|
||||
OriginatorBlockAckAgreement::NotifyMpduTransmission (void)
|
||||
{
|
||||
NS_ASSERT (m_sentMpdus < m_bufferSize);
|
||||
m_sentMpdus++;
|
||||
}
|
||||
bool
|
||||
OriginatorBlockAckAgreement::NeedBlockAckRequest (void) const
|
||||
{
|
||||
return (m_sentMpdus == m_bufferSize/2)?true:false;
|
||||
}
|
||||
void
|
||||
OriginatorBlockAckAgreement::CompleteExchange (void)
|
||||
{
|
||||
m_sentMpdus = 0;
|
||||
}
|
||||
|
||||
} //namespace ns3
|
||||
@@ -0,0 +1,115 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 MIRKO BANCHI
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mirko Banchi <mk.banchi@gmail.com>
|
||||
*/
|
||||
#ifndef ORIGINATOR_BLOCK_ACK_AGREEMENT_H
|
||||
#define ORIGINATOR_BLOCK_ACK_AGREEMENT_H
|
||||
|
||||
#include "block-ack-agreement.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/* \brief Maintains the state and information about trasmitted MPDUs with ack policy block ack
|
||||
* for an originator station.
|
||||
*/
|
||||
class OriginatorBlockAckAgreement : public BlockAckAgreement
|
||||
{
|
||||
friend class BlockAckManager;
|
||||
public:
|
||||
OriginatorBlockAckAgreement ();
|
||||
OriginatorBlockAckAgreement (Mac48Address recipient, uint8_t tid);
|
||||
~OriginatorBlockAckAgreement ();
|
||||
/* receive ADDBAResponse
|
||||
* send ADDBARequest --------------- status code = success ---------------
|
||||
* ----------------->| PENDING |------------------------>| ESTABLISHED |-----
|
||||
* --------------- --------------- |
|
||||
* | / ^ ^ |
|
||||
* receive ADDBAResponse | receive BlockAck / | | | receive BlockAck
|
||||
* status code = failure | retryPkts + queuePkts / | | | retryPkts + queuePkts
|
||||
* v < / | | | >=
|
||||
* --------------- blockAckThreshold / | | | blockAckThreshold
|
||||
* | UNSUCCESSFUL | / | | |
|
||||
* --------------- v | ----------|
|
||||
* -------------- |
|
||||
* | INACTIVE | |
|
||||
* -------------- |
|
||||
* send a MPDU (Normal Ack) | |
|
||||
* retryPkts + queuePkts | |
|
||||
* >= | |
|
||||
* blockAckThreshold |----------------
|
||||
*/
|
||||
/**
|
||||
* Represents the state for this agreement.
|
||||
*
|
||||
* PENDING:
|
||||
* If an agreement is in PENDING state it means that an ADDBARequest frame was sent to
|
||||
* recipient in order to setup the block ack and the originator is waiting for the relative
|
||||
* ADDBAResponse frame.
|
||||
*
|
||||
* ESTABLISHED:
|
||||
* The block ack is active and all packets relative to this agreement are trasmitted
|
||||
* with ack policy set to block ack.
|
||||
*
|
||||
* INACTIVE:
|
||||
* In our implementation, block ack tear-down happens only if an inactivity timeout occurs
|
||||
* so we could have an active block ack but a number of packets that doesn't reach the value of
|
||||
* m_blockAckThreshold (see ns3::BlocAckManager). In these conditions the agreement becomes
|
||||
* INACTIVE until that the number of packets reaches the value of m_blockAckThreshold again.
|
||||
*
|
||||
* UNSUCCESSFUL (not used for now):
|
||||
* The agremeent's state becomes UNSUCCESSFUL if:
|
||||
*
|
||||
* - its previous state was PENDING and an ADDBAResponse frame wasn't received from
|
||||
* recipient station within an interval of time defined by m_bAckSetupTimeout attribute
|
||||
* in ns3::WifiMac.
|
||||
* - an ADDBAResponse frame is received from recipient and the Status Code field is set
|
||||
* to failure.
|
||||
*
|
||||
* In both cases for station addressed by BlockAckAgreement::m_peer and for
|
||||
* TID BlockAckAgreement::m_tid block ack mechanism won't be used.
|
||||
*/
|
||||
enum State {
|
||||
PENDING,
|
||||
ESTABLISHED,
|
||||
INACTIVE,
|
||||
UNSUCCESSFUL
|
||||
};
|
||||
void SetState (enum State state);
|
||||
bool IsPending (void) const;
|
||||
bool IsEstablished (void) const;
|
||||
bool IsInactive (void) const;
|
||||
bool IsUnsuccessful (void) const;
|
||||
/**
|
||||
* Notifies a packet's transmission with ack policy Block Ack.
|
||||
*/
|
||||
void NotifyMpduTransmission (void);
|
||||
/**
|
||||
* Returns true if all packets for which a block ack was negotiated have been transmitted so
|
||||
* a block ack request is needed in order to acknowledge them.
|
||||
*/
|
||||
bool NeedBlockAckRequest (void) const;
|
||||
void CompleteExchange (void);
|
||||
|
||||
private:
|
||||
enum State m_state;
|
||||
uint8_t m_sentMpdus;
|
||||
};
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
#endif /* ORIGINATOR_BLOCK_ACK_AGREEMENT_H */
|
||||
@@ -147,6 +147,18 @@ QadhocWifiMac::SetAckTimeout (Time ackTimeout)
|
||||
m_low->SetAckTimeout (ackTimeout);
|
||||
}
|
||||
|
||||
void
|
||||
QadhocWifiMac::SetBasicBlockAckTimeout (Time blockAckTimeout)
|
||||
{
|
||||
m_low->SetBasicBlockAckTimeout (blockAckTimeout);
|
||||
}
|
||||
|
||||
void
|
||||
QadhocWifiMac::SetCompressedBlockAckTimeout (Time blockAckTimeout)
|
||||
{
|
||||
m_low->SetCompressedBlockAckTimeout (blockAckTimeout);
|
||||
}
|
||||
|
||||
void
|
||||
QadhocWifiMac::SetCtsTimeout (Time ctsTimeout)
|
||||
{
|
||||
@@ -183,6 +195,18 @@ QadhocWifiMac::GetAckTimeout (void) const
|
||||
return m_low->GetAckTimeout ();
|
||||
}
|
||||
|
||||
Time
|
||||
QadhocWifiMac::GetBasicBlockAckTimeout (void) const
|
||||
{
|
||||
return m_low->GetBasicBlockAckTimeout ();
|
||||
}
|
||||
|
||||
Time
|
||||
QadhocWifiMac::GetCompressedBlockAckTimeout (void) const
|
||||
{
|
||||
return m_low->GetCompressedBlockAckTimeout ();
|
||||
}
|
||||
|
||||
Time
|
||||
QadhocWifiMac::GetCtsTimeout (void) const
|
||||
{
|
||||
@@ -354,7 +378,42 @@ QadhocWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
|
||||
}
|
||||
else if (hdr->IsMgt ())
|
||||
{
|
||||
//Handling action frames
|
||||
if (hdr->IsAction ())
|
||||
{
|
||||
WifiActionHeader actionHdr;
|
||||
packet->RemoveHeader (actionHdr);
|
||||
if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK &&
|
||||
actionHdr.GetAction().blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_REQUEST)
|
||||
{
|
||||
MgtAddBaRequestHeader reqHdr;
|
||||
packet->RemoveHeader (reqHdr);
|
||||
SendAddBaResponse (&reqHdr, hdr->GetAddr2 ());
|
||||
}
|
||||
else if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK &&
|
||||
actionHdr.GetAction().blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_REQUEST)
|
||||
{
|
||||
MgtAddBaResponseHeader respHdr;
|
||||
packet->RemoveHeader (respHdr);
|
||||
m_queues[QosUtilsMapTidToAc (respHdr.GetTid ())]->GotAddBaResponse (&respHdr, hdr->GetAddr2 ());
|
||||
}
|
||||
else if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK &&
|
||||
actionHdr.GetAction().blockAck == WifiActionHeader::BLOCK_ACK_DELBA)
|
||||
{
|
||||
MgtDelBaHeader delBaHdr;
|
||||
packet->RemoveHeader (delBaHdr);
|
||||
if (delBaHdr.IsByOriginator ())
|
||||
{
|
||||
/* Delba frame was sent by originator, this means that an ingoing established
|
||||
agreement exists in MacLow */
|
||||
m_low->DestroyBlockAckAgreement (hdr->GetAddr2 (), delBaHdr.GetTid ()); }
|
||||
else
|
||||
{
|
||||
/* We must notify correct queue tear down of agreement */
|
||||
AccessClass ac = QosUtilsMapTidToAc (delBaHdr.GetTid ());
|
||||
m_queues[ac]->GotDelBaFrame (&delBaHdr, hdr->GetAddr2 ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,6 +461,8 @@ QadhocWifiMac::SetQueue (enum AccessClass ac)
|
||||
edca->SetManager (m_dcfManager);
|
||||
edca->SetTypeOfStation (ADHOC_STA);
|
||||
edca->SetTxMiddle (m_txMiddle);
|
||||
edca->SetAccessClass (ac);
|
||||
edca->CompleteConfig ();
|
||||
m_queues.insert (std::make_pair(ac, edca));
|
||||
}
|
||||
|
||||
@@ -446,4 +507,59 @@ QadhocWifiMac::FinishConfigureStandard (enum WifiPhyStandard standard)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
QadhocWifiMac::SendAddBaResponse (const MgtAddBaRequestHeader *reqHdr, Mac48Address originator)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
WifiMacHeader hdr;
|
||||
hdr.SetAction ();
|
||||
hdr.SetAddr1 (originator);
|
||||
hdr.SetAddr2 (m_low->GetAddress ());
|
||||
hdr.SetAddr3 (m_low->GetAddress ());
|
||||
hdr.SetDsNotFrom ();
|
||||
hdr.SetDsNotTo ();
|
||||
|
||||
MgtAddBaResponseHeader respHdr;
|
||||
StatusCode code;
|
||||
code.SetSuccess ();
|
||||
respHdr.SetStatusCode (code);
|
||||
//Here a control about queues type?
|
||||
respHdr.SetAmsduSupport (reqHdr->IsAmsduSupported ());
|
||||
|
||||
if (reqHdr->IsImmediateBlockAck ())
|
||||
{
|
||||
respHdr.SetImmediateBlockAck ();
|
||||
}
|
||||
else
|
||||
{
|
||||
respHdr.SetDelayedBlockAck ();
|
||||
}
|
||||
respHdr.SetTid (reqHdr->GetTid ());
|
||||
/* For now there's not no control about limit of reception.
|
||||
We assume that receiver has no limit on reception.
|
||||
However we assume that a receiver sets a bufferSize in order to satisfy
|
||||
next equation:
|
||||
(bufferSize + 1) % 16 = 0
|
||||
So if a recipient is able to buffer a packet, it should be also able to buffer
|
||||
all possible packet's fragments.
|
||||
See section 7.3.1.14 in IEEE802.11e for more details. */
|
||||
respHdr.SetBufferSize (1023);
|
||||
respHdr.SetTimeout (reqHdr->GetTimeout ());
|
||||
|
||||
WifiActionHeader actionHdr;
|
||||
WifiActionHeader::ActionValue action;
|
||||
action.blockAck = WifiActionHeader::BLOCK_ACK_ADDBA_RESPONSE;
|
||||
actionHdr.SetAction (WifiActionHeader::BLOCK_ACK, action);
|
||||
|
||||
Ptr<Packet> packet = Create<Packet> ();
|
||||
packet->AddHeader (respHdr);
|
||||
packet->AddHeader (actionHdr);
|
||||
|
||||
/* ns3::MacLow have to buffer all correctly received packet for this block ack session */
|
||||
m_low->CreateBlockAckAgreement (&respHdr, originator, reqHdr->GetStartingSequence ());
|
||||
|
||||
//Better a management queue?
|
||||
m_queues[QosUtilsMapTidToAc (reqHdr->GetTid ())]->PushFront (packet, hdr);
|
||||
}
|
||||
} //namespace ns3
|
||||
|
||||
@@ -38,6 +38,7 @@ class WifiPhy;
|
||||
class DcfManager;
|
||||
class MacLow;
|
||||
class MacRxMiddle;
|
||||
class MgtAddBaRequestHeader;
|
||||
|
||||
class QadhocWifiMac : public WifiMac
|
||||
{
|
||||
@@ -73,6 +74,10 @@ public:
|
||||
virtual void SetAddress (Mac48Address address);
|
||||
virtual void SetSsid (Ssid ssid);
|
||||
virtual Mac48Address GetBssid (void) const;
|
||||
virtual void SetBasicBlockAckTimeout (Time blockAckTimeout);
|
||||
virtual void SetCompressedBlockAckTimeout (Time blockAckTimeout);
|
||||
virtual Time GetBasicBlockAckTimeout (void) const;
|
||||
virtual Time GetCompressedBlockAckTimeout (void) const;
|
||||
|
||||
|
||||
private:
|
||||
@@ -82,7 +87,8 @@ private:
|
||||
void ForwardUp (Ptr<Packet> packet, Mac48Address from, Mac48Address to);
|
||||
QadhocWifiMac &operator = (const QadhocWifiMac &);
|
||||
QadhocWifiMac (const QadhocWifiMac &);
|
||||
|
||||
void SendAddBaResponse (const MgtAddBaRequestHeader *reqHdr, Mac48Address originator);
|
||||
|
||||
/**
|
||||
* When an A-MSDU is received, is deaggregated by this method and all extracted packets are
|
||||
* forwarded up.
|
||||
|
||||
@@ -197,6 +197,18 @@ QapWifiMac::SetAckTimeout (Time ackTimeout)
|
||||
m_low->SetAckTimeout (ackTimeout);
|
||||
}
|
||||
|
||||
void
|
||||
QapWifiMac::SetBasicBlockAckTimeout (Time blockAckTimeout)
|
||||
{
|
||||
m_low->SetBasicBlockAckTimeout (blockAckTimeout);
|
||||
}
|
||||
|
||||
void
|
||||
QapWifiMac::SetCompressedBlockAckTimeout (Time blockAckTimeout)
|
||||
{
|
||||
m_low->SetCompressedBlockAckTimeout (blockAckTimeout);
|
||||
}
|
||||
|
||||
void
|
||||
QapWifiMac::SetCtsTimeout (Time ctsTimeout)
|
||||
{
|
||||
@@ -233,6 +245,18 @@ QapWifiMac::GetAckTimeout (void) const
|
||||
return m_low->GetAckTimeout ();
|
||||
}
|
||||
|
||||
Time
|
||||
QapWifiMac::GetBasicBlockAckTimeout () const
|
||||
{
|
||||
return m_low->GetBasicBlockAckTimeout ();
|
||||
}
|
||||
|
||||
Time
|
||||
QapWifiMac::GetCompressedBlockAckTimeout () const
|
||||
{
|
||||
return m_low->GetCompressedBlockAckTimeout ();
|
||||
}
|
||||
|
||||
Time
|
||||
QapWifiMac::GetCtsTimeout (void) const
|
||||
{
|
||||
@@ -673,7 +697,44 @@ QapWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
|
||||
else if (hdr->IsReassocReq ())
|
||||
{
|
||||
/* we don't support reassoc frames for now */
|
||||
}
|
||||
}
|
||||
else if (hdr->IsAction ())
|
||||
{
|
||||
WifiActionHeader actionHdr;
|
||||
packet->RemoveHeader (actionHdr);
|
||||
if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK &&
|
||||
actionHdr.GetAction().blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_REQUEST)
|
||||
{
|
||||
MgtAddBaRequestHeader reqHdr;
|
||||
packet->RemoveHeader (reqHdr);
|
||||
SendAddBaResponse (&reqHdr, hdr->GetAddr2 ());
|
||||
}
|
||||
else if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK &&
|
||||
actionHdr.GetAction().blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_RESPONSE)
|
||||
{
|
||||
MgtAddBaResponseHeader respHdr;
|
||||
packet->RemoveHeader (respHdr);
|
||||
m_queues[QosUtilsMapTidToAc (respHdr.GetTid ())]->GotAddBaResponse (&respHdr, hdr->GetAddr2 ());
|
||||
}
|
||||
else if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK &&
|
||||
actionHdr.GetAction().blockAck == WifiActionHeader::BLOCK_ACK_DELBA)
|
||||
{
|
||||
MgtDelBaHeader delBaHdr;
|
||||
packet->RemoveHeader (delBaHdr);
|
||||
if (delBaHdr.IsByOriginator ())
|
||||
{
|
||||
/* Delba frame was sent by originator, this means that an ingoing established
|
||||
agreement exists in MacLow */
|
||||
m_low->DestroyBlockAckAgreement (hdr->GetAddr2 (), delBaHdr.GetTid ());
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We must notify correct queue tear down of agreement */
|
||||
AccessClass ac = QosUtilsMapTidToAc (delBaHdr.GetTid ());
|
||||
m_queues[ac]->GotDelBaFrame (&delBaHdr, hdr->GetAddr2 ());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (hdr->IsAuthentication () ||
|
||||
hdr->IsDeauthentication ())
|
||||
{
|
||||
@@ -744,6 +805,8 @@ QapWifiMac::SetQueue (enum AccessClass ac)
|
||||
edca->SetTxMiddle (m_txMiddle);
|
||||
edca->SetTxOkCallback (MakeCallback (&QapWifiMac::TxOk, this));
|
||||
edca->SetTxFailedCallback (MakeCallback (&QapWifiMac::TxFailed, this));
|
||||
edca->SetAccessClass (ac);
|
||||
edca->CompleteConfig ();
|
||||
m_queues.insert (std::make_pair(ac, edca));
|
||||
}
|
||||
|
||||
@@ -799,4 +862,59 @@ QapWifiMac::DoStart (void)
|
||||
WifiMac::DoStart ();
|
||||
}
|
||||
|
||||
void
|
||||
QapWifiMac::SendAddBaResponse (const MgtAddBaRequestHeader *reqHdr, Mac48Address originator)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
WifiMacHeader hdr;
|
||||
hdr.SetAction ();
|
||||
hdr.SetAddr1 (originator);
|
||||
hdr.SetAddr2 (m_low->GetAddress ());
|
||||
hdr.SetAddr3 (m_low->GetAddress ());
|
||||
hdr.SetDsNotFrom ();
|
||||
hdr.SetDsNotTo ();
|
||||
|
||||
MgtAddBaResponseHeader respHdr;
|
||||
StatusCode code;
|
||||
code.SetSuccess ();
|
||||
respHdr.SetStatusCode (code);
|
||||
//Here a control about queues type?
|
||||
respHdr.SetAmsduSupport (reqHdr->IsAmsduSupported ());
|
||||
|
||||
if (reqHdr->IsImmediateBlockAck ())
|
||||
{
|
||||
respHdr.SetImmediateBlockAck ();
|
||||
}
|
||||
else
|
||||
{
|
||||
respHdr.SetDelayedBlockAck ();
|
||||
}
|
||||
respHdr.SetTid (reqHdr->GetTid ());
|
||||
/* For now there's not no control about limit of reception.
|
||||
We assume that receiver has no limit on reception.
|
||||
However we assume that a receiver sets a bufferSize in order to satisfy
|
||||
next equation:
|
||||
(bufferSize + 1) % 16 = 0
|
||||
So if a recipient is able to buffer a packet, it should be also able to buffer
|
||||
all possible packet's fragments.
|
||||
See section 7.3.1.14 in IEEE802.11e for more details. */
|
||||
respHdr.SetBufferSize (1023);
|
||||
respHdr.SetTimeout (reqHdr->GetTimeout ());
|
||||
|
||||
WifiActionHeader actionHdr;
|
||||
WifiActionHeader::ActionValue action;
|
||||
action.blockAck = WifiActionHeader::BLOCK_ACK_ADDBA_RESPONSE;
|
||||
actionHdr.SetAction (WifiActionHeader::BLOCK_ACK, action);
|
||||
|
||||
Ptr<Packet> packet = Create<Packet> ();
|
||||
packet->AddHeader (respHdr);
|
||||
packet->AddHeader (actionHdr);
|
||||
|
||||
/* ns3::MacLow have to buffer all correctly received packet for this block ack session */
|
||||
m_low->CreateBlockAckAgreement (&respHdr, originator, reqHdr->GetStartingSequence ());
|
||||
|
||||
//Better a management queue?
|
||||
m_queues[QosUtilsMapTidToAc (reqHdr->GetTid ())]->PushFront (packet, hdr);
|
||||
}
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
@@ -47,6 +47,7 @@ class MacTxMiddle;
|
||||
class DcfManager;
|
||||
class AmsduSubframeHeader;
|
||||
class MsduAggregator;
|
||||
class MgtAddBaRequestHeader;
|
||||
|
||||
class QapWifiMac : public WifiMac
|
||||
{
|
||||
@@ -81,6 +82,10 @@ public:
|
||||
virtual void SetAddress (Mac48Address address);
|
||||
virtual void SetSsid (Ssid ssid);
|
||||
virtual Mac48Address GetBssid (void) const;
|
||||
virtual void SetBasicBlockAckTimeout (Time blockAckTimeout);
|
||||
virtual void SetCompressedBlockAckTimeout (Time blockAckTimeout);
|
||||
virtual Time GetBasicBlockAckTimeout (void) const;
|
||||
virtual Time GetCompressedBlockAckTimeout (void) const;
|
||||
|
||||
void SetBeaconInterval (Time interval);
|
||||
Time GetBeaconInterval (void) const;
|
||||
@@ -103,6 +108,7 @@ private:
|
||||
void TxFailed (const WifiMacHeader& hdr);
|
||||
void SendProbeResp (Mac48Address to);
|
||||
void SendAssocResp (Mac48Address to, bool success);
|
||||
void SendAddBaResponse (const MgtAddBaRequestHeader *reqHdr, Mac48Address originator);
|
||||
void SendOneBeacon (void);
|
||||
SupportedRates GetSupportedRates (void) const;
|
||||
void SetBeaconGeneration (bool enable);
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005, 2009 INRIA
|
||||
* Copyright (c) 2009 MIRKO BANCHI
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mirko Banchi <mk.banchi@gmail.com>
|
||||
*/
|
||||
#include "qos-blocked-destinations.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
QosBlockedDestinations::QosBlockedDestinations ()
|
||||
{}
|
||||
|
||||
QosBlockedDestinations::~QosBlockedDestinations ()
|
||||
{}
|
||||
|
||||
bool
|
||||
QosBlockedDestinations::IsBlocked (Mac48Address dest, uint8_t tid) const
|
||||
{
|
||||
for (BlockedPacketsCI i = m_blockedQosPackets.begin (); i != m_blockedQosPackets.end (); i++)
|
||||
{
|
||||
if (i->first == dest && i->second == tid)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
QosBlockedDestinations::Block (Mac48Address dest, uint8_t tid)
|
||||
{
|
||||
if (!IsBlocked (dest, tid))
|
||||
{
|
||||
m_blockedQosPackets.push_back (std::make_pair (dest, tid));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
QosBlockedDestinations::Unblock (Mac48Address dest, uint8_t tid)
|
||||
{
|
||||
for (BlockedPacketsI i = m_blockedQosPackets.begin (); i != m_blockedQosPackets.end (); i++)
|
||||
{
|
||||
if (i->first == dest && i->second == tid)
|
||||
{
|
||||
m_blockedQosPackets.erase (i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace ns3
|
||||
@@ -0,0 +1,48 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005, 2009 INRIA
|
||||
* Copyright (c) 2009 MIRKO BANCHI
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mirko Banchi <mk.banchi@gmail.com>
|
||||
*/
|
||||
#ifndef QOS_BLOCKED_DESTINATIONS_H
|
||||
#define QOS_BLOCKED_DESTINATIONS_H
|
||||
|
||||
#include <list>
|
||||
#include "ns3/mac48-address.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class QosBlockedDestinations
|
||||
{
|
||||
public:
|
||||
QosBlockedDestinations ();
|
||||
~QosBlockedDestinations ();
|
||||
|
||||
void Block (Mac48Address dest, uint8_t tid);
|
||||
void Unblock (Mac48Address dest, uint8_t tid);
|
||||
bool IsBlocked (Mac48Address dest, uint8_t tid) const;
|
||||
|
||||
private:
|
||||
typedef std::list<std::pair<Mac48Address, uint8_t> > BlockedPackets;
|
||||
typedef std::list<std::pair<Mac48Address, uint8_t> >::iterator BlockedPacketsI;
|
||||
typedef std::list<std::pair<Mac48Address, uint8_t> >::const_iterator BlockedPacketsCI;
|
||||
BlockedPackets m_blockedQosPackets;
|
||||
};
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
#endif /* QOS_BLOCKED_DESTINATIONS_H */
|
||||
@@ -16,6 +16,7 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mirko Banchi <mk.banchi@gmail.com>
|
||||
* Author: Cecchi Niccolò <insa@igeek.it>
|
||||
*/
|
||||
#include "qos-utils.h"
|
||||
#include "qos-tag.h"
|
||||
@@ -69,4 +70,16 @@ QosUtilsGetTidForPacket (Ptr<const Packet> packet)
|
||||
return tid;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
QosUtilsMapSeqControlToUniqueInteger (uint16_t seqControl, uint16_t endSequence)
|
||||
{
|
||||
uint32_t integer = 0;
|
||||
uint16_t numberSeq = (seqControl>>4) & 0x0fff;
|
||||
integer = (4096 - (endSequence + 1) + numberSeq) % 4096;
|
||||
integer *= 16;
|
||||
integer += (seqControl & 0x000f);
|
||||
return integer;
|
||||
}
|
||||
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
@@ -45,6 +45,13 @@ AccessClass QosUtilsMapTidToAc (uint8_t tid);
|
||||
*/
|
||||
uint8_t QosUtilsGetTidForPacket (Ptr<const Packet> packet);
|
||||
|
||||
/*
|
||||
* Next function is useful to correctly sort buffered packets under block ack.
|
||||
* When an BAR is received from originator station, completed "old"
|
||||
* (see section 9.10.3 in IEEE802.11e) packets must be forwarded up before "new" packets.
|
||||
*/
|
||||
uint32_t QosUtilsMapSeqControlToUniqueInteger (uint16_t seqControl, uint16_t endSequence);
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
#endif /* QOS_UTILS_H */
|
||||
|
||||
@@ -169,6 +169,18 @@ QstaWifiMac::SetAckTimeout (Time ackTimeout)
|
||||
m_low->SetAckTimeout (ackTimeout);
|
||||
}
|
||||
|
||||
void
|
||||
QstaWifiMac::SetBasicBlockAckTimeout (Time blockAckTimeout)
|
||||
{
|
||||
m_low->SetBasicBlockAckTimeout (blockAckTimeout);
|
||||
}
|
||||
|
||||
void
|
||||
QstaWifiMac::SetCompressedBlockAckTimeout (Time blockAckTimeout)
|
||||
{
|
||||
m_low->SetCompressedBlockAckTimeout (blockAckTimeout);
|
||||
}
|
||||
|
||||
void
|
||||
QstaWifiMac::SetCtsTimeout (Time ctsTimeout)
|
||||
{
|
||||
@@ -205,6 +217,18 @@ QstaWifiMac::GetAckTimeout (void) const
|
||||
return m_low->GetAckTimeout ();
|
||||
}
|
||||
|
||||
Time
|
||||
QstaWifiMac::GetBasicBlockAckTimeout (void) const
|
||||
{
|
||||
return m_low->GetBasicBlockAckTimeout ();
|
||||
}
|
||||
|
||||
Time
|
||||
QstaWifiMac::GetCompressedBlockAckTimeout (void) const
|
||||
{
|
||||
return m_low->GetCompressedBlockAckTimeout ();
|
||||
}
|
||||
|
||||
Time
|
||||
QstaWifiMac::GetCtsTimeout (void) const
|
||||
{
|
||||
@@ -674,6 +698,43 @@ QstaWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (hdr->IsAction ())
|
||||
{
|
||||
WifiActionHeader actionHdr;
|
||||
packet->RemoveHeader (actionHdr);
|
||||
if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK &&
|
||||
actionHdr.GetAction().blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_REQUEST)
|
||||
{
|
||||
MgtAddBaRequestHeader reqHdr;
|
||||
packet->RemoveHeader (reqHdr);
|
||||
SendAddBaResponse (&reqHdr, hdr->GetAddr2 ());
|
||||
}
|
||||
else if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK &&
|
||||
actionHdr.GetAction().blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_RESPONSE)
|
||||
{
|
||||
MgtAddBaResponseHeader respHdr;
|
||||
packet->RemoveHeader (respHdr);
|
||||
m_queues[QosUtilsMapTidToAc (respHdr.GetTid ())]->GotAddBaResponse (&respHdr, hdr->GetAddr2 ());
|
||||
}
|
||||
else if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK &&
|
||||
actionHdr.GetAction().blockAck == WifiActionHeader::BLOCK_ACK_DELBA)
|
||||
{
|
||||
MgtDelBaHeader delBaHdr;
|
||||
packet->RemoveHeader (delBaHdr);
|
||||
if (delBaHdr.IsByOriginator ())
|
||||
{
|
||||
/* Delba frame was sent by originator, this means that an ingoing established
|
||||
agreement exists in MacLow */
|
||||
m_low->DestroyBlockAckAgreement (hdr->GetAddr2 (), delBaHdr.GetTid ());
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We must notify correct queue tear down of agreement */
|
||||
AccessClass ac = QosUtilsMapTidToAc (delBaHdr.GetTid ());
|
||||
m_queues[ac]->GotDelBaFrame (&delBaHdr, hdr->GetAddr2 ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SupportedRates
|
||||
@@ -731,6 +792,8 @@ QstaWifiMac::SetQueue (enum AccessClass ac)
|
||||
edca->SetManager (m_dcfManager);
|
||||
edca->SetTypeOfStation (STA);
|
||||
edca->SetTxMiddle (m_txMiddle);
|
||||
edca->SetAccessClass (ac);
|
||||
edca->CompleteConfig ();
|
||||
m_queues.insert (std::make_pair(ac, edca));
|
||||
}
|
||||
|
||||
@@ -775,5 +838,59 @@ QstaWifiMac::FinishConfigureStandard (enum WifiPhyStandard standard)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
QstaWifiMac::SendAddBaResponse (const MgtAddBaRequestHeader *reqHdr, Mac48Address originator)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
WifiMacHeader hdr;
|
||||
hdr.SetAction ();
|
||||
hdr.SetAddr1 (originator);
|
||||
hdr.SetAddr2 (m_low->GetAddress ());
|
||||
hdr.SetAddr3 (m_low->GetAddress ());
|
||||
hdr.SetDsNotFrom ();
|
||||
hdr.SetDsNotTo ();
|
||||
|
||||
MgtAddBaResponseHeader respHdr;
|
||||
StatusCode code;
|
||||
code.SetSuccess ();
|
||||
respHdr.SetStatusCode (code);
|
||||
//Here a control about queues type?
|
||||
respHdr.SetAmsduSupport (reqHdr->IsAmsduSupported ());
|
||||
|
||||
if (reqHdr->IsImmediateBlockAck ())
|
||||
{
|
||||
respHdr.SetImmediateBlockAck ();
|
||||
}
|
||||
else
|
||||
{
|
||||
respHdr.SetDelayedBlockAck ();
|
||||
}
|
||||
respHdr.SetTid (reqHdr->GetTid ());
|
||||
/* For now there's not no control about limit of reception.
|
||||
We assume that receiver has no limit on reception.
|
||||
However we assume that a receiver sets a bufferSize in order to satisfy
|
||||
next equation:
|
||||
(bufferSize + 1) % 16 = 0
|
||||
So if a recipient is able to buffer a packet, it should be also able to buffer
|
||||
all possible packet's fragments.
|
||||
See section 7.3.1.14 in IEEE802.11e for more details. */
|
||||
respHdr.SetBufferSize (1023);
|
||||
respHdr.SetTimeout (reqHdr->GetTimeout ());
|
||||
|
||||
WifiActionHeader actionHdr;
|
||||
WifiActionHeader::ActionValue action;
|
||||
action.blockAck = WifiActionHeader::BLOCK_ACK_ADDBA_RESPONSE;
|
||||
actionHdr.SetAction (WifiActionHeader::BLOCK_ACK, action);
|
||||
|
||||
Ptr<Packet> packet = Create<Packet> ();
|
||||
packet->AddHeader (respHdr);
|
||||
packet->AddHeader (actionHdr);
|
||||
|
||||
/* ns3::MacLow have to buffer all correctly received packet for this block ack session */
|
||||
m_low->CreateBlockAckAgreement (&respHdr, originator, reqHdr->GetStartingSequence ());
|
||||
|
||||
//Better a management queue?
|
||||
m_queues[QosUtilsMapTidToAc (reqHdr->GetTid ())]->PushFront (packet, hdr);
|
||||
}
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
@@ -45,6 +45,7 @@ class MacLow;
|
||||
class WifiMacHeader;
|
||||
class AmsduSubframeHeader;
|
||||
class MsduAggregator;
|
||||
class MgtAddBaRequestHeader;
|
||||
|
||||
class QstaWifiMac : public WifiMac
|
||||
{
|
||||
@@ -80,6 +81,10 @@ public:
|
||||
virtual void SetAddress (Mac48Address address);
|
||||
virtual void SetSsid (Ssid ssid);
|
||||
virtual Mac48Address GetBssid (void) const;
|
||||
virtual void SetBasicBlockAckTimeout (Time blockAckTimeout);
|
||||
virtual void SetCompressedBlockAckTimeout (Time blockAckTimeout);
|
||||
virtual Time GetBasicBlockAckTimeout (void) const;
|
||||
virtual Time GetCompressedBlockAckTimeout (void) const;
|
||||
|
||||
void SetMaxMissedBeacons (uint32_t missed);
|
||||
void SetProbeRequestTimeout (Time timeout);
|
||||
@@ -100,6 +105,7 @@ private:
|
||||
void ProbeRequestTimeout (void);
|
||||
void SendAssociationRequest (void);
|
||||
void SendProbeRequest (void);
|
||||
void SendAddBaResponse (const MgtAddBaRequestHeader *reqHdr, Mac48Address originator);
|
||||
void TryToEnsureAssociated (void);
|
||||
bool IsAssociated (void) const;
|
||||
bool IsWaitAssocResp (void) const;
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
#include "wifi-channel.h"
|
||||
#include "wifi-net-device.h"
|
||||
#include "yans-wifi-phy.h"
|
||||
#include "propagation-loss-model.h"
|
||||
#include "propagation-delay-model.h"
|
||||
#include "ns3/propagation-loss-model.h"
|
||||
#include "ns3/propagation-delay-model.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("WifiChannel");
|
||||
|
||||
|
||||
@@ -122,6 +122,19 @@ WifiMacHeader::SetBeacon (void)
|
||||
m_ctrlType = TYPE_MGT;
|
||||
m_ctrlSubtype = 8;
|
||||
}
|
||||
void
|
||||
WifiMacHeader::SetBlockAckReq (void)
|
||||
{
|
||||
m_ctrlType = TYPE_CTL;
|
||||
m_ctrlSubtype = 8;
|
||||
}
|
||||
void
|
||||
WifiMacHeader::SetBlockAck (void)
|
||||
{
|
||||
m_ctrlType = TYPE_CTL;
|
||||
m_ctrlSubtype = 9;
|
||||
}
|
||||
|
||||
void
|
||||
WifiMacHeader::SetTypeData (void)
|
||||
{
|
||||
@@ -348,6 +361,21 @@ void WifiMacHeader::SetQosAckPolicy (enum QosAckPolicy policy)
|
||||
break;
|
||||
}
|
||||
}
|
||||
void
|
||||
WifiMacHeader::SetQosNormalAck ()
|
||||
{
|
||||
m_qosAckPolicy = 0;
|
||||
}
|
||||
void
|
||||
WifiMacHeader::SetQosBlockAck ()
|
||||
{
|
||||
m_qosAckPolicy = 3;
|
||||
}
|
||||
void
|
||||
WifiMacHeader::SetQosNoAck ()
|
||||
{
|
||||
m_qosAckPolicy = 1;
|
||||
}
|
||||
void WifiMacHeader::SetQosAmsdu (void)
|
||||
{
|
||||
m_amsduPresent = 1;
|
||||
@@ -630,6 +658,16 @@ WifiMacHeader::IsMultihopAction (void) const
|
||||
{
|
||||
return (GetType () == WIFI_MAC_MGT_MULTIHOP_ACTION);
|
||||
}
|
||||
bool
|
||||
WifiMacHeader::IsBlockAckReq (void) const
|
||||
{
|
||||
return (GetType () == WIFI_MAC_CTL_BACKREQ)?true:false;
|
||||
}
|
||||
bool
|
||||
WifiMacHeader::IsBlockAck (void) const
|
||||
{
|
||||
return (GetType () == WIFI_MAC_CTL_BACKRESP)?true:false;
|
||||
}
|
||||
|
||||
|
||||
uint16_t
|
||||
@@ -808,8 +846,7 @@ WifiMacHeader::GetSize (void) const
|
||||
break;
|
||||
case SUBTYPE_CTL_BACKREQ:
|
||||
case SUBTYPE_CTL_BACKRESP:
|
||||
// NOT IMPLEMENTED
|
||||
NS_ASSERT (false);
|
||||
size = 2+2+6+6;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1018,8 +1055,7 @@ WifiMacHeader::Serialize (Buffer::Iterator i) const
|
||||
break;
|
||||
case SUBTYPE_CTL_BACKREQ:
|
||||
case SUBTYPE_CTL_BACKRESP:
|
||||
// NOT IMPLEMENTED
|
||||
NS_ASSERT (false);
|
||||
WriteTo (i, m_addr2);
|
||||
break;
|
||||
default:
|
||||
//NOTREACHED
|
||||
@@ -1068,8 +1104,7 @@ WifiMacHeader::Deserialize (Buffer::Iterator start)
|
||||
break;
|
||||
case SUBTYPE_CTL_BACKREQ:
|
||||
case SUBTYPE_CTL_BACKRESP:
|
||||
// NOT IMPLEMENTED
|
||||
NS_ASSERT (false);
|
||||
ReadFrom (i, m_addr2);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -102,6 +102,8 @@ public:
|
||||
void SetBeacon (void);
|
||||
void SetTypeData (void);
|
||||
void SetAction ();
|
||||
void SetBlockAckReq (void);
|
||||
void SetBlockAck (void);
|
||||
void SetMultihopAction();
|
||||
void SetDsFrom (void);
|
||||
void SetDsNotFrom (void);
|
||||
@@ -125,6 +127,9 @@ public:
|
||||
void SetQosEosp ();
|
||||
void SetQosNoEosp ();
|
||||
void SetQosAckPolicy (enum QosAckPolicy);
|
||||
void SetQosNormalAck (void);
|
||||
void SetQosBlockAck (void);
|
||||
void SetQosNoAck (void);
|
||||
void SetQosAmsdu (void);
|
||||
void SetQosNoAmsdu (void);
|
||||
void SetQosTxopLimit (uint8_t txop);
|
||||
@@ -145,6 +150,8 @@ public:
|
||||
bool IsRts (void) const;
|
||||
bool IsCts (void) const;
|
||||
bool IsAck (void) const;
|
||||
bool IsBlockAckReq (void) const;
|
||||
bool IsBlockAck (void) const;
|
||||
bool IsAssocReq (void) const;
|
||||
bool IsAssocResp (void) const;
|
||||
bool IsReassocReq (void) const;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "ns3/uinteger.h"
|
||||
|
||||
#include "wifi-mac-queue.h"
|
||||
#include "qos-blocked-destinations.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -111,18 +112,19 @@ WifiMacQueue::Cleanup (void)
|
||||
|
||||
Time now = Simulator::Now ();
|
||||
uint32_t n = 0;
|
||||
PacketQueueI end = m_queue.begin ();
|
||||
for (PacketQueueI i = m_queue.begin (); i != m_queue.end (); i++)
|
||||
for (PacketQueueI i = m_queue.begin (); i != m_queue.end ();)
|
||||
{
|
||||
if (i->tstamp + m_maxDelay > now)
|
||||
{
|
||||
end = i;
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = m_queue.erase (i);
|
||||
n++;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
m_size -= n;
|
||||
m_queue.erase (m_queue.begin (), end);
|
||||
}
|
||||
|
||||
Ptr<const Packet>
|
||||
@@ -260,4 +262,81 @@ WifiMacQueue::Remove (Ptr<const Packet> packet)
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
WifiMacQueue::PushFront (Ptr<const Packet> packet, const WifiMacHeader &hdr)
|
||||
{
|
||||
Cleanup ();
|
||||
if (m_size == m_maxSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Time now = Simulator::Now ();
|
||||
m_queue.push_front (Item (packet, hdr, now));
|
||||
m_size++;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
WifiMacQueue::GetNPacketsByTidAndAddress (uint8_t tid, WifiMacHeader::AddressType type,
|
||||
Mac48Address addr)
|
||||
{
|
||||
Cleanup ();
|
||||
uint32_t nPackets = 0;
|
||||
if (!m_queue.empty ())
|
||||
{
|
||||
PacketQueueI it;
|
||||
NS_ASSERT (type <= 4);
|
||||
for (it = m_queue.begin (); it != m_queue.end (); it++)
|
||||
{
|
||||
if (GetAddressForPacket (type, it) == addr)
|
||||
{
|
||||
if (it->hdr.IsQosData () && it->hdr.GetQosTid () == tid)
|
||||
{
|
||||
nPackets++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nPackets;
|
||||
}
|
||||
|
||||
Ptr<const Packet>
|
||||
WifiMacQueue::DequeueFirstAvailable (WifiMacHeader *hdr, Time ×tamp,
|
||||
const QosBlockedDestinations *blockedPackets)
|
||||
{
|
||||
Cleanup ();
|
||||
Ptr<const Packet> packet = 0;
|
||||
for (PacketQueueI it = m_queue.begin (); it != m_queue.end (); it++)
|
||||
{
|
||||
if (!it->hdr.IsQosData () ||
|
||||
!blockedPackets->IsBlocked (it->hdr.GetAddr1 (), it->hdr.GetQosTid ()))
|
||||
{
|
||||
*hdr = it->hdr;
|
||||
timestamp = it->tstamp;
|
||||
packet = it->packet;
|
||||
m_queue.erase (it);
|
||||
m_size--;
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
Ptr<const Packet>
|
||||
WifiMacQueue::PeekFirstAvailable (WifiMacHeader *hdr, Time ×tamp,
|
||||
const QosBlockedDestinations *blockedPackets)
|
||||
{
|
||||
Cleanup ();
|
||||
for (PacketQueueI it = m_queue.begin (); it != m_queue.end (); it++)
|
||||
{
|
||||
if (!it->hdr.IsQosData () ||
|
||||
!blockedPackets->IsBlocked (it->hdr.GetAddr1 (), it->hdr.GetQosTid ()))
|
||||
{
|
||||
*hdr = it->hdr;
|
||||
timestamp = it->tstamp;
|
||||
return it->packet;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
namespace ns3 {
|
||||
|
||||
class WifiMacParameters;
|
||||
class QosBlockedDestinations;
|
||||
|
||||
/**
|
||||
* \brief a 802.11e-specific queue.
|
||||
@@ -61,6 +62,7 @@ public:
|
||||
Time GetMaxDelay (void) const;
|
||||
|
||||
void Enqueue (Ptr<const Packet> packet, const WifiMacHeader &hdr);
|
||||
void PushFront (Ptr<const Packet> packet, const WifiMacHeader &hdr);
|
||||
Ptr<const Packet> Dequeue (WifiMacHeader *hdr);
|
||||
Ptr<const Packet> Peek (WifiMacHeader *hdr);
|
||||
/**
|
||||
@@ -91,12 +93,33 @@ public:
|
||||
* performed in linear time (O(n)).
|
||||
*/
|
||||
bool Remove (Ptr<const Packet> packet);
|
||||
|
||||
/**
|
||||
* Returns number of QoS packets having tid equals to <i>tid</i> and address
|
||||
* specified by <i>type</i> equals to <i>addr</i>.
|
||||
*/
|
||||
uint32_t GetNPacketsByTidAndAddress (uint8_t tid,
|
||||
WifiMacHeader::AddressType type,
|
||||
Mac48Address addr);
|
||||
/**
|
||||
* Returns first available packet for transmission. A packet could be no available
|
||||
* if it's a QoS packet with a tid and an address1 fields equal to <i>tid</i> and <i>addr</i>
|
||||
* respectively that index a pending agreement in the BlockAckManager object.
|
||||
* So that packet must not be transmitted until reception of an ADDBA response frame from station
|
||||
* addressed by <i>addr</i>. This method removes the packet from queue.
|
||||
*/
|
||||
Ptr<const Packet> DequeueFirstAvailable (WifiMacHeader *hdr,
|
||||
Time &tStamp,
|
||||
const QosBlockedDestinations *blockedPackets);
|
||||
/**
|
||||
* Returns first available packet for transmission. The packet isn't removed from queue.
|
||||
*/
|
||||
Ptr<const Packet> PeekFirstAvailable (WifiMacHeader *hdr,
|
||||
Time &tStamp,
|
||||
const QosBlockedDestinations *blockedPackets);
|
||||
void Flush (void);
|
||||
|
||||
bool IsEmpty (void);
|
||||
uint32_t GetSize (void);
|
||||
|
||||
private:
|
||||
struct Item;
|
||||
|
||||
|
||||
@@ -69,6 +69,63 @@ WifiMac::GetDefaultCtsAckTimeout (void)
|
||||
return ctsTimeout;
|
||||
}
|
||||
|
||||
Time
|
||||
WifiMac::GetDefaultBasicBlockAckDelay (void)
|
||||
{
|
||||
// This value must be rivisited
|
||||
return MicroSeconds (250);
|
||||
}
|
||||
Time
|
||||
WifiMac::GetDefaultCompressedBlockAckDelay (void)
|
||||
{
|
||||
// This value must be rivisited
|
||||
return MicroSeconds (68);
|
||||
}
|
||||
Time
|
||||
WifiMac::GetDefaultBasicBlockAckTimeout (void)
|
||||
{
|
||||
Time blockAckTimeout = GetDefaultSifs ();
|
||||
blockAckTimeout += GetDefaultBasicBlockAckDelay ();
|
||||
blockAckTimeout += MicroSeconds (GetDefaultMaxPropagationDelay ().GetMicroSeconds () * 2);
|
||||
blockAckTimeout += GetDefaultSlot ();
|
||||
return blockAckTimeout;
|
||||
}
|
||||
Time
|
||||
WifiMac::GetDefaultCompressedBlockAckTimeout (void)
|
||||
{
|
||||
Time blockAckTimeout = GetDefaultSifs ();
|
||||
blockAckTimeout += GetDefaultCompressedBlockAckDelay ();
|
||||
blockAckTimeout += MicroSeconds (GetDefaultMaxPropagationDelay ().GetMicroSeconds () * 2);
|
||||
blockAckTimeout += GetDefaultSlot ();
|
||||
return blockAckTimeout;
|
||||
}
|
||||
|
||||
void
|
||||
WifiMac::SetBasicBlockAckTimeout (Time blockAckTimeout)
|
||||
{
|
||||
//this method must be implemented by QoS WifiMacs
|
||||
}
|
||||
|
||||
Time
|
||||
WifiMac::GetBasicBlockAckTimeout (void) const
|
||||
{
|
||||
//this method must be implemented by QoS WifiMacs
|
||||
return MicroSeconds (0);
|
||||
}
|
||||
|
||||
void
|
||||
WifiMac::SetCompressedBlockAckTimeout (Time blockAckTimeout)
|
||||
{
|
||||
//this methos must be implemented by QoS WifiMacs
|
||||
}
|
||||
|
||||
Time
|
||||
WifiMac::GetCompressedBlockAckTimeout (void) const
|
||||
{
|
||||
//this method must be implemented by QoS WifiMacs
|
||||
return MicroSeconds (0);
|
||||
}
|
||||
|
||||
TypeId
|
||||
WifiMac::GetTypeId (void)
|
||||
{
|
||||
@@ -84,6 +141,16 @@ WifiMac::GetTypeId (void)
|
||||
MakeTimeAccessor (&WifiMac::GetAckTimeout,
|
||||
&WifiMac::SetAckTimeout),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("BasicBlockAckTimeout", "When this timeout expires, the BASIC_BLOCK_ACK_REQ/BASIC_BLOCK_ACK handshake has failed.",
|
||||
TimeValue (GetDefaultBasicBlockAckTimeout ()),
|
||||
MakeTimeAccessor (&WifiMac::GetBasicBlockAckTimeout,
|
||||
&WifiMac::SetBasicBlockAckTimeout),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("CompressedBlockAckTimeout", "When this timeout expires, the COMPRESSED_BLOCK_ACK_REQ/COMPRESSED_BLOCK_ACK handshake has failed.",
|
||||
TimeValue (GetDefaultCompressedBlockAckTimeout ()),
|
||||
MakeTimeAccessor (&WifiMac::GetCompressedBlockAckTimeout,
|
||||
&WifiMac::SetCompressedBlockAckTimeout),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("Sifs", "The value of the SIFS constant.",
|
||||
TimeValue (GetDefaultSifs ()),
|
||||
MakeTimeAccessor (&WifiMac::SetSifs,
|
||||
|
||||
@@ -179,6 +179,13 @@ public:
|
||||
* \param linkDown the callback to invoke when the link becomes down.
|
||||
*/
|
||||
virtual void SetLinkDownCallback (Callback<void> linkDown) = 0;
|
||||
/* Next functions are not pure vitual so non Qos WifiMacs are not
|
||||
* forced to implement them.
|
||||
*/
|
||||
virtual void SetBasicBlockAckTimeout (Time blockAckTimeout);
|
||||
virtual Time GetBasicBlockAckTimeout (void) const;
|
||||
virtual void SetCompressedBlockAckTimeout (Time blockAckTimeout);
|
||||
virtual Time GetCompressedBlockAckTimeout (void) const;
|
||||
|
||||
/**
|
||||
* Public method used to fire a MacTx trace. Implemented for encapsulation
|
||||
@@ -224,6 +231,10 @@ private:
|
||||
static Time GetDefaultEifsNoDifs (void);
|
||||
static Time GetDefaultCtsAckDelay (void);
|
||||
static Time GetDefaultCtsAckTimeout (void);
|
||||
static Time GetDefaultBasicBlockAckDelay (void);
|
||||
static Time GetDefaultBasicBlockAckTimeout (void);
|
||||
static Time GetDefaultCompressedBlockAckDelay (void);
|
||||
static Time GetDefaultCompressedBlockAckTimeout (void);
|
||||
/**
|
||||
* \param standard the phy standard to be used
|
||||
*
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#include "wifi-net-device.h"
|
||||
#include "yans-wifi-channel.h"
|
||||
#include "yans-wifi-phy.h"
|
||||
#include "propagation-loss-model.h"
|
||||
#include "propagation-delay-model.h"
|
||||
#include "ns3/propagation-loss-model.h"
|
||||
#include "ns3/propagation-delay-model.h"
|
||||
#include "error-rate-model.h"
|
||||
#include "yans-error-rate-model.h"
|
||||
#include "ns3/ptr.h"
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
#include "adhoc-wifi-mac.h"
|
||||
#include "yans-wifi-phy.h"
|
||||
#include "arf-wifi-manager.h"
|
||||
#include "propagation-delay-model.h"
|
||||
#include "propagation-loss-model.h"
|
||||
#include "ns3/propagation-delay-model.h"
|
||||
#include "ns3/propagation-loss-model.h"
|
||||
#include "error-rate-model.h"
|
||||
#include "yans-error-rate-model.h"
|
||||
#include "ns3/constant-position-mobility-model.h"
|
||||
|
||||
@@ -3,10 +3,6 @@
|
||||
def build(bld):
|
||||
obj = bld.create_ns3_module('wifi', ['node'])
|
||||
obj.source = [
|
||||
'propagation-delay-model.cc',
|
||||
'propagation-loss-model.cc',
|
||||
'propagation-loss-model-test-suite.cc',
|
||||
'jakes-propagation-loss-model.cc',
|
||||
'wifi-channel.cc',
|
||||
'wifi-mode.cc',
|
||||
'ssid.cc',
|
||||
@@ -58,14 +54,17 @@ def build(bld):
|
||||
'amsdu-subframe-header.cc',
|
||||
'msdu-standard-aggregator.cc',
|
||||
'minstrel-wifi-manager.cc',
|
||||
'originator-block-ack-agreement.cc',
|
||||
'dcf.cc',
|
||||
'ctrl-headers.cc',
|
||||
'qos-blocked-destinations.cc',
|
||||
'block-ack-agreement.cc',
|
||||
'block-ack-manager.cc',
|
||||
'block-ack-test-suite.cc',
|
||||
]
|
||||
headers = bld.new_task_gen('ns3header')
|
||||
headers.module = 'wifi'
|
||||
headers.source = [
|
||||
'propagation-delay-model.h',
|
||||
'propagation-loss-model.h',
|
||||
'jakes-propagation-loss-model.h',
|
||||
'wifi-net-device.h',
|
||||
'wifi-channel.h',
|
||||
'wifi-mode.h',
|
||||
@@ -109,7 +108,11 @@ def build(bld):
|
||||
'mac-rx-middle.h',
|
||||
'mac-low.h',
|
||||
'minstrel-wifi-manager.h',
|
||||
'originator-block-ack-agreement.h',
|
||||
'dcf.h',
|
||||
'ctrl-headers.h',
|
||||
'block-ack-agreement.h',
|
||||
'block-ack-manager.h',
|
||||
]
|
||||
|
||||
if bld.env['ENABLE_GSL']:
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
#include "ns3/object-factory.h"
|
||||
#include "yans-wifi-channel.h"
|
||||
#include "yans-wifi-phy.h"
|
||||
#include "propagation-loss-model.h"
|
||||
#include "propagation-delay-model.h"
|
||||
#include "ns3/propagation-loss-model.h"
|
||||
#include "ns3/propagation-delay-model.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("YansWifiChannel");
|
||||
|
||||
|
||||
@@ -2610,8 +2610,6 @@ Ptr<Ipv4Route>
|
||||
RoutingProtocol::RouteOutput (Ptr<Packet> p, const Ipv4Header &header, Ptr<NetDevice> oif, Socket::SocketErrno &sockerr)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << " " << m_ipv4->GetObject<Node> ()->GetId() << " " << header.GetDestination () << " " << oif);
|
||||
// TBD: oif is unused; can be used to restrict the outgoing interface
|
||||
// of the found route if application bound to a source interface
|
||||
Ptr<Ipv4Route> rtentry;
|
||||
RoutingTableEntry entry1, entry2;
|
||||
if (Lookup (header.GetDestination (), entry1) != 0)
|
||||
@@ -2621,9 +2619,22 @@ RoutingProtocol::RouteOutput (Ptr<Packet> p, const Ipv4Header &header, Ptr<NetDe
|
||||
{
|
||||
NS_FATAL_ERROR ("FindSendEntry failure");
|
||||
}
|
||||
uint32_t interfaceIdx = entry2.interface;
|
||||
if (oif && m_ipv4->GetInterfaceForDevice (oif) != static_cast<int> (interfaceIdx))
|
||||
{
|
||||
// We do not attempt to perform a constrained routing search
|
||||
// if the caller specifies the oif; we just enforce that
|
||||
// that the found route matches the requested outbound interface
|
||||
NS_LOG_DEBUG ("Olsr node " << m_mainAddress
|
||||
<< ": RouteOutput for dest=" << header.GetDestination ()
|
||||
<< " Route interface " << interfaceIdx
|
||||
<< " does not match requested output interface "
|
||||
<< m_ipv4->GetInterfaceForDevice (oif));
|
||||
sockerr = Socket::ERROR_NOROUTETOHOST;
|
||||
return rtentry;
|
||||
}
|
||||
rtentry = Create<Ipv4Route> ();
|
||||
rtentry->SetDestination (header.GetDestination ());
|
||||
uint32_t interfaceIdx = entry2.interface;
|
||||
// the source address is the interface address that matches
|
||||
// the destination address (when multiple are present on the
|
||||
// outgoing interface, one is selected via scoping rules)
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* \ingroup utils
|
||||
* \defgroup CheckStyle check-style.py
|
||||
*
|
||||
* The check-style.py script will test and reformat code according to the
|
||||
* ns-3 coding style posted at http://www.nsnam.org/codingstyle.html
|
||||
* It requires that you install 'uncrustify'
|
||||
*
|
||||
* It has multiple levels of conformance:
|
||||
* - level=0: the default: merely checks indentation
|
||||
* - level=1: checks also for missing spaces before parentheses
|
||||
* - level=2: checks also for missing newlines and braces around single-line statements
|
||||
* - level=3: checks also for missing trailing whitespaces
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* check a single file (level 0 by default):
|
||||
\verbatim
|
||||
./check-style.py -f src/core/object.h
|
||||
\endverbatim
|
||||
*
|
||||
* fix the style of a single file:
|
||||
\verbatim
|
||||
./check-style.py --level=2 --in-place -f src/core/object.h
|
||||
\endverbatim
|
||||
*
|
||||
* look at the changes needed for a single file:
|
||||
\verbatim
|
||||
./check-style.py --diff --level=1 -f src/core/object.h | less
|
||||
\endverbatim
|
||||
*
|
||||
* look at the status of all files modified in your mercurial repository:
|
||||
\verbatim
|
||||
./check-style.py --check-hg
|
||||
\endverbatim
|
||||
*
|
||||
* look at the changes needed for all modified files in your mercurial
|
||||
* repository:
|
||||
\verbatim
|
||||
./check-style.py --check-hg --diff |less
|
||||
\endverbatim
|
||||
*
|
||||
* Enable this script to run as a 'commit' hook in your repository and
|
||||
* disallow commits which contain files with invalid style:
|
||||
*
|
||||
\verbatim
|
||||
cat hgrc (can be appended to .hg/hgrc or ~/.hg/hgrc or /etc/hg/hgrc
|
||||
[hooks]
|
||||
# uncomment below line to enable: works only with mercurial >= 1.3
|
||||
#pretxncommit.indent = path-to-binary/check-indent.py --check-hg-hook
|
||||
# uncomment below line to enable: works with all (?) versions
|
||||
# of mercurial but requires that PYTHONPATH is defined to point to
|
||||
# the directory which contains check-indent.py
|
||||
#pretxncommit.indent = python:check-indent.run_as_hg_hook
|
||||
\endverbatim
|
||||
*
|
||||
* Usage:
|
||||
\verbatim
|
||||
Usage: check-style.py [options]
|
||||
|
||||
Options:
|
||||
-h, --help show this help message and exit
|
||||
--debug Output some debugging information
|
||||
-l LEVEL, --level=LEVEL
|
||||
Level of style conformance: higher levels include all
|
||||
lower levels. level=0: re-indent only. level=1: add
|
||||
extra spaces. level=2: insert extra newlines and extra
|
||||
braces around single-line statements. level=3: remove
|
||||
all trailing spaces
|
||||
--check-hg-hook Get the list of files to check from mercurial's list
|
||||
of modified and added files and assume that the script
|
||||
runs as a pretxncommit mercurial hook
|
||||
--check-hg Get the list of files to check from mercurial's list
|
||||
of modified and added files
|
||||
-f FILE, --check-file=FILE
|
||||
Check a single file
|
||||
--diff Generate a diff on stdout of the indented files
|
||||
-i, --in-place Indent the input files in-place
|
||||
\endverbatim
|
||||
*/
|
||||
Reference in New Issue
Block a user