branch merge

This commit is contained in:
Craig Dowell
2010-02-04 06:26:55 -08:00
55 changed files with 6244 additions and 741 deletions
+1 -1
View File
@@ -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)
+1
View File
@@ -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
+4
View File
@@ -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
*/
+141
View File
@@ -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;
}
+3
View File
@@ -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'
+7
View File
@@ -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',
]
File diff suppressed because it is too large Load Diff
+175 -135
View File
@@ -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
+119
View File
@@ -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
+68
View File
@@ -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 */
+617
View File
@@ -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
+297
View File
@@ -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 */
+214
View File
@@ -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;
+681
View File
@@ -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
+159
View File
@@ -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
View File
@@ -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
+50
View File
@@ -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
View File
@@ -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
View File
@@ -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
+13
View File
@@ -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
+1
View File
@@ -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;
+467
View File
@@ -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
+123
View File
@@ -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 */
+117 -1
View File
@@ -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
+7 -1
View File
@@ -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.
+119 -1
View File
@@ -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
+6
View File
@@ -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 */
+13
View File
@@ -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
+7
View File
@@ -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 */
+117
View File
@@ -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
+6
View File
@@ -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;
+2 -2
View File
@@ -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");
+41 -6
View File
@@ -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;
+7
View File
@@ -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;
+85 -6
View File
@@ -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 &timestamp,
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 &timestamp,
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
+25 -2
View File
@@ -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;
+67
View File
@@ -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,
+11
View File
@@ -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
*
+2 -2
View File
@@ -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"
+2 -2
View File
@@ -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"
+10 -7
View File
@@ -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']:
+2 -2
View File
@@ -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");
+14 -3
View File
@@ -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)
+80
View File
@@ -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
*/