summaryrefslogtreecommitdiffstats
path: root/emu-radio/ns3-patch
diff options
context:
space:
mode:
authorJordan Augé <jordan.auge+fdio@email.com>2017-02-24 14:58:01 +0100
committerJordan Augé <jordan.auge+fdio@cisco.com>2017-02-24 18:36:29 +0000
commit85a341d645b57b7cd88a26ed2ea0a314704240ea (patch)
treebdda2b35003aae20103a796f86daced160b8a730 /emu-radio/ns3-patch
parent9b30fc10fb1cbebe651e5a107e8ca5b24de54675 (diff)
Initial commit: vICN
Change-Id: I7ce66c4e84a6a1921c63442f858b49e083adc7a7 Signed-off-by: Jordan Augé <jordan.auge+fdio@cisco.com>
Diffstat (limited to 'emu-radio/ns3-patch')
-rw-r--r--emu-radio/ns3-patch/README.md22
-rw-r--r--emu-radio/ns3-patch/epc-tft-classifier.cc181
-rw-r--r--emu-radio/ns3-patch/tap-bridge.cc1214
-rw-r--r--emu-radio/ns3-patch/wifi/helper/wifi-radio-energy-model-helper.h124
-rw-r--r--emu-radio/ns3-patch/wifi/model/ap-info-collection.cc72
-rw-r--r--emu-radio/ns3-patch/wifi/model/ap-info-collection.h155
-rw-r--r--emu-radio/ns3-patch/wifi/model/ap-wifi-mac.cc876
-rw-r--r--emu-radio/ns3-patch/wifi/model/ap-wifi-mac.h230
-rw-r--r--emu-radio/ns3-patch/wifi/model/block-ack-manager.cc1028
-rw-r--r--emu-radio/ns3-patch/wifi/model/block-ack-manager.h462
-rw-r--r--emu-radio/ns3-patch/wifi/model/edca-txop-n.cc1584
-rw-r--r--emu-radio/ns3-patch/wifi/model/edca-txop-n.h570
-rw-r--r--emu-radio/ns3-patch/wifi/model/mac-low.cc3347
-rw-r--r--emu-radio/ns3-patch/wifi/model/mac-low.h1404
-rw-r--r--emu-radio/ns3-patch/wifi/model/minstrel-ht-wifi-manager.cc1127
-rw-r--r--emu-radio/ns3-patch/wifi/model/minstrel-ht-wifi-manager.h202
-rw-r--r--emu-radio/ns3-patch/wifi/model/originator-block-ack-agreement.cc111
-rw-r--r--emu-radio/ns3-patch/wifi/model/originator-block-ack-agreement.h155
-rw-r--r--emu-radio/ns3-patch/wifi/model/regular-wifi-mac.cc780
-rw-r--r--emu-radio/ns3-patch/wifi/model/regular-wifi-mac.h480
-rw-r--r--emu-radio/ns3-patch/wifi/model/sta-wifi-mac.cc1085
-rw-r--r--emu-radio/ns3-patch/wifi/model/sta-wifi-mac.h238
-rw-r--r--emu-radio/ns3-patch/wifi/model/wifi-phy.cc1570
-rw-r--r--emu-radio/ns3-patch/wifi/model/wifi-phy.h1326
-rw-r--r--emu-radio/ns3-patch/wifi/model/wifi-remote-station-manager.cc1751
-rw-r--r--emu-radio/ns3-patch/wifi/model/wifi-remote-station-manager.h1177
-rw-r--r--emu-radio/ns3-patch/wifi/model/yans-wifi-phy.cc1390
-rw-r--r--emu-radio/ns3-patch/wifi/model/yans-wifi-phy.h615
-rw-r--r--emu-radio/ns3-patch/wifi/wscript187
29 files changed, 23463 insertions, 0 deletions
diff --git a/emu-radio/ns3-patch/README.md b/emu-radio/ns3-patch/README.md
new file mode 100644
index 00000000..ac3b244d
--- /dev/null
+++ b/emu-radio/ns3-patch/README.md
@@ -0,0 +1,22 @@
+# patches to ns3 wifi module
+
+## General description of patch to ns3 wifi
+
+For the wifi emulator, we use ns3 based emulation to create a emulated 802.11n wifi channel. We choose 802.11n to have high throughput and to incorporate some of the latest features of 802.11 wifi technology.
+
+However, the codes for wifi 802.11n model in ns3 is not bug free up even in the latest ns3.25 release. We integrated some bug fixes for 802.11n wifi model from both ns3 dev branch and our own bug fixes.
+
+The fixes/patches are intended for issues in 802.11n wifi model of ns3 including:
+minstrel rate adaptation, RSSI based wifi handover(missing), block ack agreement destroyment and reinitialization in scenario with wifi handover and various exceptions handling when stations are mobile and makes frequent handovers.
+
+## Notes
+
+* Our patches are with respect to ns3.24.1 official release(can be downloaded here: https://www.nsnam.org/ns-3-24/download/)
+* all the patched file should be in ns3/src/wifi/ folder of ns3 codebase
+* We may port the patch to the latest ns3 release in the future.
+
+## instruction to apply the patch
+you just need to replace the original files in ns3/src/wifi with the ones that are patched, to do so:
+* cd ns3-patch
+* cp -r wifi/ path/to/ns3/src/wifi
+
diff --git a/emu-radio/ns3-patch/epc-tft-classifier.cc b/emu-radio/ns3-patch/epc-tft-classifier.cc
new file mode 100644
index 00000000..5c501b8d
--- /dev/null
+++ b/emu-radio/ns3-patch/epc-tft-classifier.cc
@@ -0,0 +1,181 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 CTTC
+ * Copyright (c) 2010 TELEMATICS LAB, DEE - Politecnico di Bari
+ * Copyright (c) 2017 Irt Systemx and/or its affiliates.
+ *
+ * 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
+ *
+ * Authors:
+ * Nicola Baldo <nbaldo@cttc.es> (the EpcTftClassifier class)
+ * Giuseppe Piro <g.piro@poliba.it> (part of the code in EpcTftClassifier::Classify ()
+ * which comes from RrcEntity::Classify of the GSoC 2010 LTE module)
+ *
+ */
+
+#include "epc-tft-classifier.h"
+#include "epc-tft.h"
+#include "ns3/log.h"
+#include "ns3/packet.h"
+#include "ns3/ipv4-header.h"
+#include "ns3/udp-header.h"
+#include "ns3/tcp-header.h"
+#include "ns3/udp-l4-protocol.h"
+#include "ns3/tcp-l4-protocol.h"
+
+#ifndef PING_ENABLED
+#define PING_ENABLED 1
+#endif
+
+#ifdef PING_ENABLED
+#include "ns3/icmpv4-l4-protocol.h"
+#endif
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("EpcTftClassifier");
+
+EpcTftClassifier::EpcTftClassifier ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+void
+EpcTftClassifier::Add (Ptr<EpcTft> tft, uint32_t id)
+{
+ NS_LOG_FUNCTION (this << tft);
+
+ m_tftMap[id] = tft;
+
+ // simple sanity check: there shouldn't be more than 16 bearers (hence TFTs) per UE
+ NS_ASSERT (m_tftMap.size () <= 16);
+}
+
+void
+EpcTftClassifier::Delete (uint32_t id)
+{
+ NS_LOG_FUNCTION (this << id);
+ m_tftMap.erase (id);
+}
+
+
+uint32_t
+EpcTftClassifier::Classify (Ptr<Packet> p, EpcTft::Direction direction)
+{
+ NS_LOG_FUNCTION (this << p << direction);
+
+ Ptr<Packet> pCopy = p->Copy ();
+
+ Ipv4Header ipv4Header;
+ pCopy->RemoveHeader (ipv4Header);
+
+ Ipv4Address localAddress;
+ Ipv4Address remoteAddress;
+
+
+ if (direction == EpcTft::UPLINK)
+ {
+ localAddress = ipv4Header.GetSource ();
+ remoteAddress = ipv4Header.GetDestination ();
+ }
+ else
+ {
+ NS_ASSERT (direction == EpcTft::DOWNLINK);
+ remoteAddress = ipv4Header.GetSource ();
+ localAddress = ipv4Header.GetDestination ();
+ }
+
+ uint8_t protocol = ipv4Header.GetProtocol ();
+
+ uint8_t tos = ipv4Header.GetTos ();
+
+ uint16_t localPort = 0;
+ uint16_t remotePort = 0;
+
+ if (protocol == UdpL4Protocol::PROT_NUMBER)
+ {
+ UdpHeader udpHeader;
+ pCopy->RemoveHeader (udpHeader);
+
+ if (direction == EpcTft::UPLINK)
+ {
+ localPort = udpHeader.GetSourcePort ();
+ remotePort = udpHeader.GetDestinationPort ();
+ }
+ else
+ {
+ remotePort = udpHeader.GetSourcePort ();
+ localPort = udpHeader.GetDestinationPort ();
+ }
+ }
+ else if (protocol == TcpL4Protocol::PROT_NUMBER)
+ {
+ TcpHeader tcpHeader;
+ pCopy->RemoveHeader (tcpHeader);
+ if (direction == EpcTft::UPLINK)
+ {
+ localPort = tcpHeader.GetSourcePort ();
+ remotePort = tcpHeader.GetDestinationPort ();
+ }
+ else
+ {
+ remotePort = tcpHeader.GetSourcePort ();
+ localPort = tcpHeader.GetDestinationPort ();
+ }
+ }
+#ifdef PING_ENABLED
+ else if (protocol == Icmpv4L4Protocol::PROT_NUMBER) //for ICMP(ping, and etc) protocol, use the default bearer always, added by zeng
+ {
+ NS_LOG_DEBUG("ICMP protocol, like ping is assigned the default bearer");
+
+ remotePort=0;
+ localPort=0;
+ }
+#endif
+ else
+ {
+ NS_LOG_INFO ("Unknown protocol: " << protocol);
+ return 0; // no match
+ }
+
+ NS_LOG_INFO ("Classifing packet:"
+ << " localAddr=" << localAddress
+ << " remoteAddr=" << remoteAddress
+ << " localPort=" << localPort
+ << " remotePort=" << remotePort
+ << " tos=0x" << (uint16_t) tos );
+
+ // now it is possible to classify the packet!
+ // we use a reverse iterator since filter priority is not implemented properly.
+ // This way, since the default bearer is expected to be added first, it will be evaluated last.
+ std::map <uint32_t, Ptr<EpcTft> >::const_reverse_iterator it;
+ NS_LOG_LOGIC ("TFT MAP size: " << m_tftMap.size ());
+
+ for (it = m_tftMap.rbegin (); it != m_tftMap.rend (); ++it)
+ {
+ NS_LOG_LOGIC ("TFT id: " << it->first );
+ NS_LOG_LOGIC (" Ptr<EpcTft>: " << it->second);
+ Ptr<EpcTft> tft = it->second;
+ if (tft->Matches (direction, remoteAddress, localAddress, remotePort, localPort, tos))
+ {
+ NS_LOG_LOGIC ("matches with TFT ID = " << it->first);
+ return it->first; // the id of the matching TFT
+ }
+ }
+ NS_LOG_LOGIC ("no match");
+ return 0; // no match
+}
+
+
+} // namespace ns3
diff --git a/emu-radio/ns3-patch/tap-bridge.cc b/emu-radio/ns3-patch/tap-bridge.cc
new file mode 100644
index 00000000..f6c95048
--- /dev/null
+++ b/emu-radio/ns3-patch/tap-bridge.cc
@@ -0,0 +1,1214 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 University of Washington
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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
+ */
+
+#include "tap-bridge.h"
+#include "tap-encode-decode.h"
+
+#include "ns3/node.h"
+#include "ns3/channel.h"
+#include "ns3/packet.h"
+#include "ns3/ethernet-header.h"
+#include "ns3/llc-snap-header.h"
+#include "ns3/log.h"
+#include "ns3/abort.h"
+#include "ns3/boolean.h"
+#include "ns3/string.h"
+#include "ns3/enum.h"
+#include "ns3/ipv4.h"
+#include "ns3/simulator.h"
+#include "ns3/realtime-simulator-impl.h"
+#include "ns3/unix-fd-reader.h"
+#include "ns3/uinteger.h"
+
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <cerrno>
+#include <limits>
+#include <cstdlib>
+#include <unistd.h>
+
+#ifndef INFRASTRUCTURE_WIFI_PATCH
+#define INFRASTRUCTURE_WIFI_PATCH
+#endif
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("TapBridge");
+
+FdReader::Data TapBridgeFdReader::DoRead (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+
+ uint32_t bufferSize = 65536;
+ uint8_t *buf = (uint8_t *)std::malloc (bufferSize);
+ NS_ABORT_MSG_IF (buf == 0, "malloc() failed");
+
+ NS_LOG_LOGIC ("Calling read on tap device fd " << m_fd);
+ ssize_t len = read (m_fd, buf, bufferSize);
+ if (len <= 0)
+ {
+ NS_LOG_INFO ("TapBridgeFdReader::DoRead(): done");
+ std::free (buf);
+ buf = 0;
+ len = 0;
+ }
+
+ return FdReader::Data (buf, len);
+}
+
+#define TAP_MAGIC 95549
+
+NS_OBJECT_ENSURE_REGISTERED (TapBridge);
+
+TypeId
+TapBridge::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::TapBridge")
+ .SetParent<NetDevice> ()
+ .SetGroupName ("TapBridge")
+ .AddConstructor<TapBridge> ()
+ .AddAttribute ("Mtu", "The MAC-level Maximum Transmission Unit",
+ UintegerValue (0),
+ MakeUintegerAccessor (&TapBridge::SetMtu,
+ &TapBridge::GetMtu),
+ MakeUintegerChecker<uint16_t> ())
+ .AddAttribute ("DeviceName",
+ "The name of the tap device to create.",
+ StringValue (""),
+ MakeStringAccessor (&TapBridge::m_tapDeviceName),
+ MakeStringChecker ())
+ .AddAttribute ("Gateway",
+ "The IP address of the default gateway to assign to the host machine, when in ConfigureLocal mode.",
+ Ipv4AddressValue ("255.255.255.255"),
+ MakeIpv4AddressAccessor (&TapBridge::m_tapGateway),
+ MakeIpv4AddressChecker ())
+ .AddAttribute ("IpAddress",
+ "The IP address to assign to the tap device, when in ConfigureLocal mode. "
+ "This address will override the discovered IP address of the simulated device.",
+ Ipv4AddressValue ("255.255.255.255"),
+ MakeIpv4AddressAccessor (&TapBridge::m_tapIp),
+ MakeIpv4AddressChecker ())
+ .AddAttribute ("MacAddress",
+ "The MAC address to assign to the tap device, when in ConfigureLocal mode. "
+ "This address will override the discovered MAC address of the simulated device.",
+ Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")),
+ MakeMac48AddressAccessor (&TapBridge::m_tapMac),
+ MakeMac48AddressChecker ())
+ .AddAttribute ("Netmask",
+ "The network mask to assign to the tap device, when in ConfigureLocal mode. "
+ "This address will override the discovered MAC address of the simulated device.",
+ Ipv4MaskValue ("255.255.255.255"),
+ MakeIpv4MaskAccessor (&TapBridge::m_tapNetmask),
+ MakeIpv4MaskChecker ())
+ .AddAttribute ("Start",
+ "The simulation time at which to spin up the tap device read thread.",
+ TimeValue (Seconds (0.)),
+ MakeTimeAccessor (&TapBridge::m_tStart),
+ MakeTimeChecker ())
+ .AddAttribute ("Stop",
+ "The simulation time at which to tear down the tap device read thread.",
+ TimeValue (Seconds (0.)),
+ MakeTimeAccessor (&TapBridge::m_tStop),
+ MakeTimeChecker ())
+ .AddAttribute ("Mode",
+ "The operating and configuration mode to use.",
+ EnumValue (USE_LOCAL),
+ MakeEnumAccessor (&TapBridge::SetMode),
+ MakeEnumChecker (CONFIGURE_LOCAL, "ConfigureLocal",
+ USE_LOCAL, "UseLocal",
+ USE_BRIDGE, "UseBridge"))
+ ;
+ return tid;
+}
+
+TapBridge::TapBridge ()
+ : m_node (0),
+ m_ifIndex (0),
+ m_sock (-1),
+ m_startEvent (),
+ m_stopEvent (),
+ m_fdReader (0),
+ m_ns3AddressRewritten (false)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_packetBuffer = new uint8_t[65536];
+ Start (m_tStart);
+}
+
+TapBridge::~TapBridge()
+{
+ NS_LOG_FUNCTION_NOARGS ();
+
+ StopTapDevice ();
+
+ delete [] m_packetBuffer;
+ m_packetBuffer = 0;
+
+ m_bridgedDevice = 0;
+}
+
+void
+TapBridge::DoDispose ()
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ NetDevice::DoDispose ();
+}
+
+void
+TapBridge::Start (Time tStart)
+{
+ NS_LOG_FUNCTION (tStart);
+
+ //
+ // Cancel any pending start event and schedule a new one at some relative time in the future.
+ //
+ Simulator::Cancel (m_startEvent);
+ m_startEvent = Simulator::Schedule (tStart, &TapBridge::StartTapDevice, this);
+}
+
+void
+TapBridge::Stop (Time tStop)
+{
+ NS_LOG_FUNCTION (tStop);
+ //
+ // Cancel any pending stop event and schedule a new one at some relative time in the future.
+ //
+ Simulator::Cancel (m_stopEvent);
+ m_startEvent = Simulator::Schedule (tStop, &TapBridge::StopTapDevice, this);
+}
+
+void
+TapBridge::StartTapDevice (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+
+ NS_ABORT_MSG_IF (m_sock != -1, "TapBridge::StartTapDevice(): Tap is already started");
+
+ //
+ // A similar story exists for the node ID. We can't just naively do a
+ // GetNode ()->GetId () since GetNode is going to give us a Ptr<Node> which
+ // is reference counted. We need to stash away the node ID for use in the
+ // read thread.
+ //
+ m_nodeId = GetNode ()->GetId ();
+
+ //
+ // Spin up the tap bridge and start receiving packets.
+ //
+ NS_LOG_LOGIC ("Creating tap device");
+
+ //
+ // Call out to a separate process running as suid root in order to get the
+ // tap device allocated and set up. We do this to avoid having the entire
+ // simulation running as root. If this method returns, we'll have a socket
+ // waiting for us in m_sock that we can use to talk to the newly created
+ // tap device.
+ //
+ CreateTap ();
+
+ // Declare the link up
+ NotifyLinkUp ();
+
+ //
+ // Now spin up a read thread to read packets from the tap device.
+ //
+ NS_ABORT_MSG_IF (m_fdReader != 0,"TapBridge::StartTapDevice(): Receive thread is already running");
+ NS_LOG_LOGIC ("Spinning up read thread");
+
+ m_fdReader = Create<TapBridgeFdReader> ();
+ m_fdReader->Start (m_sock, MakeCallback (&TapBridge::ReadCallback, this));
+}
+
+void
+TapBridge::StopTapDevice (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+
+ if (m_fdReader != 0)
+ {
+ m_fdReader->Stop ();
+ m_fdReader = 0;
+ }
+
+ if (m_sock != -1)
+ {
+ close (m_sock);
+ m_sock = -1;
+ }
+}
+
+void
+TapBridge::CreateTap (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+
+ //
+ // The TapBridge has three distinct operating modes. At this point, the
+ // differences revolve around who is responsible for creating and configuring
+ // the underlying network tap that we use. In ConfigureLocal mode, the
+ // TapBridge has the responsibility for creating and configuring the TAP.
+ //
+ // In UseBridge or UseLocal modes, the user will provide us a configuration
+ // and we have to adapt to it. For example, in UseLocal mode, the user will
+ // be configuring a tap device outside the scope of the ns-3 simulation and
+ // will be expecting us to work with it. The user will do something like:
+ //
+ // sudo tunctl -t tap0
+ // sudo ifconfig tap0 hw ether 00:00:00:00:00:01
+ // sudo ifconfig tap0 10.1.1.1 netmask 255.255.255.0 up
+ //
+ // The user will then set the "Mode" Attribute of the TapBridge to "UseLocal"
+ // and the "DeviceName" Attribute to "tap0" in this case.
+ //
+ // In ConfigureLocal mode, the user is asking the TapBridge to do the
+ // configuration and create a TAP with the provided "DeviceName" with which
+ // the user can later do what she wants. We need to extract values for the
+ // MAC address, IP address, net mask, etc, from the simualtion itself and
+ // use them to initialize corresponding values on the created tap device.
+ //
+ // In UseBridge mode, the user is asking us to use an existing tap device
+ // has been included in an OS bridge. She is asking us to take the simulated
+ // net device and logically add it to the existing bridge. We expect that
+ // the user has done something like:
+ //
+ // sudo brctl addbr mybridge
+ // sudo tunctl -t mytap
+ // sudo ifconfig mytap hw ether 00:00:00:00:00:01
+ // sudo ifconfig mytap 0.0.0.0 up
+ // sudo brctl addif mybridge mytap
+ // sudo brctl addif mybridge ...
+ // sudo ifconfig mybridge 10.1.1.1 netmask 255.255.255.0 up
+ //
+ // The bottom line at this point is that we want to either create or use a
+ // tap device on the host based on the verb part "Use" or "Configure" of the
+ // operating mode. Unfortunately for us you have to have root privileges to
+ // do either. Instead of running the entire simulation as root, we decided
+ // to make a small program who's whole reason for being is to run as suid
+ // root and do what it takes to create the tap. We're just going to pass
+ // off the configuration information to that program and let it deal with
+ // the situation.
+ //
+ // We're going to fork and exec that program soon, but first we need to have
+ // a socket to talk to it with. So we create a local interprocess (Unix)
+ // socket for that purpose.
+ //
+ int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
+ NS_ABORT_MSG_IF (sock == -1, "TapBridge::CreateTap(): Unix socket creation error, errno = " << std::strerror (errno));
+
+ //
+ // Bind to that socket and let the kernel allocate an endpoint
+ //
+ struct sockaddr_un un;
+ memset (&un, 0, sizeof (un));
+ un.sun_family = AF_UNIX;
+ int status = bind (sock, (struct sockaddr*)&un, sizeof (sa_family_t));
+ NS_ABORT_MSG_IF (status == -1, "TapBridge::CreateTap(): Could not bind(): errno = " << std::strerror (errno));
+ NS_LOG_INFO ("Created Unix socket");
+ NS_LOG_INFO ("sun_family = " << un.sun_family);
+ NS_LOG_INFO ("sun_path = " << un.sun_path);
+
+ //
+ // We have a socket here, but we want to get it there -- to the program we're
+ // going to exec. What we'll do is to do a getsockname and then encode the
+ // resulting address information as a string, and then send the string to the
+ // program as an argument. So we need to get the sock name.
+ //
+ socklen_t len = sizeof (un);
+ status = getsockname (sock, (struct sockaddr*)&un, &len);
+ NS_ABORT_MSG_IF (status == -1, "TapBridge::CreateTap(): Could not getsockname(): errno = " << std::strerror (errno));
+
+ //
+ // Now encode that socket name (family and path) as a string of hex digits
+ //
+ std::string path = TapBufferToString ((uint8_t *)&un, len);
+ NS_LOG_INFO ("Encoded Unix socket as \"" << path << "\"");
+
+ //
+ // Tom Goff reports the possiblility of a deadlock when trying to acquire the
+ // python GIL here. He says that this might be due to trying to access Python
+ // objects after fork() without calling PyOS_AfterFork() to properly reset
+ // Python state (including the GIL). Originally these next three lines were
+ // done after the fork, but were moved here to work around the deadlock.
+ //
+ Ptr<NetDevice> nd = GetBridgedNetDevice ();
+ Ptr<Node> n = nd->GetNode ();
+ Ptr<Ipv4> ipv4 = n->GetObject<Ipv4> ();
+
+ //
+ // Fork and exec the process to create our socket. If we're us (the parent)
+ // we wait for the child (the creator) to complete and read the socket it
+ // created and passed back using the ancillary data mechanism.
+ //
+ pid_t pid = ::fork ();
+ if (pid == 0)
+ {
+ NS_LOG_DEBUG ("Child process");
+
+ //
+ // build a command line argument from the encoded endpoint string that
+ // the socket creation process will use to figure out how to respond to
+ // the (now) parent process. We're going to have to give this program
+ // quite a bit of information.
+ //
+ // -d<device-name> The name of the tap device we want to create;
+ // -g<gateway-address> The IP address to use as the default gateway;
+ // -i<IP-address> The IP address to assign to the new tap device;
+ // -m<MAC-address> The MAC-48 address to assign to the new tap device;
+ // -n<network-mask> The network mask to assign to the new tap device;
+ // -o<operating mode> The operating mode of the bridge (1=ConfigureLocal, 2=UseLocal, 3=UseBridge)
+ // -p<path> the path to the unix socket described above.
+ //
+ // Example tap-creator -dnewdev -g1.2.3.2 -i1.2.3.1 -m08:00:2e:00:01:23 -n255.255.255.0 -o1 -pblah
+ //
+ // We want to get as much of this stuff automagically as possible.
+ //
+ // For CONFIGURE_LOCAL mode only:
+ // <IP-address> is the IP address we are going to set in the newly
+ // created Tap device on the Linux host. At the point in the simulation
+ // where devices are coming up, we should have all of our IP addresses
+ // assigned. That means that we can find the IP address to assign to
+ // the new Tap device from the IP address associated with the bridged
+ // net device.
+ //
+
+ bool wantIp = (m_mode == CONFIGURE_LOCAL);
+
+ if (wantIp
+ && (ipv4 == 0)
+ && m_tapIp.IsBroadcast ()
+ && m_tapNetmask.IsEqual (Ipv4Mask::GetOnes ()))
+ {
+ NS_FATAL_ERROR ("TapBridge::CreateTap(): Tap device IP configuration requested but neither IP address nor IP netmask is provided");
+ }
+
+ // Some stub values to make tap-creator happy
+ Ipv4Address ipv4Address ("255.255.255.255");
+ Ipv4Mask ipv4Mask ("255.255.255.255");
+
+ if (ipv4 != 0)
+ {
+ uint32_t index = ipv4->GetInterfaceForDevice (nd);
+ if (ipv4->GetNAddresses (index) > 1)
+ {
+ NS_LOG_WARN ("Underlying bridged NetDevice has multiple IP addresses; using first one.");
+ }
+ ipv4Address = ipv4->GetAddress (index, 0).GetLocal ();
+
+ //
+ // The net mask is sitting right there next to the ipv4 address.
+ //
+ ipv4Mask = ipv4->GetAddress (index, 0).GetMask ();
+ }
+
+ //
+ // The MAC address should also already be assigned and waiting for us in
+ // the bridged net device.
+ //
+ Address address = nd->GetAddress ();
+ Mac48Address mac48Address = Mac48Address::ConvertFrom (address);
+
+ //
+ // The device-name is something we may want the system to make up in
+ // every case. We also rely on it being configured via an Attribute
+ // through the helper. By default, it is set to the empty string
+ // which tells the system to make up a device name such as "tap123".
+ //
+ std::ostringstream ossDeviceName;
+ ossDeviceName << "-d" << m_tapDeviceName;
+
+ //
+ // The gateway-address is something we can't derive, so we rely on it
+ // being configured via an Attribute through the helper.
+ //
+ std::ostringstream ossGateway;
+ ossGateway << "-g" << m_tapGateway;
+
+ //
+ // For flexibility, we do allow a client to override any of the values
+ // above via attributes, so only use our found values if the Attribute
+ // is not equal to its default value (empty string or broadcast address).
+ //
+ std::ostringstream ossIp;
+ if (m_tapIp.IsBroadcast ())
+ {
+ ossIp << "-i" << ipv4Address;
+ }
+ else
+ {
+ ossIp << "-i" << m_tapIp;
+ }
+
+ std::ostringstream ossMac;
+ if (m_tapMac.IsBroadcast ())
+ {
+ ossMac << "-m" << mac48Address;
+ }
+ else
+ {
+ ossMac << "-m" << m_tapMac;
+ }
+
+ std::ostringstream ossNetmask;
+ if (m_tapNetmask.IsEqual (Ipv4Mask::GetOnes ()))
+ {
+ ossNetmask << "-n" << ipv4Mask;
+ }
+ else
+ {
+ ossNetmask << "-n" << m_tapNetmask;
+ }
+
+ std::ostringstream ossMode;
+ ossMode << "-o";
+ if (m_mode == CONFIGURE_LOCAL)
+ {
+ ossMode << "1";
+ }
+ else if (m_mode == USE_LOCAL)
+ {
+ ossMode << "2";
+ }
+ else
+ {
+ ossMode << "3";
+ }
+
+ std::ostringstream ossPath;
+ ossPath << "-p" << path;
+ //
+ // Execute the socket creation process image.
+ //
+ status = ::execlp (TAP_CREATOR,
+ TAP_CREATOR, // argv[0] (filename)
+ ossDeviceName.str ().c_str (), // argv[1] (-d<device name>)
+ ossGateway.str ().c_str (), // argv[2] (-g<gateway>)
+ ossIp.str ().c_str (), // argv[3] (-i<IP address>)
+ ossMac.str ().c_str (), // argv[4] (-m<MAC address>)
+ ossNetmask.str ().c_str (), // argv[5] (-n<net mask>)
+ ossMode.str ().c_str (), // argv[6] (-o<operating mode>)
+ ossPath.str ().c_str (), // argv[7] (-p<path>)
+ (char *)NULL);
+
+ //
+ // If the execlp successfully completes, it never returns. If it returns it failed or the OS is
+ // broken. In either case, we bail.
+ //
+ NS_FATAL_ERROR ("TapBridge::CreateTap(): Back from execlp(), errno = " << ::strerror (errno));
+ }
+ else
+ {
+ NS_LOG_DEBUG ("Parent process");
+ //
+ // We're the process running the emu net device. We need to wait for the
+ // socket creator process to finish its job.
+ //
+ int st;
+ pid_t waited = waitpid (pid, &st, 0);
+ NS_ABORT_MSG_IF (waited == -1, "TapBridge::CreateTap(): waitpid() fails, errno = " << std::strerror (errno));
+ NS_ASSERT_MSG (pid == waited, "TapBridge::CreateTap(): pid mismatch");
+
+ //
+ // Check to see if the socket creator exited normally and then take a
+ // look at the exit code. If it bailed, so should we. If it didn't
+ // even exit normally, we bail too.
+ //
+ if (WIFEXITED (st))
+ {
+ int exitStatus = WEXITSTATUS (st);
+ NS_ABORT_MSG_IF (exitStatus != 0,
+ "TapBridge::CreateTap(): socket creator exited normally with status " << exitStatus);
+ }
+ else
+ {
+ NS_FATAL_ERROR ("TapBridge::CreateTap(): socket creator exited abnormally");
+ }
+
+ //
+ // At this point, the socket creator has run successfully and should
+ // have created our tap device, initialized it with the information we
+ // passed and sent it back to the socket address we provided. A socket
+ // (fd) we can use to talk to this tap device should be waiting on the
+ // Unix socket we set up to receive information back from the creator
+ // program. We've got to do a bunch of grunt work to get at it, though.
+ //
+ // The struct iovec below is part of a scatter-gather list. It describes a
+ // buffer. In this case, it describes a buffer (an integer) that will
+ // get the data that comes back from the socket creator process. It will
+ // be a magic number that we use as a consistency/sanity check.
+ //
+ struct iovec iov;
+ uint32_t magic;
+ iov.iov_base = &magic;
+ iov.iov_len = sizeof(magic);
+
+ //
+ // The CMSG macros you'll see below are used to create and access control
+ // messages (which is another name for ancillary data). The ancillary
+ // data is made up of pairs of struct cmsghdr structures and associated
+ // data arrays.
+ //
+ // First, we're going to allocate a buffer on the stack to receive our
+ // data array (that contains the socket). Sometimes you'll see this called
+ // an "ancillary element" but the msghdr uses the control message termimology
+ // so we call it "control."
+ //
+ size_t msg_size = sizeof(int);
+ char control[CMSG_SPACE (msg_size)];
+
+ //
+ // There is a msghdr that is used to minimize the number of parameters
+ // passed to recvmsg (which we will use to receive our ancillary data).
+ // This structure uses terminology corresponding to control messages, so
+ // you'll see msg_control, which is the pointer to the ancillary data and
+ // controllen which is the size of the ancillary data array.
+ //
+ // So, initialize the message header that describes the ancillary/control
+ // data we expect to receive and point it to buffer.
+ //
+ struct msghdr msg;
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = control;
+ msg.msg_controllen = sizeof (control);
+ msg.msg_flags = 0;
+
+ //
+ // Now we can actually receive the interesting bits from the tap
+ // creator process. Lots of pain to get four bytes.
+ //
+ ssize_t bytesRead = recvmsg (sock, &msg, 0);
+ NS_ABORT_MSG_IF (bytesRead != sizeof(int), "TapBridge::CreateTap(): Wrong byte count from socket creator");
+
+ //
+ // There may be a number of message headers/ancillary data arrays coming in.
+ // Let's look for the one with a type SCM_RIGHTS which indicates it's the
+ // one we're interested in.
+ //
+ struct cmsghdr *cmsg;
+ for (cmsg = CMSG_FIRSTHDR (&msg); cmsg != NULL; cmsg = CMSG_NXTHDR (&msg, cmsg))
+ {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS)
+ {
+ //
+ // This is the type of message we want. Check to see if the magic
+ // number is correct and then pull out the socket we care about if
+ // it matches
+ //
+ if (magic == TAP_MAGIC)
+ {
+ NS_LOG_INFO ("Got SCM_RIGHTS with correct magic " << magic);
+ int *rawSocket = (int*)CMSG_DATA (cmsg);
+ NS_LOG_INFO ("Got the socket from the socket creator = " << *rawSocket);
+ m_sock = *rawSocket;
+ break;
+ }
+ else
+ {
+ NS_LOG_INFO ("Got SCM_RIGHTS, but with bad magic " << magic);
+ }
+ }
+ }
+ if (cmsg == NULL)
+ {
+ NS_FATAL_ERROR ("Did not get the raw socket from the socket creator");
+ }
+
+ if (m_mode == USE_LOCAL || m_mode == USE_BRIDGE)
+ {
+#ifndef INFRASTRUCTURE_WIFI_PATCH
+ //
+ // Set the ns-3 device's mac address to the overlying container's
+ // mac address
+ //
+ struct ifreq s;
+ strncpy (s.ifr_name, m_tapDeviceName.c_str (), sizeof (s.ifr_name));
+
+ NS_LOG_INFO ("Trying to get MacAddr of " << m_tapDeviceName);
+ int ioctlResult = ioctl (sock, SIOCGIFHWADDR, &s);
+ if (ioctlResult == 0)
+ {
+ Mac48Address learnedMac;
+ learnedMac.CopyFrom ((uint8_t *)s.ifr_hwaddr.sa_data);
+ NS_LOG_INFO ("Learned Tap device MacAddr is " << learnedMac << ": setting ns-3 device to use this address");
+ m_bridgedDevice->SetAddress (learnedMac);
+ m_ns3AddressRewritten = true;
+ }
+
+ if (!m_ns3AddressRewritten)
+ {
+ NS_LOG_INFO ("Cannot get MacAddr of Tap device: " << m_tapDeviceName << " while in USE_LOCAL/USE_BRIDGE mode: " << std::strerror (errno));
+ NS_LOG_INFO ("Underlying ns-3 device will continue to use default address, what can lead to connectivity errors");
+ }
+#else
+ m_ns3AddressRewritten = true;
+#endif
+ }
+ }
+
+ close (sock);
+}
+
+void
+TapBridge::ReadCallback (uint8_t *buf, ssize_t len)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+
+ NS_ASSERT_MSG (buf != 0, "invalid buf argument");
+ NS_ASSERT_MSG (len > 0, "invalid len argument");
+
+ //
+ // It's important to remember that we're in a completely different thread
+ // than the simulator is running in. We need to synchronize with that
+ // other thread to get the packet up into ns-3. What we will need to do
+ // is to schedule a method to deal with the packet using the multithreaded
+ // simulator we are most certainly running. However, I just said it -- we
+ // are talking about two threads here, so it is very, very dangerous to do
+ // any kind of reference counting on a shared object. Just don't do it.
+ // So what we're going to do is pass the buffer allocated on the heap
+ // into the ns-3 context thread where it will create the packet.
+ //
+
+ NS_LOG_INFO ("TapBridge::ReadCallback(): Received packet on node " << m_nodeId);
+ NS_LOG_INFO ("TapBridge::ReadCallback(): Scheduling handler");
+ Simulator::ScheduleWithContext (m_nodeId, Seconds (0.0), MakeEvent (&TapBridge::ForwardToBridgedDevice, this, buf, len));
+}
+
+void
+TapBridge::ForwardToBridgedDevice (uint8_t *buf, ssize_t len)
+{
+ NS_LOG_FUNCTION (buf << len);
+
+ //
+ // There are three operating modes for the TapBridge
+ //
+ // CONFIGURE_LOCAL means that ns-3 will create and configure a tap device
+ // and we are expected to use it. The tap device and the ns-3 net device
+ // will have the same MAC address by definition. Thus Send and SendFrom
+ // are equivalent in this case. We use Send to allow all ns-3 devices to
+ // participate in this mode.
+ //
+ // USE_LOCAL mode tells us that we have got to USE a pre-created tap device
+ // that will have a different MAC address from the ns-3 net device. We
+ // also enforce the requirement that there will only be one MAC address
+ // bridged on the Linux side so we can use Send (instead of SendFrom) in
+ // the linux to ns-3 direction. Again, all ns-3 devices can participate
+ // in this mode.
+ //
+ // USE_BRIDGE mode tells us that we are logically extending a Linux bridge
+ // on which lies our tap device. In this case there may be many linux
+ // net devices on the other side of the bridge and so we must use SendFrom
+ // to preserve the possibly many source addresses. Thus, ns-3 devices
+ // must support SendFrom in order to be considered for USE_BRIDGE mode.
+ //
+
+ //
+ // First, create a packet out of the byte buffer we received and free that
+ // buffer.
+ //
+ Ptr<Packet> packet = Create<Packet> (reinterpret_cast<const uint8_t *> (buf), len);
+ std::free (buf);
+ buf = 0;
+
+ //
+ // Make sure the packet we received is reasonable enough for the rest of the
+ // system to handle and get it ready to be injected directly into an ns-3
+ // device. What should come back is a packet with the Ethernet header
+ // (and possibly an LLC header as well) stripped off.
+ //
+ Address src, dst;
+ uint16_t type;
+
+ NS_LOG_LOGIC ("Received packet from tap device");
+
+ Ptr<Packet> p = Filter (packet, &src, &dst, &type);
+ if (p == 0)
+ {
+ NS_LOG_LOGIC ("TapBridge::ForwardToBridgedDevice: Discarding packet as unfit for ns-3 consumption");
+ return;
+ }
+
+ NS_LOG_LOGIC ("Pkt source is " << src);
+ NS_LOG_LOGIC ("Pkt destination is " << dst);
+ NS_LOG_LOGIC ("Pkt LengthType is " << type);
+ if (m_mode == USE_LOCAL)
+ {
+ //
+ // Packets we are going to forward should not be from a broadcast src
+ //
+ NS_ASSERT_MSG (Mac48Address::ConvertFrom (src) != Mac48Address ("ff:ff:ff:ff:ff:ff"),
+ "TapBridge::ForwardToBridgedDevice: Source addr is broadcast");
+
+ //m_ns3AddressRewritten = true;
+
+ if (m_ns3AddressRewritten == false)
+ {
+ //
+ // Set the ns-3 device's mac address to the overlying container's
+ // mac address
+ //
+ Mac48Address learnedMac = Mac48Address::ConvertFrom (src);
+ NS_LOG_LOGIC ("Learned MacAddr is " << learnedMac << ": setting ns-3 device to use this address");
+ m_bridgedDevice->SetAddress (Mac48Address::ConvertFrom (learnedMac));
+ m_ns3AddressRewritten = true;
+ }
+ //
+ // If we are operating in USE_LOCAL mode, we may be attached to an ns-3
+ // device that does not support bridging (SupportsSendFrom returns false).
+ // But, since the mac addresses are now aligned, we can call Send()
+ //
+ NS_LOG_LOGIC ("Forwarding packet to ns-3 device via Send()");
+ m_bridgedDevice->Send (packet, dst, type);
+ return;
+ }
+
+ //
+ // If we are operating in USE_BRIDGE mode, we have the
+ // situation described below:
+ //
+ // Other Device <-bridge-> Tap Device <-bridge-> ns3 device
+ // Mac Addr A Mac Addr B Mac Addr C
+ //
+ // In Linux, "Other Device" and "Tap Device" are bridged together. By this
+ // we mean that a user has sone something in Linux like:
+ //
+ // brctl addbr mybridge
+ // brctl addif other-device
+ // brctl addif tap-device
+ //
+ // In USE_BRIDGE mode, we want to logically extend this Linux behavior to the
+ // simulated ns3 device and make it appear as if it is connected to the Linux
+ // subnet. As you may expect, this means that we need to act like a real
+ // Linux bridge and take all packets that come from "Tap Device" and ask
+ // "ns3 Device" to send them down its directly connected network. Just like
+ // in a normal everyday bridge we need to call SendFrom in order to preserve
+ //the original packet's from address.
+ //
+ // If we are operating in CONFIGURE_LOCAL mode, we simply simply take all packets
+ // that come from "Tap Device" and ask "ns3 Device" to send them down its
+ // directly connected network. A normal bridge would need to call SendFrom
+ // in order to preserve the original from address, but in CONFIGURE_LOCAL mode
+ // the tap device and the ns-3 device have the same MAC address by definition so
+ // we can call Send.
+ //
+ NS_LOG_LOGIC ("Forwarding packet");
+
+ if (m_mode == USE_BRIDGE)
+ {
+ m_bridgedDevice->SendFrom (packet, src, dst, type);
+ }
+ else
+ {
+ NS_ASSERT_MSG (m_mode == CONFIGURE_LOCAL, "TapBridge::ForwardToBridgedDevice(): Internal error");
+ m_bridgedDevice->Send (packet, dst, type);
+ }
+}
+
+Ptr<Packet>
+TapBridge::Filter (Ptr<Packet> p, Address *src, Address *dst, uint16_t *type)
+{
+ NS_LOG_FUNCTION (p);
+ uint32_t pktSize;
+
+ //
+ // We have a candidate packet for injection into ns-3. We expect that since
+ // it came over a socket that provides Ethernet packets, it should be big
+ // enough to hold an EthernetHeader. If it can't, we signify the packet
+ // should be filtered out by returning 0.
+ //
+ pktSize = p->GetSize ();
+ EthernetHeader header (false);
+ if (pktSize < header.GetSerializedSize ())
+ {
+ return 0;
+ }
+
+ uint32_t headerSize = p->PeekHeader (header);
+ p->RemoveAtStart (headerSize);
+
+ NS_LOG_LOGIC ("Pkt source is " << header.GetSource ());
+ NS_LOG_LOGIC ("Pkt destination is " << header.GetDestination ());
+ NS_LOG_LOGIC ("Pkt LengthType is " << header.GetLengthType ());
+
+ //
+ // If the length/type is less than 1500, it corresponds to a length
+ // interpretation packet. In this case, it is an 802.3 packet and
+ // will also have an 802.2 LLC header. If greater than 1500, we
+ // find the protocol number (Ethernet type) directly.
+ //
+ if (header.GetLengthType () <= 1500)
+ {
+ *src = header.GetSource ();
+ *dst = header.GetDestination ();
+
+ pktSize = p->GetSize ();
+ LlcSnapHeader llc;
+ if (pktSize < llc.GetSerializedSize ())
+ {
+ return 0;
+ }
+
+ p->RemoveHeader (llc);
+ *type = llc.GetType ();
+ }
+ else
+ {
+ *src = header.GetSource ();
+ *dst = header.GetDestination ();
+ *type = header.GetLengthType ();
+ }
+
+ //
+ // What we give back is a packet without the Ethernet header (nor the
+ // possible llc/snap header) on it. We think it is ready to send on
+ // out the bridged net device.
+ //
+ return p;
+}
+
+Ptr<NetDevice>
+TapBridge::GetBridgedNetDevice (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_bridgedDevice;
+}
+
+void
+TapBridge::SetBridgedNetDevice (Ptr<NetDevice> bridgedDevice)
+{
+ NS_LOG_FUNCTION (bridgedDevice);
+
+ NS_ASSERT_MSG (m_node != 0, "TapBridge::SetBridgedDevice: Bridge not installed in a node");
+ NS_ASSERT_MSG (bridgedDevice != this, "TapBridge::SetBridgedDevice: Cannot bridge to self");
+ NS_ASSERT_MSG (m_bridgedDevice == 0, "TapBridge::SetBridgedDevice: Already bridged");
+
+ if (!Mac48Address::IsMatchingType (bridgedDevice->GetAddress ()))
+ {
+ NS_FATAL_ERROR ("TapBridge::SetBridgedDevice: Device does not support eui 48 addresses: cannot be added to bridge.");
+ }
+
+ if (m_mode == USE_BRIDGE && !bridgedDevice->SupportsSendFrom ())
+ {
+ NS_FATAL_ERROR ("TapBridge::SetBridgedDevice: Device does not support SendFrom: cannot be added to bridge.");
+ }
+
+ //
+ // We need to disconnect the bridged device from the internet stack on our
+ // node to ensure that only one stack responds to packets inbound over the
+ // bridged device. That one stack lives outside ns-3 so we just blatantly
+ // steal the device callbacks.
+ //
+ // N.B This can be undone if someone does a RegisterProtocolHandler later
+ // on this node.
+ //
+ bridgedDevice->SetReceiveCallback (MakeCallback (&TapBridge::DiscardFromBridgedDevice, this));
+ bridgedDevice->SetPromiscReceiveCallback (MakeCallback (&TapBridge::ReceiveFromBridgedDevice, this));
+ m_bridgedDevice = bridgedDevice;
+}
+
+bool
+TapBridge::DiscardFromBridgedDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol, const Address &src)
+{
+ NS_LOG_FUNCTION (device << packet << protocol << src);
+ NS_LOG_LOGIC ("Discarding packet stolen from bridged device " << device);
+ return true;
+}
+
+bool
+TapBridge::ReceiveFromBridgedDevice (
+ Ptr<NetDevice> device,
+ Ptr<const Packet> packet,
+ uint16_t protocol,
+ const Address &src,
+ const Address &dst,
+ PacketType packetType)
+{
+ NS_LOG_FUNCTION (device << packet << protocol << src << dst << packetType);
+ NS_ASSERT_MSG (device == m_bridgedDevice, "TapBridge::SetBridgedDevice: Received packet from unexpected device");
+ NS_LOG_DEBUG ("Packet UID is " << packet->GetUid ());
+
+ //
+ // There are three operating modes for the TapBridge
+ //
+ // CONFIGURE_LOCAL means that ns-3 will create and configure a tap device
+ // and we are expected to use it. The tap device and the ns-3 net device
+ // will have the same MAC address by definition.
+ //
+ // USE_LOCAL mode tells us that we have got to USE a pre-created tap device
+ // that will have a different MAC address from the ns-3 net device. In this
+ // case we will be spoofing the MAC address of a received packet to match
+ // the single allowed address on the Linux side.
+ //
+ // USE_BRIDGE mode tells us that we are logically extending a Linux bridge
+ // on which lies our tap device.
+ //
+
+ if (m_mode == CONFIGURE_LOCAL && packetType == PACKET_OTHERHOST)
+ {
+ //
+ // We hooked the promiscuous mode protocol handler so we could get the
+ // destination address of the actual packet. This means we will be
+ // getting PACKET_OTHERHOST packets (not broadcast, not multicast, not
+ // unicast to the ns-3 net device, but to some other address). In
+ // CONFIGURE_LOCAL mode we are not interested in these packets since they
+ // don't refer to the single MAC address shared by the ns-3 device and
+ // the TAP device. If, however, we are in USE_LOCAL or USE_BRIDGE mode,
+ // we want to act like a bridge and forward these PACKET_OTHERHOST
+ // packets.
+ //
+ return true;
+ }
+
+ Mac48Address from = Mac48Address::ConvertFrom (src);
+ Mac48Address to = Mac48Address::ConvertFrom (dst);
+
+ Ptr<Packet> p = packet->Copy ();
+ EthernetHeader header = EthernetHeader (false);
+ header.SetSource (from);
+ header.SetDestination (to);
+
+ header.SetLengthType (protocol);
+ p->AddHeader (header);
+
+ NS_LOG_LOGIC ("Writing packet to Linux host");
+ NS_LOG_LOGIC ("Pkt source is " << header.GetSource ());
+ NS_LOG_LOGIC ("Pkt destination is " << header.GetDestination ());
+ NS_LOG_LOGIC ("Pkt LengthType is " << header.GetLengthType ());
+ NS_LOG_LOGIC ("Pkt size is " << p->GetSize ());
+
+ NS_ASSERT_MSG (p->GetSize () <= 65536, "TapBridge::ReceiveFromBridgedDevice: Packet too big " << p->GetSize ());
+ p->CopyData (m_packetBuffer, p->GetSize ());
+
+ uint32_t bytesWritten = write (m_sock, m_packetBuffer, p->GetSize ());
+ NS_ABORT_MSG_IF (bytesWritten != p->GetSize (), "TapBridge::ReceiveFromBridgedDevice(): Write error.");
+
+ NS_LOG_LOGIC ("End of receive packet handling on node " << m_node->GetId ());
+ return true;
+}
+
+void
+TapBridge::SetIfIndex (const uint32_t index)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_ifIndex = index;
+}
+
+uint32_t
+TapBridge::GetIfIndex (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_ifIndex;
+}
+
+Ptr<Channel>
+TapBridge::GetChannel (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return 0;
+}
+
+void
+TapBridge::SetAddress (Address address)
+{
+ NS_LOG_FUNCTION (address);
+ m_address = Mac48Address::ConvertFrom (address);
+}
+
+Address
+TapBridge::GetAddress (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_address;
+}
+
+void
+TapBridge::SetMode (enum Mode mode)
+{
+ NS_LOG_FUNCTION (mode);
+ m_mode = mode;
+}
+
+TapBridge::Mode
+TapBridge::GetMode (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_mode;
+}
+
+bool
+TapBridge::SetMtu (const uint16_t mtu)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_mtu = mtu;
+ return true;
+}
+
+uint16_t
+TapBridge::GetMtu (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_mtu;
+}
+
+void
+TapBridge::NotifyLinkUp (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ if (!m_linkUp)
+ {
+ m_linkUp = true;
+ m_linkChangeCallbacks ();
+ }
+}
+
+bool
+TapBridge::IsLinkUp (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_linkUp;
+}
+
+void
+TapBridge::AddLinkChangeCallback (Callback<void> callback)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_linkChangeCallbacks.ConnectWithoutContext (callback);
+}
+
+bool
+TapBridge::IsBroadcast (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return true;
+}
+
+Address
+TapBridge::GetBroadcast (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return Mac48Address ("ff:ff:ff:ff:ff:ff");
+}
+
+bool
+TapBridge::IsMulticast (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return true;
+}
+
+Address
+TapBridge::GetMulticast (Ipv4Address multicastGroup) const
+{
+ NS_LOG_FUNCTION (this << multicastGroup);
+ Mac48Address multicast = Mac48Address::GetMulticast (multicastGroup);
+ return multicast;
+}
+
+bool
+TapBridge::IsPointToPoint (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return false;
+}
+
+bool
+TapBridge::IsBridge (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ //
+ // Returning false from IsBridge in a device called TapBridge may seem odd
+ // at first glance, but this test is for a device that bridges ns-3 devices
+ // together. The Tap bridge doesn't do that -- it bridges an ns-3 device to
+ // a Linux device. This is a completely different story.
+ //
+ return false;
+}
+
+bool
+TapBridge::Send (Ptr<Packet> packet, const Address& dst, uint16_t protocol)
+{
+ NS_LOG_FUNCTION (packet << dst << protocol);
+ NS_FATAL_ERROR ("TapBridge::Send: You may not call Send on a TapBridge directly");
+ return false;
+}
+
+bool
+TapBridge::SendFrom (Ptr<Packet> packet, const Address& src, const Address& dst, uint16_t protocol)
+{
+ NS_LOG_FUNCTION (packet << src << dst << protocol);
+ NS_FATAL_ERROR ("TapBridge::Send: You may not call SendFrom on a TapBridge directly");
+ return false;
+}
+
+Ptr<Node>
+TapBridge::GetNode (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_node;
+}
+
+void
+TapBridge::SetNode (Ptr<Node> node)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_node = node;
+}
+
+bool
+TapBridge::NeedsArp (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return true;
+}
+
+void
+TapBridge::SetReceiveCallback (NetDevice::ReceiveCallback cb)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_rxCallback = cb;
+}
+
+void
+TapBridge::SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_promiscRxCallback = cb;
+}
+
+bool
+TapBridge::SupportsSendFrom () const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return true;
+}
+
+Address TapBridge::GetMulticast (Ipv6Address addr) const
+{
+ NS_LOG_FUNCTION (this << addr);
+ return Mac48Address::GetMulticast (addr);
+}
+
+} // namespace ns3
+
diff --git a/emu-radio/ns3-patch/wifi/helper/wifi-radio-energy-model-helper.h b/emu-radio/ns3-patch/wifi/helper/wifi-radio-energy-model-helper.h
new file mode 100644
index 00000000..156238bb
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/helper/wifi-radio-energy-model-helper.h
@@ -0,0 +1,124 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+* Copyright (c) 2010 Network Security Lab, University of Washington, Seattle.
+*
+* 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: Sidharth Nabar <snabar@uw.edu>, He Wu <mdzz@u.washington.edu>
+*/
+
+#ifndef WIFI_RADIO_ENERGY_MODEL_HELPER_H
+#define WIFI_RADIO_ENERGY_MODEL_HELPER_H
+
+#include "ns3/energy-model-helper.h"
+#include "ns3/wifi-radio-energy-model.h"
+
+namespace ns3 {
+
+/**
+ * \ingroup energy
+ * \brief Assign WifiRadioEnergyModel to wifi devices.
+ *
+ * This installer installs WifiRadioEnergyModel for only WifiNetDevice objects.
+ *
+ */
+class WifiRadioEnergyModelHelper : public DeviceEnergyModelHelper
+{
+public:
+ /**
+ * Construct a helper which is used to add a radio energy model to a node
+ */
+ WifiRadioEnergyModelHelper ();
+
+ /**
+ * Destroy a RadioEnergy Helper
+ */
+ ~WifiRadioEnergyModelHelper ();
+
+ /**
+ * \param name the name of the attribute to set
+ * \param v the value of the attribute
+ *
+ * Sets an attribute of the underlying PHY object.
+ */
+ void Set (std::string name, const AttributeValue &v);
+
+ /**
+ * \param callback Callback function for energy depletion handling.
+ *
+ * Sets the callback to be invoked when energy is depleted.
+ */
+ void SetDepletionCallback (
+ WifiRadioEnergyModel::WifiRadioEnergyDepletionCallback callback);
+
+ /**
+ * \param callback Callback function for energy recharged handling.
+ *
+ * Sets the callback to be invoked when energy is recharged.
+ */
+ void SetRechargedCallback (
+ WifiRadioEnergyModel::WifiRadioEnergyRechargedCallback callback);
+
+ /**
+ * \param name the name of the model to set
+ * \param n0 the name of the attribute to set
+ * \param v0 the value of the attribute to set
+ * \param n1 the name of the attribute to set
+ * \param v1 the value of the attribute to set
+ * \param n2 the name of the attribute to set
+ * \param v2 the value of the attribute to set
+ * \param n3 the name of the attribute to set
+ * \param v3 the value of the attribute to set
+ * \param n4 the name of the attribute to set
+ * \param v4 the value of the attribute to set
+ * \param n5 the name of the attribute to set
+ * \param v5 the value of the attribute to set
+ * \param n6 the name of the attribute to set
+ * \param v6 the value of the attribute to set
+ * \param n7 the name of the attribute to set
+ * \param v7 the value of the attribute to set
+ *
+ * Configure a propagation delay for this channel.
+ */
+ void SetTxCurrentModel (std::string name,
+ std::string n0 = "", const AttributeValue &v0 = EmptyAttributeValue (),
+ std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (),
+ std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (),
+ std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (),
+ std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue (),
+ std::string n5 = "", const AttributeValue &v5 = EmptyAttributeValue (),
+ std::string n6 = "", const AttributeValue &v6 = EmptyAttributeValue (),
+ std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue ());
+
+private:
+ /**
+ * \param device Pointer to the NetDevice to install DeviceEnergyModel.
+ * \param source Pointer to EnergySource to install.
+ *
+ * Implements DeviceEnergyModel::Install.
+ */
+ virtual Ptr<DeviceEnergyModel> DoInstall (Ptr<NetDevice> device,
+ Ptr<EnergySource> source) const;
+
+private:
+ ObjectFactory m_radioEnergy;
+ WifiRadioEnergyModel::WifiRadioEnergyDepletionCallback m_depletionCallback;
+ WifiRadioEnergyModel::WifiRadioEnergyRechargedCallback m_rechargedCallback;
+ ObjectFactory m_txCurrentModel;
+
+};
+
+} // namespace ns3
+
+#endif /* WIFI_RADIO_ENERGY_MODEL_HELPER_H */
diff --git a/emu-radio/ns3-patch/wifi/model/ap-info-collection.cc b/emu-radio/ns3-patch/wifi/model/ap-info-collection.cc
new file mode 100644
index 00000000..44d3c05b
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/ap-info-collection.cc
@@ -0,0 +1,72 @@
+#include "ap-info-collection.h"
+
+
+namespace ns3 {
+
+ApInfo::ApInfo (Mac48Address bssid, Time delayFromProbResp, double rssi, SupportedRates supportedRates)
+:m_bssid(bssid)
+,m_delayFromProbResp(delayFromProbResp)
+,m_supportedRates(supportedRates)
+{
+ m_rssiSamples.push_back(rssi);
+}
+
+ApInfo::ApInfo()
+{
+
+}
+
+void
+ApInfo::addRssi (double rssi)
+{
+ m_rssiSamples.push_back(rssi);
+}
+
+void
+ApInfo::removeRssi (double rssi)
+{
+ std::vector<double>::iterator it;
+ for(it=m_rssiSamples.begin();it!=m_rssiSamples.end();it++)
+ {
+ if(*it == rssi)
+ break;
+ }
+ m_rssiSamples.erase(it);
+}
+
+
+Mac48Address
+ApInfo::getBssid() const
+{
+ return m_bssid;
+}
+
+Time
+ApInfo::getDelayFromProbResp() const
+{
+ return m_delayFromProbResp;
+}
+
+double
+ApInfo::getAverageRssi () const
+{
+ if(m_rssiSamples.empty())
+ return -1.0;
+
+ double sum=0;
+ std::vector<double>::const_iterator it;
+ for(it=m_rssiSamples.begin();it!=m_rssiSamples.end();it++)
+ {
+ sum+=*it;
+ }
+
+ return sum/m_rssiSamples.size();
+}
+
+SupportedRates
+ApInfo::getSupportedRates() const
+{
+ return m_supportedRates;
+}
+
+} //namespace ns3
diff --git a/emu-radio/ns3-patch/wifi/model/ap-info-collection.h b/emu-radio/ns3-patch/wifi/model/ap-info-collection.h
new file mode 100644
index 00000000..704a63ba
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/ap-info-collection.h
@@ -0,0 +1,155 @@
+
+#ifndef AP_INFO_COLLECTION_H
+#define AP_INFO_COLLECTION_H
+
+#include "ns3/mac48-address.h"
+#include "ns3/nstime.h"
+#include <vector>
+
+#include "ns3/supported-rates.h"
+
+//for wifi handover triggers
+#define MAX_NUM_RSSI_SAMPMES 4
+
+namespace ns3 {
+class RssiMeasureInfo
+{
+public:
+ RssiMeasureInfo(Mac48Address bssid)
+ :m_index(0)
+ ,m_numberOfSamples(0)
+ ,m_bssid(bssid)
+ {
+ for(int i=0;i<MAX_NUM_RSSI_SAMPMES;i++)
+ m_rssiSamples[i]=0;
+ }
+
+ RssiMeasureInfo()
+ :m_index(0)
+ ,m_numberOfSamples(0)
+ {
+ for(int i=0;i<MAX_NUM_RSSI_SAMPMES;i++)
+ m_rssiSamples[i]=0;
+ }
+
+ Mac48Address getBssid() const
+ {
+ return m_bssid;
+ }
+
+ void setBssid(Mac48Address bssid)
+ {
+ m_bssid=bssid;
+ }
+
+ bool isFull() const
+ {
+ return m_numberOfSamples>=MAX_NUM_RSSI_SAMPMES;
+ }
+
+ void addRssi(double rssi)
+ {
+ m_rssiSamples[m_index]=rssi;
+ m_index=(m_index+1)%MAX_NUM_RSSI_SAMPMES;
+ if(m_numberOfSamples<MAX_NUM_RSSI_SAMPMES)
+ m_numberOfSamples++;
+ }
+
+ double getAverageRssi()
+ {
+ if(!isFull())
+ return -1;
+ else
+ {
+ double sum=0;
+ for(int i=0;i<MAX_NUM_RSSI_SAMPMES;i++)
+ sum+=m_rssiSamples[i];
+ return sum/m_numberOfSamples;
+ }
+ }
+
+ void clear()
+ {
+ m_index=0;
+ m_numberOfSamples=0;
+ for(int i=0;i<MAX_NUM_RSSI_SAMPMES;i++)
+ m_rssiSamples[i]=0;
+ }
+
+
+private:
+ double m_rssiSamples[MAX_NUM_RSSI_SAMPMES];
+ int m_index;
+ int m_numberOfSamples;
+ Mac48Address m_bssid;
+};
+
+typedef std::vector<RssiMeasureInfo> RssiMeasureInfoCollection;
+
+/**
+ * \ingroup wifi
+ *
+ * this class is used to store information about one AP, so as to facilitate the AP selection process
+ */
+class ApInfo
+{
+public:
+ /**
+ * Create an entry containning the info about an AP
+ * \param bssid the bssid of an AP
+ * \param delayFromProbResp computed delay from response according to info in proberesp
+ * \param rssi a sample rssi associated with the AP obtained from a proberesp
+ * \param supportedRates supported rates of the AP
+ */
+ ApInfo (Mac48Address bssid, Time delayFromProbResp, double rssi, SupportedRates supportedRates);
+
+ /**
+ * create an empty entry for the AP info
+ */
+ ApInfo();
+ /**
+ * add a rssi sample to this Ap info
+ * \param rssi sample rssi obtained from proberesp
+ */
+ void addRssi (double rssi);
+ /**
+ * remove a rssi sample from this AP info
+ * \param rssi
+ */
+ void removeRssi (double rssi);
+
+ /**
+ * get Bssid of thIS AP from AP info
+ * \return bssid of AP
+ */
+ Mac48Address getBssid() const;
+
+ /**
+ * get DelayFromProbResp of thIS AP from AP info
+ * \return computed DelayFromProbResp(time to wait to get into beacon missed state) of AP
+ */
+ Time getDelayFromProbResp() const;
+
+ /**
+ * get mearsured average rssi for this AP
+ * \return computed average rssi for this AP
+ *
+ */
+ double getAverageRssi () const;
+
+ SupportedRates getSupportedRates() const;
+
+private:
+ Mac48Address m_bssid; //!< bssid of AP
+ Time m_delayFromProbResp; //!< time to wait to switch into beacon missed state
+ std::vector<double> m_rssiSamples; //!< contains all rssi sapmples obtained from probe response
+ SupportedRates m_supportedRates;
+};
+
+
+
+typedef std::vector<ApInfo> ApInfoCollection;
+
+} //namespace ns3
+
+#endif /* AP_INFO_COLLECTION_H*/
diff --git a/emu-radio/ns3-patch/wifi/model/ap-wifi-mac.cc b/emu-radio/ns3-patch/wifi/model/ap-wifi-mac.cc
new file mode 100644
index 00000000..696d972c
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/ap-wifi-mac.cc
@@ -0,0 +1,876 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006, 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
+ *
+ * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Mirko Banchi <mk.banchi@gmail.com>
+ */
+
+#include "ap-wifi-mac.h"
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ns3/string.h"
+#include "ns3/pointer.h"
+#include "ns3/boolean.h"
+#include "qos-tag.h"
+#include "wifi-phy.h"
+#include "dcf-manager.h"
+#include "mac-rx-middle.h"
+#include "mac-tx-middle.h"
+#include "mgt-headers.h"
+#include "mac-low.h"
+#include "amsdu-subframe-header.h"
+#include "msdu-aggregator.h"
+
+//added: for removing packets to old station
+#include "wifi-mac-queue.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("ApWifiMac");
+
+NS_OBJECT_ENSURE_REGISTERED (ApWifiMac);
+
+TypeId
+ApWifiMac::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::ApWifiMac")
+ .SetParent<RegularWifiMac> ()
+ .SetGroupName ("Wifi")
+ .AddConstructor<ApWifiMac> ()
+ .AddAttribute ("BeaconInterval", "Delay between two beacons",
+ TimeValue (MicroSeconds (102400)),
+ MakeTimeAccessor (&ApWifiMac::GetBeaconInterval,
+ &ApWifiMac::SetBeaconInterval),
+ MakeTimeChecker ())
+ .AddAttribute ("BeaconJitter", "A uniform random variable to cause the initial beacon starting time (after simulation time 0) "
+ "to be distributed between 0 and the BeaconInterval.",
+ StringValue ("ns3::UniformRandomVariable"),
+ MakePointerAccessor (&ApWifiMac::m_beaconJitter),
+ MakePointerChecker<UniformRandomVariable> ())
+ .AddAttribute ("EnableBeaconJitter", "If beacons are enabled, whether to jitter the initial send event.",
+ BooleanValue (false),
+ MakeBooleanAccessor (&ApWifiMac::m_enableBeaconJitter),
+ MakeBooleanChecker ())
+ .AddAttribute ("BeaconGeneration", "Whether or not beacons are generated.",
+ BooleanValue (true),
+ MakeBooleanAccessor (&ApWifiMac::SetBeaconGeneration,
+ &ApWifiMac::GetBeaconGeneration),
+ MakeBooleanChecker ())
+ ;
+ return tid;
+}
+
+ApWifiMac::ApWifiMac ()
+{
+ NS_LOG_FUNCTION (this);
+ m_beaconDca = CreateObject<DcaTxop> ();
+ m_beaconDca->SetAifsn (1);
+ m_beaconDca->SetMinCw (0);
+ m_beaconDca->SetMaxCw (0);
+ m_beaconDca->SetLow (m_low);
+ m_beaconDca->SetManager (m_dcfManager);
+ m_beaconDca->SetTxMiddle (m_txMiddle);
+
+ //Let the lower layers know that we are acting as an AP.
+ SetTypeOfStation (AP);
+
+ m_enableBeaconGeneration = false;
+}
+
+ApWifiMac::~ApWifiMac ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+void
+ApWifiMac::DoDispose ()
+{
+ NS_LOG_FUNCTION (this);
+ m_beaconDca = 0;
+ m_enableBeaconGeneration = false;
+ m_beaconEvent.Cancel ();
+ RegularWifiMac::DoDispose ();
+}
+
+void
+ApWifiMac::SetAddress (Mac48Address address)
+{
+ NS_LOG_FUNCTION (this << address);
+ //As an AP, our MAC address is also the BSSID. Hence we are
+ //overriding this function and setting both in our parent class.
+ RegularWifiMac::SetAddress (address);
+ RegularWifiMac::SetBssid (address);
+}
+
+void
+ApWifiMac::SetBeaconGeneration (bool enable)
+{
+ NS_LOG_FUNCTION (this << enable);
+ if (!enable)
+ {
+ m_beaconEvent.Cancel ();
+ }
+ else if (enable && !m_enableBeaconGeneration)
+ {
+ m_beaconEvent = Simulator::ScheduleNow (&ApWifiMac::SendOneBeacon, this);
+ }
+ m_enableBeaconGeneration = enable;
+}
+
+bool
+ApWifiMac::GetBeaconGeneration (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_enableBeaconGeneration;
+}
+
+Time
+ApWifiMac::GetBeaconInterval (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_beaconInterval;
+}
+
+void
+ApWifiMac::SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> stationManager)
+{
+ NS_LOG_FUNCTION (this << stationManager);
+ m_beaconDca->SetWifiRemoteStationManager (stationManager);
+ RegularWifiMac::SetWifiRemoteStationManager (stationManager);
+}
+
+void
+ApWifiMac::SetLinkUpCallback (Callback<void> linkUp)
+{
+ NS_LOG_FUNCTION (this << &linkUp);
+ RegularWifiMac::SetLinkUpCallback (linkUp);
+
+ //The approach taken here is that, from the point of view of an AP,
+ //the link is always up, so we immediately invoke the callback if
+ //one is set
+ linkUp ();
+}
+
+void
+ApWifiMac::SetBeaconInterval (Time interval)
+{
+ NS_LOG_FUNCTION (this << interval);
+ if ((interval.GetMicroSeconds () % 1024) != 0)
+ {
+ NS_LOG_WARN ("beacon interval should be multiple of 1024us (802.11 time unit), see IEEE Std. 802.11-2012");
+ }
+ m_beaconInterval = interval;
+}
+
+void
+ApWifiMac::StartBeaconing (void)
+{
+ NS_LOG_FUNCTION (this);
+ SendOneBeacon ();
+}
+
+int64_t
+ApWifiMac::AssignStreams (int64_t stream)
+{
+ NS_LOG_FUNCTION (this << stream);
+ m_beaconJitter->SetStream (stream);
+ return 1;
+}
+
+void
+ApWifiMac::ForwardDown (Ptr<const Packet> packet, Mac48Address from,
+ Mac48Address to)
+{
+ NS_LOG_FUNCTION (this << packet << from << to);
+ //If we are not a QoS AP then we definitely want to use AC_BE to
+ //transmit the packet. A TID of zero will map to AC_BE (through \c
+ //QosUtilsMapTidToAc()), so we use that as our default here.
+ uint8_t tid = 0;
+
+ //If we are a QoS AP then we attempt to get a TID for this packet
+ if (m_qosSupported)
+ {
+ tid = QosUtilsGetTidForPacket (packet);
+ //Any value greater than 7 is invalid and likely indicates that
+ //the packet had no QoS tag, so we revert to zero, which'll
+ //mean that AC_BE is used.
+ if (tid > 7)
+ {
+ tid = 0;
+ }
+ }
+
+ ForwardDown (packet, from, to, tid);
+}
+
+void
+ApWifiMac::ForwardDown (Ptr<const Packet> packet, Mac48Address from,
+ Mac48Address to, uint8_t tid)
+{
+ NS_LOG_FUNCTION (this << packet << from << to << static_cast<uint32_t> (tid));
+ WifiMacHeader hdr;
+
+ //For now, an AP that supports QoS does not support non-QoS
+ //associations, and vice versa. In future the AP model should
+ //support simultaneously associated QoS and non-QoS STAs, at which
+ //point there will need to be per-association QoS state maintained
+ //by the association state machine, and consulted here.
+ if (m_qosSupported)
+ {
+ hdr.SetType (WIFI_MAC_QOSDATA);
+ hdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK);
+ hdr.SetQosNoEosp ();
+ hdr.SetQosNoAmsdu ();
+ //Transmission of multiple frames in the same TXOP is not
+ //supported for now
+ hdr.SetQosTxopLimit (0);
+ //Fill in the QoS control field in the MAC header
+ hdr.SetQosTid (tid);
+ }
+ else
+ {
+ hdr.SetTypeData ();
+ }
+
+ if (m_htSupported || m_vhtSupported)
+ {
+ hdr.SetNoOrder ();
+ }
+ hdr.SetAddr1 (to);
+ hdr.SetAddr2 (GetAddress ());
+ hdr.SetAddr3 (from);
+ hdr.SetDsFrom ();
+ hdr.SetDsNotTo ();
+
+ if (m_qosSupported)
+ {
+ //Sanity check that the TID is valid
+ NS_ASSERT (tid < 8);
+ m_edca[QosUtilsMapTidToAc (tid)]->Queue (packet, hdr);
+ }
+ else
+ {
+ m_dca->Queue (packet, hdr);
+ }
+}
+
+void
+ApWifiMac::Enqueue (Ptr<const Packet> packet, Mac48Address to, Mac48Address from)
+{
+ NS_LOG_FUNCTION (this << packet << to << from);
+ if (to.IsBroadcast () || m_stationManager->IsAssociated (to))
+ {
+ ForwardDown (packet, from, to);
+ }
+}
+
+void
+ApWifiMac::Enqueue (Ptr<const Packet> packet, Mac48Address to)
+{
+ NS_LOG_FUNCTION (this << packet << to);
+ //We're sending this packet with a from address that is our own. We
+ //get that address from the lower MAC and make use of the
+ //from-spoofing Enqueue() method to avoid duplicated code.
+ Enqueue (packet, to, m_low->GetAddress ());
+}
+
+bool
+ApWifiMac::SupportsSendFrom (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return true;
+}
+
+SupportedRates
+ApWifiMac::GetSupportedRates (void) const
+{
+ NS_LOG_FUNCTION (this);
+ SupportedRates rates;
+ //If it is an HT-AP then add the BSSMembershipSelectorSet
+ //which only includes 127 for HT now. The standard says that the BSSMembershipSelectorSet
+ //must have its MSB set to 1 (must be treated as a Basic Rate)
+ //Also the standard mentioned that at leat 1 element should be included in the SupportedRates the rest can be in the ExtendedSupportedRates
+ if (m_htSupported || m_vhtSupported)
+ {
+ for (uint32_t i = 0; i < m_phy->GetNBssMembershipSelectors (); i++)
+ {
+ rates.SetBasicRate (m_phy->GetBssMembershipSelector (i));
+ }
+ }
+ //Send the set of supported rates and make sure that we indicate
+ //the Basic Rate set in this set of supported rates.
+ for (uint32_t i = 0; i < m_phy->GetNModes (); i++)
+ {
+ WifiMode mode = m_phy->GetMode (i);
+ rates.AddSupportedRate (mode.GetDataRate (m_phy->GetChannelWidth (), false, 1));
+ //Add rates that are part of the BSSBasicRateSet (manufacturer dependent!)
+ //here we choose to add the mandatory rates to the BSSBasicRateSet,
+ //exept for 802.11b where we assume that only the non HR-DSSS rates are part of the BSSBasicRateSet
+ if (mode.IsMandatory () && (mode.GetModulationClass () != WIFI_MOD_CLASS_HR_DSSS))
+ {
+ m_stationManager->AddBasicMode (mode);
+ }
+ }
+ //set the basic rates
+ for (uint32_t j = 0; j < m_stationManager->GetNBasicModes (); j++)
+ {
+ WifiMode mode = m_stationManager->GetBasicMode (j);
+ rates.SetBasicRate (mode.GetDataRate (m_phy->GetChannelWidth (), false, 1));
+ }
+
+ return rates;
+}
+
+HtCapabilities
+ApWifiMac::GetHtCapabilities (void) const
+{
+ HtCapabilities capabilities;
+ capabilities.SetHtSupported (1);
+ if (m_htSupported)
+ {
+ capabilities.SetLdpc (m_phy->GetLdpc ());
+ capabilities.SetSupportedChannelWidth (m_phy->GetChannelWidth () == 40);
+ capabilities.SetShortGuardInterval20 (m_phy->GetGuardInterval ());
+ capabilities.SetShortGuardInterval40 (m_phy->GetChannelWidth () == 40 && m_phy->GetGuardInterval ());
+ capabilities.SetGreenfield (m_phy->GetGreenfield ());
+ capabilities.SetMaxAmsduLength (1); //hardcoded for now (TBD)
+ capabilities.SetLSigProtectionSupport (!m_phy->GetGreenfield ());
+ capabilities.SetMaxAmpduLength (3); //hardcoded for now (TBD)
+ uint64_t maxSupportedRate = 0; //in bit/s
+ for (uint8_t i = 0; i < m_phy->GetNMcs (); i++)
+ {
+ WifiMode mcs = m_phy->GetMcs (i);
+ capabilities.SetRxMcsBitmask (mcs.GetMcsValue ());
+ if (mcs.GetDataRate (m_phy->GetGuardInterval (), m_phy->GetGuardInterval (), 1) > maxSupportedRate)
+ {
+ maxSupportedRate = mcs.GetDataRate (m_phy->GetGuardInterval (), m_phy->GetGuardInterval (), 1);
+ }
+ }
+ capabilities.SetRxHighestSupportedDataRate (maxSupportedRate / 1e6); //in Mbit/s
+ capabilities.SetTxMcsSetDefined (m_phy->GetNMcs () > 0);
+ capabilities.SetTxMaxNSpatialStreams (m_phy->GetNumberOfTransmitAntennas ());
+ }
+ return capabilities;
+}
+
+VhtCapabilities
+ApWifiMac::GetVhtCapabilities (void) const
+{
+ VhtCapabilities capabilities;
+ capabilities.SetVhtSupported (1);
+ if (m_vhtSupported)
+ {
+ if (m_phy->GetChannelWidth () == 160)
+ {
+ capabilities.SetSupportedChannelWidthSet (1);
+ }
+ else
+ {
+ capabilities.SetSupportedChannelWidthSet (0);
+ }
+ capabilities.SetMaxMpduLength (2); //hardcoded for now (TBD)
+ capabilities.SetRxLdpc (m_phy->GetLdpc ());
+ capabilities.SetShortGuardIntervalFor80Mhz ((m_phy->GetChannelWidth () == 80) && m_phy->GetGuardInterval ());
+ capabilities.SetShortGuardIntervalFor160Mhz ((m_phy->GetChannelWidth () == 160) && m_phy->GetGuardInterval ());
+ capabilities.SetMaxAmpduLengthExponent (7); //hardcoded for now (TBD)
+ uint8_t maxMcs = 0;
+ for (uint8_t i = 0; i < m_phy->GetNMcs (); i++)
+ {
+ WifiMode mcs = m_phy->GetMcs (i);
+ if (mcs.GetMcsValue () > maxMcs)
+ {
+ maxMcs = mcs.GetMcsValue ();
+ }
+ }
+ capabilities.SetRxMcsMap (maxMcs, 1); //Only 1 SS is currently supported
+ capabilities.SetTxMcsMap (maxMcs, 1); //Only 1 SS is currently supported
+ }
+ return capabilities;
+}
+
+void
+ApWifiMac::SendProbeResp (Mac48Address to)
+{
+ NS_LOG_FUNCTION (this << to);
+ WifiMacHeader hdr;
+ hdr.SetProbeResp ();
+ hdr.SetAddr1 (to);
+ hdr.SetAddr2 (GetAddress ());
+ hdr.SetAddr3 (GetAddress ());
+ hdr.SetDsNotFrom ();
+ hdr.SetDsNotTo ();
+ Ptr<Packet> packet = Create<Packet> ();
+ MgtProbeResponseHeader probe;
+ probe.SetSsid (GetSsid ());
+ probe.SetSupportedRates (GetSupportedRates ());
+ probe.SetBeaconIntervalUs (m_beaconInterval.GetMicroSeconds ());
+ if (m_htSupported || m_vhtSupported)
+ {
+ probe.SetHtCapabilities (GetHtCapabilities ());
+ hdr.SetNoOrder ();
+ }
+ if (m_vhtSupported)
+ {
+ probe.SetVhtCapabilities (GetVhtCapabilities ());
+ }
+ packet->AddHeader (probe);
+
+ //The standard is not clear on the correct queue for management
+ //frames if we are a QoS AP. The approach taken here is to always
+ //use the DCF for these regardless of whether we have a QoS
+ //association or not.
+ m_dca->Queue (packet, hdr);
+}
+
+void
+ApWifiMac::SendAssocResp (Mac48Address to, bool success)
+{
+ NS_LOG_FUNCTION (this << to << success);
+ WifiMacHeader hdr;
+ hdr.SetAssocResp ();
+ hdr.SetAddr1 (to);
+ hdr.SetAddr2 (GetAddress ());
+ hdr.SetAddr3 (GetAddress ());
+ hdr.SetDsNotFrom ();
+ hdr.SetDsNotTo ();
+ Ptr<Packet> packet = Create<Packet> ();
+ MgtAssocResponseHeader assoc;
+ StatusCode code;
+ if (success)
+ {
+ code.SetSuccess ();
+ }
+ else
+ {
+ code.SetFailure ();
+ }
+ assoc.SetSupportedRates (GetSupportedRates ());
+ assoc.SetStatusCode (code);
+
+ if (m_htSupported || m_vhtSupported)
+ {
+ assoc.SetHtCapabilities (GetHtCapabilities ());
+ hdr.SetNoOrder ();
+ }
+ if (m_vhtSupported)
+ {
+ assoc.SetVhtCapabilities (GetVhtCapabilities ());
+ }
+ packet->AddHeader (assoc);
+
+ //The standard is not clear on the correct queue for management
+ //frames if we are a QoS AP. The approach taken here is to always
+ //use the DCF for these regardless of whether we have a QoS
+ //association or not.
+ m_dca->Queue (packet, hdr);
+}
+
+void
+ApWifiMac::SendOneBeacon (void)
+{
+ NS_LOG_FUNCTION (this);
+ WifiMacHeader hdr;
+ hdr.SetBeacon ();
+ hdr.SetAddr1 (Mac48Address::GetBroadcast ());
+ hdr.SetAddr2 (GetAddress ());
+ hdr.SetAddr3 (GetAddress ());
+ hdr.SetDsNotFrom ();
+ hdr.SetDsNotTo ();
+ Ptr<Packet> packet = Create<Packet> ();
+ MgtBeaconHeader beacon;
+ beacon.SetSsid (GetSsid ());
+ beacon.SetSupportedRates (GetSupportedRates ());
+ beacon.SetBeaconIntervalUs (m_beaconInterval.GetMicroSeconds ());
+ if (m_htSupported || m_vhtSupported)
+ {
+ beacon.SetHtCapabilities (GetHtCapabilities ());
+ hdr.SetNoOrder ();
+ }
+ if (m_vhtSupported)
+ {
+ beacon.SetVhtCapabilities (GetVhtCapabilities ());
+ }
+ packet->AddHeader (beacon);
+
+ //The beacon has it's own special queue, so we load it in there
+ m_beaconDca->Queue (packet, hdr);
+ m_beaconEvent = Simulator::Schedule (m_beaconInterval, &ApWifiMac::SendOneBeacon, this);
+}
+
+void
+ApWifiMac::TxOk (const WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this);
+ RegularWifiMac::TxOk (hdr);
+
+ if (hdr.IsAssocResp ()
+ && m_stationManager->IsWaitAssocTxOk (hdr.GetAddr1 ()))
+ {
+ NS_LOG_DEBUG ("associated with sta=" << hdr.GetAddr1 ());
+ m_stationManager->RecordGotAssocTxOk (hdr.GetAddr1 ());
+ }
+}
+
+void
+ApWifiMac::TxFailed (const WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this);
+ RegularWifiMac::TxFailed (hdr);
+
+ //modified by zeng: to avoid bugs in associaton process, transmit multiple times association response message until it is acked
+ if (hdr.IsAssocResp ()
+ && m_stationManager->IsWaitAssocTxOk (hdr.GetAddr1 ()))
+ {
+ m_stationManager->ReportGotAssocTxFailed(hdr.GetAddr1 ());
+
+ if(m_stationManager->NeedAssocRespRetransmission(hdr.GetAddr1 ()))
+ {
+ SendAssocResp(hdr.GetAddr1 (),true);//here it is hardcoded to true for the moment
+ }
+ else
+ {
+ NS_LOG_DEBUG ("assoc failed with sta=" << hdr.GetAddr1 ());
+ std::cout<<"assoc failed with sta="<<hdr.GetAddr1 ()<<"\n";
+ m_stationManager->RecordGotAssocTxFailed (hdr.GetAddr1 ());
+ }
+
+ }
+}
+
+void
+ApWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
+{
+ NS_LOG_FUNCTION (this << packet << hdr);
+
+ Mac48Address from = hdr->GetAddr2 ();
+
+ if (hdr->IsData ())
+ {
+ Mac48Address bssid = hdr->GetAddr1 ();
+ if (!hdr->IsFromDs ()
+ && hdr->IsToDs ()
+ && bssid == GetAddress ()
+ && m_stationManager->IsAssociated (from))
+ {
+ Mac48Address to = hdr->GetAddr3 ();
+ if (to == GetAddress ())
+ {
+ NS_LOG_DEBUG ("frame for me from=" << from);
+ if (hdr->IsQosData ())
+ {
+ if (hdr->IsQosAmsdu ())
+ {
+ NS_LOG_DEBUG ("Received A-MSDU from=" << from << ", size=" << packet->GetSize ());
+ DeaggregateAmsduAndForward (packet, hdr);
+ packet = 0;
+ }
+ else
+ {
+ ForwardUp (packet, from, bssid);
+ }
+ }
+ else
+ {
+ ForwardUp (packet, from, bssid);
+ }
+ }
+ else if (to.IsGroup ()
+ || m_stationManager->IsAssociated (to))
+ {
+ NS_LOG_DEBUG ("forwarding frame from=" << from << ", to=" << to);
+ Ptr<Packet> copy = packet->Copy ();
+
+ //If the frame we are forwarding is of type QoS Data,
+ //then we need to preserve the UP in the QoS control
+ //header...
+ if (hdr->IsQosData ())
+ {
+ ForwardDown (packet, from, to, hdr->GetQosTid ());
+ }
+ else
+ {
+ ForwardDown (packet, from, to);
+ }
+ ForwardUp (copy, from, to);
+ }
+ else
+ {
+ ForwardUp (packet, from, to);
+ }
+ }
+ else if (hdr->IsFromDs ()
+ && hdr->IsToDs ())
+ {
+ //this is an AP-to-AP frame
+ //we ignore for now.
+ NotifyRxDrop (packet);
+ }
+ else
+ {
+ //we can ignore these frames since
+ //they are not targeted at the AP
+ NotifyRxDrop (packet);
+ }
+ return;
+ }
+ else if (hdr->IsMgt ())
+ {
+ if (hdr->IsProbeReq ())
+ {
+ NS_ASSERT (hdr->GetAddr1 ().IsBroadcast ());
+ SendProbeResp (from);
+ return;
+ }
+ else if (hdr->GetAddr1 () == GetAddress ())
+ {
+ if (hdr->IsAssocReq ())
+ {
+ //first, verify that the the station's supported
+ //rate set is compatible with our Basic Rate set
+ MgtAssocRequestHeader assocReq;
+ packet->RemoveHeader (assocReq);
+ SupportedRates rates = assocReq.GetSupportedRates ();
+ bool problem = false;
+ for (uint32_t i = 0; i < m_stationManager->GetNBasicModes (); i++)
+ {
+ WifiMode mode = m_stationManager->GetBasicMode (i);
+ if (!rates.IsSupportedRate (mode.GetDataRate (m_phy->GetChannelWidth (), false, 1)))
+ {
+ problem = true;
+ break;
+ }
+ }
+ if (m_htSupported)
+ {
+ //check that the STA supports all MCSs in Basic MCS Set
+ HtCapabilities htcapabilities = assocReq.GetHtCapabilities ();
+ for (uint32_t i = 0; i < m_stationManager->GetNBasicMcs (); i++)
+ {
+ WifiMode mcs = m_stationManager->GetBasicMcs (i);
+ if (!htcapabilities.IsSupportedMcs (mcs.GetMcsValue ()))
+ {
+ problem = true;
+ break;
+ }
+ }
+ }
+ if (m_vhtSupported)
+ {
+ //check that the STA supports all MCSs in Basic MCS Set
+ VhtCapabilities vhtcapabilities = assocReq.GetVhtCapabilities ();
+ for (uint32_t i = 0; i < m_stationManager->GetNBasicMcs (); i++)
+ {
+ WifiMode mcs = m_stationManager->GetBasicMcs (i);
+ if (!vhtcapabilities.IsSupportedTxMcs (mcs.GetMcsValue ()))
+ {
+ problem = true;
+ break;
+ }
+ }
+ }
+ if (problem)
+ {
+ //One of the Basic Rate set mode is not
+ //supported by the station. So, we return an assoc
+ //response with an error status.
+ SendAssocResp (hdr->GetAddr2 (), false);
+ }
+ else
+ {
+ //station supports all rates in Basic Rate Set.
+
+ //added+++++++++++++++
+ //before moving on to accept assoication, we need to clean up the old states related to this station
+ //m_stationManager->RemoveStation(from);
+ //++++++++++++++++++++++++
+#ifdef WITH_MORE_FIX_TO_BA_IN_AP
+ //added: since it is a reassociation, destroy all the existing agreements immediately if exists
+ for(uint8_t tid=0; tid<=7;tid++)
+ {
+
+ MgtDelBaHeader delbaHdr;
+
+ delbaHdr.SetTid (tid);
+
+ AcIndex ac = QosUtilsMapTidToAc (tid);
+
+ //destroy aggreement with station in baMananger:
+ m_edca[ac]->GotDelBaFrame(&delbaHdr, hdr->GetAddr2 ());
+
+ //also destroy aggreement with station at mac low immediately:
+ m_low->DestroyBlockAckAgreement (hdr->GetAddr2 (), tid);
+ }
+#endif
+
+ //record all its supported modes in its associated WifiRemoteStation
+ for (uint32_t j = 0; j < m_phy->GetNModes (); j++)
+ {
+ WifiMode mode = m_phy->GetMode (j);
+ if (rates.IsSupportedRate (mode.GetDataRate (m_phy->GetChannelWidth (), false, 1)))
+ {
+ m_stationManager->AddSupportedMode (from, mode);
+ }
+ }
+ if (m_htSupported)
+ {
+ HtCapabilities htcapabilities = assocReq.GetHtCapabilities ();
+ m_stationManager->AddStationHtCapabilities (from,htcapabilities);
+ for (uint32_t j = 0; j < m_phy->GetNMcs (); j++)
+ {
+ WifiMode mcs = m_phy->GetMcs (j);
+ if (mcs.GetModulationClass () == WIFI_MOD_CLASS_HT && htcapabilities.IsSupportedMcs (mcs.GetMcsValue ()))
+ {
+ m_stationManager->AddSupportedMcs (from, mcs);
+ }
+ }
+ }
+ if (m_vhtSupported)
+ {
+ VhtCapabilities vhtCapabilities = assocReq.GetVhtCapabilities ();
+ m_stationManager->AddStationVhtCapabilities (from, vhtCapabilities);
+ for (uint32_t i = 0; i < m_phy->GetNMcs (); i++)
+ {
+ WifiMode mcs = m_phy->GetMcs (i);
+ if (mcs.GetModulationClass () == WIFI_MOD_CLASS_VHT && vhtCapabilities.IsSupportedTxMcs (mcs.GetMcsValue ()))
+ {
+ m_stationManager->AddSupportedMcs (hdr->GetAddr2 (), mcs);
+ //here should add a control to add basic MCS when it is implemented
+ }
+ }
+ }
+ m_stationManager->RecordWaitAssocTxOk (from);
+ // send assoc response with success status.
+ SendAssocResp (hdr->GetAddr2 (), true);
+ }
+ return;
+ }
+ else if (hdr->IsDisassociation ())
+ {
+ //deestroy aggreements and clean up packets to the station:
+ //destroy all block ack agreement with old AP (by pretending to receive a delba frame from AP).
+ //clean up packets for the old AP in the meanwhile
+ for(uint8_t tid=0; tid<=7;tid++)
+ {
+ MgtDelBaHeader delbaHdr;
+ delbaHdr.SetTid (tid);
+ AcIndex ac = QosUtilsMapTidToAc (tid);
+ m_edca[ac]->GotDelBaFrame(&delbaHdr, from);
+// //also destroy aggreement at mac low immediately:
+ m_low->DestroyBlockAckAgreement (from, tid);
+
+ WifiMacHeader dequeuedHdr;
+
+ //for edca:
+ Ptr<WifiMacQueue > edcaQueue=m_edca[ac]->GetEdcaQueue ();
+
+ Ptr<const Packet> dequeuedPacket = edcaQueue->DequeueByTidAndAddress (&dequeuedHdr, tid,
+ WifiMacHeader::ADDR1,
+ from);
+ // int count=0;
+ while (dequeuedPacket != 0)
+ {
+ // count++;
+ dequeuedPacket = edcaQueue->DequeueByTidAndAddress (&dequeuedHdr, tid,
+ WifiMacHeader::ADDR1,
+ from);
+ }
+
+ // if(count!=0)
+ // std::cout<<"No. of packets for old AP is "<<count<<"\n";
+
+ // count=0;
+ //for dca
+ Ptr<WifiMacQueue > dcaQueue=m_dca->GetQueue ();
+ dequeuedPacket = dcaQueue->DequeueByTidAndAddress (&dequeuedHdr, tid,
+ WifiMacHeader::ADDR1,
+ from);
+
+ while (dequeuedPacket != 0)
+ {
+// count++;
+ dequeuedPacket = dcaQueue->DequeueByTidAndAddress (&dequeuedHdr, tid,
+ WifiMacHeader::ADDR1,
+ from);
+ }
+// if(count!=0)
+// std::cout<<"No. of packets in dca for old AP is "<<count<<"\n";
+
+ }
+ m_stationManager->RecordDisassociated (from);
+ return;
+ }
+ }
+ }
+
+ //Invoke the receive handler of our parent class to deal with any
+ //other frames. Specifically, this will handle Block Ack-related
+ //Management Action frames.
+ RegularWifiMac::Receive (packet, hdr);
+}
+
+void
+ApWifiMac::DeaggregateAmsduAndForward (Ptr<Packet> aggregatedPacket,
+ const WifiMacHeader *hdr)
+{
+ NS_LOG_FUNCTION (this << aggregatedPacket << hdr);
+ MsduAggregator::DeaggregatedMsdus packets =
+ MsduAggregator::Deaggregate (aggregatedPacket);
+
+ for (MsduAggregator::DeaggregatedMsdusCI i = packets.begin ();
+ i != packets.end (); ++i)
+ {
+ if ((*i).second.GetDestinationAddr () == GetAddress ())
+ {
+ ForwardUp ((*i).first, (*i).second.GetSourceAddr (),
+ (*i).second.GetDestinationAddr ());
+ }
+ else
+ {
+ Mac48Address from = (*i).second.GetSourceAddr ();
+ Mac48Address to = (*i).second.GetDestinationAddr ();
+ NS_LOG_DEBUG ("forwarding QoS frame from=" << from << ", to=" << to);
+ ForwardDown ((*i).first, from, to, hdr->GetQosTid ());
+ }
+ }
+}
+
+void
+ApWifiMac::DoInitialize (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_beaconDca->Initialize ();
+ m_beaconEvent.Cancel ();
+ if (m_enableBeaconGeneration)
+ {
+ if (m_enableBeaconJitter)
+ {
+ int64_t jitter = m_beaconJitter->GetValue (0, m_beaconInterval.GetMicroSeconds ());
+ NS_LOG_DEBUG ("Scheduling initial beacon for access point " << GetAddress () << " at time " << jitter << " microseconds");
+ m_beaconEvent = Simulator::Schedule (MicroSeconds (jitter), &ApWifiMac::SendOneBeacon, this);
+ }
+ else
+ {
+ NS_LOG_DEBUG ("Scheduling initial beacon for access point " << GetAddress () << " at time 0");
+ m_beaconEvent = Simulator::ScheduleNow (&ApWifiMac::SendOneBeacon, this);
+ }
+ }
+ RegularWifiMac::DoInitialize ();
+}
+
+} //namespace ns3
diff --git a/emu-radio/ns3-patch/wifi/model/ap-wifi-mac.h b/emu-radio/ns3-patch/wifi/model/ap-wifi-mac.h
new file mode 100644
index 00000000..c7c5158b
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/ap-wifi-mac.h
@@ -0,0 +1,230 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006, 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
+ *
+ * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Mirko Banchi <mk.banchi@gmail.com>
+ */
+
+#ifndef AP_WIFI_MAC_H
+#define AP_WIFI_MAC_H
+
+#include "regular-wifi-mac.h"
+#include "ht-capabilities.h"
+#include "amsdu-subframe-header.h"
+#include "supported-rates.h"
+#include "ns3/random-variable-stream.h"
+#include "vht-capabilities.h"
+
+#define WITH_MORE_FIX_TO_BA_IN_AP 1
+
+namespace ns3 {
+
+/**
+ * \brief Wi-Fi AP state machine
+ * \ingroup wifi
+ *
+ * Handle association, dis-association and authentication,
+ * of STAs within an infrastructure BSS.
+ */
+class ApWifiMac : public RegularWifiMac
+{
+public:
+ static TypeId GetTypeId (void);
+
+ ApWifiMac ();
+ virtual ~ApWifiMac ();
+
+ /**
+ * \param stationManager the station manager attached to this MAC.
+ */
+ virtual void SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> stationManager);
+
+ /**
+ * \param linkUp the callback to invoke when the link becomes up.
+ */
+ virtual void SetLinkUpCallback (Callback<void> linkUp);
+
+ /**
+ * \param packet the packet to send.
+ * \param to the address to which the packet should be sent.
+ *
+ * The packet should be enqueued in a tx queue, and should be
+ * dequeued as soon as the channel access function determines that
+ * access is granted to this MAC.
+ */
+ virtual void Enqueue (Ptr<const Packet> packet, Mac48Address to);
+
+ /**
+ * \param packet the packet to send.
+ * \param to the address to which the packet should be sent.
+ * \param from the address from which the packet should be sent.
+ *
+ * The packet should be enqueued in a tx queue, and should be
+ * dequeued as soon as the channel access function determines that
+ * access is granted to this MAC. The extra parameter "from" allows
+ * this device to operate in a bridged mode, forwarding received
+ * frames without altering the source address.
+ */
+ virtual void Enqueue (Ptr<const Packet> packet, Mac48Address to, Mac48Address from);
+
+ virtual bool SupportsSendFrom (void) const;
+
+ /**
+ * \param address the current address of this MAC layer.
+ */
+ virtual void SetAddress (Mac48Address address);
+ /**
+ * \param interval the interval between two beacon transmissions.
+ */
+ void SetBeaconInterval (Time interval);
+ /**
+ * \return the interval between two beacon transmissions.
+ */
+ Time GetBeaconInterval (void) const;
+ /**
+ * Start beacon transmission immediately.
+ */
+ void StartBeaconing (void);
+
+ /**
+ * Assign a fixed random variable stream number to the random variables
+ * used by this model. Return the number of streams (possibly zero) that
+ * have been assigned.
+ *
+ * \param stream first stream index to use
+ *
+ * \return the number of stream indices assigned by this model
+ */
+ int64_t AssignStreams (int64_t stream);
+
+
+private:
+ virtual void Receive (Ptr<Packet> packet, const WifiMacHeader *hdr);
+ /**
+ * The packet we sent was successfully received by the receiver
+ * (i.e. we received an ACK from the receiver). If the packet
+ * was an association response to the receiver, we record that
+ * the receiver is now associated with us.
+ *
+ * \param hdr the header of the packet that we successfully sent
+ */
+ virtual void TxOk (const WifiMacHeader &hdr);
+ /**
+ * The packet we sent was successfully received by the receiver
+ * (i.e. we did not receive an ACK from the receiver). If the packet
+ * was an association response to the receiver, we record that
+ * the receiver is not associated with us yet.
+ *
+ * \param hdr the header of the packet that we failed to sent
+ */
+ virtual void TxFailed (const WifiMacHeader &hdr);
+
+ /**
+ * This method is called to de-aggregate an A-MSDU and forward the
+ * constituent packets up the stack. We override the WifiMac version
+ * here because, as an AP, we also need to think about redistributing
+ * to other associated STAs.
+ *
+ * \param aggregatedPacket the Packet containing the A-MSDU.
+ * \param hdr a pointer to the MAC header for \c aggregatedPacket.
+ */
+ virtual void DeaggregateAmsduAndForward (Ptr<Packet> aggregatedPacket,
+ const WifiMacHeader *hdr);
+ /**
+ * Forward the packet down to DCF/EDCAF (enqueue the packet). This method
+ * is a wrapper for ForwardDown with traffic id.
+ *
+ * \param packet the packet we are forwarding to DCF/EDCAF
+ * \param from the address to be used for Address 3 field in the header
+ * \param to the address to be used for Address 1 field in the header
+ */
+ void ForwardDown (Ptr<const Packet> packet, Mac48Address from, Mac48Address to);
+ /**
+ * Forward the packet down to DCF/EDCAF (enqueue the packet).
+ *
+ * \param packet the packet we are forwarding to DCF/EDCAF
+ * \param from the address to be used for Address 3 field in the header
+ * \param to the address to be used for Address 1 field in the header
+ * \param tid the traffic id for the packet
+ */
+ void ForwardDown (Ptr<const Packet> packet, Mac48Address from, Mac48Address to, uint8_t tid);
+ /**
+ * Forward a probe response packet to the DCF. The standard is not clear on the correct
+ * queue for management frames if QoS is supported. We always use the DCF.
+ *
+ * \param to the address of the STA we are sending a probe response to
+ */
+ void SendProbeResp (Mac48Address to);
+ /**
+ * Forward an association response packet to the DCF. The standard is not clear on the correct
+ * queue for management frames if QoS is supported. We always use the DCF.
+ *
+ * \param to the address of the STA we are sending an association response to
+ * \param success indicates whether the association was successful or not
+ */
+ void SendAssocResp (Mac48Address to, bool success);
+ /**
+ * Forward a beacon packet to the beacon special DCF.
+ */
+ void SendOneBeacon (void);
+ /**
+ * Return the HT capability of the current AP.
+ *
+ * \return the HT capability that we support
+ */
+ HtCapabilities GetHtCapabilities (void) const;
+ /**
+ * Return the VHT capability of the current AP.
+ *
+ * \return the VHT capability that we support
+ */
+ VhtCapabilities GetVhtCapabilities (void) const;
+ /**
+ * Return an instance of SupportedRates that contains all rates that we support
+ * including HT rates.
+ *
+ * \return SupportedRates all rates that we support
+ */
+ SupportedRates GetSupportedRates (void) const;
+ /**
+ * Enable or disable beacon generation of the AP.
+ *
+ * \param enable enable or disable beacon generation
+ */
+ void SetBeaconGeneration (bool enable);
+ /**
+ * Return whether the AP is generating beacons.
+ *
+ * \return true if beacons are periodically generated, false otherwise
+ */
+ bool GetBeaconGeneration (void) const;
+
+ virtual void DoDispose (void);
+ virtual void DoInitialize (void);
+
+ Ptr<DcaTxop> m_beaconDca; //!< Dedicated DcaTxop for beacons
+ Time m_beaconInterval; //!< Interval between beacons
+ bool m_enableBeaconGeneration; //!< Flag if beacons are being generated
+ EventId m_beaconEvent; //!< Event to generate one beacon
+ Ptr<UniformRandomVariable> m_beaconJitter; //!< UniformRandomVariable used to randomize the time of the first beacon
+ bool m_enableBeaconJitter; //!< Flag if the first beacon should be generated at random time
+};
+
+} //namespace ns3
+
+#endif /* AP_WIFI_MAC_H */
diff --git a/emu-radio/ns3-patch/wifi/model/block-ack-manager.cc b/emu-radio/ns3-patch/wifi/model/block-ack-manager.cc
new file mode 100644
index 00000000..521ca808
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/block-ack-manager.cc
@@ -0,0 +1,1028 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009, 2010 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"
+#include "qos-utils.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("BlockAckManager");
+
+BlockAckManager::Item::Item ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+BlockAckManager::Item::Item (Ptr<const Packet> packet, const WifiMacHeader &hdr, Time tStamp)
+ : packet (packet),
+ hdr (hdr),
+ timestamp (tStamp)
+{
+ NS_LOG_FUNCTION (this << packet << hdr << tStamp);
+}
+
+Bar::Bar ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+Bar::Bar (Ptr<const Packet> bar, Mac48Address recipient, uint8_t tid, bool immediate)
+ : bar (bar),
+ recipient (recipient),
+ tid (tid),
+ immediate (immediate)
+{
+ NS_LOG_FUNCTION (this << bar << recipient << static_cast<uint32_t> (tid) << immediate);
+}
+
+BlockAckManager::BlockAckManager ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+BlockAckManager::~BlockAckManager ()
+{
+ NS_LOG_FUNCTION (this);
+ m_queue = 0;
+ m_agreements.clear ();
+ m_retryPackets.clear ();
+}
+
+bool
+BlockAckManager::ExistsAgreement (Mac48Address recipient, uint8_t tid) const
+{
+ NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
+ 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
+{
+ NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid) << state);
+ 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)
+{
+ NS_LOG_FUNCTION (this << reqHdr << recipient);
+ // std::cout<<Simulator::Now().ToDouble(Time::S)<<", create agreement to="<<recipient<<"\n";
+ std::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 (64);
+ agreement.SetWinEnd ((agreement.GetStartingSequence () + agreement.GetBufferSize () - 1) % 4096);
+ agreement.SetTimeout (reqHdr->GetTimeout ());
+ agreement.SetAmsduSupport (reqHdr->IsAmsduSupported ());
+ agreement.SetHtSupported (m_stationManager->HasHtSupported ());
+ if (reqHdr->IsImmediateBlockAck ())
+ {
+ agreement.SetImmediateBlockAck ();
+ }
+ else
+ {
+ agreement.SetDelayedBlockAck ();
+ }
+ agreement.SetState (OriginatorBlockAckAgreement::PENDING);
+
+
+
+ PacketQueue queue (0);
+ std::pair<OriginatorBlockAckAgreement, PacketQueue> value (agreement, queue);
+ std::pair<AgreementsI,bool> InsertResult=m_agreements.insert (std::make_pair (key, value));
+ m_blockPackets (recipient, reqHdr->GetTid ());
+
+ //added++++++++++++++++++++++
+ if (agreement.GetTimeout () != 0)
+ {
+ // std::cout<<Simulator::Now().ToDouble(Time::S)<<", schedule to destroy the agreement in 0.1s\n";
+ Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
+ if(InsertResult.first->second.first.m_OriginatorInactivityEvent.IsRunning())
+ InsertResult.first->second.first.m_OriginatorInactivityEvent.Cancel();
+ InsertResult.first->second.first.m_OriginatorInactivityEvent = Simulator::Schedule (timeout,
+ &BlockAckManager::OriginatorInactivityTimeout,
+ this,
+ recipient, reqHdr->GetTid ());
+ }
+ //end++++++++++++++++++++++
+
+
+}
+
+void
+BlockAckManager::DestroyAgreement (Mac48Address recipient, uint8_t tid)
+{
+ // std::cout<<Simulator::Now().ToDouble(Time::S)<<", destroy aggreement with="<<recipient<<"\n";
+ NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
+ AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
+ if (it != m_agreements.end ())
+ {
+ for (std::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 (std::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)
+{
+ // std::cout<<Simulator::Now().ToDouble(Time::S)<<", update agreement with=" <<recipient<<"\n";
+
+ NS_LOG_FUNCTION (this << respHdr << 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);
+ if (agreement.GetTimeout () != 0)
+ {
+ Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
+ if (agreement.m_OriginatorInactivityEvent.IsRunning ())
+ agreement.m_OriginatorInactivityEvent.Cancel();
+ agreement.m_OriginatorInactivityEvent = Simulator::Schedule (timeout,
+ &BlockAckManager::OriginatorInactivityTimeout,
+ this,
+ recipient, tid);
+ }
+ }
+ m_unblockPackets (recipient, tid);
+}
+
+void
+BlockAckManager::StorePacket (Ptr<const Packet> packet, const WifiMacHeader &hdr, Time tStamp)
+{
+ NS_LOG_FUNCTION (this << packet << hdr << tStamp);
+ 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 ());
+ PacketQueueI queueIt = it->second.second.begin ();
+ for (; queueIt != it->second.second.end (); )
+ {
+ if (((hdr.GetSequenceNumber () - queueIt->hdr.GetSequenceNumber () + 4096) % 4096) > 2047)
+ {
+ queueIt = it->second.second.insert (queueIt, item);
+ break;
+ }
+ else
+ {
+ queueIt++;
+ }
+ }
+ if (queueIt == it->second.second.end ())
+ {
+ it->second.second.push_back (item);
+ }
+}
+
+void
+BlockAckManager::CompleteAmpduExchange (Mac48Address recipient, uint8_t tid)
+{
+ AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
+ NS_ASSERT (it != m_agreements.end ());
+ OriginatorBlockAckAgreement &agreement = (*it).second.first;
+ agreement.CompleteExchange ();
+}
+
+Ptr<const Packet>
+BlockAckManager::GetNextPacket (WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this << &hdr);
+ Ptr<const Packet> packet = 0;
+ uint8_t tid;
+ Mac48Address recipient;
+ CleanupBuffers ();
+ if (!m_retryPackets.empty ())
+ {
+ NS_LOG_DEBUG ("Retry buffer size is " << m_retryPackets.size ());
+ std::list<PacketQueueI>::iterator it = m_retryPackets.begin ();
+ while (it != m_retryPackets.end ())
+ {
+ if ((*it)->hdr.IsQosData ())
+ {
+ tid = (*it)->hdr.GetQosTid ();
+ }
+ else
+ {
+ NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
+ }
+ recipient = (*it)->hdr.GetAddr1 ();
+ AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid));
+ NS_ASSERT (agreement != m_agreements.end ());
+ if (QosUtilsIsOldPacket (agreement->second.first.GetStartingSequence (),(*it)->hdr.GetSequenceNumber ()))
+ {
+ //Standard says the originator should not send a packet with seqnum < winstart
+ NS_LOG_DEBUG ("The Retry packet have sequence number < WinStartO --> Discard " << (*it)->hdr.GetSequenceNumber () << " " << agreement->second.first.GetStartingSequence ());
+ agreement->second.second.erase ((*it));
+ it = m_retryPackets.erase (it);
+ continue;
+ }
+ else if ((*it)->hdr.GetSequenceNumber () > (agreement->second.first.GetStartingSequence () + 63) % 4096)
+ {
+ agreement->second.first.SetStartingSequence ((*it)->hdr.GetSequenceNumber ());
+ }
+ packet = (*it)->packet->Copy ();
+ hdr = (*it)->hdr;
+ hdr.SetRetry ();
+ NS_LOG_INFO ("Retry packet seq = " << hdr.GetSequenceNumber ());
+ if (hdr.IsQosData ())
+ {
+ tid = hdr.GetQosTid ();
+ }
+ else
+ {
+ NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
+ }
+ recipient = hdr.GetAddr1 ();
+ if (!agreement->second.first.IsHtSupported ()
+ && (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 (*it);
+ }
+ it = m_retryPackets.erase (it);
+ NS_LOG_DEBUG ("Removed one packet, retry buffer size = " << m_retryPackets.size () );
+ break;
+ }
+ }
+ return packet;
+}
+
+
+Ptr<const Packet>
+BlockAckManager::PeekNextPacket (WifiMacHeader &hdr, Mac48Address recipient, uint8_t tid, Time *tstamp)
+{
+ NS_LOG_FUNCTION (this);
+ Ptr<const Packet> packet = 0;
+ CleanupBuffers ();
+ AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid));
+ NS_ASSERT (agreement != m_agreements.end ());
+ std::list<PacketQueueI>::iterator it = m_retryPackets.begin ();
+ for (; it != m_retryPackets.end (); it++)
+ {
+ if (!(*it)->hdr.IsQosData ())
+ {
+ NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
+ }
+ if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
+ {
+ if (QosUtilsIsOldPacket (agreement->second.first.GetStartingSequence (),(*it)->hdr.GetSequenceNumber ()))
+ {
+ //standard says the originator should not send a packet with seqnum < winstart
+ NS_LOG_DEBUG ("The Retry packet have sequence number < WinStartO --> Discard " << (*it)->hdr.GetSequenceNumber () << " " << agreement->second.first.GetStartingSequence ());
+ agreement->second.second.erase ((*it));
+ it = m_retryPackets.erase (it);
+ it--;
+ continue;
+ }
+ else if ((*it)->hdr.GetSequenceNumber () > (agreement->second.first.GetStartingSequence () + 63) % 4096)
+ {
+ agreement->second.first.SetStartingSequence ((*it)->hdr.GetSequenceNumber ());
+ }
+ packet = (*it)->packet->Copy ();
+ hdr = (*it)->hdr;
+ hdr.SetRetry ();
+ *tstamp = (*it)->timestamp;
+ NS_LOG_INFO ("Retry packet seq = " << hdr.GetSequenceNumber ());
+ Mac48Address recipient = hdr.GetAddr1 ();
+ if (!agreement->second.first.IsHtSupported ()
+ && (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);
+ }
+ NS_LOG_DEBUG ("Peeked one packet from retry buffer size = " << m_retryPackets.size () );
+ return packet;
+ }
+ }
+ return packet;
+}
+
+bool
+BlockAckManager::RemovePacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber)
+{
+
+ std::list<PacketQueueI>::iterator it = m_retryPackets.begin ();
+ for (; it != m_retryPackets.end (); it++)
+ {
+ if (!(*it)->hdr.IsQosData ())
+ {
+ NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
+ }
+ if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid && (*it)->hdr.GetSequenceNumber () == seqnumber)
+ {
+ WifiMacHeader hdr = (*it)->hdr;
+ uint8_t tid = hdr.GetQosTid ();
+ Mac48Address recipient = hdr.GetAddr1 ();
+
+ AgreementsI i = m_agreements.find (std::make_pair (recipient, tid));
+ i->second.second.erase ((*it));
+
+ m_retryPackets.erase (it);
+ NS_LOG_DEBUG ("Removed Packet from retry queue = " << hdr.GetSequenceNumber () << " " << (uint32_t) tid << " " << recipient << " Buffer Size = " << m_retryPackets.size ());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+BlockAckManager::HasBar (struct Bar &bar)
+{
+ NS_LOG_FUNCTION (this << &bar);
+ if (m_bars.size () > 0)
+ {
+ bar = m_bars.front ();
+ m_bars.pop_front ();
+ return true;
+ }
+ return false;
+}
+
+bool
+BlockAckManager::HasPackets (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return (m_retryPackets.size () > 0 || m_bars.size () > 0);
+}
+
+uint32_t
+BlockAckManager::GetNBufferedPackets (Mac48Address recipient, uint8_t tid) const
+{
+ NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
+ 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
+{
+ NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
+ uint32_t nPackets = 0;
+ uint16_t currentSeq = 0;
+ if (ExistsAgreement (recipient, tid))
+ {
+ std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
+ while (it != m_retryPackets.end ())
+ {
+ if (!(*it)->hdr.IsQosData ())
+ {
+ NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
+ }
+ 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++;
+ }
+ }
+ //go to next packet
+ if (it != m_retryPackets.end ())
+ {
+ it++;
+ }
+ }
+ }
+ return nPackets;
+}
+
+void
+BlockAckManager::SetBlockAckThreshold (uint8_t nPackets)
+{
+ NS_LOG_FUNCTION (this << static_cast<uint32_t> (nPackets));
+ m_blockAckThreshold = nPackets;
+}
+
+void
+BlockAckManager::SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> manager)
+{
+ NS_LOG_FUNCTION (this << manager);
+ m_stationManager = manager;
+}
+
+bool
+BlockAckManager::AlreadyExists (uint16_t currentSeq, Mac48Address recipient, uint8_t tid)
+{
+ std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
+ while (it != m_retryPackets.end ())
+ {
+ NS_LOG_FUNCTION (this << (*it)->hdr.GetType ());
+ if (!(*it)->hdr.IsQosData ())
+ {
+ NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
+ }
+ if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid && currentSeq == (*it)->hdr.GetSequenceNumber ())
+ {
+ return true;
+ }
+ it++;
+ }
+ return false;
+}
+
+void
+BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, WifiMode txMode)
+{
+ NS_LOG_FUNCTION (this << blockAck << recipient);
+ 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 (it->second.first.m_OriginatorInactivityEvent.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_OriginatorInactivityEvent.Cancel ();
+ Time timeout = MicroSeconds (1024 * it->second.first.GetTimeout ());
+ it->second.first.m_OriginatorInactivityEvent = Simulator::Schedule (timeout,
+ &BlockAckManager::OriginatorInactivityTimeout,
+ 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);
+ }
+
+ if (!AlreadyExists ((*queueIt).hdr.GetSequenceNumber (),recipient,tid))
+ {
+ InsertInRetryQueue (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)
+ {
+ //notify remote station of successful transmission
+ m_stationManager->ReportDataOk ((*queueIt).hdr.GetAddr1 (), &(*queueIt).hdr, 0, txMode, 0);
+ if (!m_txOkCallback.IsNull ())
+ {
+ m_txOkCallback ((*queueIt).hdr);
+ }
+ queueIt = it->second.second.erase (queueIt);
+ }
+ }
+ else
+ {
+ if (!foundFirstLost)
+ {
+ foundFirstLost = true;
+ sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber ();
+ (*it).second.first.SetStartingSequence (sequenceFirstLost);
+ }
+ //notify remote station of unsuccessful transmission
+ m_stationManager->ReportDataFailed ((*queueIt).hdr.GetAddr1 (), &(*queueIt).hdr);
+ if (!m_txFailedCallback.IsNull ())
+ {
+ m_txFailedCallback ((*queueIt).hdr);
+ }
+ if (!AlreadyExists ((*queueIt).hdr.GetSequenceNumber (),recipient,tid))
+ {
+ InsertInRetryQueue (queueIt);
+ }
+ queueIt++;
+ }
+ }
+ }
+ uint16_t newSeq = m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, recipient);
+ if ((foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, sequenceFirstLost))
+ || (!foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, newSeq)))
+ {
+ it->second.first.CompleteExchange ();
+ }
+ }
+ }
+ else
+ {
+ //NOT SUPPORTED FOR NOW
+ NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
+ }
+}
+
+void
+BlockAckManager::SetBlockAckType (enum BlockAckType bAckType)
+{
+ NS_LOG_FUNCTION (this << 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 << recipient << static_cast<uint32_t> (tid));
+ AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
+ NS_ASSERT (it != m_agreements.end ());
+
+ if ((*it).second.first.IsBlockAckRequestNeeded ()
+ || (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)
+{
+ NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
+ m_blockAckInactivityTimeout (recipient, tid, true);
+}
+
+void
+BlockAckManager::OriginatorInactivityTimeout (Mac48Address recipient, uint8_t tid)
+{
+ NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
+// std::cout<<Simulator::Now().ToDouble(Time::S)<<", aggreement to=" <<recipient<<" teared down"<<"\n";
+ DestroyAgreement(recipient, tid);
+ // std::cout<<Simulator::Now().ToDouble(Time::S)<<", code after DestroyAgreement call(unblock packets, flush aggregate queue) is executed\n";
+ m_unblockPackets(recipient, tid);
+ //inform edca-txop to flush out the aggregate queue of its mac
+ m_originatorBlockAckInactivityTimeout(recipient, tid, true);
+}
+
+void
+BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
+{
+ NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid) << startingSeq);
+ 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 << recipient << static_cast<uint32_t> (tid));
+ 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, uint16_t nextSeqNumber, enum WifiMacHeader::QosAckPolicy policy)
+{
+ NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid) << nextSeqNumber);
+ Ptr<Packet> bar = 0;
+ AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
+ NS_ASSERT (it != m_agreements.end ());
+
+ uint16_t nextSeq;
+ if (GetNRetryNeededPackets (recipient, tid) > 0)
+ {
+ nextSeq = GetSeqNumOfNextRetryPacket (recipient, tid);
+ }
+ else
+ {
+ nextSeq = nextSeqNumber;
+ }
+ it->second.first.NotifyMpduTransmission (nextSeq);
+ if (policy == WifiMacHeader::BLOCK_ACK)
+ {
+ 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)
+{
+ NS_LOG_FUNCTION (this << queue);
+ m_queue = queue;
+}
+
+bool
+BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
+{
+ NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid) << startingSeq);
+ 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 << recipient << static_cast<uint32_t> (tid));
+ // std::cout<<Simulator::Now().ToDouble(Time::S)<<", tear down BlockAck agreement to="<<recipient<<"\n";
+ DestroyAgreement (recipient, tid);
+ m_unblockPackets(recipient, tid);
+ //inform edca-txop to flush out the aggregate queue of its mac
+ m_originatorBlockAckInactivityTimeout(recipient, tid, true);
+}
+
+bool
+BlockAckManager::HasOtherFragments (uint16_t sequenceNumber) const
+{
+ NS_LOG_FUNCTION (this << sequenceNumber);
+ 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
+{
+ NS_LOG_FUNCTION (this);
+ uint32_t size = 0;
+ if (m_retryPackets.size () > 0)
+ {
+ Item next = *(m_retryPackets.front ());
+ size = next.packet->GetSize ();
+ }
+ return size;
+}
+
+bool BlockAckManager::NeedBarRetransmission (uint8_t tid, uint16_t seqNumber, Mac48Address recipient)
+{
+ //The standard says the BAR gets discarded when all MSDUs lifetime expires
+ AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
+ NS_ASSERT (it != m_agreements.end ());
+ CleanupBuffers ();
+ if ((seqNumber + 63) < it->second.first.GetStartingSequence ())
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+void
+BlockAckManager::CleanupBuffers (void)
+{
+ NS_LOG_FUNCTION (this);
+ 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 (std::list<PacketQueueI>::iterator it = m_retryPackets.begin (); it != m_retryPackets.end (); )
+ {
+ if ((*it)->hdr.GetAddr1 () == j->second.first.GetPeer ()
+ && (*it)->hdr.GetQosTid () == j->second.first.GetTid ()
+ && (*it)->hdr.GetSequenceNumber () == i->hdr.GetSequenceNumber ())
+ {
+ it = m_retryPackets.erase (it);
+ }
+ else
+ {
+ 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 << maxDelay);
+ m_maxDelay = maxDelay;
+}
+
+void
+BlockAckManager::SetBlockAckInactivityCallback (Callback<void, Mac48Address, uint8_t, bool> callback)
+{
+ NS_LOG_FUNCTION (this << &callback);
+ m_blockAckInactivityTimeout = callback;
+}
+
+void
+BlockAckManager::SetOriginatorBlockAckInactivityCallback (Callback<void, Mac48Address, uint8_t, bool> callback)
+{
+ NS_LOG_FUNCTION (this << &callback);
+ m_originatorBlockAckInactivityTimeout = callback;
+}
+void
+BlockAckManager::SetBlockDestinationCallback (Callback<void, Mac48Address, uint8_t> callback)
+{
+ NS_LOG_FUNCTION (this << &callback);
+ m_blockPackets = callback;
+}
+
+void
+BlockAckManager::SetUnblockDestinationCallback (Callback<void, Mac48Address, uint8_t> callback)
+{
+ NS_LOG_FUNCTION (this << &callback);
+ m_unblockPackets = callback;
+}
+
+void
+BlockAckManager::SetTxMiddle (MacTxMiddle* txMiddle)
+{
+ NS_LOG_FUNCTION (this << txMiddle);
+ m_txMiddle = txMiddle;
+}
+
+uint16_t
+BlockAckManager::GetSeqNumOfNextRetryPacket (Mac48Address recipient, uint8_t tid) const
+{
+ NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
+ std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
+ while (it != m_retryPackets.end ())
+ {
+ if (!(*it)->hdr.IsQosData ())
+ {
+ NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
+ }
+ if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
+ {
+ return (*it)->hdr.GetSequenceNumber ();
+ }
+ it++;
+ }
+ return 4096;
+}
+
+void
+BlockAckManager::SetTxOkCallback (TxOk callback)
+{
+ m_txOkCallback = callback;
+}
+
+void
+BlockAckManager::SetTxFailedCallback (TxFailed callback)
+{
+ m_txFailedCallback = callback;
+}
+
+void
+BlockAckManager::InsertInRetryQueue (PacketQueueI item)
+{
+ NS_LOG_INFO ("Adding to retry queue " << (*item).hdr.GetSequenceNumber ());
+ if (m_retryPackets.size () == 0)
+ {
+ m_retryPackets.push_back (item);
+ }
+ else
+ {
+ for (std::list<PacketQueueI>::iterator it = m_retryPackets.begin (); it != m_retryPackets.end (); )
+ {
+ if (((item->hdr.GetSequenceNumber () - (*it)->hdr.GetSequenceNumber () + 4096) % 4096) > 2047)
+ {
+ it = m_retryPackets.insert (it, item);
+ break;
+ }
+ else
+ {
+ it++;
+ if (it == m_retryPackets.end ())
+ {
+ m_retryPackets.push_back (item);
+ }
+ }
+ }
+ }
+}
+
+} //namespace ns3
diff --git a/emu-radio/ns3-patch/wifi/model/block-ack-manager.h b/emu-radio/ns3-patch/wifi/model/block-ack-manager.h
new file mode 100644
index 00000000..da2298c3
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/block-ack-manager.h
@@ -0,0 +1,462 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009, 2010 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"
+#include "wifi-mode.h"
+#include "wifi-remote-station-manager.h"
+
+namespace ns3 {
+
+class MgtAddBaResponseHeader;
+class MgtAddBaRequestHeader;
+class MgtDelBaHeader;
+class MacTxMiddle;
+class WifiMacQueue;
+
+/**
+ * \ingroup wifi
+ * \brief Block Ack Request
+ *
+ */
+struct Bar
+{
+ Bar ();
+ /**
+ * Construct Block ACK request for a given packet,
+ * receiver address, Traffic ID, and ACK policy.
+ *
+ * \param packet
+ * \param recipient
+ * \param tid
+ * \param immediate
+ */
+ 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.
+ * \ingroup wifi
+ */
+class BlockAckManager
+{
+private:
+ BlockAckManager (const BlockAckManager&);
+ BlockAckManager& operator= (const BlockAckManager&);
+
+
+public:
+ BlockAckManager ();
+ ~BlockAckManager ();
+
+ /**
+ * Set up WifiRemoteStationManager associated with this BlockAckManager.
+ *
+ * \param manager WifiRemoteStationManager associated with this BlockAckManager
+ */
+ void SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> manager);
+ /**
+ * \param recipient Address of peer station involved in block ack mechanism.
+ * \param tid Traffic ID.
+ *
+ * \return true if a block ack agreement exists, false otherwise
+ *
+ * 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
+ *
+ * \return true if a block ack agreement exists, false otherwise
+ *
+ * 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/Transmitted.
+ */
+ 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.
+ * \param tStamp time stamp 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).
+ *
+ * \return the packet
+ *
+ * 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 scheduled. Returns false otherwise.
+ *
+ * \return true if there are packets that need of retransmission or at least a BAR is scheduled,
+ * false otherwise
+ */
+ bool HasPackets (void) const;
+ /**
+ * \param blockAck The received block ack frame.
+ * \param recipient Sender of block ack frame.
+ * \param txMode mode 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 acknowledged MPDU is removed from the buffer, retransmitted otherwise.
+ */
+ void NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, WifiMode txMode);
+ /**
+ * \param recipient Address of peer station involved in block ack mechanism.
+ * \param tid Traffic ID.
+ *
+ * \return the number of packets buffered for a specified agreement
+ *
+ * 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.
+ *
+ * \return the number of packets for a specific agreement that need retransmission
+ *
+ * Returns number of packets for a specific agreement that need retransmission.
+ * This method doesn't return number of MPDUs that need retransmission but number of 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.
+ * \param startingSeq starting sequence field
+ *
+ * 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 ADDBA Response 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.
+ * \param nextSeqNumber Sequence number of the next packet that would be trasmitted by EdcaTxopN.
+ * \param policy ack policy of the transmitted packet.
+ *
+ * This method 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.
+ * The <i>nextSeqNumber</i> parameter is used to block transmission of packets that are out of bitmap.
+ */
+ void NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber, WifiMacHeader::QosAckPolicy policy);
+ /**
+ * \param recipient Address of peer station involved in block ack mechanism.
+ * \param tid Traffic ID of transmitted packet.
+ *
+ * This method to set the number of packets waitin for blockAck = 0 since the receiver will send the blockAck right away
+ */
+ void CompleteAmpduExchange (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 destroyed.
+ */
+ void TearDownBlockAck (Mac48Address recipient, uint8_t tid);
+ /**
+ * \param sequenceNumber Sequence number of the packet which fragment is
+ * part of.
+ * \return true if another fragment with the given sequence number is scheduled
+ * for retransmission.
+ *
+ * Returns true if another fragment with sequence number <i>sequenceNumber</i> is scheduled
+ * for retransmission.
+ */
+ bool HasOtherFragments (uint16_t sequenceNumber) const;
+ /**
+ * \return the size of the next packet that needs retransmission
+ *
+ * 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);
+
+ /**
+ * \param recipient
+ * \param tid
+ * \param startingSeq
+ *
+ * \return true if there are packets in the queue that could be sent under block ACK,
+ * false otherwise
+ *
+ * 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);
+ /**
+ * \param recipient
+ * \param tid
+ *
+ * \return the sequence number of the next retry packet for a specific agreement
+ *
+ * Returns the sequence number of the next retry packet for a specific agreement.
+ * If there are no packets that need retransmission for the specified agreement or
+ * the agreement doesn't exist the function returns 4096;
+ */
+ uint16_t GetSeqNumOfNextRetryPacket (Mac48Address recipient, uint8_t tid) const;
+ /**
+ * Checks if the packet already exists in the retransmit queue or not if it does then it doesn't add it again
+ */
+ bool AlreadyExists (uint16_t currentSeq, Mac48Address recipient, uint8_t tid);
+ /**
+ * Remove a packet after you peek in the queue and get it
+ */
+ bool RemovePacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber);
+ /*
+ * Peek in retransmit queue and get the next packet without removing it from the queue
+ */
+ Ptr<const Packet> PeekNextPacket (WifiMacHeader &hdr, Mac48Address recipient, uint8_t tid, Time *timestamp);
+ /**
+ * This function returns true if the lifetime of the packets a BAR refers to didn't expire yet else it returns false.
+ * If it return false then the BAR will be discarded (i.e. will not be re-transmitted)
+ */
+ bool NeedBarRetransmission (uint8_t tid, uint16_t seqNumber, Mac48Address recipient);
+
+ /**
+ * typedef for a callback to invoke when a
+ * packet transmission was completed successfully.
+ */
+ typedef Callback <void, const WifiMacHeader&> TxOk;
+ /**
+ * typedef for a callback to invoke when a
+ * packet transmission was failed.
+ */
+ typedef Callback <void, const WifiMacHeader&> TxFailed;
+ /**
+ * \param callback the callback to invoke when a
+ * packet transmission was completed successfully.
+ */
+ void SetTxOkCallback (TxOk callback);
+ /**
+ * \param callback the callback to invoke when a
+ * packet transmission was completed unsuccessfully.
+ */
+ void SetTxFailedCallback (TxFailed callback);
+
+
+private:
+ /**
+ * \param recipient
+ * \param tid
+ *
+ * \return a packet
+ *
+ * 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 exceeded.
+ */
+ void CleanupBuffers (void);
+ void InactivityTimeout (Mac48Address, uint8_t);
+ void OriginatorInactivityTimeout (Mac48Address, uint8_t);
+
+ struct Item;
+ /**
+ * typedef for a list of Item struct.
+ */
+ typedef std::list<Item> PacketQueue;
+ /**
+ * typedef for an iterator for PacketQueue.
+ */
+ typedef std::list<Item>::iterator PacketQueueI;
+ /**
+ * typedef for a const iterator for PacketQueue.
+ */
+ typedef std::list<Item>::const_iterator PacketQueueCI;
+ /**
+ * typedef for a map between MAC address and block ACK agreement.
+ */
+ typedef std::map<std::pair<Mac48Address, uint8_t>,
+ std::pair<OriginatorBlockAckAgreement, PacketQueue> > Agreements;
+ /**
+ * typedef for an iterator for Agreements.
+ */
+ typedef std::map<std::pair<Mac48Address, uint8_t>,
+ std::pair<OriginatorBlockAckAgreement, PacketQueue> >::iterator AgreementsI;
+ /**
+ * typedef for a const iterator for Agreements.
+ */
+ typedef std::map<std::pair<Mac48Address, uint8_t>,
+ std::pair<OriginatorBlockAckAgreement, PacketQueue> >::const_iterator AgreementsCI;
+
+ /**
+ * A struct for packet, Wifi header, and timestamp.
+ * Used in queue by block ACK manager.
+ */
+ struct Item
+ {
+ Item ();
+ Item (Ptr<const Packet> packet,
+ const WifiMacHeader &hdr,
+ Time tStamp);
+ Ptr<const Packet> packet;
+ WifiMacHeader hdr;
+ Time timestamp;
+ };
+ /**
+ * \param item
+ *
+ * Insert item in retransmission queue.
+ * This method ensures packets are retransmitted in the correct order.
+ */
+ void InsertInRetryQueue (PacketQueueI item);
+
+ /**
+ * 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 received 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;
+ TxOk m_txOkCallback;
+ TxFailed m_txFailedCallback;
+ Ptr<WifiRemoteStationManager> m_stationManager;
+
+ //added++++++++
+ Callback<void, Mac48Address, uint8_t, bool> m_originatorBlockAckInactivityTimeout;
+
+public:
+ void SetOriginatorBlockAckInactivityCallback (Callback<void, Mac48Address, uint8_t, bool> callback);
+};
+
+} //namespace ns3
+
+#endif /* BLOCK_ACK_MANAGER_H */
diff --git a/emu-radio/ns3-patch/wifi/model/edca-txop-n.cc b/emu-radio/ns3-patch/wifi/model/edca-txop-n.cc
new file mode 100644
index 00000000..bba10469
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/edca-txop-n.cc
@@ -0,0 +1,1584 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006, 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
+ *
+ * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Mirko Banchi <mk.banchi@gmail.com>
+ */
+
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include "ns3/pointer.h"
+#include "edca-txop-n.h"
+#include "mac-low.h"
+#include "dcf-manager.h"
+#include "mac-tx-middle.h"
+#include "wifi-mac-trailer.h"
+#include "wifi-mac.h"
+#include "random-stream.h"
+#include "wifi-mac-queue.h"
+#include "msdu-aggregator.h"
+#include "mgt-headers.h"
+#include "qos-blocked-destinations.h"
+
+#undef NS_LOG_APPEND_CONTEXT
+#define NS_LOG_APPEND_CONTEXT if (m_low != 0) { std::clog << "[mac=" << m_low->GetAddress () << "] "; }
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("EdcaTxopN");
+
+class EdcaTxopN::Dcf : public DcfState
+{
+public:
+ Dcf (EdcaTxopN * txop)
+ : m_txop (txop)
+ {
+ }
+
+private:
+ virtual void DoNotifyAccessGranted (void)
+ {
+ m_txop->NotifyAccessGranted ();
+ }
+ virtual void DoNotifyInternalCollision (void)
+ {
+ m_txop->NotifyInternalCollision ();
+ }
+ virtual void DoNotifyCollision (void)
+ {
+ m_txop->NotifyCollision ();
+ }
+ virtual void DoNotifyChannelSwitching (void)
+ {
+ m_txop->NotifyChannelSwitching ();
+ }
+ virtual void DoNotifySleep (void)
+ {
+ m_txop->NotifySleep ();
+ }
+ virtual void DoNotifyWakeUp (void)
+ {
+ m_txop->NotifyWakeUp ();
+ }
+
+ EdcaTxopN *m_txop;
+};
+
+
+class EdcaTxopN::TransmissionListener : public MacLowTransmissionListener
+{
+public:
+ TransmissionListener (EdcaTxopN * txop)
+ : MacLowTransmissionListener (),
+ m_txop (txop)
+ {
+ }
+
+ virtual ~TransmissionListener ()
+ {
+ }
+
+ virtual void GotCts (double snr, WifiMode txMode)
+ {
+ m_txop->GotCts (snr, txMode);
+ }
+ virtual void MissedCts (void)
+ {
+ m_txop->MissedCts ();
+ }
+ virtual void GotAck (double snr, WifiMode txMode)
+ {
+ m_txop->GotAck (snr, txMode);
+ }
+ virtual void MissedAck (void)
+ {
+ m_txop->MissedAck ();
+ }
+ virtual void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source, WifiMode txMode)
+ {
+ m_txop->GotBlockAck (blockAck, source,txMode);
+ }
+ virtual void MissedBlockAck (void)
+ {
+ m_txop->MissedBlockAck ();
+ }
+ virtual void StartNext (void)
+ {
+ m_txop->StartNext ();
+ }
+ virtual void Cancel (void)
+ {
+ m_txop->Cancel ();
+ }
+ virtual void EndTxNoAck (void)
+ {
+ m_txop->EndTxNoAck ();
+ }
+ virtual Ptr<WifiMacQueue> GetQueue (void)
+ {
+ return m_txop->GetEdcaQueue ();
+ }
+
+private:
+ EdcaTxopN *m_txop;
+};
+
+
+class EdcaTxopN::AggregationCapableTransmissionListener : public MacLowAggregationCapableTransmissionListener
+{
+public:
+ AggregationCapableTransmissionListener (EdcaTxopN * txop)
+ : MacLowAggregationCapableTransmissionListener (),
+ m_txop (txop)
+ {
+ }
+ virtual ~AggregationCapableTransmissionListener ()
+ {
+ }
+
+ virtual void BlockAckInactivityTimeout (Mac48Address address, uint8_t tid)
+ {
+ m_txop->SendDelbaFrame (address, tid, false);
+
+ //also remove the agreement record at mac m_low
+ //m_txop->Low()->DestroyBlockAckAgreement (address, tid);
+ }
+ virtual Ptr<WifiMacQueue> GetQueue (void)
+ {
+ return m_txop->GetEdcaQueue ();
+ }
+ virtual void CompleteTransfer (Mac48Address recipient, uint8_t tid)
+ {
+ m_txop->CompleteAmpduTransfer (recipient, tid);
+ }
+ virtual void SetAmpdu (bool ampdu)
+ {
+ return m_txop->SetAmpduExist (ampdu);
+ }
+ virtual void CompleteMpduTx (Ptr<const Packet> packet, WifiMacHeader hdr, Time tstamp)
+ {
+ m_txop->CompleteMpduTx (packet, hdr, tstamp);
+ }
+ virtual uint16_t GetNextSequenceNumberfor (WifiMacHeader *hdr)
+ {
+ return m_txop->GetNextSequenceNumberfor (hdr);
+ }
+ virtual uint16_t PeekNextSequenceNumberfor (WifiMacHeader *hdr)
+ {
+ return m_txop->PeekNextSequenceNumberfor (hdr);
+ }
+ virtual Ptr<const Packet> PeekNextPacketInBaQueue (WifiMacHeader &header, Mac48Address recipient, uint8_t tid, Time *timestamp)
+ {
+ return m_txop->PeekNextRetransmitPacket (header, recipient, tid, timestamp);
+ }
+ virtual void RemoveFromBaQueue (uint8_t tid, Mac48Address recipient, uint16_t seqnumber)
+ {
+ m_txop->RemoveRetransmitPacket (tid, recipient, seqnumber);
+ }
+ virtual bool GetBlockAckAgreementExists (Mac48Address address, uint8_t tid)
+ {
+ return m_txop->GetBaAgreementExists (address,tid);
+ }
+ virtual uint32_t GetNOutstandingPackets (Mac48Address address, uint8_t tid)
+ {
+ return m_txop->GetNOutstandingPacketsInBa (address, tid);
+ }
+ virtual uint32_t GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const
+ {
+ return m_txop->GetNRetryNeededPackets (recipient, tid);
+ }
+ virtual Ptr<MsduAggregator> GetMsduAggregator (void) const
+ {
+ return m_txop->GetMsduAggregator ();
+ }
+ virtual Mac48Address GetSrcAddressForAggregation (const WifiMacHeader &hdr)
+ {
+ return m_txop->MapSrcAddressForAggregation (hdr);
+ }
+ virtual Mac48Address GetDestAddressForAggregation (const WifiMacHeader &hdr)
+ {
+ return m_txop->MapDestAddressForAggregation (hdr);
+ }
+
+private:
+ EdcaTxopN *m_txop;
+};
+
+NS_OBJECT_ENSURE_REGISTERED (EdcaTxopN);
+
+TypeId
+EdcaTxopN::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::EdcaTxopN")
+ .SetParent<ns3::Dcf> ()
+ .SetGroupName ("Wifi")
+ .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::SetBlockAckInactivityTimeout),
+ MakeUintegerChecker<uint16_t> ())
+ .AddAttribute ("Queue",
+ "The WifiMacQueue object",
+ PointerValue (),
+ MakePointerAccessor (&EdcaTxopN::GetEdcaQueue),
+ MakePointerChecker<WifiMacQueue> ())
+ ;
+ return tid;
+}
+
+EdcaTxopN::EdcaTxopN ()
+ : m_manager (0),
+ m_currentPacket (0),
+ m_aggregator (0),
+ m_typeOfStation (STA),
+ m_blockAckType (COMPRESSED_BLOCK_ACK),
+ m_ampduExist (false)
+{
+ NS_LOG_FUNCTION (this);
+ m_transmissionListener = new EdcaTxopN::TransmissionListener (this);
+ m_blockAckListener = new EdcaTxopN::AggregationCapableTransmissionListener (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 ());
+ m_baManager->SetTxOkCallback (MakeCallback (&EdcaTxopN::BaTxOk, this));
+ m_baManager->SetTxFailedCallback (MakeCallback (&EdcaTxopN::BaTxFailed, this));
+}
+
+EdcaTxopN::~EdcaTxopN ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+void
+EdcaTxopN::DoDispose (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_queue = 0;
+ m_low = 0;
+ m_stationManager = 0;
+ 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;
+}
+
+bool
+EdcaTxopN::GetBaAgreementExists (Mac48Address address, uint8_t tid)
+{
+ return m_baManager->ExistsAgreement (address, tid);
+}
+
+uint32_t
+EdcaTxopN::GetNOutstandingPacketsInBa (Mac48Address address, uint8_t tid)
+{
+ return m_baManager->GetNBufferedPackets (address, tid);
+}
+
+uint32_t
+EdcaTxopN::GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const
+{
+ return m_baManager->GetNRetryNeededPackets (recipient, tid);
+}
+
+void
+EdcaTxopN::CompleteAmpduTransfer (Mac48Address recipient, uint8_t tid)
+{
+ m_baManager->CompleteAmpduExchange (recipient, tid);
+}
+
+void
+EdcaTxopN::SetManager (DcfManager *manager)
+{
+ NS_LOG_FUNCTION (this << manager);
+ m_manager = manager;
+ m_manager->Add (m_dcf);
+}
+
+void
+EdcaTxopN::SetTxOkCallback (TxOk callback)
+{
+ NS_LOG_FUNCTION (this << &callback);
+ m_txOkCallback = callback;
+}
+
+void
+EdcaTxopN::SetTxFailedCallback (TxFailed callback)
+{
+ NS_LOG_FUNCTION (this << &callback);
+ m_txFailedCallback = callback;
+}
+
+void
+EdcaTxopN::SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> remoteManager)
+{
+ NS_LOG_FUNCTION (this << remoteManager);
+ m_stationManager = remoteManager;
+ m_baManager->SetWifiRemoteStationManager (m_stationManager);
+}
+
+void
+EdcaTxopN::SetTypeOfStation (enum TypeOfStation type)
+{
+ NS_LOG_FUNCTION (this << static_cast<uint32_t> (type));
+ m_typeOfStation = type;
+}
+
+enum TypeOfStation
+EdcaTxopN::GetTypeOfStation (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_typeOfStation;
+}
+
+Ptr<WifiMacQueue >
+EdcaTxopN::GetEdcaQueue () const
+{
+ NS_LOG_FUNCTION (this);
+ return m_queue;
+}
+
+void
+EdcaTxopN::SetMinCw (uint32_t minCw)
+{
+ NS_LOG_FUNCTION (this << minCw);
+ m_dcf->SetCwMin (minCw);
+}
+
+void
+EdcaTxopN::SetMaxCw (uint32_t maxCw)
+{
+ NS_LOG_FUNCTION (this << maxCw);
+ m_dcf->SetCwMax (maxCw);
+}
+
+void
+EdcaTxopN::SetAifsn (uint32_t aifsn)
+{
+ NS_LOG_FUNCTION (this << aifsn);
+ m_dcf->SetAifsn (aifsn);
+}
+
+uint32_t
+EdcaTxopN::GetMinCw (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_dcf->GetCwMin ();
+}
+
+uint32_t
+EdcaTxopN::GetMaxCw (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_dcf->GetCwMax ();
+}
+
+uint32_t
+EdcaTxopN::GetAifsn (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_dcf->GetAifsn ();
+}
+
+void
+EdcaTxopN::SetTxMiddle (MacTxMiddle *txMiddle)
+{
+ NS_LOG_FUNCTION (this << txMiddle);
+ m_txMiddle = txMiddle;
+}
+
+Ptr<MacLow>
+EdcaTxopN::Low (void)
+{
+ NS_LOG_FUNCTION (this);
+ return m_low;
+}
+
+void
+EdcaTxopN::SetLow (Ptr<MacLow> low)
+{
+ NS_LOG_FUNCTION (this << low);
+ m_low = low;
+}
+
+bool
+EdcaTxopN::NeedsAccess (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return !m_queue->IsEmpty () || m_currentPacket != 0 || m_baManager->HasPackets ();
+}
+
+uint16_t EdcaTxopN::GetNextSequenceNumberfor (WifiMacHeader *hdr)
+{
+ return m_txMiddle->GetNextSequenceNumberfor (hdr);
+}
+
+uint16_t EdcaTxopN::PeekNextSequenceNumberfor (WifiMacHeader *hdr)
+{
+ return m_txMiddle->PeekNextSequenceNumberfor (hdr);
+}
+
+Ptr<const Packet>
+EdcaTxopN::PeekNextRetransmitPacket (WifiMacHeader &header,Mac48Address recipient, uint8_t tid, Time *timestamp)
+{
+ return m_baManager->PeekNextPacket (header,recipient,tid, timestamp);
+}
+
+void
+EdcaTxopN::RemoveRetransmitPacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber)
+{
+ m_baManager->RemovePacket (tid, recipient, seqnumber);
+}
+
+void
+EdcaTxopN::NotifyAccessGranted (void)
+{
+ NS_LOG_FUNCTION (this);
+ if (m_currentPacket == 0)
+ {
+ if (m_queue->IsEmpty () && !m_baManager->HasPackets ())
+ {
+ NS_LOG_DEBUG ("queue is empty");
+ return;
+ }
+ if (m_baManager->HasBar (m_currentBar))
+ {
+ SendBlockAckRequest (m_currentBar);
+ 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)
+ {
+ NS_LOG_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_stationManager->UpdateFragmentationThreshold ();
+ m_currentHdr.SetFragmentNumber (0);
+ m_currentHdr.SetNoMoreFragments ();
+ m_currentHdr.SetNoRetry ();
+ m_fragmentNumber = 0;
+ NS_LOG_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 ();
+ if (m_currentHdr.GetAddr1 ().IsGroup ())
+ {
+ params.DisableRts ();
+ params.DisableAck ();
+ params.DisableNextData ();
+ m_low->StartTransmission (m_currentPacket,
+ &m_currentHdr,
+ params,
+ m_transmissionListener);
+
+ NS_LOG_DEBUG ("tx broadcast");
+ }
+ else if (m_currentHdr.GetType () == WIFI_MAC_CTL_BACKREQ)
+ {
+ SendBlockAckRequest (m_currentBar);
+ }
+ else
+ {
+ if (m_currentHdr.IsQosData () && m_currentHdr.IsQosBlockAck ())
+ {
+ params.DisableAck ();
+ }
+ else
+ {
+ params.EnableAck ();
+ }
+ if (NeedFragmentation () && ((m_currentHdr.IsQosData ()
+ && !m_currentHdr.IsQosAmsdu ())
+ ||
+ (m_currentHdr.IsData ()
+ && !m_currentHdr.IsQosData () && m_currentHdr.IsQosAmsdu ()))
+ && (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);
+ if (IsLastFragment ())
+ {
+ NS_LOG_DEBUG ("fragmenting last fragment size=" << fragment->GetSize ());
+ params.DisableNextData ();
+ }
+ else
+ {
+ NS_LOG_DEBUG ("fragmenting size=" << fragment->GetSize ());
+ params.EnableNextData (GetNextFragmentSize ());
+ }
+ m_low->StartTransmission (fragment, &hdr, params,
+ m_transmissionListener);
+ }
+ else
+ {
+ WifiMacHeader peekedHdr;
+ Time tstamp;
+ if (m_currentHdr.IsQosData ()
+ && m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (),
+ WifiMacHeader::ADDR1, m_currentHdr.GetAddr1 (), &tstamp)
+ && !m_currentHdr.GetAddr1 ().IsBroadcast ()
+ && m_aggregator != 0 && !m_currentHdr.IsRetry ())
+ {
+ /* here is performed aggregation */
+ Ptr<Packet> currentAggregatedPacket = Create<Packet> ();
+ m_aggregator->Aggregate (m_currentPacket, currentAggregatedPacket,
+ MapSrcAddressForAggregation (peekedHdr),
+ MapDestAddressForAggregation (peekedHdr));
+ bool aggregated = false;
+ bool isAmsdu = false;
+ Ptr<const Packet> peekedPacket = m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (),
+ WifiMacHeader::ADDR1,
+ m_currentHdr.GetAddr1 (), &tstamp);
+ while (peekedPacket != 0)
+ {
+ aggregated = m_aggregator->Aggregate (peekedPacket, currentAggregatedPacket,
+ MapSrcAddressForAggregation (peekedHdr),
+ MapDestAddressForAggregation (peekedHdr));
+ if (aggregated)
+ {
+ isAmsdu = true;
+ m_queue->Remove (peekedPacket);
+ }
+ else
+ {
+ break;
+ }
+ peekedPacket = m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (),
+ WifiMacHeader::ADDR1, m_currentHdr.GetAddr1 (), &tstamp);
+ }
+ if (isAmsdu)
+ {
+ m_currentHdr.SetQosAmsdu ();
+ m_currentHdr.SetAddr3 (m_low->GetBssid ());
+ m_currentPacket = currentAggregatedPacket;
+ currentAggregatedPacket = 0;
+ NS_LOG_DEBUG ("tx unicast A-MSDU");
+ }
+ }
+ if (NeedRts ())
+ {
+ params.EnableRts ();
+ NS_LOG_DEBUG ("tx unicast rts");
+ }
+ else
+ {
+ params.DisableRts ();
+ NS_LOG_DEBUG ("tx unicast");
+ }
+ params.DisableNextData ();
+ m_low->StartTransmission (m_currentPacket, &m_currentHdr,
+ params, m_transmissionListener);
+ if (!GetAmpduExist ())
+ {
+ CompleteTx ();
+ }
+ }
+ }
+}
+
+void EdcaTxopN::NotifyInternalCollision (void)
+{
+ NS_LOG_FUNCTION (this);
+ NotifyCollision ();
+}
+
+void
+EdcaTxopN::NotifyCollision (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+ RestartAccessIfNeeded ();
+}
+
+void
+EdcaTxopN::GotCts (double snr, WifiMode txMode)
+{
+ NS_LOG_FUNCTION (this << snr << txMode);
+ NS_LOG_DEBUG ("got cts");
+}
+
+void
+EdcaTxopN::MissedCts (void)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_DEBUG ("missed cts");
+ if (!NeedRtsRetransmission ())
+ {
+ NS_LOG_DEBUG ("Cts Fail");
+ bool resetCurrentPacket = true;
+ m_stationManager->ReportFinalRtsFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
+ if (!m_txFailedCallback.IsNull ())
+ {
+ m_txFailedCallback (m_currentHdr);
+ }
+ if (GetAmpduExist ())
+ {
+ m_low->FlushAggregateQueue ();
+ uint8_t tid = 0;
+ if (m_currentHdr.IsQosData ())
+ {
+ tid = m_currentHdr.GetQosTid ();
+ }
+ else
+ {
+ NS_FATAL_ERROR ("Current packet is not Qos Data");
+ }
+
+ if (GetBaAgreementExists (m_currentHdr.GetAddr1 (), tid))
+ {
+ NS_LOG_DEBUG ("Transmit Block Ack Request");
+ CtrlBAckRequestHeader reqHdr;
+ reqHdr.SetType (COMPRESSED_BLOCK_ACK);
+ reqHdr.SetStartingSequence (m_txMiddle->PeekNextSequenceNumberfor (&m_currentHdr));
+ reqHdr.SetTidInfo (tid);
+ reqHdr.SetHtImmediateAck (true);
+ Ptr<Packet> bar = Create<Packet> ();
+ bar->AddHeader (reqHdr);
+ Bar request (bar, m_currentHdr.GetAddr1 (), tid, reqHdr.MustSendHtImmediateAck ());
+ m_currentBar = request;
+ WifiMacHeader hdr;
+ hdr.SetType (WIFI_MAC_CTL_BACKREQ);
+ hdr.SetAddr1 (request.recipient);
+ hdr.SetAddr2 (m_low->GetAddress ());
+ hdr.SetAddr3 (m_low->GetBssid ());
+ hdr.SetDsNotTo ();
+ hdr.SetDsNotFrom ();
+ hdr.SetNoRetry ();
+ hdr.SetNoMoreFragments ();
+ m_currentPacket = request.bar;
+ m_currentHdr = hdr;
+ resetCurrentPacket = false;
+ }
+ }
+ //to reset the dcf.
+ if (resetCurrentPacket == true)
+ {
+ m_currentPacket = 0;
+ }
+ m_dcf->ResetCw ();
+ }
+ else
+ {
+ m_dcf->UpdateFailedCw ();
+ }
+ m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+ RestartAccessIfNeeded ();
+}
+
+void
+EdcaTxopN::NotifyChannelSwitching (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_queue->Flush ();
+ m_currentPacket = 0;
+}
+
+void
+EdcaTxopN::NotifySleep (void)
+{
+ NS_LOG_FUNCTION (this);
+ if (m_currentPacket != 0)
+ {
+ m_queue->PushFront (m_currentPacket, m_currentHdr);
+ m_currentPacket = 0;
+ }
+}
+
+void
+EdcaTxopN::NotifyWakeUp (void)
+{
+ NS_LOG_FUNCTION (this);
+ RestartAccessIfNeeded ();
+}
+
+void
+EdcaTxopN::Queue (Ptr<const Packet> packet, const WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this << packet << &hdr);
+ WifiMacTrailer fcs;
+ uint32_t fullPacketSize = hdr.GetSerializedSize () + packet->GetSize () + fcs.GetSerializedSize ();
+ m_stationManager->PrepareForQueue (hdr.GetAddr1 (), &hdr,
+ packet, fullPacketSize);
+ m_queue->Enqueue (packet, hdr);
+ StartAccessIfNeeded ();
+}
+
+void
+EdcaTxopN::GotAck (double snr, WifiMode txMode)
+{
+ NS_LOG_FUNCTION (this << snr << txMode);
+ if (!NeedFragmentation ()
+ || IsLastFragment ()
+ || m_currentHdr.IsQosAmsdu ())
+ {
+ NS_LOG_DEBUG ("got ack. tx done.");
+ if (!m_txOkCallback.IsNull ())
+ {
+ 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 ();
+ m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+ RestartAccessIfNeeded ();
+ }
+ else
+ {
+ NS_LOG_DEBUG ("got ack. tx not done, size=" << m_currentPacket->GetSize ());
+ }
+}
+
+void
+EdcaTxopN::MissedAck (void)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_DEBUG ("missed ack");
+ if (!NeedDataRetransmission ())
+ {
+ //NS_LOG_DEBUG ("Ack Fail");
+
+ m_stationManager->ReportFinalDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
+ bool resetCurrentPacket = true;
+ if (!m_txFailedCallback.IsNull ())
+ {
+ m_txFailedCallback (m_currentHdr);
+ }
+ if (GetAmpduExist ())
+ {
+ uint8_t tid = 0;
+ if (m_currentHdr.IsQosData ())
+ {
+ tid = m_currentHdr.GetQosTid ();
+ }
+ else if (m_currentHdr.IsAction ())
+ {
+ NS_LOG_DEBUG ("action frame (ADDBA request/response) failed");
+
+ WifiActionHeader actionHdr;
+ m_currentPacket->PeekHeader (actionHdr);
+ Mac48Address to = m_currentHdr.GetAddr1 ();
+
+ if(actionHdr.GetAction ().blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_REQUEST) //Block ack request
+ {
+ // std::cout<<"block ack request failed, tear down agreement in pending\n";
+ MgtAddBaRequestHeader reqHdr;
+ m_currentPacket->PeekHeader (reqHdr);
+ m_baManager->DestroyAgreement(to,reqHdr.GetTid ());
+ m_qosBlockedDestinations->Unblock(to,reqHdr.GetTid ());
+ }
+ else if(actionHdr.GetAction ().blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_RESPONSE)
+ {
+ MgtAddBaResponseHeader respHdr;
+ m_currentPacket->PeekHeader (respHdr);
+ m_low->DestroyBlockAckAgreement(to,respHdr.GetTid ());
+ }
+
+ }
+ else
+ {
+ NS_FATAL_ERROR ("Current packet is not Qos Data");
+ }
+
+ if (GetBaAgreementExists (m_currentHdr.GetAddr1 (), tid))
+ {
+ //send Block ACK Request in order to shift WinStart at the receiver
+ CtrlBAckRequestHeader reqHdr;
+ reqHdr.SetType (COMPRESSED_BLOCK_ACK);
+ reqHdr.SetStartingSequence (m_txMiddle->PeekNextSequenceNumberfor (&m_currentHdr));
+ reqHdr.SetTidInfo (tid);
+ reqHdr.SetHtImmediateAck (true);
+ Ptr<Packet> bar = Create<Packet> ();
+ bar->AddHeader (reqHdr);
+ Bar request (bar, m_currentHdr.GetAddr1 (), tid, reqHdr.MustSendHtImmediateAck ());
+ m_currentBar = request;
+ WifiMacHeader hdr;
+ hdr.SetType (WIFI_MAC_CTL_BACKREQ);
+ hdr.SetAddr1 (request.recipient);
+ hdr.SetAddr2 (m_low->GetAddress ());
+ hdr.SetAddr3 (m_low->GetBssid ());
+ hdr.SetDsNotTo ();
+ hdr.SetDsNotFrom ();
+ hdr.SetNoRetry ();
+ hdr.SetNoMoreFragments ();
+ m_currentPacket = request.bar;
+ m_currentHdr = hdr;
+ resetCurrentPacket = false;
+ }
+ }
+ //to reset the dcf.
+ if (resetCurrentPacket == true)
+ {
+ m_currentPacket = 0;
+ }
+ m_dcf->ResetCw ();
+ }
+ else
+ {
+ NS_LOG_DEBUG ("Retransmit");
+ m_currentHdr.SetRetry ();
+ m_dcf->UpdateFailedCw ();
+ }
+ m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+ RestartAccessIfNeeded ();
+}
+
+void
+EdcaTxopN::MissedBlockAck (void)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_DEBUG ("missed block ack");
+ if (NeedBarRetransmission ())
+ {
+ if (!GetAmpduExist ())
+ {
+ //should i report this to station addressed by ADDR1?
+ NS_LOG_DEBUG ("Retransmit block ack request");
+ m_currentHdr.SetRetry ();
+ }
+ else
+ {
+ //standard says when loosing a BlockAck originator may send a BAR page 139
+ NS_LOG_DEBUG("Transmit Block Ack Request");
+ CtrlBAckRequestHeader reqHdr;
+ reqHdr.SetType (COMPRESSED_BLOCK_ACK);
+ uint8_t tid = 0;
+ if (m_currentHdr.IsQosData ())
+ {
+ tid = m_currentHdr.GetQosTid ();
+ reqHdr.SetStartingSequence (m_currentHdr.GetSequenceNumber ());
+ }
+ else if (m_currentHdr.IsBlockAckReq ())
+ {
+ CtrlBAckRequestHeader baReqHdr;
+ m_currentPacket->PeekHeader (baReqHdr);
+ tid = baReqHdr.GetTidInfo ();
+ reqHdr.SetStartingSequence (baReqHdr.GetStartingSequence ());
+ }
+ else if (m_currentHdr.IsBlockAck ())
+ {
+ CtrlBAckResponseHeader baRespHdr;
+ m_currentPacket->PeekHeader (baRespHdr);
+ tid = baRespHdr.GetTidInfo ();
+ reqHdr.SetStartingSequence (m_currentHdr.GetSequenceNumber ());
+ }
+ reqHdr.SetTidInfo (tid);
+ reqHdr.SetHtImmediateAck (true);
+ Ptr<Packet> bar = Create<Packet> ();
+ bar->AddHeader (reqHdr);
+ Bar request (bar, m_currentHdr.GetAddr1 (), tid, reqHdr.MustSendHtImmediateAck ());
+ m_currentBar = request;
+ WifiMacHeader hdr;
+ hdr.SetType (WIFI_MAC_CTL_BACKREQ);
+ hdr.SetAddr1 (request.recipient);
+ hdr.SetAddr2 (m_low->GetAddress ());
+ hdr.SetAddr3 (m_low->GetBssid ());
+ hdr.SetDsNotTo ();
+ hdr.SetDsNotFrom ();
+ hdr.SetNoRetry ();
+ hdr.SetNoMoreFragments ();
+
+ m_currentPacket = request.bar;
+ m_currentHdr = hdr;
+ }
+ m_dcf->UpdateFailedCw ();
+ }
+ else
+ {
+ NS_LOG_DEBUG ("Block Ack Request Fail");
+ //to reset the dcf.
+ m_currentPacket = 0;
+ m_dcf->ResetCw ();
+ }
+ m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+ RestartAccessIfNeeded ();
+}
+
+Ptr<MsduAggregator>
+EdcaTxopN::GetMsduAggregator (void) const
+{
+ return m_aggregator;
+}
+
+void
+EdcaTxopN::RestartAccessIfNeeded (void)
+{
+ NS_LOG_FUNCTION (this);
+ if ((m_currentPacket != 0
+ || !m_queue->IsEmpty () || m_baManager->HasPackets ())
+ && !m_dcf->IsAccessRequested ())
+ {
+ m_manager->RequestAccess (m_dcf);
+ }
+}
+
+void
+EdcaTxopN::StartAccessIfNeeded (void)
+{
+ NS_LOG_FUNCTION (this);
+ if (m_currentPacket == 0
+ && (!m_queue->IsEmpty () || m_baManager->HasPackets ())
+ && !m_dcf->IsAccessRequested ())
+ {
+ m_manager->RequestAccess (m_dcf);
+ }
+}
+
+bool
+EdcaTxopN::NeedRts (void)
+{
+ NS_LOG_FUNCTION (this);
+ return m_stationManager->NeedRts (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ m_currentPacket);
+}
+
+bool
+EdcaTxopN::NeedRtsRetransmission (void)
+{
+ NS_LOG_FUNCTION (this);
+ return m_stationManager->NeedRtsRetransmission (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ m_currentPacket);
+}
+
+bool
+EdcaTxopN::NeedDataRetransmission (void)
+{
+ NS_LOG_FUNCTION (this);
+ return m_stationManager->NeedDataRetransmission (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ m_currentPacket);
+}
+
+bool
+EdcaTxopN::NeedBarRetransmission (void)
+{
+ uint8_t tid = 0;
+ uint16_t seqNumber = 0;
+ if (m_currentHdr.IsQosData ())
+ {
+ tid = m_currentHdr.GetQosTid ();
+ seqNumber = m_currentHdr.GetSequenceNumber ();
+ }
+ else if (m_currentHdr.IsBlockAckReq ())
+ {
+ CtrlBAckRequestHeader baReqHdr;
+ m_currentPacket->PeekHeader (baReqHdr);
+ tid = baReqHdr.GetTidInfo ();
+ seqNumber = baReqHdr.GetStartingSequence ();
+ }
+ else if (m_currentHdr.IsBlockAck ())
+ {
+ CtrlBAckResponseHeader baRespHdr;
+ m_currentPacket->PeekHeader (baRespHdr);
+ tid = baRespHdr.GetTidInfo ();
+ seqNumber = m_currentHdr.GetSequenceNumber ();
+ }
+ if( !m_baManager->ExistsAgreement(m_currentHdr.GetAddr1 (),tid) )
+ {
+ return false;
+ }
+
+ return m_baManager->NeedBarRetransmission (tid, seqNumber, m_currentHdr.GetAddr1 ())
+ // && m_stationManager->NeedDataRetransmission (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ // m_currentPacket)
+ ;
+}
+
+void
+EdcaTxopN::NextFragment (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_fragmentNumber++;
+}
+
+void
+EdcaTxopN::StartNext (void)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_DEBUG ("start next packet fragment");
+ /* this callback is used only for fragments. */
+ NextFragment ();
+ WifiMacHeader hdr;
+ Ptr<Packet> fragment = GetFragmentPacket (&hdr);
+ MacLowTransmissionParameters params;
+ params.EnableAck ();
+ params.DisableRts ();
+ params.DisableOverrideDurationId ();
+ if (IsLastFragment ())
+ {
+ params.DisableNextData ();
+ }
+ else
+ {
+ params.EnableNextData (GetNextFragmentSize ());
+ }
+ Low ()->StartTransmission (fragment, &hdr, params, m_transmissionListener);
+}
+
+void
+EdcaTxopN::Cancel (void)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_DEBUG ("transmission cancelled");
+}
+
+void
+EdcaTxopN::EndTxNoAck (void)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_DEBUG ("a transmission that did not require an ACK just finished");
+ m_currentPacket = 0;
+ m_dcf->ResetCw ();
+ m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+ StartAccessIfNeeded ();
+}
+
+bool
+EdcaTxopN::NeedFragmentation (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_stationManager->NeedFragmentation (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ m_currentPacket);
+}
+
+uint32_t
+EdcaTxopN::GetFragmentSize (void)
+{
+ NS_LOG_FUNCTION (this);
+ return m_stationManager->GetFragmentSize (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ m_currentPacket, m_fragmentNumber);
+}
+
+uint32_t
+EdcaTxopN::GetNextFragmentSize (void)
+{
+ NS_LOG_FUNCTION (this);
+ return m_stationManager->GetFragmentSize (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ m_currentPacket, m_fragmentNumber + 1);
+}
+
+uint32_t
+EdcaTxopN::GetFragmentOffset (void)
+{
+ NS_LOG_FUNCTION (this);
+ return m_stationManager->GetFragmentOffset (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ m_currentPacket, m_fragmentNumber);
+}
+
+
+bool
+EdcaTxopN::IsLastFragment (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_stationManager->IsLastFragment (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ m_currentPacket, m_fragmentNumber);
+}
+
+Ptr<Packet>
+EdcaTxopN::GetFragmentPacket (WifiMacHeader *hdr)
+{
+ NS_LOG_FUNCTION (this << hdr);
+ *hdr = m_currentHdr;
+ hdr->SetFragmentNumber (m_fragmentNumber);
+ uint32_t startOffset = GetFragmentOffset ();
+ Ptr<Packet> fragment;
+ if (IsLastFragment ())
+ {
+ hdr->SetNoMoreFragments ();
+ }
+ else
+ {
+ hdr->SetMoreFragments ();
+ }
+ fragment = m_currentPacket->CreateFragment (startOffset,
+ GetFragmentSize ());
+ return fragment;
+}
+
+void
+EdcaTxopN::SetAccessCategory (enum AcIndex ac)
+{
+ NS_LOG_FUNCTION (this << static_cast<uint32_t> (ac));
+ m_ac = ac;
+}
+
+Mac48Address
+EdcaTxopN::MapSrcAddressForAggregation (const WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this << &hdr);
+ Mac48Address retval;
+ if (m_typeOfStation == STA || m_typeOfStation == ADHOC_STA)
+ {
+ retval = hdr.GetAddr2 ();
+ }
+ else
+ {
+ retval = hdr.GetAddr3 ();
+ }
+ return retval;
+}
+
+Mac48Address
+EdcaTxopN::MapDestAddressForAggregation (const WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this << &hdr);
+ Mac48Address retval;
+ if (m_typeOfStation == AP || m_typeOfStation == ADHOC_STA)
+ {
+ retval = hdr.GetAddr1 ();
+ }
+ else
+ {
+ retval = hdr.GetAddr3 ();
+ }
+ return retval;
+}
+
+void
+EdcaTxopN::SetMsduAggregator (Ptr<MsduAggregator> aggr)
+{
+ NS_LOG_FUNCTION (this << 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 ();
+ m_stationManager->PrepareForQueue (hdr.GetAddr1 (), &hdr,
+ packet, fullPacketSize);
+ m_queue->PushFront (packet, hdr);
+ StartAccessIfNeeded ();
+}
+
+void
+EdcaTxopN::GotAddBaResponse (const MgtAddBaResponseHeader *respHdr, Mac48Address recipient)
+{
+ NS_LOG_FUNCTION (this << respHdr << recipient);
+ NS_LOG_DEBUG ("received ADDBA response from " << recipient);
+ // std::cout<<"received ADDBA response from " << recipient<<"\n";
+ uint8_t tid = respHdr->GetTid ();
+ if (m_baManager->ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::PENDING))
+ {
+ if (respHdr->GetStatusCode ().IsSuccess ())
+ {
+ NS_LOG_DEBUG ("block ack agreement established with " << recipient);
+ m_baManager->UpdateAgreement (respHdr, recipient);
+ }
+ else
+ {
+ NS_LOG_DEBUG ("discard ADDBA response" << recipient);
+ m_baManager->NotifyAgreementUnsuccessful (recipient, tid);
+ }
+ }
+ RestartAccessIfNeeded ();
+}
+
+void
+EdcaTxopN::GotDelBaFrame (const MgtDelBaHeader *delBaHdr, Mac48Address recipient)
+{
+ NS_LOG_FUNCTION (this << delBaHdr << recipient);
+ NS_LOG_DEBUG ("received DELBA frame from=" << recipient);
+ m_baManager->TearDownBlockAck (recipient, delBaHdr->GetTid ());
+}
+
+void
+EdcaTxopN::GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, WifiMode txMode)
+{
+ NS_LOG_FUNCTION (this << blockAck << recipient);
+ NS_LOG_DEBUG ("got block ack from=" << recipient);
+ m_baManager->NotifyGotBlockAck (blockAck, recipient, txMode);
+ if (!m_txOkCallback.IsNull ())
+ {
+ m_txOkCallback (m_currentHdr);
+ }
+ 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_low->GetMpduAggregator () == 0))
+ {
+ m_currentHdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK);
+ }
+}
+
+bool EdcaTxopN::GetAmpduExist (void)
+{
+ return m_ampduExist;
+}
+
+void EdcaTxopN::SetAmpduExist (bool ampdu)
+{
+ m_ampduExist = ampdu;
+}
+
+void
+EdcaTxopN::CompleteTx (void)
+{
+ NS_LOG_FUNCTION (this);
+ 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 (),
+ m_txMiddle->GetNextSeqNumberByTidAndAddress (m_currentHdr.GetQosTid (),
+ m_currentHdr.GetAddr1 ()), WifiMacHeader::BLOCK_ACK);
+ }
+}
+
+void
+EdcaTxopN::CompleteMpduTx (Ptr<const Packet> packet, WifiMacHeader hdr, Time tstamp)
+{
+ NS_ASSERT (hdr.IsQosData ());
+ m_baManager->StorePacket (packet, hdr, tstamp);
+ m_baManager->NotifyMpduTransmission (hdr.GetAddr1 (), hdr.GetQosTid (),
+ m_txMiddle->GetNextSeqNumberByTidAndAddress (hdr.GetQosTid (),
+ hdr.GetAddr1 ()), WifiMacHeader::NORMAL_ACK);
+}
+
+bool
+EdcaTxopN::SetupBlockAckIfNeeded ()
+{
+ NS_LOG_FUNCTION (this);
+ 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 << &bar);
+ 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));
+ m_baManager->SetOriginatorBlockAckInactivityCallback (MakeCallback (&EdcaTxopN::cleanUpAggregateQueue, this));
+}
+
+/** clean up the aggregateQueue in mac low layer
+ */
+void
+EdcaTxopN::cleanUpAggregateQueue(Mac48Address addr, uint8_t tid, bool byOriginator)
+{
+ m_low->FlushAggregateQueue(addr);
+}
+
+void
+EdcaTxopN::SetBlockAckThreshold (uint8_t threshold)
+{
+ NS_LOG_FUNCTION (this << static_cast<uint32_t> (threshold));
+ m_blockAckThreshold = threshold;
+ m_baManager->SetBlockAckThreshold (threshold);
+}
+
+void
+EdcaTxopN::SetBlockAckInactivityTimeout (uint16_t timeout)
+{
+ NS_LOG_FUNCTION (this << timeout);
+ m_blockAckInactivityTimeout = timeout;
+}
+
+uint8_t
+EdcaTxopN::GetBlockAckThreshold (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_blockAckThreshold;
+}
+
+void
+EdcaTxopN::SendAddBaRequest (Mac48Address dest, uint8_t tid, uint16_t startSeq,
+ uint16_t timeout, bool immediateBAck)
+{
+ NS_LOG_FUNCTION (this << dest << static_cast<uint32_t> (tid) << startSeq << timeout << immediateBAck);
+ NS_LOG_DEBUG ("sent ADDBA request to " << dest);
+ // // std::cout<<"send ADDBA request to " << dest<<"\n";
+ 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)
+{
+ NS_LOG_FUNCTION (this << addr << static_cast<uint32_t> (tid) << byOriginator);
+
+ //destroy the agreement:
+ m_low->DestroyBlockAckAgreement (addr, tid);
+ 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);
+}
+
+int64_t
+EdcaTxopN::AssignStreams (int64_t stream)
+{
+ NS_LOG_FUNCTION (this << stream);
+ m_rng->AssignStreams (stream);
+ return 1;
+}
+
+void
+EdcaTxopN::DoInitialize ()
+{
+ NS_LOG_FUNCTION (this);
+ m_dcf->ResetCw ();
+ m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+ ns3::Dcf::DoInitialize ();
+}
+
+void
+EdcaTxopN::BaTxOk (const WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this << hdr);
+ if (!m_txOkCallback.IsNull ())
+ {
+ m_txOkCallback (m_currentHdr);
+ }
+}
+
+void
+EdcaTxopN::BaTxFailed (const WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this << hdr);
+ if (!m_txFailedCallback.IsNull ())
+ {
+ m_txFailedCallback (m_currentHdr);
+ }
+}
+
+} //namespace ns3
diff --git a/emu-radio/ns3-patch/wifi/model/edca-txop-n.h b/emu-radio/ns3-patch/wifi/model/edca-txop-n.h
new file mode 100644
index 00000000..8d038c19
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/edca-txop-n.h
@@ -0,0 +1,570 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006, 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
+ *
+ * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Mirko Banchi <mk.banchi@gmail.com>
+ */
+#ifndef EDCA_TXOP_N_H
+#define EDCA_TXOP_N_H
+
+#include "ns3/object.h"
+#include "ns3/mac48-address.h"
+#include "ns3/packet.h"
+#include "wifi-mode.h"
+#include "wifi-mac-header.h"
+#include "wifi-remote-station-manager.h"
+#include "qos-utils.h"
+#include "dcf.h"
+#include "ctrl-headers.h"
+#include "block-ack-manager.h"
+#include <map>
+#include <list>
+
+
+#define WITH_FIX_TO_BLOCK_ACK_TIMEOUT 1
+
+namespace ns3 {
+
+class DcfState;
+class DcfManager;
+class MacLow;
+class MacTxMiddle;
+class WifiMac;
+class WifiMacParameters;
+class WifiMacQueue;
+class RandomStream;
+class QosBlockedDestinations;
+class MsduAggregator;
+class MgtAddBaResponseHeader;
+class BlockAckManager;
+class MgtDelBaHeader;
+
+/**
+ * Enumeration for type of station
+ */
+enum TypeOfStation
+{
+ STA,
+ AP,
+ ADHOC_STA,
+ MESH,
+ HT_STA,
+ HT_AP,
+ HT_ADHOC_STA,
+ OCB
+};
+
+
+/**
+ * \ingroup wifi
+ * This queue contains packets for a particular access class.
+ * possibles access classes are:
+ *
+ * -AC_VO : voice, tid = 6,7 ^
+ * -AC_VI : video, tid = 4,5 |
+ * -AC_BE : best-effort, tid = 0,3 | priority
+ * -AC_BK : background, tid = 1,2 |
+ *
+ * For more details see section 9.1.3.1 in 802.11 standard.
+ */
+class EdcaTxopN : public Dcf
+{
+public:
+ /**
+ * typedef for a callback to invoke when a
+ * packet transmission was completed successfully.
+ */
+ typedef Callback <void, const WifiMacHeader&> TxOk;
+ /**
+ * typedef for a callback to invoke when a
+ * packet transmission was failed.
+ */
+ typedef Callback <void, const WifiMacHeader&> TxFailed;
+
+ static TypeId GetTypeId (void);
+ EdcaTxopN ();
+ virtual ~EdcaTxopN ();
+ void DoDispose ();
+
+ /**
+ * Set MacLow associated with this EdcaTxopN.
+ *
+ * \param low MacLow
+ */
+ void SetLow (Ptr<MacLow> low);
+ void SetTxMiddle (MacTxMiddle *txMiddle);
+ /**
+ * Set DcfManager this EdcaTxopN is associated to.
+ *
+ * \param manager DcfManager
+ */
+ void SetManager (DcfManager *manager);
+ /**
+ * \param callback the callback to invoke when a
+ * packet transmission was completed successfully.
+ */
+ void SetTxOkCallback (TxOk callback);
+ /**
+ * \param callback the callback to invoke when a
+ * packet transmission was completed unsuccessfully.
+ */
+ void SetTxFailedCallback (TxFailed callback);
+ /**
+ * Set WifiRemoteStationsManager this EdcaTxopN is associated to.
+ *
+ * \param remoteManager WifiRemoteStationManager
+ */
+ void SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> remoteManager);
+ /**
+ * Set type of station with the given type.
+ *
+ * \param type
+ */
+ void SetTypeOfStation (enum TypeOfStation type);
+ /**
+ * Return type of station.
+ *
+ * \return type of station
+ */
+ enum TypeOfStation GetTypeOfStation (void) const;
+ /**
+ * Return the packet queue associated with this EdcaTxopN.
+ *
+ * \return WifiMacQueue
+ */
+ Ptr<WifiMacQueue > GetEdcaQueue () const;
+
+ virtual void SetMinCw (uint32_t minCw);
+ virtual void SetMaxCw (uint32_t maxCw);
+ virtual void SetAifsn (uint32_t aifsn);
+ virtual uint32_t GetMinCw (void) const;
+ virtual uint32_t GetMaxCw (void) const;
+ virtual uint32_t GetAifsn (void) const;
+
+ /**
+ * Return the MacLow associated with this EdcaTxopN.
+ *
+ * \return MacLow
+ */
+ Ptr<MacLow> Low (void);
+
+ Ptr<MsduAggregator> GetMsduAggregator (void) const;
+ /**
+ * \param recipient address of the peer station
+ * \param tid traffic ID.
+ * \return true if a block ack agreement exists, false otherwise
+ *
+ * Checks if a block ack agreement exists with station addressed by
+ * <i>recipient</i> for tid <i>tid</i>.
+ */
+ bool GetBaAgreementExists (Mac48Address address, uint8_t tid);
+ /**
+ * \param recipient address of peer station involved in block ack mechanism.
+ * \param tid traffic ID.
+ * \return the number of packets buffered for a specified agreement
+ *
+ * Returns number of packets buffered for a specified agreement.
+ */
+ uint32_t GetNOutstandingPacketsInBa (Mac48Address address, uint8_t tid);
+ /**
+ * \param recipient address of peer station involved in block ack mechanism.
+ * \param tid traffic ID.
+ * \return the number of packets for a specific agreement that need retransmission
+ *
+ * Returns number of packets for a specific agreement that need retransmission.
+ */
+ uint32_t GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const;
+ /**
+ * \param recipient address of peer station involved in block ack mechanism.
+ * \param tid Ttraffic ID of transmitted packet.
+ *
+ * This function resets the status of OriginatorBlockAckAgreement after the transfer
+ * of an A-MPDU with ImmediateBlockAck policy (i.e. no BAR is scheduled)
+ */
+ void CompleteAmpduTransfer (Mac48Address recipient, uint8_t tid);
+
+ /* dcf notifications forwarded here */
+ /**
+ * Check if the EDCAF requires access.
+ *
+ * \return true if the EDCAF requires access,
+ * false otherwise
+ */
+ bool NeedsAccess (void) const;
+ /**
+ * Notify the EDCAF that access has been granted.
+ */
+ void NotifyAccessGranted (void);
+ /**
+ * Notify the EDCAF that internal collision has occurred.
+ */
+ void NotifyInternalCollision (void);
+ /**
+ * Notify the EDCAF that collision has occurred.
+ */
+ void NotifyCollision (void);
+ /**
+ * When a channel switching occurs, enqueued packets are removed.
+ */
+ void NotifyChannelSwitching (void);
+ /**
+ * When sleep operation occurs, re-insert pending packet into front of the queue
+ */
+ void NotifySleep (void);
+ /**
+ * When wake up operation occurs, restart channel access
+ */
+ void NotifyWakeUp (void);
+
+ /* Event handlers */
+ /**
+ * Event handler when a CTS is received.
+ *
+ * \param snr
+ * \param txMode
+ */
+ void GotCts (double snr, WifiMode txMode);
+ /**
+ * Event handler when a CTS timeout has occurred.
+ */
+ void MissedCts (void);
+ /**
+ * Event handler when an ACK is received.
+ *
+ * \param snr
+ * \param txMode
+ */
+ void GotAck (double snr, WifiMode txMode);
+ /**
+ * Event handler when a Block ACK is received.
+ *
+ * \param blockAck
+ * \param recipient
+ * \param txMode
+ */
+ void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, WifiMode txMode);
+ /**
+ * Event handler when a Block ACK timeout has occurred.
+ */
+ void MissedBlockAck (void);
+ void GotAddBaResponse (const MgtAddBaResponseHeader *respHdr, Mac48Address recipient);
+ void GotDelBaFrame (const MgtDelBaHeader *delBaHdr, Mac48Address recipient);
+ /**
+ * Event handler when an ACK is received.
+ */
+ void MissedAck (void);
+ /**
+ * Start transmission for the next fragment.
+ * This is called for fragment only.
+ */
+ void StartNext (void);
+ /**
+ * Cancel the transmission.
+ */
+ void Cancel (void);
+ /**
+ * Event handler when a transmission that
+ * does not require an ACK has completed.
+ */
+ void EndTxNoAck (void);
+ /**
+ * Restart access request if needed.
+ */
+ void RestartAccessIfNeeded (void);
+ /**
+ * Request access from DCF manager if needed.
+ */
+ void StartAccessIfNeeded (void);
+ /**
+ * Check if the current packet should be sent with a RTS protection.
+ *
+ * \return true if RTS protection should be used,
+ * false otherwise
+ */
+ bool NeedRts (void);
+ /**
+ * Check if RTS should be re-transmitted if CTS was missed.
+ *
+ * \return true if RTS should be re-transmitted,
+ * false otherwise
+ */
+ bool NeedRtsRetransmission (void);
+ /**
+ * Check if DATA should be re-transmitted if ACK was missed.
+ *
+ * \return true if DATA should be re-transmitted,
+ * false otherwise
+ */
+ bool NeedDataRetransmission (void);
+ /**
+ * Check if Block ACK Request should be re-transmitted.
+ *
+ * \return true if BAR should be re-transmitted,
+ * false otherwise
+ */
+ bool NeedBarRetransmission (void);
+ /**
+ * Check if the current packet should be fragmented.
+ *
+ * \return true if the current packet should be fragmented,
+ * false otherwise
+ */
+ bool NeedFragmentation (void) const;
+ /**
+ * Calculate the size of the next fragment.
+ *
+ * \return the size of the next fragment
+ */
+ uint32_t GetNextFragmentSize (void);
+ /**
+ * Calculate the size of the current fragment.
+ *
+ * \return the size of the current fragment
+ */
+ uint32_t GetFragmentSize (void);
+ /**
+ * Calculate the offset for the current fragment.
+ *
+ * \return the offset for the current fragment
+ */
+ uint32_t GetFragmentOffset (void);
+ /**
+ * Check if the current fragment is the last fragment.
+ *
+ * \return true if the current fragment is the last fragment,
+ * false otherwise
+ */
+ bool IsLastFragment (void) const;
+ /**
+ * Continue to the next fragment. This method simply
+ * increments the internal variable that keep track
+ * of the current fragment number.
+ */
+ void NextFragment (void);
+ /**
+ * Get the next fragment from the packet with
+ * appropriate Wifi header for the fragment.
+ *
+ * \param hdr
+ * \return the fragment with the current fragment number
+ */
+ Ptr<Packet> GetFragmentPacket (WifiMacHeader *hdr);
+
+ /**
+ * Set the access category of this EDCAF.
+ *
+ * \param ac
+ */
+ void SetAccessCategory (enum AcIndex ac);
+
+ /**
+ * \param packet packet to send
+ * \param hdr header of packet to send.
+ *
+ * Store the packet in the internal queue until it
+ * can be sent safely.
+ */
+ void Queue (Ptr<const Packet> packet, const WifiMacHeader &hdr);
+
+ void SetMsduAggregator (Ptr<MsduAggregator> aggr);
+
+ /**
+ * \param packet packet to send
+ * \param hdr header of packet to send.
+ *
+ * Store the packet in the front of the internal queue until it
+ * can be sent safely.
+ */
+ void PushFront (Ptr<const Packet> packet, const WifiMacHeader &hdr);
+
+ /**
+ * Complete block ACK configuration.
+ */
+ void CompleteConfig (void);
+
+ /**
+ * Set threshold for block ACK mechanism. If number of packets in the
+ * queue reaches the threshold, block ACK mechanism is used.
+ *
+ * \param threshold
+ */
+ void SetBlockAckThreshold (uint8_t threshold);
+ /**
+ * Return the current threshold for block ACK mechanism.
+ *
+ * \return the current threshold for block ACK mechanism
+ */
+ uint8_t GetBlockAckThreshold (void) const;
+
+ void SetBlockAckInactivityTimeout (uint16_t timeout);
+ void SendDelbaFrame (Mac48Address addr, uint8_t tid, bool byOriginator);
+ void CompleteMpduTx (Ptr<const Packet> packet, WifiMacHeader hdr, Time tstamp);
+ bool GetAmpduExist (void);
+ void SetAmpduExist (bool ampdu);
+
+ /**
+ * Return the next sequence number for the given header.
+ *
+ * \param hdr Wi-Fi header
+ *
+ * \return the next sequence number
+ */
+ uint16_t GetNextSequenceNumberfor (WifiMacHeader *hdr);
+ /**
+ * Return the next sequence number for the Traffic ID and destination, but do not pick it (i.e. the current sequence number remains unchanged).
+ *
+ * \param hdr Wi-Fi header
+ *
+ * \return the next sequence number
+ */
+ uint16_t PeekNextSequenceNumberfor (WifiMacHeader *hdr);
+ /**
+ * Remove a packet after you peek in the retransmit queue and get it
+ */
+ void RemoveRetransmitPacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber);
+ /*
+ * Peek in retransmit queue and get the next packet without removing it from the queue
+ */
+ Ptr<const Packet> PeekNextRetransmitPacket (WifiMacHeader &header, Mac48Address recipient, uint8_t tid, Time *timestamp);
+ /**
+ * The packet we sent was successfully received by the receiver
+ *
+ * \param hdr the header of the packet that we successfully sent
+ */
+ void BaTxOk (const WifiMacHeader &hdr);
+ /**
+ * The packet we sent was successfully received by the receiver
+ *
+ * \param hdr the header of the packet that we failed to sent
+ */
+ void BaTxFailed (const WifiMacHeader &hdr);
+
+ /**
+ * Assign a fixed random variable stream number to the random variables
+ * used by this model. Return the number of streams (possibly zero) that
+ * have been assigned.
+ *
+ * \param stream first stream index to use
+ * \return the number of stream indices assigned by this model
+ */
+ int64_t AssignStreams (int64_t stream);
+
+
+private:
+ void DoInitialize ();
+ /**
+ * This functions are used only to correctly set addresses in a-msdu subframe.
+ * If aggregating sta is a STA (in an infrastructured network):
+ * SA = Address2
+ * DA = Address3
+ * If aggregating sta is an AP
+ * SA = Address3
+ * DA = Address1
+ *
+ * \param hdr
+ * \return Mac48Address
+ */
+ Mac48Address MapSrcAddressForAggregation (const WifiMacHeader &hdr);
+ Mac48Address MapDestAddressForAggregation (const WifiMacHeader &hdr);
+ EdcaTxopN &operator = (const EdcaTxopN &);
+ EdcaTxopN (const EdcaTxopN &);
+
+ /**
+ * If number of packets in the queue reaches m_blockAckThreshold value, an ADDBA Request frame
+ * is sent to destination in order to setup a block ack.
+ *
+ * \return true if we tried to set up block ACK, false otherwise
+ */
+ bool SetupBlockAckIfNeeded ();
+ /**
+ * Sends an ADDBA Request to establish a block ack agreement with sta
+ * addressed by <i>recipient</i> for tid <i>tid</i>.
+ *
+ * \param recipient
+ * \param tid
+ * \param startSeq
+ * \param timeout
+ * \param immediateBAck
+ */
+ 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.
+ *
+ * \param bar
+ */
+ 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);
+
+ AcIndex m_ac;
+ class Dcf;
+ class TransmissionListener;
+ class AggregationCapableTransmissionListener;
+ friend class Dcf;
+ friend class TransmissionListener;
+ Dcf *m_dcf;
+ DcfManager *m_manager;
+ Ptr<WifiMacQueue> m_queue;
+ TxOk m_txOkCallback;
+ TxFailed m_txFailedCallback;
+ Ptr<MacLow> m_low;
+ MacTxMiddle *m_txMiddle;
+ TransmissionListener *m_transmissionListener;
+ AggregationCapableTransmissionListener *m_blockAckListener;
+ RandomStream *m_rng;
+ Ptr<WifiRemoteStationManager> m_stationManager;
+ uint8_t m_fragmentNumber;
+
+ /* current packet could be a simple MSDU or, if an aggregator for this queue is
+ present, could be an A-MSDU.
+ */
+ Ptr<const Packet> m_currentPacket;
+
+ WifiMacHeader m_currentHdr;
+ Ptr<MsduAggregator> m_aggregator;
+ TypeOfStation m_typeOfStation;
+ QosBlockedDestinations *m_qosBlockedDestinations;
+ BlockAckManager *m_baManager;
+ /*
+ * Represents the minimum number of packets for use of block ack.
+ */
+ uint8_t m_blockAckThreshold;
+ enum BlockAckType m_blockAckType;
+ Time m_currentPacketTimestamp;
+ uint16_t m_blockAckInactivityTimeout;
+ struct Bar m_currentBar;
+ bool m_ampduExist;
+
+
+ //added
+ void cleanUpAggregateQueue(Mac48Address addr, uint8_t tid, bool byOriginator);
+};
+
+} //namespace ns3
+
+#endif /* EDCA_TXOP_N_H */
diff --git a/emu-radio/ns3-patch/wifi/model/mac-low.cc b/emu-radio/ns3-patch/wifi/model/mac-low.cc
new file mode 100644
index 00000000..aa86bad2
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/mac-low.cc
@@ -0,0 +1,3347 @@
+/* -*- 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
+ * 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
+ *
+ * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Mirko Banchi <mk.banchi@gmail.com>
+ */
+
+#include "ns3/assert.h"
+#include "ns3/packet.h"
+#include "ns3/simulator.h"
+#include "ns3/tag.h"
+#include "ns3/log.h"
+#include "ns3/node.h"
+#include "ns3/double.h"
+#include "mac-low.h"
+#include "wifi-phy.h"
+#include "wifi-mac-trailer.h"
+#include "qos-utils.h"
+#include "edca-txop-n.h"
+#include "snr-tag.h"
+#include "yans-wifi-phy.h"
+#include "ampdu-tag.h"
+#include "wifi-mac-queue.h"
+#include "mpdu-standard-aggregator.h"
+
+#undef NS_LOG_APPEND_CONTEXT
+#define NS_LOG_APPEND_CONTEXT std::clog << "[mac=" << m_self << "] "
+
+#define WITH_FIX_RECEIVE_BAR_BEFORE_CTS_TIMEOUT 1
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("MacLow");
+
+MacLowTransmissionListener::MacLowTransmissionListener ()
+{
+}
+MacLowTransmissionListener::~MacLowTransmissionListener ()
+{
+}
+void
+MacLowTransmissionListener::GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source, WifiMode mode)
+{
+}
+void
+MacLowTransmissionListener::MissedBlockAck (void)
+{
+}
+
+MacLowDcfListener::MacLowDcfListener ()
+{
+}
+MacLowDcfListener::~MacLowDcfListener ()
+{
+}
+
+MacLowAggregationCapableTransmissionListener::MacLowAggregationCapableTransmissionListener ()
+{
+}
+MacLowAggregationCapableTransmissionListener::~MacLowAggregationCapableTransmissionListener ()
+{
+}
+void MacLowAggregationCapableTransmissionListener::SetAmpdu (bool ampdu)
+{
+}
+void MacLowAggregationCapableTransmissionListener::CompleteTransfer (Mac48Address address, uint8_t tid)
+{
+}
+void
+MacLowAggregationCapableTransmissionListener::CompleteMpduTx (Ptr<const Packet> packet, WifiMacHeader hdr, Time tstamp)
+{
+}
+uint16_t
+MacLowAggregationCapableTransmissionListener::GetNextSequenceNumberfor (WifiMacHeader *hdr)
+{
+ return 0;
+}
+uint16_t
+MacLowAggregationCapableTransmissionListener::PeekNextSequenceNumberfor (WifiMacHeader *hdr)
+{
+ return 0;
+}
+Ptr<const Packet>
+MacLowAggregationCapableTransmissionListener::PeekNextPacketInBaQueue (WifiMacHeader &header, Mac48Address recipient, uint8_t tid, Time *timestamp)
+{
+ return 0;
+}
+void
+MacLowAggregationCapableTransmissionListener::RemoveFromBaQueue (uint8_t tid, Mac48Address recipient, uint16_t seqnumber)
+{
+}
+uint32_t
+MacLowAggregationCapableTransmissionListener::GetNOutstandingPackets (Mac48Address recipient, uint8_t tid)
+{
+ return 0;
+}
+uint32_t
+MacLowAggregationCapableTransmissionListener::GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const
+{
+ return 0;
+}
+Ptr<MsduAggregator>
+MacLowAggregationCapableTransmissionListener::GetMsduAggregator (void) const
+{
+ return 0;
+}
+Mac48Address
+MacLowAggregationCapableTransmissionListener::GetSrcAddressForAggregation (const WifiMacHeader &hdr)
+{
+ return 0;
+}
+Mac48Address
+MacLowAggregationCapableTransmissionListener::GetDestAddressForAggregation (const WifiMacHeader &hdr)
+{
+ return 0;
+}
+
+MacLowTransmissionParameters::MacLowTransmissionParameters ()
+ : m_nextSize (0),
+ m_waitAck (ACK_NONE),
+ m_sendRts (false),
+ m_overrideDurationId (Seconds (0))
+{
+}
+void
+MacLowTransmissionParameters::EnableNextData (uint32_t size)
+{
+ m_nextSize = size;
+}
+void
+MacLowTransmissionParameters::DisableNextData (void)
+{
+ m_nextSize = 0;
+}
+void
+MacLowTransmissionParameters::EnableOverrideDurationId (Time durationId)
+{
+ m_overrideDurationId = durationId;
+}
+void
+MacLowTransmissionParameters::DisableOverrideDurationId (void)
+{
+ m_overrideDurationId = Seconds (0);
+}
+void
+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)
+{
+ m_waitAck = ACK_FAST;
+}
+void
+MacLowTransmissionParameters::EnableAck (void)
+{
+ m_waitAck = ACK_NORMAL;
+}
+void
+MacLowTransmissionParameters::DisableAck (void)
+{
+ m_waitAck = ACK_NONE;
+}
+void
+MacLowTransmissionParameters::EnableRts (void)
+{
+ m_sendRts = true;
+}
+void
+MacLowTransmissionParameters::DisableRts (void)
+{
+ m_sendRts = false;
+}
+bool
+MacLowTransmissionParameters::MustWaitAck (void) const
+{
+ return (m_waitAck != ACK_NONE);
+}
+bool
+MacLowTransmissionParameters::MustWaitNormalAck (void) const
+{
+ return (m_waitAck == ACK_NORMAL);
+}
+bool
+MacLowTransmissionParameters::MustWaitFastAck (void) const
+{
+ return (m_waitAck == ACK_FAST);
+}
+bool
+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
+{
+ return m_sendRts;
+}
+bool
+MacLowTransmissionParameters::HasDurationId (void) const
+{
+ return (m_overrideDurationId != Seconds (0));
+}
+Time
+MacLowTransmissionParameters::GetDurationId (void) const
+{
+ NS_ASSERT (m_overrideDurationId != Seconds (0));
+ return m_overrideDurationId;
+}
+bool
+MacLowTransmissionParameters::HasNextPacket (void) const
+{
+ return (m_nextSize != 0);
+}
+uint32_t
+MacLowTransmissionParameters::GetNextPacketSize (void) const
+{
+ NS_ASSERT (HasNextPacket ());
+ return m_nextSize;
+}
+
+std::ostream &operator << (std::ostream &os, const MacLowTransmissionParameters &params)
+{
+ os << "["
+ << "send rts=" << params.m_sendRts << ", "
+ << "next size=" << params.m_nextSize << ", "
+ << "dur=" << params.m_overrideDurationId << ", "
+ << "ack=";
+ switch (params.m_waitAck)
+ {
+ case MacLowTransmissionParameters::ACK_NONE:
+ os << "none";
+ break;
+ case MacLowTransmissionParameters::ACK_NORMAL:
+ os << "normal";
+ break;
+ case MacLowTransmissionParameters::ACK_FAST:
+ os << "fast";
+ break;
+ 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;
+}
+
+
+/**
+ * Listener for PHY events. Forwards to MacLow
+ */
+class PhyMacLowListener : public ns3::WifiPhyListener
+{
+public:
+ /**
+ * Create a PhyMacLowListener for the given MacLow.
+ *
+ * \param macLow
+ */
+ PhyMacLowListener (ns3::MacLow *macLow)
+ : m_macLow (macLow)
+ {
+ }
+ virtual ~PhyMacLowListener ()
+ {
+ }
+ virtual void NotifyRxStart (Time duration)
+ {
+ }
+ virtual void NotifyRxEndOk (void)
+ {
+ }
+ virtual void NotifyRxEndError (void)
+ {
+ }
+ virtual void NotifyTxStart (Time duration, double txPowerDbm)
+ {
+ }
+ virtual void NotifyMaybeCcaBusyStart (Time duration)
+ {
+ }
+ virtual void NotifySwitchingStart (Time duration)
+ {
+ m_macLow->NotifySwitchingStartNow (duration);
+ }
+ virtual void NotifySleep (void)
+ {
+ m_macLow->NotifySleepNow ();
+ }
+ virtual void NotifyWakeup (void)
+ {
+ }
+private:
+ ns3::MacLow *m_macLow;
+};
+
+
+MacLow::MacLow ()
+ : m_normalAckTimeoutEvent (),
+ m_fastAckTimeoutEvent (),
+ m_superFastAckTimeoutEvent (),
+ m_fastAckFailedTimeoutEvent (),
+ m_blockAckTimeoutEvent (),
+ m_ctsTimeoutEvent (),
+ m_sendCtsEvent (),
+ m_sendAckEvent (),
+ m_sendDataEvent (),
+ m_waitSifsEvent (),
+ m_endTxNoAckEvent (),
+ m_mpduAggregator (0),
+ m_currentPacket (0),
+ m_listener (0),
+ m_phyMacLowListener (0),
+ m_ctsToSelfSupported (false),
+ m_receivedAtLeastOneMpdu (false),
+ m_mpduReferenceNumber (0)
+{
+ NS_LOG_FUNCTION (this);
+ m_lastNavDuration = Seconds (0);
+ m_lastNavStart = Seconds (0);
+ m_promisc = false;
+ m_ampdu = false;
+ m_sentMpdus = 0;
+ m_aggregateQueue = CreateObject<WifiMacQueue> ();
+}
+
+MacLow::~MacLow ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+/* static */
+TypeId
+MacLow::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::MacLow")
+ .SetParent<Object> ()
+ .SetGroupName ("Wifi")
+ .AddConstructor<MacLow> ()
+ ;
+ return tid;
+}
+
+void
+MacLow::SetupPhyMacLowListener (Ptr<WifiPhy> phy)
+{
+ m_phyMacLowListener = new PhyMacLowListener (this);
+ phy->RegisterListener (m_phyMacLowListener);
+}
+
+void
+MacLow::RemovePhyMacLowListener (Ptr<WifiPhy> phy)
+{
+ if (m_phyMacLowListener != 0 )
+ {
+ phy->UnregisterListener (m_phyMacLowListener);
+ delete m_phyMacLowListener;
+ m_phyMacLowListener = 0;
+ }
+}
+
+void
+MacLow::DoDispose (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_normalAckTimeoutEvent.Cancel ();
+ m_fastAckTimeoutEvent.Cancel ();
+ m_superFastAckTimeoutEvent.Cancel ();
+ m_fastAckFailedTimeoutEvent.Cancel ();
+ m_blockAckTimeoutEvent.Cancel ();
+ m_ctsTimeoutEvent.Cancel ();
+ m_sendCtsEvent.Cancel ();
+ m_sendAckEvent.Cancel ();
+ m_sendDataEvent.Cancel ();
+ m_waitSifsEvent.Cancel ();
+ m_endTxNoAckEvent.Cancel ();
+ m_waitRifsEvent.Cancel ();
+ m_phy = 0;
+ m_stationManager = 0;
+ if (m_phyMacLowListener != 0)
+ {
+ delete m_phyMacLowListener;
+ m_phyMacLowListener = 0;
+ }
+ m_mpduAggregator = 0;
+ m_sentMpdus = 0;
+ m_aggregateQueue = 0;
+ m_ampdu = false;
+}
+
+void
+MacLow::CancelAllEvents (void)
+{
+ NS_LOG_FUNCTION (this);
+ bool oneRunning = false;
+ if (m_normalAckTimeoutEvent.IsRunning ())
+ {
+ m_normalAckTimeoutEvent.Cancel ();
+ oneRunning = true;
+ }
+ if (m_fastAckTimeoutEvent.IsRunning ())
+ {
+ m_fastAckTimeoutEvent.Cancel ();
+ oneRunning = true;
+ }
+ if (m_superFastAckTimeoutEvent.IsRunning ())
+ {
+ m_superFastAckTimeoutEvent.Cancel ();
+ oneRunning = true;
+ }
+ if (m_fastAckFailedTimeoutEvent.IsRunning ())
+ {
+ m_fastAckFailedTimeoutEvent.Cancel ();
+ oneRunning = true;
+ }
+ if (m_blockAckTimeoutEvent.IsRunning ())
+ {
+ m_blockAckTimeoutEvent.Cancel ();
+ oneRunning = true;
+ }
+ if (m_ctsTimeoutEvent.IsRunning ())
+ {
+ m_ctsTimeoutEvent.Cancel ();
+ oneRunning = true;
+ }
+ if (m_sendCtsEvent.IsRunning ())
+ {
+ m_sendCtsEvent.Cancel ();
+ oneRunning = true;
+ }
+ if (m_sendAckEvent.IsRunning ())
+ {
+ m_sendAckEvent.Cancel ();
+ oneRunning = true;
+ }
+ if (m_sendDataEvent.IsRunning ())
+ {
+ m_sendDataEvent.Cancel ();
+ oneRunning = true;
+ }
+ if (m_waitSifsEvent.IsRunning ())
+ {
+ m_waitSifsEvent.Cancel ();
+ oneRunning = true;
+ }
+ if (m_waitRifsEvent.IsRunning ())
+ {
+ m_waitRifsEvent.Cancel ();
+ oneRunning = true;
+ }
+ if (m_endTxNoAckEvent.IsRunning ())
+ {
+ m_endTxNoAckEvent.Cancel ();
+ oneRunning = true;
+ }
+ if (oneRunning && m_listener != 0)
+ {
+ m_listener->Cancel ();
+ m_listener = 0;
+ }
+}
+
+void
+MacLow::SetPhy (Ptr<WifiPhy> phy)
+{
+ m_phy = phy;
+ m_phy->SetReceiveOkCallback (MakeCallback (&MacLow::DeaggregateAmpduAndReceive, this));
+ m_phy->SetReceiveErrorCallback (MakeCallback (&MacLow::ReceiveError, this));
+ SetupPhyMacLowListener (phy);
+}
+
+Ptr<WifiPhy>
+MacLow::GetPhy (void) const
+{
+ return m_phy;
+}
+
+void
+MacLow::ResetPhy (void)
+{
+ m_phy->SetReceiveOkCallback (MakeNullCallback<void, Ptr<Packet>, double, WifiTxVector, enum WifiPreamble> ());
+ m_phy->SetReceiveErrorCallback (MakeNullCallback<void, Ptr<const Packet>, double> ());
+ RemovePhyMacLowListener (m_phy);
+ m_phy = 0;
+}
+
+void
+MacLow::SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> manager)
+{
+ m_stationManager = manager;
+}
+
+void
+MacLow::SetAddress (Mac48Address ad)
+{
+ m_self = ad;
+}
+
+void
+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::SetCtsToSelfSupported (bool enable)
+{
+ m_ctsToSelfSupported = enable;
+}
+
+bool
+MacLow::GetCtsToSelfSupported () const
+{
+ return m_ctsToSelfSupported;
+}
+
+void
+MacLow::SetCtsTimeout (Time ctsTimeout)
+{
+ m_ctsTimeout = ctsTimeout;
+}
+
+void
+MacLow::SetSifs (Time sifs)
+{
+ m_sifs = sifs;
+}
+
+void
+MacLow::SetSlotTime (Time slotTime)
+{
+ m_slotTime = slotTime;
+}
+
+void
+MacLow::SetPifs (Time pifs)
+{
+ m_pifs = pifs;
+}
+
+void
+MacLow::SetRifs (Time rifs)
+{
+ m_rifs = rifs;
+}
+
+void
+MacLow::SetBssid (Mac48Address bssid)
+{
+ m_bssid = bssid;
+}
+
+void
+MacLow::SetPromisc (void)
+{
+ m_promisc = true;
+}
+
+Mac48Address
+MacLow::GetAddress (void) const
+{
+ return m_self;
+}
+
+Time
+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
+{
+ return m_ctsTimeout;
+}
+
+Time
+MacLow::GetSifs (void) const
+{
+ return m_sifs;
+}
+
+Time
+MacLow::GetRifs (void) const
+{
+ return m_rifs;
+}
+
+Time
+MacLow::GetSlotTime (void) const
+{
+ return m_slotTime;
+}
+
+Time
+MacLow::GetPifs (void) const
+{
+ return m_pifs;
+}
+
+Mac48Address
+MacLow::GetBssid (void) const
+{
+ return m_bssid;
+}
+
+bool
+MacLow::IsPromisc (void) const
+{
+ return m_promisc;
+}
+
+void
+MacLow::SetRxCallback (Callback<void, Ptr<Packet>, const WifiMacHeader *> callback)
+{
+ m_rxCallback = callback;
+}
+
+void
+MacLow::RegisterDcfListener (MacLowDcfListener *listener)
+{
+ m_dcfListeners.push_back (listener);
+}
+
+bool
+MacLow::IsAmpdu (Ptr<const Packet> packet, const WifiMacHeader hdr)
+{
+ uint32_t size, actualSize;
+ WifiMacTrailer fcs;
+ size = packet->GetSize () + hdr.GetSize () + fcs.GetSerializedSize ();
+ Ptr<Packet> p = AggregateToAmpdu (packet, hdr);
+ actualSize = p->GetSize ();
+ if (actualSize > size)
+ {
+ m_currentPacket = p;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void
+MacLow::StartTransmission (Ptr<const Packet> packet,
+ const WifiMacHeader* hdr,
+ MacLowTransmissionParameters params,
+ MacLowTransmissionListener *listener)
+{
+ NS_LOG_FUNCTION (this << packet << hdr << params << listener);
+ /* m_currentPacket is not NULL because someone started
+ * a transmission and was interrupted before one of:
+ * - ctsTimeout
+ * - sendDataAfterCTS
+ * expired. This means that one of these timers is still
+ * running. They are all cancelled below anyway by the
+ * call to CancelAllEvents (because of at least one
+ * of these two timers) which will trigger a call to the
+ * previous listener's cancel method.
+ *
+ * This typically happens because the high-priority
+ * QapScheduler has taken access to the channel from
+ * one of the Edca of the QAP.
+ */
+ m_currentPacket = packet->Copy ();
+ m_currentHdr = *hdr;
+ CancelAllEvents ();
+ m_listener = listener;
+ m_txParams = params;
+
+ if (!m_currentHdr.IsQosData () && !m_currentHdr.IsBlockAck () && !m_currentHdr.IsBlockAckReq ())
+ {
+ //This is mainly encountered when a higher priority control frame (such as beacons)
+ //is sent between A-MPDU transmissions. It avoids to unexpectedly flush the aggregate
+ //queue when previous RTS request has failed.
+ m_ampdu = false;
+ }
+ else if (m_aggregateQueue->GetSize () > 0)
+ {
+ //m_aggregateQueue > 0 occurs when a RTS/CTS exchange failed before an A-MPDU transmission.
+ //In that case, we transmit the same A-MPDU as previously.
+ m_sentMpdus = m_aggregateQueue->GetSize ();
+ m_ampdu = true;
+ if (m_sentMpdus > 1)
+ {
+ m_txParams.EnableCompressedBlockAck ();
+ }
+ else if (m_currentHdr.IsQosData ())
+ {
+ //VHT single MPDUs are followed by normal ACKs
+ m_txParams.EnableAck ();
+ }
+ }
+ else
+ {
+ //Perform MPDU aggregation if possible
+ m_ampdu = IsAmpdu (m_currentPacket, m_currentHdr);
+ if (m_ampdu)
+ {
+ AmpduTag ampdu;
+ m_currentPacket->PeekPacketTag (ampdu);
+ if (ampdu.GetNoOfMpdus () > 1)
+ {
+ m_txParams.EnableCompressedBlockAck ();
+ }
+ else if (m_currentHdr.IsQosData ())
+ {
+ //VHT single MPDUs are followed by normal ACKs
+ m_txParams.EnableAck ();
+ }
+ }
+ }
+
+// if (NeedRts ())
+// {
+// m_txParams.EnableRts ();
+// }
+// else
+// {
+// m_txParams.DisableRts ();
+// }
+
+ NS_LOG_DEBUG ("startTx size=" << GetSize (m_currentPacket, &m_currentHdr) <<
+ ", to=" << m_currentHdr.GetAddr1 () << ", listener=" << m_listener);
+
+ if (m_txParams.MustSendRts ())
+ {
+ SendRtsForPacket ();
+ }
+ else
+ {
+ if (NeedCtsToSelf () && m_ctsToSelfSupported)
+ {
+ SendCtsToSelf ();
+ }
+ else
+ {
+ SendDataPacket ();
+ }
+ }
+
+ /* When this method completes, we have taken ownership of the medium. */
+ NS_ASSERT (m_phy->IsStateTx ());
+}
+
+bool
+MacLow::NeedRts (void)
+{
+ return m_stationManager->NeedRts (m_currentHdr.GetAddr1 (),
+ &m_currentHdr,
+ m_currentPacket);
+}
+
+bool
+MacLow::NeedCtsToSelf (void)
+{
+ WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr);
+ return m_stationManager->NeedCtsToSelf (dataTxVector);
+}
+
+void
+MacLow::ReceiveError (Ptr<const Packet> packet, double rxSnr)
+{
+ NS_LOG_FUNCTION (this << packet << rxSnr);
+ NS_LOG_DEBUG ("rx failed ");
+ AmpduTag ampdu;
+ Ptr<Packet> pkt = packet->Copy ();
+ bool isInAmpdu = pkt->RemovePacketTag (ampdu);
+
+ if (isInAmpdu && m_receivedAtLeastOneMpdu && (ampdu.GetNoOfMpdus () == 1))
+ {
+ MpduAggregator::DeaggregatedMpdus packets = MpduAggregator::Deaggregate (pkt);
+ MpduAggregator::DeaggregatedMpdusCI n = packets.begin ();
+ WifiMacHeader hdr;
+ (*n).first->PeekHeader (hdr);
+#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW
+ //further check if last mpdu is received from the same source
+ if(m_lastmpduFrom==hdr.GetAddr2())
+ {
+#endif
+ if (hdr.IsQosData ())
+ {
+ uint8_t tid = hdr.GetQosTid ();
+ AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), tid));
+ if (it != m_bAckAgreements.end ())
+ {
+#ifndef WITHOUT_BA_RESPONSE_WHEN_LAST_AMPDU_FAIL
+ NS_LOG_DEBUG ("last a-mpdu subframe detected/sendImmediateBlockAck from=" << hdr.GetAddr2 ());
+ m_sendAckEvent = Simulator::Schedule (GetSifs (),
+ &MacLow::SendBlockAckAfterAmpdu, this,
+ hdr.GetQosTid (),
+ hdr.GetAddr2 (),
+ hdr.GetDuration (),
+ m_currentTxVector);
+#endif
+ m_receivedAtLeastOneMpdu = false;
+ }
+ }
+ else if (hdr.IsBlockAckReq ())
+ {
+ NS_LOG_DEBUG ("last a-mpdu subframe is BAR");
+ m_receivedAtLeastOneMpdu = false;
+ }
+#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW
+ }
+#endif
+ }
+ else if (m_txParams.MustWaitFastAck ())
+ {
+ NS_ASSERT (m_fastAckFailedTimeoutEvent.IsExpired ());
+ m_fastAckFailedTimeoutEvent = Simulator::Schedule (GetSifs (),
+ &MacLow::FastAckFailedTimeout, this);
+ }
+ return;
+}
+
+void
+MacLow::NotifySwitchingStartNow (Time duration)
+{
+ NS_LOG_DEBUG ("switching channel. Cancelling MAC pending events");
+ m_stationManager->Reset ();
+ CancelAllEvents ();
+ if (m_navCounterResetCtsMissed.IsRunning ())
+ {
+ m_navCounterResetCtsMissed.Cancel ();
+ }
+ m_lastNavStart = Simulator::Now ();
+ m_lastNavDuration = Seconds (0);
+ m_currentPacket = 0;
+ m_listener = 0;
+}
+
+void
+MacLow::NotifySleepNow (void)
+{
+ NS_LOG_DEBUG ("Device in sleep mode. Cancelling MAC pending events");
+ CancelAllEvents ();
+ if (m_navCounterResetCtsMissed.IsRunning ())
+ {
+ m_navCounterResetCtsMissed.Cancel ();
+ }
+ m_lastNavStart = Simulator::Now ();
+ m_lastNavDuration = Seconds (0);
+ m_currentPacket = 0;
+ m_listener = 0;
+}
+
+void
+MacLow::ReceiveOk (Ptr<Packet> packet, double rxSnr, WifiTxVector txVector, WifiPreamble preamble, bool ampduSubframe)
+{
+ NS_LOG_FUNCTION (this << packet << rxSnr << txVector.GetMode () << preamble);
+ /* A packet is received from the PHY.
+ * When we have handled this packet,
+ * we handle any packet present in the
+ * packet queue.
+ */
+ WifiMacHeader hdr;
+ packet->RemoveHeader (hdr);
+
+ bool isPrevNavZero = IsNavZero ();
+ NS_LOG_DEBUG ("duration/id=" << hdr.GetDuration ());
+ NotifyNav (packet, hdr, preamble);
+ if (hdr.IsRts ())
+ {
+ /* see section 9.2.5.7 802.11-1999
+ * A STA that is addressed by an RTS frame shall transmit a CTS frame after a SIFS
+ * period if the NAV at the STA receiving the RTS frame indicates that the medium is
+ * idle. If the NAV at the STA receiving the RTS indicates the medium is not idle,
+ * that STA shall not respond to the RTS frame.
+ */
+ if (ampduSubframe)
+ {
+ NS_FATAL_ERROR ("Received RTS as part of an A-MPDU");
+ }
+ else
+ {
+ if (isPrevNavZero
+ && hdr.GetAddr1 () == m_self)
+ {
+ NS_LOG_DEBUG ("rx RTS from=" << hdr.GetAddr2 () << ", schedule CTS");
+ NS_ASSERT (m_sendCtsEvent.IsExpired ());
+ m_stationManager->ReportRxOk (hdr.GetAddr2 (), &hdr,
+ rxSnr, txVector.GetMode ());
+ m_sendCtsEvent = Simulator::Schedule (GetSifs (),
+ &MacLow::SendCtsAfterRts, this,
+ hdr.GetAddr2 (),
+ hdr.GetDuration (),
+ txVector,
+ rxSnr);
+ }
+ else
+ {
+ NS_LOG_DEBUG ("rx RTS from=" << hdr.GetAddr2 () << ", cannot schedule CTS");
+ }
+ }
+ }
+ else if (hdr.IsCts ()
+ && hdr.GetAddr1 () == m_self
+ && m_ctsTimeoutEvent.IsRunning ()
+ && m_currentPacket != 0)
+ {
+ if (ampduSubframe)
+ {
+ NS_FATAL_ERROR ("Received CTS as part of an A-MPDU");
+ }
+
+ NS_LOG_DEBUG ("receive cts from=" << m_currentHdr.GetAddr1 ());
+
+ SnrTag tag;
+ packet->RemovePacketTag (tag);
+ m_stationManager->ReportRxOk (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ rxSnr, txVector.GetMode ());
+ m_stationManager->ReportRtsOk (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ rxSnr, txVector.GetMode (), tag.Get ());
+
+ m_ctsTimeoutEvent.Cancel ();
+ NotifyCtsTimeoutResetNow ();
+ m_listener->GotCts (rxSnr, txVector.GetMode ());
+ NS_ASSERT (m_sendDataEvent.IsExpired ());
+ m_sendDataEvent = Simulator::Schedule (GetSifs (),
+ &MacLow::SendDataAfterCts, this,
+ hdr.GetAddr1 (),
+ hdr.GetDuration ());
+ }
+ else if (hdr.IsAck ()
+ && hdr.GetAddr1 () == m_self
+ && (m_normalAckTimeoutEvent.IsRunning ()
+ || m_fastAckTimeoutEvent.IsRunning ()
+ || m_superFastAckTimeoutEvent.IsRunning ())
+ && m_txParams.MustWaitAck ())
+ {
+ NS_LOG_DEBUG ("receive ack from=" << m_currentHdr.GetAddr1 ());
+ SnrTag tag;
+ packet->RemovePacketTag (tag);
+ m_stationManager->ReportRxOk (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ rxSnr, txVector.GetMode ());
+ m_stationManager->ReportDataOk (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ rxSnr, txVector.GetMode (), tag.Get ());
+
+ FlushAggregateQueue ();
+ m_ampdu = false;
+ bool gotAck = false;
+
+ if (m_txParams.MustWaitNormalAck ()
+ && m_normalAckTimeoutEvent.IsRunning ())
+ {
+ m_normalAckTimeoutEvent.Cancel ();
+ NotifyAckTimeoutResetNow ();
+ gotAck = true;
+ }
+ if (m_txParams.MustWaitFastAck ()
+ && m_fastAckTimeoutEvent.IsRunning ())
+ {
+ m_fastAckTimeoutEvent.Cancel ();
+ NotifyAckTimeoutResetNow ();
+ gotAck = true;
+ }
+ if (gotAck)
+ {
+ m_listener->GotAck (rxSnr, txVector.GetMode ());
+ }
+ if (m_txParams.HasNextPacket ())
+ {
+ m_waitSifsEvent = Simulator::Schedule (GetSifs (),
+ &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 ();
+ NotifyAckTimeoutResetNow ();
+ m_listener->GotBlockAck (&blockAck, hdr.GetAddr2 (), txVector.GetMode ());
+ m_sentMpdus = 0;
+ m_ampdu = false;
+ FlushAggregateQueue ();
+ }
+ else if (hdr.IsBlockAckReq () && hdr.GetAddr1 () == m_self)
+ {
+#ifdef WITH_FIX_RECEIVE_BAR_BEFORE_CTS_TIMEOUT
+ if(m_ctsTimeoutEvent.IsRunning())
+ return;
+#endif
+ CtrlBAckRequestHeader blockAckReq;
+ packet->RemoveHeader (blockAckReq);
+ if (!blockAckReq.IsMultiTid ())
+ {
+ uint8_t tid = blockAckReq.GetTidInfo ();
+ AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), tid));
+ if (it != m_bAckAgreements.end ())
+ {
+ //Update block ack cache
+ BlockAckCachesI i = m_bAckCaches.find (std::make_pair (hdr.GetAddr2 (), tid));
+ NS_ASSERT (i != m_bAckCaches.end ());
+ (*i).second.UpdateWithBlockAckReq (blockAckReq.GetStartingSequence ());
+
+ NS_ASSERT (m_sendAckEvent.IsExpired ());
+ /* See section 11.5.3 in IEEE 802.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 (),
+ txVector.GetMode ());
+ }
+ else
+ {
+ NS_FATAL_ERROR ("Delayed block ack not supported.");
+ }
+ m_receivedAtLeastOneMpdu = false;
+ }
+ 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 ());
+ m_receivedAtLeastOneMpdu = false;
+ }
+ else if (hdr.GetAddr1 () == m_self)
+ {
+ m_stationManager->ReportRxOk (hdr.GetAddr2 (), &hdr,
+ rxSnr, txVector.GetMode ());
+ if (hdr.IsQosData () && ReceiveMpdu (packet, hdr))
+ {
+ /* From section 9.10.4 in IEEE 802.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 () && !ampduSubframe)
+ {
+ NS_LOG_DEBUG ("rx QoS unicast/sendAck from=" << hdr.GetAddr2 ());
+ AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), hdr.GetQosTid ()));
+
+ RxCompleteBufferedPacketsWithSmallerSequence (it->second.first.GetStartingSequenceControl (),
+ hdr.GetAddr2 (), hdr.GetQosTid ());
+ RxCompleteBufferedPacketsUntilFirstLost (hdr.GetAddr2 (), hdr.GetQosTid ());
+ NS_ASSERT (m_sendAckEvent.IsExpired ());
+ m_sendAckEvent = Simulator::Schedule (GetSifs (),
+ &MacLow::SendAckAfterData, this,
+ hdr.GetAddr2 (),
+ hdr.GetDuration (),
+ txVector.GetMode (),
+ rxSnr);
+ m_receivedAtLeastOneMpdu = false;
+ }
+ else if (hdr.IsQosBlockAck ())
+ {
+ AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), hdr.GetQosTid ()));
+ /* See section 11.5.3 in IEEE 802.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 IEEE 802.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. */
+ AcIndex ac = QosUtilsMapTidToAc (hdr.GetQosTid ());
+ m_edcaListeners[ac]->BlockAckInactivityTimeout (hdr.GetAddr2 (), hdr.GetQosTid ());
+ return;
+ }
+ else if (hdr.IsQosData () && hdr.IsQosNoAck ())
+ {
+ if (ampduSubframe)
+ {
+ NS_LOG_DEBUG ("rx Ampdu with No Ack Policy from=" << hdr.GetAddr2 ());
+ }
+ else
+ {
+ NS_LOG_DEBUG ("rx unicast/noAck from=" << hdr.GetAddr2 ());
+ }
+ }
+ else if (hdr.IsData () || hdr.IsMgt ())
+ {
+ if (hdr.IsMgt () && ampduSubframe)
+ {
+ NS_FATAL_ERROR ("Received management packet as part of an A-MPDU");
+ }
+ else
+ {
+#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW
+ if(hdr.IsData () && ampduSubframe)
+ {
+ AcIndex ac = QosUtilsMapTidToAc (hdr.GetQosTid ());
+ m_edcaListeners[ac]->BlockAckInactivityTimeout (hdr.GetAddr2 (), hdr.GetQosTid ());
+ return;
+ }
+#endif
+ NS_LOG_DEBUG ("rx unicast/sendAck from=" << hdr.GetAddr2 ());
+ NS_ASSERT (m_sendAckEvent.IsExpired ());
+ m_sendAckEvent = Simulator::Schedule (GetSifs (),
+ &MacLow::SendAckAfterData, this,
+ hdr.GetAddr2 (),
+ hdr.GetDuration (),
+ txVector.GetMode (),
+ rxSnr);
+ m_receivedAtLeastOneMpdu = false;
+ }
+ }
+ goto rxPacket;
+ }
+ else if (hdr.GetAddr1 ().IsGroup ())
+ {
+ if (ampduSubframe)
+ {
+ NS_FATAL_ERROR ("Received group addressed packet as part of an A-MPDU");
+ }
+ else
+ {
+ if (hdr.IsData () || hdr.IsMgt ())
+ {
+ NS_LOG_DEBUG ("rx group from=" << hdr.GetAddr2 ());
+ m_receivedAtLeastOneMpdu = false;
+ goto rxPacket;
+ }
+ else
+ {
+ // DROP
+ }
+ }
+ }
+ else if (m_promisc)
+ {
+ NS_ASSERT (hdr.GetAddr1 () != m_self);
+ if (hdr.IsData ())
+ {
+ goto rxPacket;
+ }
+ }
+ else
+ {
+ //NS_LOG_DEBUG_VERBOSE ("rx not-for-me from %d", GetSource (packet));
+ }
+ return;
+rxPacket:
+ WifiMacTrailer fcs;
+ packet->RemoveTrailer (fcs);
+ m_rxCallback (packet, &hdr);
+ return;
+}
+
+uint8_t
+MacLow::GetTid (Ptr<const Packet> packet, const WifiMacHeader hdr) const
+{
+ uint8_t tid = 0;
+ if (hdr.IsQosData ())
+ {
+ tid = hdr.GetQosTid ();
+ }
+ else if (hdr.IsBlockAckReq ())
+ {
+ CtrlBAckRequestHeader baReqHdr;
+ packet->PeekHeader (baReqHdr);
+ tid = baReqHdr.GetTidInfo ();
+ }
+ else if (hdr.IsBlockAck ())
+ {
+ CtrlBAckResponseHeader baRespHdr;
+ packet->PeekHeader (baRespHdr);
+ tid = baRespHdr.GetTidInfo ();
+ }
+ return tid;
+}
+
+uint32_t
+MacLow::GetAckSize (void) const
+{
+ WifiMacHeader ack;
+ 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
+{
+ WifiMacHeader rts;
+ rts.SetType (WIFI_MAC_CTL_RTS);
+ return rts.GetSize () + 4;
+}
+
+Time
+MacLow::GetAckDuration (Mac48Address to, WifiTxVector dataTxVector) const
+{
+ WifiTxVector ackTxVector = GetAckTxVectorForData (to, dataTxVector.GetMode ());
+ return GetAckDuration (ackTxVector);
+}
+
+Time
+MacLow::GetAckDuration (WifiTxVector ackTxVector) const
+{
+ NS_ASSERT (ackTxVector.GetMode ().GetModulationClass () != WIFI_MOD_CLASS_HT); //ACK should always use non-HT PPDU (HT PPDU cases not supported yet)
+ return m_phy->CalculateTxDuration (GetAckSize (), ackTxVector, WIFI_PREAMBLE_LONG, m_phy->GetFrequency (), 0, 0);
+}
+
+Time
+MacLow::GetBlockAckDuration (Mac48Address to, WifiTxVector blockAckReqTxVector, enum BlockAckType type) const
+{
+ /*
+ * For immediate Basic BlockAck we should transmit the frame with the same WifiMode
+ * as the BlockAckReq.
+ */
+ WifiPreamble preamble;
+ if (blockAckReqTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT && type == BASIC_BLOCK_ACK)
+ {
+ preamble = WIFI_PREAMBLE_HT_MF;
+ }
+ else
+ {
+ preamble = WIFI_PREAMBLE_LONG;
+ }
+ return m_phy->CalculateTxDuration (GetBlockAckSize (type), blockAckReqTxVector, preamble, m_phy->GetFrequency (), 0, 0);
+}
+
+Time
+MacLow::GetCtsDuration (Mac48Address to, WifiTxVector rtsTxVector) const
+{
+ WifiTxVector ctsTxVector = GetCtsTxVectorForRts (to, rtsTxVector.GetMode ());
+ return GetCtsDuration (ctsTxVector);
+}
+
+Time
+MacLow::GetCtsDuration (WifiTxVector ctsTxVector) const
+{
+ NS_ASSERT (ctsTxVector.GetMode ().GetModulationClass () != WIFI_MOD_CLASS_HT); //CTS should always use non-HT PPDU (HT PPDU cases not supported yet)
+ return m_phy->CalculateTxDuration (GetCtsSize (), ctsTxVector, WIFI_PREAMBLE_LONG, m_phy->GetFrequency (), 0, 0);
+}
+
+uint32_t
+MacLow::GetCtsSize (void) const
+{
+ WifiMacHeader cts;
+ cts.SetType (WIFI_MAC_CTL_CTS);
+ return cts.GetSize () + 4;
+}
+
+uint32_t
+MacLow::GetSize (Ptr<const Packet> packet, const WifiMacHeader *hdr) const
+{
+ uint32_t size;
+ WifiMacTrailer fcs;
+ if (m_ampdu)
+ {
+ size = packet->GetSize ();
+ }
+ else
+ {
+ size = packet->GetSize () + hdr->GetSize () + fcs.GetSerializedSize ();
+ }
+ return size;
+}
+
+WifiTxVector
+MacLow::GetCtsToSelfTxVector (Ptr<const Packet> packet, const WifiMacHeader *hdr) const
+{
+ return m_stationManager->GetCtsToSelfTxVector (hdr, packet);
+}
+
+WifiTxVector
+MacLow::GetRtsTxVector (Ptr<const Packet> packet, const WifiMacHeader *hdr) const
+{
+ Mac48Address to = hdr->GetAddr1 ();
+ return m_stationManager->GetRtsTxVector (to, hdr, packet);
+}
+
+WifiTxVector
+MacLow::GetDataTxVector (Ptr<const Packet> packet, const WifiMacHeader *hdr) const
+{
+ Mac48Address to = hdr->GetAddr1 ();
+ WifiMacTrailer fcs;
+ uint32_t size = packet->GetSize () + hdr->GetSize () + fcs.GetSerializedSize ();
+ //size is not used in anything!! will not worry about aggregation
+ return m_stationManager->GetDataTxVector (to, hdr, packet, size);
+}
+
+WifiTxVector
+MacLow::GetCtsTxVector (Mac48Address to, WifiMode rtsTxMode) const
+{
+ return m_stationManager->GetCtsTxVector (to, rtsTxMode);
+}
+
+WifiTxVector
+MacLow::GetAckTxVector (Mac48Address to, WifiMode dataTxMode) const
+{
+ return m_stationManager->GetAckTxVector (to, dataTxMode);
+}
+
+WifiTxVector
+MacLow::GetBlockAckTxVector (Mac48Address to, WifiMode dataTxMode) const
+{
+ return m_stationManager->GetBlockAckTxVector (to, dataTxMode);
+}
+
+WifiTxVector
+MacLow::GetCtsTxVectorForRts (Mac48Address to, WifiMode rtsTxMode) const
+{
+ return GetCtsTxVector (to, rtsTxMode);
+}
+
+WifiTxVector
+MacLow::GetAckTxVectorForData (Mac48Address to, WifiMode dataTxMode) const
+{
+ return GetAckTxVector (to, dataTxMode);
+}
+
+Time
+MacLow::CalculateOverallTxTime (Ptr<const Packet> packet,
+ const WifiMacHeader* hdr,
+ const MacLowTransmissionParameters& params) const
+{
+ WifiPreamble preamble;
+ Time txTime = Seconds (0);
+ if (params.MustSendRts ())
+ {
+ WifiTxVector rtsTxVector = GetRtsTxVector (packet, hdr);
+ //standard says RTS packets can have GF format sec 9.6.0e.1 page 110 bullet b 2
+ if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
+ {
+ preamble = WIFI_PREAMBLE_HT_GF;
+ }
+ else
+ {
+ //Otherwise, RTS should always use non-HT PPDU (HT PPDU cases not supported yet)
+ preamble = WIFI_PREAMBLE_LONG;
+ }
+ txTime += m_phy->CalculateTxDuration (GetRtsSize (), rtsTxVector, preamble, m_phy->GetFrequency (), 0, 0);
+ txTime += GetCtsDuration (hdr->GetAddr1 (), rtsTxVector);
+ txTime += Time (GetSifs () * 2);
+ }
+ WifiTxVector dataTxVector = GetDataTxVector (packet, hdr);
+ if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_VHT)
+ {
+ preamble = WIFI_PREAMBLE_VHT;
+ }
+ else if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
+ {
+ preamble = WIFI_PREAMBLE_HT_GF;
+ }
+ else if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT)
+ {
+ preamble = WIFI_PREAMBLE_HT_MF;
+ }
+ else
+ {
+ preamble = WIFI_PREAMBLE_LONG;
+ }
+ uint32_t dataSize = GetSize (packet, hdr);
+ txTime += m_phy->CalculateTxDuration (dataSize, dataTxVector, preamble, m_phy->GetFrequency (), 0, 0);
+ if (params.MustWaitAck ())
+ {
+ txTime += GetSifs ();
+ txTime += GetAckDuration (hdr->GetAddr1 (), dataTxVector);
+ }
+ return txTime;
+}
+
+Time
+MacLow::CalculateTransmissionTime (Ptr<const Packet> packet,
+ const WifiMacHeader* hdr,
+ const MacLowTransmissionParameters& params) const
+{
+ Time txTime = CalculateOverallTxTime (packet, hdr, params);
+ if (params.HasNextPacket ())
+ {
+ WifiTxVector dataTxVector = GetDataTxVector (packet, hdr);
+ WifiPreamble preamble;
+ if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT)
+ {
+ preamble = WIFI_PREAMBLE_VHT;
+ }
+ if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
+ {
+ preamble = WIFI_PREAMBLE_HT_GF;
+ }
+ else if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT)
+ {
+ preamble = WIFI_PREAMBLE_HT_MF;
+ }
+ else
+ {
+ preamble = WIFI_PREAMBLE_LONG;
+ }
+ txTime += GetSifs ();
+ txTime += m_phy->CalculateTxDuration (params.GetNextPacketSize (), dataTxVector, preamble, m_phy->GetFrequency (), 0, 0);
+ }
+ return txTime;
+}
+
+void
+MacLow::NotifyNav (Ptr<const Packet> packet,const WifiMacHeader &hdr, WifiPreamble preamble)
+{
+ NS_ASSERT (m_lastNavStart <= Simulator::Now ());
+ Time duration = hdr.GetDuration ();
+
+ if (hdr.IsCfpoll ()
+ && hdr.GetAddr2 () == m_bssid)
+ {
+ //see section 9.3.2.2 802.11-1999
+ DoNavResetNow (duration);
+ return;
+ }
+ /// \todo We should also handle CF_END specially here
+ /// but we don't for now because we do not generate them.
+ else if (hdr.GetAddr1 () != m_self)
+ {
+ // see section 9.2.5.4 802.11-1999
+ bool navUpdated = DoNavStartNow (duration);
+ if (hdr.IsRts () && navUpdated)
+ {
+ /**
+ * A STA that used information from an RTS frame as the most recent basis to update its NAV setting
+ * is permitted to reset its NAV if no PHY-RXSTART.indication is detected from the PHY during a
+ * period with a duration of (2 * aSIFSTime) + (CTS_Time) + (2 * aSlotTime) starting at the
+ * PHY-RXEND.indication corresponding to the detection of the RTS frame. The “CTS_Time” shall
+ * be calculated using the length of the CTS frame and the data rate at which the RTS frame
+ * used for the most recent NAV update was received.
+ */
+ WifiMacHeader cts;
+ cts.SetType (WIFI_MAC_CTL_CTS);
+ WifiTxVector txVector = GetRtsTxVector (packet, &hdr);
+ Time navCounterResetCtsMissedDelay =
+ m_phy->CalculateTxDuration (cts.GetSerializedSize (), txVector, preamble, m_phy->GetFrequency (), 0, 0) +
+ Time (2 * GetSifs ()) + Time (2 * GetSlotTime ());
+ m_navCounterResetCtsMissed = Simulator::Schedule (navCounterResetCtsMissedDelay,
+ &MacLow::NavCounterResetCtsMissed, this,
+ Simulator::Now ());
+ }
+ }
+}
+
+void
+MacLow::NavCounterResetCtsMissed (Time rtsEndRxTime)
+{
+ if (m_phy->GetLastRxStartTime () < rtsEndRxTime)
+ {
+ DoNavResetNow (Seconds (0.0));
+ }
+}
+
+void
+MacLow::DoNavResetNow (Time duration)
+{
+ for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++)
+ {
+ (*i)->NavReset (duration);
+ }
+ m_lastNavStart = Simulator::Now ();
+ m_lastNavDuration = duration;
+}
+
+bool
+MacLow::DoNavStartNow (Time duration)
+{
+ for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++)
+ {
+ (*i)->NavStart (duration);
+ }
+ Time newNavEnd = Simulator::Now () + duration;
+ Time oldNavEnd = m_lastNavStart + m_lastNavDuration;
+ if (newNavEnd > oldNavEnd)
+ {
+ m_lastNavStart = Simulator::Now ();
+ m_lastNavDuration = duration;
+ return true;
+ }
+ return false;
+}
+
+void
+MacLow::NotifyAckTimeoutStartNow (Time duration)
+{
+ for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++)
+ {
+ (*i)->AckTimeoutStart (duration);
+ }
+}
+
+void
+MacLow::NotifyAckTimeoutResetNow ()
+{
+ for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++)
+ {
+ (*i)->AckTimeoutReset ();
+ }
+}
+
+void
+MacLow::NotifyCtsTimeoutStartNow (Time duration)
+{
+ for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++)
+ {
+ (*i)->CtsTimeoutStart (duration);
+ }
+}
+
+void
+MacLow::NotifyCtsTimeoutResetNow ()
+{
+ for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++)
+ {
+ (*i)->CtsTimeoutReset ();
+ }
+}
+
+void
+MacLow::ForwardDown (Ptr<const Packet> packet, const WifiMacHeader* hdr,
+ WifiTxVector txVector, WifiPreamble preamble)
+{
+ NS_LOG_FUNCTION (this << packet << hdr << txVector);
+ NS_LOG_DEBUG ("send " << hdr->GetTypeString () <<
+ ", to=" << hdr->GetAddr1 () <<
+ ", size=" << packet->GetSize () <<
+ ", mode=" << txVector.GetMode () <<
+ ", duration=" << hdr->GetDuration () <<
+ ", seq=0x" << std::hex << m_currentHdr.GetSequenceControl () << std::dec);
+
+/*std::cout<<"send " << hdr->GetTypeString () <<
+ ", size=" << packet->GetSize () <<
+ ", mode=" << txVector.GetMode () <<"\n";
+ */
+ if (!m_ampdu || hdr->IsRts ())
+ {
+ m_phy->SendPacket (packet, txVector, preamble, 0, 0);
+ }
+ else
+ {
+ Ptr<Packet> newPacket;
+ Ptr <const Packet> dequeuedPacket;
+ WifiMacHeader newHdr;
+ WifiMacTrailer fcs;
+ uint32_t queueSize = m_aggregateQueue->GetSize ();
+ bool vhtSingleMpdu = false;
+ bool last = false;
+ uint8_t packetType = 0;
+
+ if (queueSize == 1)
+ {
+ vhtSingleMpdu = true;
+ }
+
+ //Add packet tag
+ AmpduTag ampdutag;
+ ampdutag.SetAmpdu (true);
+ Time delay = Seconds (0);
+ if (queueSize > 1 || vhtSingleMpdu)
+ {
+ txVector.SetAggregation (true);
+ }
+ for (; queueSize > 0; queueSize--)
+ {
+ dequeuedPacket = m_aggregateQueue->Dequeue (&newHdr);
+ newPacket = dequeuedPacket->Copy ();
+ newHdr.SetDuration (hdr->GetDuration ());
+ newPacket->AddHeader (newHdr);
+ newPacket->AddTrailer (fcs);
+ if (queueSize == 1)
+ {
+ last = true;
+ packetType = 2;
+ }
+ m_mpduAggregator->AddHeaderAndPad (newPacket, last, vhtSingleMpdu);
+
+ ampdutag.SetNoOfMpdus (queueSize);
+ newPacket->AddPacketTag (ampdutag);
+ if (delay == Seconds (0))
+ {
+ if (!vhtSingleMpdu)
+ {
+ NS_LOG_DEBUG ("Sending MPDU as part of A-MPDU");
+ packetType = 1;
+ }
+ else
+ {
+ packetType = 0;
+ }
+ m_phy->SendPacket (newPacket, txVector, preamble, packetType, m_mpduReferenceNumber);
+ }
+ else
+ {
+ Simulator::Schedule (delay, &MacLow::SendPacket, this, newPacket, txVector, preamble, packetType, m_mpduReferenceNumber);
+ }
+ if (queueSize > 1)
+ {
+ delay = delay + m_phy->CalculateTxDuration (GetSize (newPacket, &newHdr), txVector, preamble, m_phy->GetFrequency (), packetType, 0);
+ }
+ preamble = WIFI_PREAMBLE_NONE;
+ }
+ m_mpduReferenceNumber = ((m_mpduReferenceNumber + 1) % 4294967296);
+ }
+}
+
+void
+MacLow::SendPacket (Ptr<const Packet> packet, WifiTxVector txVector, WifiPreamble preamble, uint8_t packetType, uint32_t mpduReferenceNumber)
+{
+ NS_LOG_DEBUG ("Sending MPDU as part of A-MPDU");
+ m_phy->SendPacket (packet, txVector, preamble, packetType, mpduReferenceNumber);
+}
+
+void
+MacLow::CtsTimeout (void)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_DEBUG ("cts timeout");
+ /// \todo should check that there was no rx start before now.
+ /// we should restart a new cts timeout now until the expected
+ /// end of rx if there was a rx start before now.
+ m_stationManager->ReportRtsFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
+ if (m_sentMpdus == 0)
+ {
+ m_currentPacket = 0;
+ }
+ MacLowTransmissionListener *listener = m_listener;
+ m_listener = 0;
+ m_sentMpdus = 0;
+ m_ampdu = false;
+ listener->MissedCts ();
+}
+
+void
+MacLow::NormalAckTimeout (void)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_DEBUG ("normal ack timeout");
+ /// \todo should check that there was no rx start before now.
+ /// we should restart a new ack timeout now until the expected
+ /// end of rx if there was a rx start before now.
+ m_stationManager->ReportDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
+ MacLowTransmissionListener *listener = m_listener;
+ m_listener = 0;
+ m_sentMpdus = 0;
+ m_ampdu = false;
+ FlushAggregateQueue ();
+ listener->MissedAck ();
+}
+
+void
+MacLow::FastAckTimeout (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_stationManager->ReportDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
+ MacLowTransmissionListener *listener = m_listener;
+ m_listener = 0;
+ if (m_phy->IsStateIdle ())
+ {
+ NS_LOG_DEBUG ("fast Ack idle missed");
+ listener->MissedAck ();
+ }
+ else
+ {
+ NS_LOG_DEBUG ("fast Ack ok");
+ }
+}
+
+void
+MacLow::BlockAckTimeout (void)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_DEBUG ("block ack timeout");
+
+ m_stationManager->ReportDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
+ MacLowTransmissionListener *listener = m_listener;
+ m_listener = 0;
+ m_sentMpdus = 0;
+ m_ampdu = false;
+ FlushAggregateQueue ();
+ listener->MissedBlockAck ();
+}
+
+void
+MacLow::SuperFastAckTimeout ()
+{
+ NS_LOG_FUNCTION (this);
+ m_stationManager->ReportDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
+ MacLowTransmissionListener *listener = m_listener;
+ m_listener = 0;
+ if (m_phy->IsStateIdle ())
+ {
+ NS_LOG_DEBUG ("super fast Ack failed");
+ listener->MissedAck ();
+ }
+ else
+ {
+ NS_LOG_DEBUG ("super fast Ack ok");
+ listener->GotAck (0.0, WifiMode ());
+ }
+}
+
+void
+MacLow::SendRtsForPacket (void)
+{
+ NS_LOG_FUNCTION (this);
+ /* send an RTS for this packet. */
+ WifiMacHeader rts;
+ rts.SetType (WIFI_MAC_CTL_RTS);
+ rts.SetDsNotFrom ();
+ rts.SetDsNotTo ();
+ rts.SetNoRetry ();
+ rts.SetNoMoreFragments ();
+ rts.SetAddr1 (m_currentHdr.GetAddr1 ());
+ rts.SetAddr2 (m_self);
+ WifiTxVector rtsTxVector = GetRtsTxVector (m_currentPacket, &m_currentHdr);
+ Time duration = Seconds (0);
+
+ WifiPreamble preamble;
+ //standard says RTS packets can have GF format sec 9.6.0e.1 page 110 bullet b 2
+ if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
+ {
+ preamble = WIFI_PREAMBLE_HT_GF;
+ }
+ else //Otherwise, RTS should always use non-HT PPDU (HT PPDU cases not supported yet)
+ {
+ preamble = WIFI_PREAMBLE_LONG;
+ }
+
+ if (m_txParams.HasDurationId ())
+ {
+ duration += m_txParams.GetDurationId ();
+ }
+ else
+ {
+ WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr);
+ duration += GetSifs ();
+ duration += GetCtsDuration (m_currentHdr.GetAddr1 (), rtsTxVector);
+ duration += GetSifs ();
+ duration += m_phy->CalculateTxDuration (GetSize (m_currentPacket, &m_currentHdr),
+ dataTxVector, preamble, m_phy->GetFrequency (), 0, 0);
+ duration += GetSifs ();
+ if (m_txParams.MustWaitBasicBlockAck ())
+ {
+ WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode ());
+ duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, BASIC_BLOCK_ACK);
+ }
+ else if (m_txParams.MustWaitCompressedBlockAck ())
+ {
+ WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode ());
+ duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK);
+ }
+ else if (m_txParams.MustWaitAck ())
+ {
+ duration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector);
+ }
+ if (m_txParams.HasNextPacket ())
+ {
+ duration += m_phy->CalculateTxDuration (m_txParams.GetNextPacketSize (),
+ dataTxVector, preamble, m_phy->GetFrequency (), 0, 0);
+ if (m_txParams.MustWaitAck ())
+ {
+ duration += GetSifs ();
+ duration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector);
+ }
+ }
+ }
+ rts.SetDuration (duration);
+
+ Time txDuration = m_phy->CalculateTxDuration (GetRtsSize (), rtsTxVector, preamble, m_phy->GetFrequency (), 0, 0);
+ Time timerDelay = txDuration + GetCtsTimeout ();
+
+ NS_ASSERT (m_ctsTimeoutEvent.IsExpired ());
+ NotifyCtsTimeoutStartNow (timerDelay);
+ m_ctsTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::CtsTimeout, this);
+
+ Ptr<Packet> packet = Create<Packet> ();
+ packet->AddHeader (rts);
+ WifiMacTrailer fcs;
+ packet->AddTrailer (fcs);
+
+ ForwardDown (packet, &rts, rtsTxVector,preamble);
+}
+
+void
+MacLow::StartDataTxTimers (WifiTxVector dataTxVector)
+{
+ WifiPreamble preamble;
+
+ if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_VHT)
+ {
+ preamble = WIFI_PREAMBLE_VHT;
+ }
+ //Since it is data then it can have format = GF
+ else if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
+ {
+ preamble = WIFI_PREAMBLE_HT_GF;
+ }
+ else if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT)
+ {
+ preamble = WIFI_PREAMBLE_HT_MF;
+ }
+ else
+ {
+ preamble = WIFI_PREAMBLE_LONG;
+ }
+
+ Time txDuration = m_phy->CalculateTxDuration (GetSize (m_currentPacket, &m_currentHdr), dataTxVector, preamble, m_phy->GetFrequency (), 0, 0);
+ if (m_txParams.MustWaitNormalAck ())
+ {
+ Time timerDelay = txDuration + GetAckTimeout ();
+ NS_ASSERT (m_normalAckTimeoutEvent.IsExpired ());
+ NotifyAckTimeoutStartNow (timerDelay);
+ m_normalAckTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::NormalAckTimeout, this);
+ }
+ else if (m_txParams.MustWaitFastAck ())
+ {
+ Time timerDelay = txDuration + GetPifs ();
+ NS_ASSERT (m_fastAckTimeoutEvent.IsExpired ());
+ NotifyAckTimeoutStartNow (timerDelay);
+ m_fastAckTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::FastAckTimeout, this);
+ }
+ else if (m_txParams.MustWaitSuperFastAck ())
+ {
+ Time timerDelay = txDuration + GetPifs ();
+ NS_ASSERT (m_superFastAckTimeoutEvent.IsExpired ());
+ NotifyAckTimeoutStartNow (timerDelay);
+ m_superFastAckTimeoutEvent = Simulator::Schedule (timerDelay,
+ &MacLow::SuperFastAckTimeout, this);
+ }
+ else if (m_txParams.MustWaitBasicBlockAck ())
+ {
+ Time timerDelay = txDuration + GetBasicBlockAckTimeout ();
+ NS_ASSERT (m_blockAckTimeoutEvent.IsExpired ());
+ NotifyAckTimeoutStartNow (timerDelay);
+ m_blockAckTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::BlockAckTimeout, this);
+ }
+ else if (m_txParams.MustWaitCompressedBlockAck ())
+ {
+ Time timerDelay = txDuration + GetCompressedBlockAckTimeout ();
+ NS_ASSERT (m_blockAckTimeoutEvent.IsExpired ());
+ NotifyAckTimeoutStartNow (timerDelay);
+ m_blockAckTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::BlockAckTimeout, this);
+ }
+ else if (m_txParams.HasNextPacket ())
+ {
+ if (m_stationManager->HasHtSupported ())
+ {
+ Time delay = txDuration + GetRifs ();
+ NS_ASSERT (m_waitRifsEvent.IsExpired ());
+ m_waitRifsEvent = Simulator::Schedule (delay, &MacLow::WaitSifsAfterEndTx, this);
+ }
+ else
+ {
+ Time delay = txDuration + GetSifs ();
+ NS_ASSERT (m_waitSifsEvent.IsExpired ());
+ m_waitSifsEvent = Simulator::Schedule (delay, &MacLow::WaitSifsAfterEndTx, this);
+ }
+ }
+ else
+ {
+ // since we do not expect any timer to be triggered.
+ Simulator::Schedule (txDuration, &MacLow::EndTxNoAck, this);
+ }
+}
+
+void
+MacLow::SendDataPacket (void)
+{
+ NS_LOG_FUNCTION (this);
+ /* send this packet directly. No RTS is needed. */
+ WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr);
+ WifiPreamble preamble;
+ if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_VHT)
+ {
+ preamble = WIFI_PREAMBLE_VHT;
+ }
+ else if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
+ {
+ //In the future has to make sure that receiver has greenfield enabled
+ preamble = WIFI_PREAMBLE_HT_GF;
+ }
+ else if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT)
+ {
+ preamble = WIFI_PREAMBLE_HT_MF;
+ }
+ else
+ {
+ preamble = WIFI_PREAMBLE_LONG;
+ }
+
+ StartDataTxTimers (dataTxVector);
+
+ Time duration = Seconds (0.0);
+ if (m_txParams.HasDurationId ())
+ {
+ duration += m_txParams.GetDurationId ();
+ NS_LOG_DEBUG("duration add durationId="<<m_txParams.GetDurationId ());
+
+ }
+ else
+ {
+ if (m_txParams.MustWaitBasicBlockAck ())
+ {
+ duration += GetSifs ();
+ WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode ());
+ NS_LOG_DEBUG("expected BA tx vector="<<blockAckReqTxVector.GetMode());
+ duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, BASIC_BLOCK_ACK);
+ NS_LOG_DEBUG("add basic BA duration="<<GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, BASIC_BLOCK_ACK));
+ }
+ else if (m_txParams.MustWaitCompressedBlockAck ())
+ {
+ duration += GetSifs ();
+ WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode ());
+ NS_LOG_DEBUG("expected BA tx vector="<<blockAckReqTxVector.GetMode());
+ duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK);
+ NS_LOG_DEBUG("add compressed BA duration="<<GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK));
+
+ }
+ else if (m_txParams.MustWaitAck ())
+ {
+ duration += GetSifs ();
+ duration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector);
+ }
+ if (m_txParams.HasNextPacket ())
+ {
+ duration += GetSifs ();
+ duration += m_phy->CalculateTxDuration (m_txParams.GetNextPacketSize (),
+ dataTxVector, preamble, m_phy->GetFrequency (), 0, 0);
+ NS_LOG_DEBUG("add next packet duration="<<GetSifs ()<<" " <<m_phy->CalculateTxDuration (m_txParams.GetNextPacketSize (),
+ dataTxVector, preamble, m_phy->GetFrequency (), 0, 0));
+
+ if (m_txParams.MustWaitAck ())
+ {
+ duration += GetSifs ();
+ duration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector);
+ }
+ NS_LOG_DEBUG("add must wait ack of next, duration="<<GetSifs ()<<" " <<GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector));
+ }
+ }
+ m_currentHdr.SetDuration (duration);
+ NS_LOG_DEBUG("final duration="<<duration);
+
+ if (!m_ampdu)
+ {
+ m_currentPacket->AddHeader (m_currentHdr);
+ WifiMacTrailer fcs;
+ m_currentPacket->AddTrailer (fcs);
+ }
+
+ ForwardDown (m_currentPacket, &m_currentHdr, dataTxVector, preamble);
+ m_currentPacket = 0;
+}
+
+bool
+MacLow::IsNavZero (void) const
+{
+ if (m_lastNavStart + m_lastNavDuration < Simulator::Now ())
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void
+MacLow::SendCtsToSelf (void)
+{
+ WifiMacHeader cts;
+ cts.SetType (WIFI_MAC_CTL_CTS);
+ cts.SetDsNotFrom ();
+ cts.SetDsNotTo ();
+ cts.SetNoMoreFragments ();
+ cts.SetNoRetry ();
+ cts.SetAddr1 (m_self);
+
+ WifiTxVector ctsTxVector = GetCtsToSelfTxVector (m_currentPacket, &m_currentHdr);
+
+ WifiPreamble preamble;
+ if (ctsTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT)
+ {
+ preamble = WIFI_PREAMBLE_HT_MF;
+ }
+ else
+ {
+ preamble = WIFI_PREAMBLE_LONG;
+ }
+
+ Time duration = Seconds (0);
+
+ if (m_txParams.HasDurationId ())
+ {
+ duration += m_txParams.GetDurationId ();
+ }
+ else
+ {
+ WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr);
+ duration += GetSifs ();
+ duration += m_phy->CalculateTxDuration (GetSize (m_currentPacket,&m_currentHdr),
+ dataTxVector, preamble, m_phy->GetFrequency (), 0, 0);
+ if (m_txParams.MustWaitBasicBlockAck ())
+ {
+
+ duration += GetSifs ();
+ WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode ());
+ duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, BASIC_BLOCK_ACK);
+ }
+ else if (m_txParams.MustWaitCompressedBlockAck ())
+ {
+ duration += GetSifs ();
+ WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode ());
+ duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK);
+ }
+ else if (m_txParams.MustWaitAck ())
+ {
+ duration += GetSifs ();
+ duration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector);
+ }
+ if (m_txParams.HasNextPacket ())
+ {
+ duration += GetSifs ();
+ duration += m_phy->CalculateTxDuration (m_txParams.GetNextPacketSize (),
+ dataTxVector, preamble, m_phy->GetFrequency (), 0, 0);
+ if (m_txParams.MustWaitCompressedBlockAck ())
+ {
+ duration += GetSifs ();
+ WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode ());
+ duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK);
+ }
+ else if (m_txParams.MustWaitAck ())
+ {
+ duration += GetSifs ();
+ duration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector);
+ }
+ }
+ }
+
+ cts.SetDuration (duration);
+
+ Ptr<Packet> packet = Create<Packet> ();
+ packet->AddHeader (cts);
+ WifiMacTrailer fcs;
+ packet->AddTrailer (fcs);
+
+ ForwardDown (packet, &cts, ctsTxVector,preamble);
+
+ Time txDuration = m_phy->CalculateTxDuration (GetCtsSize (), ctsTxVector, preamble, m_phy->GetFrequency (), 0, 0);
+ txDuration += GetSifs ();
+ NS_ASSERT (m_sendDataEvent.IsExpired ());
+
+ m_sendDataEvent = Simulator::Schedule (txDuration,
+ &MacLow::SendDataAfterCts, this,
+ cts.GetAddr1 (),
+ duration);
+
+}
+
+void
+MacLow::SendCtsAfterRts (Mac48Address source, Time duration, WifiTxVector rtsTxVector, double rtsSnr)
+{
+ NS_LOG_FUNCTION (this << source << duration << rtsTxVector.GetMode () << rtsSnr);
+ /* send a CTS when you receive a RTS
+ * right after SIFS.
+ */
+ WifiTxVector ctsTxVector = GetCtsTxVector (source, rtsTxVector.GetMode ());
+ WifiMacHeader cts;
+ cts.SetType (WIFI_MAC_CTL_CTS);
+ cts.SetDsNotFrom ();
+ cts.SetDsNotTo ();
+ cts.SetNoMoreFragments ();
+ cts.SetNoRetry ();
+ cts.SetAddr1 (source);
+ duration -= GetCtsDuration (source, rtsTxVector);
+ duration -= GetSifs ();
+ NS_ASSERT (duration >= MicroSeconds (0));
+ cts.SetDuration (duration);
+
+ Ptr<Packet> packet = Create<Packet> ();
+ packet->AddHeader (cts);
+ WifiMacTrailer fcs;
+ packet->AddTrailer (fcs);
+
+ SnrTag tag;
+ tag.Set (rtsSnr);
+ packet->AddPacketTag (tag);
+
+ ForwardDown (packet, &cts, ctsTxVector, WIFI_PREAMBLE_LONG);
+}
+
+void
+MacLow::SendDataAfterCts (Mac48Address source, Time duration)
+{
+ NS_LOG_FUNCTION (this);
+ /* send the third step in a
+ * RTS/CTS/DATA/ACK hanshake
+ */
+ NS_ASSERT (m_currentPacket != 0);
+ WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr);
+
+ if (m_aggregateQueue->GetSize () != 0)
+ {
+ for (std::vector<Item>::size_type i = 0; i != m_txPackets.size (); i++)
+ {
+ uint8_t tid = GetTid (m_txPackets.at (i).packet, m_txPackets.at (i).hdr);
+ AcIndex ac = QosUtilsMapTidToAc (tid);
+ std::map<AcIndex, MacLowAggregationCapableTransmissionListener*>::const_iterator listenerIt = m_edcaListeners.find (ac);
+
+ listenerIt->second->CompleteMpduTx (m_txPackets.at (i).packet, m_txPackets.at (i).hdr, m_txPackets.at (i).timestamp);
+ }
+ m_txPackets.clear ();
+ }
+
+ WifiPreamble preamble;
+ if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_VHT)
+ {
+ preamble = WIFI_PREAMBLE_VHT;
+ }
+ else if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
+ {
+ //In the future has to make sure that receiver has greenfield enabled
+ preamble = WIFI_PREAMBLE_HT_GF;
+ }
+ else if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT)
+ {
+ preamble = WIFI_PREAMBLE_HT_MF;
+ }
+ else
+ {
+ preamble = WIFI_PREAMBLE_LONG;
+ }
+
+ StartDataTxTimers (dataTxVector);
+ Time newDuration = Seconds (0);
+ if (m_txParams.MustWaitBasicBlockAck ())
+ {
+ newDuration += GetSifs ();
+ WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode ());
+ newDuration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, BASIC_BLOCK_ACK);
+ }
+ else if (m_txParams.MustWaitCompressedBlockAck ())
+ {
+ newDuration += GetSifs ();
+ WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode ());
+ newDuration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK);
+ }
+ else if (m_txParams.MustWaitAck ())
+ {
+ newDuration += GetSifs ();
+ newDuration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector);
+ }
+ if (m_txParams.HasNextPacket ())
+ {
+ newDuration += GetSifs ();
+ newDuration += m_phy->CalculateTxDuration (m_txParams.GetNextPacketSize (), dataTxVector, preamble, m_phy->GetFrequency (), 0, 0);
+ if (m_txParams.MustWaitCompressedBlockAck ())
+ {
+ newDuration += GetSifs ();
+ WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode ());
+ newDuration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK);
+ }
+ else if (m_txParams.MustWaitAck ())
+ {
+ newDuration += GetSifs ();
+ newDuration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector);
+ }
+ }
+
+ Time txDuration = m_phy->CalculateTxDuration (GetSize (m_currentPacket, &m_currentHdr), dataTxVector, preamble, m_phy->GetFrequency (), 0, 0);
+ duration -= txDuration;
+ duration -= GetSifs ();
+
+ duration = std::max (duration, newDuration);
+ NS_ASSERT (duration >= MicroSeconds (0));
+ m_currentHdr.SetDuration (duration);
+
+ if (!m_ampdu)
+ {
+ m_currentPacket->AddHeader (m_currentHdr);
+ WifiMacTrailer fcs;
+ m_currentPacket->AddTrailer (fcs);
+ }
+
+ ForwardDown (m_currentPacket, &m_currentHdr, dataTxVector, preamble);
+ m_currentPacket = 0;
+}
+
+void
+MacLow::WaitSifsAfterEndTx (void)
+{
+ m_listener->StartNext ();
+}
+
+void
+MacLow::EndTxNoAck (void)
+{
+ MacLowTransmissionListener *listener = m_listener;
+ m_listener = 0;
+ listener->EndTxNoAck ();
+}
+
+void
+MacLow::FastAckFailedTimeout (void)
+{
+ NS_LOG_FUNCTION (this);
+ MacLowTransmissionListener *listener = m_listener;
+ m_listener = 0;
+ listener->MissedAck ();
+ NS_LOG_DEBUG ("fast Ack busy but missed");
+}
+
+void
+MacLow::SendAckAfterData (Mac48Address source, Time duration, WifiMode dataTxMode, double dataSnr)
+{
+ NS_LOG_FUNCTION (this);
+ /* send an ACK when you receive
+ * a packet after SIFS.
+ */
+ WifiTxVector ackTxVector = GetAckTxVector (source, dataTxMode);
+ WifiMacHeader ack;
+ ack.SetType (WIFI_MAC_CTL_ACK);
+ ack.SetDsNotFrom ();
+ ack.SetDsNotTo ();
+ ack.SetNoRetry ();
+ ack.SetNoMoreFragments ();
+ ack.SetAddr1 (source);
+ duration -= GetAckDuration (ackTxVector);
+ duration -= GetSifs ();
+ NS_ASSERT (duration >= MicroSeconds (0));
+ ack.SetDuration (duration);
+
+ Ptr<Packet> packet = Create<Packet> ();
+ packet->AddHeader (ack);
+ WifiMacTrailer fcs;
+ packet->AddTrailer (fcs);
+
+ SnrTag tag;
+ tag.Set (dataSnr);
+ packet->AddPacketTag (tag);
+
+ //ACK should always use non-HT PPDU (HT PPDU cases not supported yet)
+ ForwardDown (packet, &ack, ackTxVector, WIFI_PREAMBLE_LONG);
+}
+
+bool
+MacLow::IsInWindow (uint16_t seq, uint16_t winstart, uint16_t winsize)
+{
+ return ((seq - winstart + 4096) % 4096) < winsize;
+}
+
+bool
+MacLow::ReceiveMpdu (Ptr<Packet> packet, WifiMacHeader hdr)
+{
+ if (m_stationManager->HasHtSupported () || m_stationManager->HasVhtSupported ())
+ {
+ Mac48Address originator = hdr.GetAddr2 ();
+ uint8_t tid = 0;
+ if (hdr.IsQosData ())
+ {
+ tid = hdr.GetQosTid ();
+ }
+ uint16_t seqNumber = hdr.GetSequenceNumber ();
+ AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid));
+ if (it != m_bAckAgreements.end ())
+ {
+ //Implement HT immediate Block Ack support for HT Delayed Block Ack is not added yet
+ if (!QosUtilsIsOldPacket ((*it).second.first.GetStartingSequence (), seqNumber))
+ {
+ StoreMpduIfNeeded (packet, hdr);
+ if (!IsInWindow (hdr.GetSequenceNumber (), (*it).second.first.GetStartingSequence (), (*it).second.first.GetBufferSize ()))
+ {
+ uint16_t delta = (seqNumber - (*it).second.first.GetWinEnd () + 4096) % 4096;
+ if (delta > 1)
+ {
+ (*it).second.first.SetWinEnd (seqNumber);
+ int16_t winEnd = (*it).second.first.GetWinEnd ();
+ int16_t bufferSize = (*it).second.first.GetBufferSize ();
+ uint16_t sum = ((uint16_t)(std::abs (winEnd - bufferSize + 1))) % 4096;
+ (*it).second.first.SetStartingSequence (sum);
+ RxCompleteBufferedPacketsWithSmallerSequence ((*it).second.first.GetStartingSequenceControl (), originator, tid);
+ }
+ }
+ RxCompleteBufferedPacketsUntilFirstLost (originator, tid); //forwards up packets starting from winstart and set winstart to last +1
+ (*it).second.first.SetWinEnd (((*it).second.first.GetStartingSequence () + (*it).second.first.GetBufferSize () - 1) % 4096);
+ }
+ return true;
+ }
+ return false;
+ }
+ else
+ {
+ return StoreMpduIfNeeded (packet, hdr);
+ }
+}
+
+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);
+
+ //Update block ack cache
+ BlockAckCachesI j = m_bAckCaches.find (std::make_pair (hdr.GetAddr2 (), hdr.GetQosTid ()));
+ NS_ASSERT (j != m_bAckCaches.end ());
+ (*j).second.UpdateWithMpdu (&hdr);
+ return true;
+ }
+ return false;
+}
+
+void
+MacLow::CreateBlockAckAgreement (const MgtAddBaResponseHeader *respHdr, Mac48Address originator,
+ uint16_t startingSeq)
+{
+ NS_LOG_FUNCTION(originator<<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 () + 1);
+ 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));
+
+ BlockAckCache cache;
+ cache.Init (startingSeq, respHdr->GetBufferSize () + 1);
+ m_bAckCaches.insert (std::make_pair (key, cache));
+
+ if (respHdr->GetTimeout () != 0)
+ {
+ AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, respHdr->GetTid ()));
+ Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
+
+ AcIndex ac = QosUtilsMapTidToAc (agreement.GetTid ());
+
+ it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
+ &MacLowAggregationCapableTransmissionListener::BlockAckInactivityTimeout,
+ m_edcaListeners[ac],
+ originator, tid);
+ }
+}
+
+void
+MacLow::DestroyBlockAckAgreement (Mac48Address originator, uint8_t tid)
+{
+ NS_LOG_FUNCTION(originator<<tid);
+ AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid));
+ if (it != m_bAckAgreements.end ())
+ {
+ RxCompleteBufferedPacketsWithSmallerSequence (it->second.first.GetStartingSequenceControl (), originator, tid);
+ RxCompleteBufferedPacketsUntilFirstLost (originator, tid);
+ m_bAckAgreements.erase (it);
+
+ BlockAckCachesI i = m_bAckCaches.find (std::make_pair (originator, tid));
+ NS_ASSERT (i != m_bAckCaches.end ());
+ m_bAckCaches.erase (i);
+ }
+#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW
+ //added+++++++++ when agreement with the originator is destroyed
+ //we should reset the status of m_receivedAtLeastOneMpdu if last mpdu is received from originator
+ if(m_lastmpduFrom==originator && m_receivedAtLeastOneMpdu)
+ m_receivedAtLeastOneMpdu=false;
+#endif
+}
+
+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 ())
+ {
+ uint16_t endSequence = ((*it).second.first.GetStartingSequence () + 2047) % 4096;
+ uint16_t mappedStart = QosUtilsMapSeqControlToUniqueInteger (seq, endSequence);
+ BufferedPacketI last = (*it).second.second.begin ();
+ uint16_t guard = 0;
+ if (last != (*it).second.second.end ())
+ {
+ guard = (*it).second.second.begin ()->second.GetSequenceControl ();
+ }
+ BufferedPacketI i = (*it).second.second.begin ();
+ for (; i != (*it).second.second.end ()
+ && QosUtilsMapSeqControlToUniqueInteger ((*i).second.GetSequenceControl (), endSequence) < mappedStart; )
+ {
+ if (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++;
+ /* go to next packet */
+ while (i != (*it).second.second.end () && guard == (*i).second.GetSequenceControl ())
+ {
+ i++;
+ }
+ if (i != (*it).second.second.end ())
+ {
+ guard = (*i).second.GetSequenceControl ();
+ last = i;
+ }
+ }
+ else
+ {
+ guard++;
+ }
+ }
+ else
+ {
+ /* go to next packet */
+ while (i != (*it).second.second.end () && guard == (*i).second.GetSequenceControl ())
+ {
+ i++;
+ }
+ if (i != (*it).second.second.end ())
+ {
+ guard = (*i).second.GetSequenceControl ();
+ last = i;
+ }
+ }
+ }
+ (*it).second.second.erase ((*it).second.second.begin (), i);
+ }
+}
+
+void
+MacLow::RxCompleteBufferedPacketsUntilFirstLost (Mac48Address originator, uint8_t tid)
+{
+ AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid));
+ if (it != m_bAckAgreements.end ())
+ {
+ uint16_t guard = (*it).second.first.GetStartingSequenceControl ();
+ 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.SetStartingSequenceControl (guard);
+ /* 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 ();
+
+ WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (originator, blockAckReqTxMode);
+
+ NS_LOG_DEBUG("actual block ack tx vector used="<<blockAckReqTxVector.GetMode());
+ m_currentPacket = packet;
+ m_currentHdr = hdr;
+ if (immediate)
+ {
+ m_txParams.DisableAck ();
+ NS_LOG_DEBUG("duration="<<duration);
+ duration -= GetSifs ();
+ NS_LOG_DEBUG("from duration, extract sifi="<<GetSifs ());
+ if (blockAck->IsBasic ())
+ {
+ duration -= GetBlockAckDuration (originator, blockAckReqTxVector, BASIC_BLOCK_ACK);
+ NS_LOG_DEBUG("from duration,extract baisc block ack duration="<<GetBlockAckDuration (originator, blockAckReqTxVector, BASIC_BLOCK_ACK));
+ }
+ else if (blockAck->IsCompressed ())
+ {
+ duration -= GetBlockAckDuration (originator, blockAckReqTxVector, COMPRESSED_BLOCK_ACK);
+ NS_LOG_DEBUG("from duration,extract compressed block ack duration="<<GetBlockAckDuration (originator, blockAckReqTxVector, BASIC_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, blockAckReqTxVector);
+ }
+ m_txParams.DisableNextData ();
+
+ if (!immediate)
+ {
+ StartDataTxTimers (blockAckReqTxVector);
+ }
+
+ 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);
+ WifiPreamble preamble;
+ if (blockAckReqTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT)
+ {
+ preamble = WIFI_PREAMBLE_HT_MF;
+ }
+ else
+ {
+ preamble = WIFI_PREAMBLE_LONG;
+ }
+ ForwardDown (packet, &hdr, blockAckReqTxVector, preamble);
+ m_currentPacket = 0;
+}
+
+void
+MacLow::SendBlockAckAfterAmpdu (uint8_t tid, Mac48Address originator, Time duration, WifiTxVector blockAckReqTxVector)
+{
+ NS_LOG_FUNCTION (this);
+ CtrlBAckResponseHeader blockAck;
+ uint16_t seqNumber = 0;
+ BlockAckCachesI i = m_bAckCaches.find (std::make_pair (originator, tid));
+ NS_ASSERT (i != m_bAckCaches.end ());
+ seqNumber = (*i).second.GetWinStart ();
+
+ bool immediate = true;
+ AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid));
+ blockAck.SetStartingSequence (seqNumber);
+ blockAck.SetTidInfo (tid);
+ immediate = (*it).second.first.IsImmediateBlockAck ();
+ blockAck.SetType (COMPRESSED_BLOCK_ACK);
+ NS_LOG_DEBUG ("Got Implicit block Ack Req with seq " << seqNumber);
+ (*i).second.FillBlockAckBitmap (&blockAck);
+
+ SendBlockAckResponse (&blockAck, originator, immediate, duration, blockAckReqTxVector.GetMode ());
+}
+
+void
+MacLow::SendBlockAckAfterBlockAckRequest (const CtrlBAckRequestHeader reqHdr, Mac48Address originator,
+ Time duration, WifiMode blockAckReqTxMode)
+{
+ NS_LOG_FUNCTION (this);
+ CtrlBAckResponseHeader blockAck;
+ uint8_t tid = 0;
+ bool immediate = false;
+ if (!reqHdr.IsMultiTid ())
+ {
+ tid = reqHdr.GetTidInfo ();
+ AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid));
+ if (it != m_bAckAgreements.end ())
+ {
+ blockAck.SetStartingSequence (reqHdr.GetStartingSequence ());
+ blockAck.SetTidInfo (tid);
+ immediate = (*it).second.first.IsImmediateBlockAck ();
+ if (reqHdr.IsBasic ())
+ {
+ blockAck.SetType (BASIC_BLOCK_ACK);
+ }
+ else if (reqHdr.IsCompressed ())
+ {
+ blockAck.SetType (COMPRESSED_BLOCK_ACK);
+ }
+ BlockAckCachesI i = m_bAckCaches.find (std::make_pair (originator, tid));
+ NS_ASSERT (i != m_bAckCaches.end ());
+ (*i).second.FillBlockAckBitmap (&blockAck);
+ NS_LOG_DEBUG ("Got block Ack Req with seq " << reqHdr.GetStartingSequence ());
+
+ if (!m_stationManager->HasHtSupported () && !m_stationManager->HasVhtSupported ())
+ {
+ /* All packets with smaller sequence than starting sequence control must be passed up to Wifimac
+ * See 9.10.3 in IEEE 802.11e standard.
+ */
+ RxCompleteBufferedPacketsWithSmallerSequence (reqHdr.GetStartingSequenceControl (), originator, tid);
+ RxCompleteBufferedPacketsUntilFirstLost (originator, tid);
+ }
+ else
+ {
+ if (!QosUtilsIsOldPacket ((*it).second.first.GetStartingSequence (), reqHdr.GetStartingSequence ()))
+ {
+ (*it).second.first.SetStartingSequence (reqHdr.GetStartingSequence ());
+ (*it).second.first.SetWinEnd (((*it).second.first.GetStartingSequence () + (*it).second.first.GetBufferSize () - 1) % 4096);
+ RxCompleteBufferedPacketsWithSmallerSequence (reqHdr.GetStartingSequenceControl (), originator, tid);
+ RxCompleteBufferedPacketsUntilFirstLost (originator, tid);
+ (*it).second.first.SetWinEnd (((*it).second.first.GetStartingSequence () + (*it).second.first.GetBufferSize () - 1) % 4096);
+ }
+ }
+ }
+ 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 ());
+ AcIndex ac = QosUtilsMapTidToAc (agreement.GetTid ());
+ agreement.m_inactivityEvent = Simulator::Schedule (timeout,
+ &MacLowAggregationCapableTransmissionListener::BlockAckInactivityTimeout,
+ m_edcaListeners[ac],
+ agreement.GetPeer (),
+ agreement.GetTid ());
+ }
+}
+
+void
+MacLow::RegisterBlockAckListenerForAc (enum AcIndex ac, MacLowAggregationCapableTransmissionListener *listener)
+{
+ m_edcaListeners.insert (std::make_pair (ac, listener));
+}
+
+void
+MacLow::SetMpduAggregator (Ptr<MpduAggregator> aggregator)
+{
+ m_mpduAggregator = aggregator;
+}
+
+Ptr<MpduAggregator>
+MacLow::GetMpduAggregator (void)
+{
+ return m_mpduAggregator;
+}
+
+void
+MacLow::DeaggregateAmpduAndReceive (Ptr<Packet> aggregatedPacket, double rxSnr, WifiTxVector txVector, WifiPreamble preamble)
+{
+#ifndef WITH_MORE_FIX_TO_BA_IN_MAC_LOW
+ m_currentTxVector = txVector;
+#endif
+ NS_LOG_FUNCTION (this);
+ AmpduTag ampdu;
+ bool normalAck = false;
+ bool ampduSubframe = false; //flag indicating the packet belongs to an A-MPDU and is not a VHT single MPDU
+ if (aggregatedPacket->RemovePacketTag (ampdu))
+ {
+ ampduSubframe = true;
+#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW
+ m_currentTxVector = txVector;
+#endif
+ MpduAggregator::DeaggregatedMpdus packets = MpduAggregator::Deaggregate (aggregatedPacket);
+ MpduAggregator::DeaggregatedMpdusCI n = packets.begin ();
+
+ WifiMacHeader firsthdr;
+ (*n).first->PeekHeader (firsthdr);
+ NS_LOG_DEBUG ("duration/id=" << firsthdr.GetDuration ());
+ NotifyNav ((*n).first, firsthdr, preamble);
+
+ bool vhtSingleMpdu = (*n).second.GetEof ();
+ if (vhtSingleMpdu == true)
+ {
+ //If the MPDU is sent as a VHT single MPDU (EOF=1 in A-MPDU subframe header), then the responder sends an ACK.
+ NS_LOG_DEBUG ("Receive VHT single MPDU");
+ ampduSubframe = false;
+ }
+
+ if (firsthdr.GetAddr1 () == m_self)
+ {
+#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW
+ if (!vhtSingleMpdu)
+ {
+ m_receivedAtLeastOneMpdu = true;
+ m_lastmpduFrom=firsthdr.GetAddr2();
+ }
+#else
+ m_receivedAtLeastOneMpdu = true;
+#endif
+ if (firsthdr.IsAck () || firsthdr.IsBlockAck () || firsthdr.IsBlockAckReq ())
+ {
+ ReceiveOk ((*n).first, rxSnr, txVector, preamble, ampduSubframe);
+ }
+ else if (firsthdr.IsData () || firsthdr.IsQosData ())
+ {
+ NS_LOG_DEBUG ("Deaggregate packet from " << firsthdr.GetAddr2 () << " with sequence=" << firsthdr.GetSequenceNumber ());
+ ReceiveOk ((*n).first, rxSnr, txVector, preamble, ampduSubframe);
+ if (firsthdr.IsQosAck ())
+ {
+ NS_LOG_DEBUG ("Normal Ack");
+ normalAck = true;
+ }
+ }
+ else
+ {
+ NS_FATAL_ERROR ("Received A-MPDU with invalid first MPDU type");
+ }
+ }
+#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW
+ if (ampdu.GetNoOfMpdus () == 1 && !vhtSingleMpdu)
+#else
+ if (normalAck && (ampdu.GetNoOfMpdus () == 1) && !vhtSingleMpdu)
+#endif
+ {
+#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW
+ if (normalAck)
+ {
+#endif
+ //send block Ack
+ if (firsthdr.IsBlockAckReq ())
+ {
+ NS_FATAL_ERROR ("Sending a BlockAckReq with QosPolicy equal to Normal Ack");
+ }
+ uint8_t tid = firsthdr.GetQosTid ();
+ AgreementsI it = m_bAckAgreements.find (std::make_pair (firsthdr.GetAddr2 (), tid));
+ if (it != m_bAckAgreements.end ())
+ {
+ NS_ASSERT (m_sendAckEvent.IsExpired ());
+ /* See section 11.5.3 in IEEE 802.11 for mean of this timer */
+ ResetBlockAckInactivityTimerIfNeeded (it->second.first);
+ NS_LOG_DEBUG ("rx A-MPDU/sendImmediateBlockAck from=" << firsthdr.GetAddr2 ());
+ m_sendAckEvent = Simulator::Schedule (GetSifs (),
+ &MacLow::SendBlockAckAfterAmpdu, this,
+ firsthdr.GetQosTid (),
+ firsthdr.GetAddr2 (),
+ firsthdr.GetDuration (),
+ txVector);
+ }
+ else
+ {
+ NS_LOG_DEBUG ("There's not a valid agreement for this block ack request.");
+ }
+#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW
+ }
+#endif
+ m_receivedAtLeastOneMpdu = false;
+ }
+ }
+ else
+ {
+ ReceiveOk (aggregatedPacket, rxSnr, txVector, preamble, ampduSubframe);
+ }
+}
+
+bool
+MacLow::StopMpduAggregation (Ptr<const Packet> peekedPacket, WifiMacHeader peekedHdr, Ptr<Packet> aggregatedPacket, uint16_t size) const
+{
+ WifiPreamble preamble;
+ WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr);
+ if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_VHT)
+ {
+ preamble = WIFI_PREAMBLE_VHT;
+ }
+ else if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
+ {
+ preamble = WIFI_PREAMBLE_HT_GF;
+ }
+ else if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT)
+ {
+ preamble = WIFI_PREAMBLE_HT_MF;
+ }
+ else
+ {
+ preamble = WIFI_PREAMBLE_LONG;
+ }
+
+ if (peekedPacket == 0)
+ {
+ NS_LOG_DEBUG ("no more packets in queue");
+ return true;
+ }
+
+ NS_LOG_DEBUG("in stopMpduAgg check, peeked size="<<peekedPacket->GetSize()<<", aggregated size="<<aggregatedPacket->GetSize());
+
+
+ //An HT STA shall not transmit a PPDU that has a duration that is greater than aPPDUMaxTime (10 milliseconds)
+ if (m_phy->CalculateTxDuration (aggregatedPacket->GetSize () + peekedPacket->GetSize () + peekedHdr.GetSize () + WIFI_MAC_FCS_LENGTH, dataTxVector, preamble, m_phy->GetFrequency (), 0, 0) > MilliSeconds (10))
+ {
+ NS_LOG_DEBUG ("no more packets can be aggregated to satisfy PPDU <= aPPDUMaxTime");
+ return true;
+ }
+
+ if (!m_mpduAggregator->CanBeAggregated (peekedPacket->GetSize () + peekedHdr.GetSize () + WIFI_MAC_FCS_LENGTH, aggregatedPacket, size))
+ {
+ NS_LOG_DEBUG ("no more packets can be aggregated because the maximum A-MPDU size has been reached");
+ return true;
+ }
+
+ return false;
+}
+
+Ptr<Packet>
+MacLow::AggregateToAmpdu (Ptr<const Packet> packet, const WifiMacHeader hdr)
+{
+ NS_LOG_DEBUG("come into Aggregate to Ampdu procedure in mac low");
+ NS_ASSERT (m_aggregateQueue->GetSize () == 0);
+ bool isAmpdu = false;
+ Ptr<Packet> newPacket, tempPacket;
+ WifiMacHeader peekedHdr;
+ newPacket = packet->Copy ();
+ Ptr<Packet> currentAggregatedPacket;
+ //missing hdr.IsAck() since we have no means of knowing the Tid of the Ack yet
+ if (hdr.IsQosData () || hdr.IsBlockAck ()|| hdr.IsBlockAckReq ())
+ {
+ Time tstamp;
+ uint8_t tid = GetTid (packet, hdr);
+ Ptr<WifiMacQueue> queue;
+ AcIndex ac = QosUtilsMapTidToAc (tid);
+ //since a blockack agreement always preceeds mpdu aggregation there should always exist blockAck listener
+ std::map<AcIndex, MacLowAggregationCapableTransmissionListener*>::const_iterator listenerIt = m_edcaListeners.find (ac);
+ NS_ASSERT (listenerIt != m_edcaListeners.end ());
+ queue = listenerIt->second->GetQueue ();
+
+ if (!hdr.GetAddr1 ().IsBroadcast () && m_mpduAggregator != 0)
+ {
+ //Have to make sure that their exist a block Ack agreement before sending an AMPDU (BlockAck Manager)
+ if (listenerIt->second->GetBlockAckAgreementExists (hdr.GetAddr1 (), tid))
+ {
+ /* here is performed mpdu aggregation */
+ /* MSDU aggregation happened in edca if the user asked for it so m_currentPacket may contains a normal packet or a A-MSDU*/
+ currentAggregatedPacket = Create<Packet> ();
+ peekedHdr = hdr;
+ uint16_t startingSequenceNumber = 0;
+ uint16_t currentSequenceNumber = 0;
+ uint8_t qosPolicy = 0;
+ uint16_t blockAckSize = 0;
+ bool aggregated = false;
+ int i = 0;
+ Ptr<Packet> aggPacket = newPacket->Copy ();
+
+ if (!hdr.IsBlockAckReq ())
+ {
+ if (!hdr.IsBlockAck ())
+ {
+ startingSequenceNumber = peekedHdr.GetSequenceNumber ();
+ peekedHdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK);
+ }
+ currentSequenceNumber = peekedHdr.GetSequenceNumber ();
+ newPacket->AddHeader (peekedHdr);
+ WifiMacTrailer fcs;
+ newPacket->AddTrailer (fcs);
+
+ aggregated = m_mpduAggregator->Aggregate (newPacket, currentAggregatedPacket);
+
+ NS_LOG_DEBUG("QUEUE SIZE="<<queue->GetSize());
+ if (aggregated)
+ {
+ NS_LOG_DEBUG ("first, Adding packet with Sequence number " << peekedHdr.GetSequenceNumber () << " to A-MPDU, packet size = " << newPacket->GetSize () << ", A-MPDU size = " << currentAggregatedPacket->GetSize ());
+ i++;
+ m_sentMpdus++;
+ m_aggregateQueue->Enqueue (aggPacket, peekedHdr);
+ }
+ }
+ else if (hdr.IsBlockAckReq ())
+ {
+ blockAckSize = packet->GetSize () + hdr.GetSize () + WIFI_MAC_FCS_LENGTH;
+ qosPolicy = 3; //if the last subrame is block ack req then set ack policy of all frames to blockack
+ CtrlBAckRequestHeader blockAckReq;
+ packet->PeekHeader (blockAckReq);
+ startingSequenceNumber = blockAckReq.GetStartingSequence ();
+ }
+ aggregated = false;
+ bool retry = false;
+ //looks for other packets to the same destination with the same Tid need to extend that to include MSDUs
+ Ptr<const Packet> peekedPacket = listenerIt->second->PeekNextPacketInBaQueue (peekedHdr, peekedHdr.GetAddr1 (), tid, &tstamp);
+ if (peekedPacket == 0)
+ {
+ peekedPacket = queue->PeekByTidAndAddress (&peekedHdr, tid,
+ WifiMacHeader::ADDR1,
+ hdr.GetAddr1 (), &tstamp);
+ currentSequenceNumber = listenerIt->second->PeekNextSequenceNumberfor (&peekedHdr);
+
+ /* here is performed MSDU aggregation (two-level aggregation) */
+ if (peekedPacket != 0 && listenerIt->second->GetMsduAggregator () != 0)
+ {
+ tempPacket = PerformMsduAggregation (peekedPacket, &peekedHdr, &tstamp, currentAggregatedPacket, blockAckSize);
+ if (tempPacket != 0) //MSDU aggregation
+ {
+ peekedPacket = tempPacket->Copy ();
+ }
+ }
+ }
+ else
+ {
+ retry = true;
+ currentSequenceNumber = peekedHdr.GetSequenceNumber ();
+ }
+
+ NS_LOG_DEBUG("before coming into loop, queue size="<<queue->GetSize());
+ while (IsInWindow (currentSequenceNumber, startingSequenceNumber, 64) && !StopMpduAggregation (peekedPacket, peekedHdr, currentAggregatedPacket, blockAckSize))
+ {
+ NS_LOG_DEBUG("come into loop");
+ //for now always send AMPDU with normal ACK
+ if (retry == false)
+ {
+ currentSequenceNumber = listenerIt->second->GetNextSequenceNumberfor (&peekedHdr);
+ peekedHdr.SetSequenceNumber (currentSequenceNumber);
+ peekedHdr.SetFragmentNumber (0);
+ peekedHdr.SetNoMoreFragments ();
+ peekedHdr.SetNoRetry ();
+ }
+ if (qosPolicy == 0)
+ {
+ NS_LOG_DEBUG("QOS policy=0, set normal ack");
+ peekedHdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK);
+ }
+ else
+ {
+ peekedHdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK);
+ }
+
+ newPacket = peekedPacket->Copy ();
+ Ptr<Packet> aggPacket = newPacket->Copy ();
+
+ newPacket->AddHeader (peekedHdr);
+ WifiMacTrailer fcs;
+ newPacket->AddTrailer (fcs);
+ aggregated = m_mpduAggregator->Aggregate (newPacket, currentAggregatedPacket);
+ if (aggregated)
+ {
+ m_aggregateQueue->Enqueue (aggPacket, peekedHdr);
+ if (i == 1 && hdr.IsQosData ())
+ {
+ if (!m_txParams.MustSendRts ())
+ {
+ listenerIt->second->CompleteMpduTx (packet, hdr, tstamp);
+ }
+ else
+ {
+ InsertInTxQueue (packet, hdr, tstamp);
+ }
+ }
+ NS_LOG_DEBUG ("second, Adding packet with Sequence number " << peekedHdr.GetSequenceNumber () << " to A-MPDU, packet size = " << newPacket->GetSize () << ", A-MPDU size = " << currentAggregatedPacket->GetSize ());
+ i++;
+ isAmpdu = true;
+ m_sentMpdus++;
+ if (!m_txParams.MustSendRts ())
+ {
+ listenerIt->second->CompleteMpduTx (peekedPacket, peekedHdr, tstamp);
+ }
+ else
+ {
+ InsertInTxQueue (peekedPacket, peekedHdr, tstamp);
+ }
+ if (retry)
+ {
+ listenerIt->second->RemoveFromBaQueue (tid, hdr.GetAddr1 (), peekedHdr.GetSequenceNumber ());
+ }
+ else
+ {
+ queue->Remove (peekedPacket);
+ }
+ newPacket = 0;
+ }
+ else
+ {
+ break;
+ }
+ if (retry == true)
+ {
+ peekedPacket = listenerIt->second->PeekNextPacketInBaQueue (peekedHdr, hdr.GetAddr1 (), tid, &tstamp);
+ if (peekedPacket == 0)
+ {
+ //I reached the first packet that I added to this A-MPDU
+ retry = false;
+ peekedPacket = queue->PeekByTidAndAddress (&peekedHdr, tid,
+ WifiMacHeader::ADDR1, hdr.GetAddr1 (), &tstamp);
+ if (peekedPacket != 0)
+ {
+ //find what will the sequence number be so that we don't send more than 64 packets apart
+ currentSequenceNumber = listenerIt->second->PeekNextSequenceNumberfor (&peekedHdr);
+
+ if (listenerIt->second->GetMsduAggregator () != 0)
+ {
+ tempPacket = PerformMsduAggregation (peekedPacket, &peekedHdr, &tstamp, currentAggregatedPacket, blockAckSize);
+ if (tempPacket != 0) //MSDU aggregation
+ {
+ peekedPacket = tempPacket->Copy ();
+ }
+ }
+ }
+ }
+ else
+ {
+ currentSequenceNumber = peekedHdr.GetSequenceNumber ();
+ }
+ }
+ else
+ {
+ peekedPacket = queue->PeekByTidAndAddress (&peekedHdr, tid,
+ WifiMacHeader::ADDR1, hdr.GetAddr1 (), &tstamp);
+ if (peekedPacket != 0)
+ {
+ //find what will the sequence number be so that we don't send more than 64 packets apart
+ currentSequenceNumber = listenerIt->second->PeekNextSequenceNumberfor (&peekedHdr);
+
+ if (listenerIt->second->GetMsduAggregator () != 0 && IsInWindow (currentSequenceNumber, startingSequenceNumber, 64))
+ {
+ tempPacket = PerformMsduAggregation (peekedPacket, &peekedHdr, &tstamp, currentAggregatedPacket, blockAckSize);
+ if (tempPacket != 0) //MSDU aggregation
+ {
+ peekedPacket = tempPacket->Copy ();
+ }
+ }
+ }
+ }
+ }
+
+ if (isAmpdu)
+ {
+ if (hdr.IsBlockAckReq ())
+ {
+ newPacket = packet->Copy ();
+ peekedHdr = hdr;
+ Ptr<Packet> aggPacket = newPacket->Copy ();
+ m_aggregateQueue->Enqueue (aggPacket, peekedHdr);
+ newPacket->AddHeader (peekedHdr);
+ WifiMacTrailer fcs;
+ newPacket->AddTrailer (fcs);
+ m_mpduAggregator->Aggregate (newPacket, currentAggregatedPacket);
+ }
+ if (qosPolicy == 0)
+ {
+ listenerIt->second->CompleteTransfer (hdr.GetAddr1 (), tid);
+ }
+ //Add packet tag
+ AmpduTag ampdutag;
+ ampdutag.SetAmpdu (true);
+ ampdutag.SetNoOfMpdus (i);
+ newPacket = currentAggregatedPacket;
+ newPacket->AddPacketTag (ampdutag);
+ NS_LOG_DEBUG ("tx unicast A-MPDU");
+ listenerIt->second->SetAmpdu (true);
+ }
+ else
+ {
+ uint32_t queueSize = m_aggregateQueue->GetSize ();
+ NS_ASSERT (queueSize <= 2); //since it is not an A-MPDU then only 2 packets should have been added to the queue no more
+ if (queueSize >= 1)
+ {
+ //remove any packets that we added to the aggregate queue
+ FlushAggregateQueue ();
+ }
+ }
+ }
+ //VHT single MPDU operation
+ WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr);
+ if (!isAmpdu && dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_VHT && hdr.IsQosData ())
+ {
+ peekedHdr = hdr;
+ peekedHdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK);
+
+ currentAggregatedPacket = Create<Packet> ();
+ m_mpduAggregator->AggregateVhtSingleMpdu (packet, currentAggregatedPacket);
+ m_aggregateQueue->Enqueue (packet, peekedHdr);
+ m_sentMpdus = 1;
+
+ if (listenerIt->second->GetBlockAckAgreementExists (hdr.GetAddr1 (), tid))
+ {
+ listenerIt->second->CompleteTransfer (peekedHdr.GetAddr1 (), tid);
+ }
+
+ //Add packet tag
+ AmpduTag ampdutag;
+ ampdutag.SetAmpdu (true);
+ ampdutag.SetNoOfMpdus (1);
+
+ newPacket = currentAggregatedPacket;
+ newPacket->AddHeader (peekedHdr);
+ WifiMacTrailer fcs;
+ newPacket->AddTrailer (fcs);
+ newPacket->AddPacketTag (ampdutag);
+
+ NS_LOG_DEBUG ("tx unicast VHT single MPDU with sequence number " << hdr.GetSequenceNumber ());
+ listenerIt->second->SetAmpdu (true);
+ }
+ }
+ NS_LOG_DEBUG ("after AMPDU aggregation complete, number of packets let in the qos queue is "<<queue->GetSize());
+
+ }
+ return newPacket;
+}
+
+void
+MacLow::FlushAggregateQueue (void)
+{
+ if (m_aggregateQueue->GetSize () > 0)
+ {
+ NS_LOG_DEBUG ("Flush aggregate queue");
+ m_aggregateQueue->Flush ();
+ }
+ m_txPackets.clear ();
+}
+
+void
+MacLow::FlushAggregateQueue (Mac48Address destAddress)
+{
+ WifiMacHeader hdr;
+ m_aggregateQueue->Peek(&hdr);
+ if(hdr.GetAddr1()==destAddress)
+ this->FlushAggregateQueue();
+}
+
+void
+MacLow::InsertInTxQueue (Ptr<const Packet> packet, const WifiMacHeader &hdr, Time tStamp)
+{
+ Item item;
+
+ item.packet = packet;
+ item.hdr = hdr;
+ item.timestamp = tStamp;
+
+ m_txPackets.push_back (item);
+}
+
+Ptr<Packet>
+MacLow::PerformMsduAggregation (Ptr<const Packet> packet, WifiMacHeader *hdr, Time *tstamp, Ptr<Packet> currentAmpduPacket, uint16_t blockAckSize)
+{
+ NS_LOG_DEBUG("come into perform Msdu aggregation");
+ bool msduAggregation = false;
+ bool isAmsdu = false;
+ Ptr<Packet> currentAmsduPacket = Create<Packet> ();
+ Ptr<Packet> tempPacket = Create<Packet> ();
+
+ Ptr<WifiMacQueue> queue;
+ AcIndex ac = QosUtilsMapTidToAc (GetTid (packet, *hdr));
+ std::map<AcIndex, MacLowAggregationCapableTransmissionListener*>::const_iterator listenerIt = m_edcaListeners.find (ac);
+ NS_ASSERT (listenerIt != m_edcaListeners.end ());
+ queue = listenerIt->second->GetQueue ();
+
+ NS_LOG_DEBUG("with queue size="<<queue->GetSize());
+
+ Ptr<const Packet> peekedPacket = queue->DequeueByTidAndAddress (hdr, hdr->GetQosTid (),
+ WifiMacHeader::ADDR1, hdr->GetAddr1 ());
+
+ listenerIt->second->GetMsduAggregator ()->Aggregate (packet, currentAmsduPacket,
+ listenerIt->second->GetSrcAddressForAggregation (*hdr),
+ listenerIt->second->GetDestAddressForAggregation (*hdr));
+
+ peekedPacket = queue->PeekByTidAndAddress (hdr, hdr->GetQosTid (),
+ WifiMacHeader::ADDR1, hdr->GetAddr1 (), tstamp);
+ NS_LOG_DEBUG("before coming into loop of PerformMsduAggregation, left packets in the queue="<<queue->GetSize());
+ while (peekedPacket != 0)
+ {
+ NS_LOG_DEBUG("come into loop of PerformMsduAggregation");
+
+ tempPacket = currentAmsduPacket;
+
+ msduAggregation = listenerIt->second->GetMsduAggregator ()->Aggregate (peekedPacket, tempPacket,
+ listenerIt->second->GetSrcAddressForAggregation (*hdr),
+ listenerIt->second->GetDestAddressForAggregation (*hdr));
+
+ if(currentAmsduPacket==tempPacket)
+ NS_LOG_DEBUG("after aggregate, it is the same");
+ else
+ NS_LOG_DEBUG("after aggregate, it is different\n");
+ if (msduAggregation && !StopMpduAggregation (tempPacket, *hdr, currentAmpduPacket, blockAckSize))
+ {
+ isAmsdu = true;
+ currentAmsduPacket = tempPacket;
+ queue->Remove (peekedPacket);
+ NS_LOG_DEBUG("MSDU aggregate, left packets in the queue="<<queue->GetSize());
+ }
+ else
+ {
+ NS_LOG_DEBUG("stopped aggregation.");
+ if(currentAmsduPacket==tempPacket)
+ NS_LOG_DEBUG("it is the same");
+ else
+ NS_LOG_DEBUG("it is different\n");
+ break;
+ }
+ if(currentAmsduPacket==tempPacket)
+ NS_LOG_DEBUG("no advance");
+ else
+ NS_LOG_DEBUG("temp is in advance");
+ peekedPacket = queue->PeekByTidAndAddress (hdr, hdr->GetQosTid (), WifiMacHeader::ADDR1, hdr->GetAddr1 (), tstamp);
+ }
+
+ if (isAmsdu)
+ {
+ NS_LOG_DEBUG ("A-MSDU with size = " << currentAmsduPacket->GetSize ());
+ hdr->SetQosAmsdu ();
+ hdr->SetAddr3 (GetBssid ());
+ return currentAmsduPacket;
+ }
+ else
+ {
+ NS_LOG_DEBUG("no AMSDU, left packets in the queue="<<queue->GetSize());
+ NS_LOG_DEBUG("push front and return 0");
+ queue->PushFront (packet, *hdr);
+ return 0;
+ }
+}
+
+} //namespace ns3
diff --git a/emu-radio/ns3-patch/wifi/model/mac-low.h b/emu-radio/ns3-patch/wifi/model/mac-low.h
new file mode 100644
index 00000000..9e849b51
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/mac-low.h
@@ -0,0 +1,1404 @@
+/* -*- 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
+ * 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: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Author: Mirko Banchi <mk.banchi@gmail.com>
+ */
+#ifndef MAC_LOW_H
+#define MAC_LOW_H
+
+#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"
+#include "block-ack-cache.h"
+#include "wifi-tx-vector.h"
+#include "mpdu-aggregator.h"
+#include "msdu-aggregator.h"
+
+#define WITH_MORE_FIX_TO_BA_IN_MAC_LOW 1
+#define WITHOUT_BA_RESPONSE_WHEN_LAST_AMPDU_FAIL 1
+
+class TwoLevelAggregationTest;
+
+namespace ns3 {
+
+class WifiPhy;
+class WifiMac;
+class EdcaTxopN;
+class WifiMacQueue;
+
+/**
+ * \ingroup wifi
+ * \brief listen to events coming from ns3::MacLow.
+ */
+class MacLowTransmissionListener
+{
+public:
+ MacLowTransmissionListener ();
+ virtual ~MacLowTransmissionListener ();
+
+ /**
+ * \param snr the snr of the cts
+ * \param txMode the txMode of the cts
+ *
+ * ns3::MacLow received an expected CTS within
+ * CtsTimeout.
+ */
+ virtual void GotCts (double snr, WifiMode txMode) = 0;
+ /**
+ * ns3::MacLow did not receive an expected CTS
+ * within CtsTimeout.
+ */
+ virtual void MissedCts (void) = 0;
+ /**
+ * \param snr the snr of the ack
+ * \param txMode the transmission mode of the ack
+ *
+ * ns3::MacLow received an expected ACK within
+ * AckTimeout. The <i>snr</i> and <i>txMode</i>
+ * arguments are not valid when SUPER_FAST_ACK is
+ * used.
+ */
+ virtual void GotAck (double snr, WifiMode txMode) = 0;
+ /**
+ * ns3::MacLow did not receive an expected ACK within
+ * AckTimeout.
+ */
+ virtual void MissedAck (void) = 0;
+ /**
+ * \param blockAck Block ack response header
+ * \param source Address of block ack sender
+ * \param txMode mode of block ack response
+ *
+ * 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, WifiMode txMode);
+ /**
+ * 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.
+ * The listener is expected to call again MacLow::StartTransmission
+ * with the "next" data to send.
+ */
+ virtual void StartNext (void) = 0;
+ /**
+ * Invoked if this transmission was canceled
+ * one way or another. When this method is invoked,
+ * you can assume that the packet has not been passed
+ * down the stack to the PHY.
+ */
+ virtual void Cancel (void) = 0;
+ /**
+ * Invoked upon the end of the transmission of a frame that does not
+ * require an ACK (e.g., broadcast and multicast frames).
+ *
+ */
+ virtual void EndTxNoAck (void) = 0;
+};
+
+
+/**
+ * \brief listen to NAV events
+ * \ingroup wifi
+ *
+ * This class is typically connected to an instance of ns3::Dcf
+ * and calls to its methods are forwards to the corresponding
+ * ns3::Dcf methods.
+ */
+class MacLowDcfListener
+{
+public:
+ MacLowDcfListener ();
+ virtual ~MacLowDcfListener ();
+ /**
+ * Norify that NAV has started for the given duration.
+ *
+ * \param duration duration of NAV timer
+ */
+ virtual void NavStart (Time duration) = 0;
+ /**
+ * Notify that NAV has resetted.
+ *
+ * \param duration duration of NAV timer
+ */
+ virtual void NavReset (Time duration) = 0;
+ /**
+ * Notify that ACK timeout has started for a given duration.
+ *
+ * \param duration duration of ACK timeout
+ */
+ virtual void AckTimeoutStart (Time duration) = 0;
+ /**
+ * Notify that ACK timeout has resetted.
+ */
+ virtual void AckTimeoutReset () = 0;
+ /**
+ * Notify that CTS timeout has started for a given duration.
+ *
+ * \param duration duration of CTS timeout
+ */
+ virtual void CtsTimeoutStart (Time duration) = 0;
+ /**
+ * Notify that CTS timeout has resetted.
+ */
+ virtual void CtsTimeoutReset () = 0;
+};
+
+/**
+ * \ingroup wifi
+ * \brief listen for block ack events.
+ */
+class MacLowAggregationCapableTransmissionListener
+{
+public:
+ MacLowAggregationCapableTransmissionListener ();
+ virtual ~MacLowAggregationCapableTransmissionListener ();
+ /**
+ * 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.
+ *
+ * \param originator MAC address of the data originator
+ * \param tid
+ */
+ virtual void BlockAckInactivityTimeout (Mac48Address originator, uint8_t tid) = 0;
+ /**
+ * Returns the EDCA queue to check if there are packets that can be aggregated with a Block Ack
+ */
+ virtual Ptr<WifiMacQueue> GetQueue (void) = 0;
+ /**
+ * \param address address of peer station involved in block ack mechanism.
+ * \param tid traffic ID of transmitted packet.
+ *
+ * Calls CompleteAmpduTransfer that resets the status of OriginatorBlockAckAgreement after the transfer
+ * of an A-MPDU with ImmediateBlockAck policy (i.e. no BAR is scheduled)
+ */
+ virtual void CompleteTransfer (Mac48Address address, uint8_t tid);
+ virtual void SetAmpdu (bool ampdu);
+ /**
+ * This function stores an MPDU (part of an A-MPDU) in blockackagreement (i.e. the sender is waiting
+ * for a blockack containing the sequence number of this MPDU).
+ * It also calls NotifyMpdu transmission that updates the status of OriginatorBlockAckAgreement.
+ */
+ virtual void CompleteMpduTx (Ptr<const Packet> packet, WifiMacHeader hdr, Time tstamp);
+ /**
+ * Return the next sequence number for the given header.
+ *
+ * \param hdr Wi-Fi header
+ * \return the next sequence number
+ */
+ virtual uint16_t GetNextSequenceNumberfor (WifiMacHeader *hdr);
+ /**
+ * Return the next sequence number for the Traffic ID and destination, but do not pick it (i.e. the current sequence number remains unchanged).
+ *
+ * \param hdr Wi-Fi header
+ * \return the next sequence number
+ */
+ virtual uint16_t PeekNextSequenceNumberfor (WifiMacHeader *hdr);
+ /*
+ * Peek in retransmit queue and get the next packet without removing it from the queue
+ */
+ virtual Ptr<const Packet> PeekNextPacketInBaQueue (WifiMacHeader &header, Mac48Address recipient, uint8_t tid, Time *timestamp);
+ /**
+ * Remove a packet after you peek in the retransmit queue and get it
+ */
+ virtual void RemoveFromBaQueue (uint8_t tid, Mac48Address recipient, uint16_t seqnumber);
+ /**
+ * \param recipient address of the peer station
+ * \param tid traffic ID.
+ * \return true if a block ack agreement exists, false otherwise
+ *
+ * Checks if a block ack agreement exists with station addressed by
+ * <i>recipient</i> for tid <i>tid</i>.
+ */
+ virtual bool GetBlockAckAgreementExists (Mac48Address address, uint8_t tid) = 0;
+ /**
+ * \param recipient address of peer station involved in block ack mechanism.
+ * \param tid traffic ID.
+ * \return the number of packets buffered for a specified agreement
+ *
+ * Returns number of packets buffered for a specified agreement.
+ */
+ virtual uint32_t GetNOutstandingPackets (Mac48Address recipient, uint8_t tid);
+ /**
+ * \param recipient address of peer station involved in block ack mechanism.
+ * \param tid traffic ID.
+ * \return the number of packets for a specific agreement that need retransmission
+ *
+ * Returns number of packets for a specific agreement that need retransmission.
+ */
+ virtual uint32_t GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const;
+ /**
+ */
+ virtual Ptr<MsduAggregator> GetMsduAggregator (void) const;
+ /**
+ */
+ virtual Mac48Address GetSrcAddressForAggregation (const WifiMacHeader &hdr);
+ /**
+ */
+ virtual Mac48Address GetDestAddressForAggregation (const WifiMacHeader &hdr);
+};
+
+/**
+ * \brief control how a packet is transmitted.
+ * \ingroup wifi
+ *
+ * The ns3::MacLow::StartTransmission method expects
+ * an instance of this class to describe how the packet
+ * should be transmitted.
+ */
+class MacLowTransmissionParameters
+{
+public:
+ MacLowTransmissionParameters ();
+
+ /**
+ * Wait ACKTimeout for an ACK. If we get an ACK
+ * on time, call MacLowTransmissionListener::GotAck.
+ * Call MacLowTransmissionListener::MissedAck otherwise.
+ */
+ void EnableAck (void);
+ /**
+ * - wait PIFS after end-of-tx. If idle, call
+ * MacLowTransmissionListener::MissedAck.
+ * - if busy at end-of-tx+PIFS, wait end-of-rx
+ * - if Ack ok at end-of-rx, call
+ * MacLowTransmissionListener::GotAck.
+ * - if Ack not ok at end-of-rx, report call
+ * MacLowTransmissionListener::MissedAck
+ * at end-of-rx+SIFS.
+ *
+ * This is really complicated but it is needed for
+ * proper HCCA support.
+ */
+ void EnableFastAck (void);
+ /**
+ * - if busy at end-of-tx+PIFS, call
+ * MacLowTransmissionListener::GotAck
+ * - if idle at end-of-tx+PIFS, call
+ * 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
+ * and send data. Otherwise, call MacLowTransmissionListener::MissedCts
+ * and do not send data.
+ */
+ void EnableRts (void);
+ /**
+ * \param size size of next data to send after current packet is
+ * sent.
+ *
+ * Add the transmission duration of the next data to the
+ * durationId of the outgoing packet and call
+ * MacLowTransmissionListener::StartNext at the end of
+ * the current transmission + SIFS.
+ */
+ void EnableNextData (uint32_t size);
+ /**
+ * \param durationId the value to set in the duration/Id field of
+ * the outgoing packet.
+ *
+ * Ignore all other durationId calculation and simply force the
+ * packet's durationId field to this value.
+ */
+ void EnableOverrideDurationId (Time durationId);
+ /**
+ * Do not wait for Ack after data transmission. Typically
+ * used for Broadcast and multicast frames.
+ */
+ void DisableAck (void);
+ /**
+ * Do not send rts and wait for cts before sending data.
+ */
+ void DisableRts (void);
+ /**
+ * Do not attempt to send data burst after current transmission
+ */
+ void DisableNextData (void);
+ /**
+ * Do not force the duration/id field of the packet: its
+ * value is automatically calculated by the MacLow before
+ * calling WifiPhy::Send.
+ */
+ void DisableOverrideDurationId (void);
+ /**
+ * \returns true if must wait for ACK after data transmission,
+ * false otherwise.
+ *
+ * This methods returns true when any of MustWaitNormalAck,
+ * MustWaitFastAck, or MustWaitSuperFastAck return true.
+ */
+ bool MustWaitAck (void) const;
+ /**
+ * \returns true if normal ACK protocol should be used, false
+ * otherwise.
+ *
+ * \sa EnableAck
+ */
+ bool MustWaitNormalAck (void) const;
+ /**
+ * \returns true if fast ack protocol should be used, false
+ * otherwise.
+ *
+ * \sa EnableFastAck
+ */
+ bool MustWaitFastAck (void) const;
+ /**
+ * \returns true if super fast ack protocol should be used, false
+ * otherwise.
+ *
+ * \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.
+ */
+ bool MustSendRts (void) const;
+ /**
+ * \returns true if a duration/id was forced with
+ * EnableOverrideDurationId, false otherwise.
+ */
+ bool HasDurationId (void) const;
+ /**
+ * \returns the duration/id forced by EnableOverrideDurationId
+ */
+ Time GetDurationId (void) const;
+ /**
+ * \returns true if EnableNextData was called, false otherwise.
+ */
+ bool HasNextPacket (void) const;
+ /**
+ * \returns the size specified by EnableNextData.
+ */
+ uint32_t GetNextPacketSize (void) const;
+
+private:
+ friend std::ostream &operator << (std::ostream &os, const MacLowTransmissionParameters &params);
+ uint32_t m_nextSize;
+ enum
+ {
+ ACK_NONE,
+ ACK_NORMAL,
+ ACK_FAST,
+ ACK_SUPER_FAST,
+ BLOCK_ACK_BASIC,
+ BLOCK_ACK_COMPRESSED,
+ BLOCK_ACK_MULTI_TID
+ } m_waitAck;
+ bool m_sendRts;
+ Time m_overrideDurationId;
+};
+
+/**
+ * Serialize MacLowTransmissionParameters to ostream in a human-readable form.
+ *
+ * \param os std::ostream
+ * \param params MacLowTransmissionParameters
+ * \return std::ostream
+ */
+std::ostream &operator << (std::ostream &os, const MacLowTransmissionParameters &params);
+
+
+/**
+ * \ingroup wifi
+ * \brief handle RTS/CTS/DATA/ACK transactions.
+ */
+class MacLow : public Object
+{
+public:
+ // Allow test cases to access private members
+ friend class ::TwoLevelAggregationTest;
+ /**
+ * typedef for a callback for MacLowRx
+ */
+ typedef Callback<void, Ptr<Packet>, const WifiMacHeader*> MacLowRxCallback;
+
+ MacLow ();
+ virtual ~MacLow ();
+
+ /**
+ * Register this type.
+ * \return The TypeId.
+ */
+ static TypeId GetTypeId (void);
+
+ /**
+ * Set up WifiPhy associated with this MacLow.
+ *
+ * \param phy WifiPhy associated with this MacLow
+ */
+ void SetPhy (Ptr<WifiPhy> phy);
+ /*
+ * \return current attached PHY device
+ */
+ Ptr<WifiPhy> GetPhy (void) const;
+ /**
+ * Remove WifiPhy associated with this MacLow.
+ *
+ * \param phy WifiPhy associated with this MacLow
+ */
+ void ResetPhy (void);
+ /**
+ * Set up WifiRemoteStationManager associated with this MacLow.
+ *
+ * \param manager WifiRemoteStationManager associated with this MacLow
+ */
+ void SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> manager);
+ /**
+ * Set up MpduAggregator associated with this MacLow.
+ *
+ * \param aggregator MpduAggregator associated with this MacLow
+ */
+ void SetMpduAggregator (Ptr<MpduAggregator> aggregator);
+ /**
+ *
+ * \return the attached MpduAggregator
+ */
+ Ptr<MpduAggregator> GetMpduAggregator (void);
+ /**
+ * Set MAC address of this MacLow.
+ *
+ * \param ad Mac48Address of this MacLow
+ */
+ void SetAddress (Mac48Address ad);
+ /**
+ * Set ACK timeout of this MacLow.
+ *
+ * \param ackTimeout ACK timeout of this MacLow
+ */
+ void SetAckTimeout (Time ackTimeout);
+ /**
+ * Set Basic Block ACK timeout of this MacLow.
+ *
+ * \param blockAckTimeout Basic Block ACK timeout of this MacLow
+ */
+ void SetBasicBlockAckTimeout (Time blockAckTimeout);
+ /**
+ * Set Compressed Block ACK timeout of this MacLow.
+ *
+ * \param blockAckTimeout Compressed Block ACK timeout of this MacLow
+ */
+ void SetCompressedBlockAckTimeout (Time blockAckTimeout);
+ /**
+ * Enable or disable CTS-to-self capability.
+ *
+ * \param enable Enable or disable CTS-to-self capability
+ */
+ void SetCtsToSelfSupported (bool enable);
+ /**
+ * Set CTS timeout of this MacLow.
+ *
+ * \param ctsTimeout CTS timeout of this MacLow
+ */
+ void SetCtsTimeout (Time ctsTimeout);
+ /**
+ * Set Short Interframe Space (SIFS) of this MacLow.
+ *
+ * \param sifs SIFS of this MacLow
+ */
+ void SetSifs (Time sifs);
+ /**
+ * Set Reduced Interframe Space (RIFS) of this MacLow.
+ *
+ * \param rifs RIFS of this MacLow
+ */
+ void SetRifs (Time rifs);
+ /**
+ * Set slot duration of this MacLow.
+ *
+ * \param slotTime slot duration of this MacLow
+ */
+ void SetSlotTime (Time slotTime);
+ /**
+ * Set PCF Interframe Space (PIFS) of this MacLow.
+ *
+ * \param pifs PIFS of this MacLow
+ */
+ void SetPifs (Time pifs);
+ /**
+ * Set the Basic Service Set Identification.
+ *
+ * \param ad the BSSID
+ */
+ void SetBssid (Mac48Address ad);
+ /**
+ * Enable promiscuous mode.
+ */
+ void SetPromisc (void);
+ /**
+ * Return whether CTS-to-self capability is supported.
+ *
+ * \return true if CTS-to-self is supported, false otherwise
+ */
+ bool GetCtsToSelfSupported () const;
+ /**
+ * Return the MAC address of this MacLow.
+ *
+ * \return Mac48Address of this MacLow
+ */
+ Mac48Address GetAddress (void) const;
+ /**
+ * Return ACK timeout of this MacLow.
+ *
+ * \return ACK timeout
+ */
+ Time GetAckTimeout (void) const;
+ /**
+ * Return Basic Block ACK timeout of this MacLow.
+ *
+ * \return Basic Block ACK timeout
+ */
+ Time GetBasicBlockAckTimeout () const;
+ /**
+ * Return Compressed Block ACK timeout of this MacLow.
+ *
+ * \return Compressed Block ACK timeout
+ */
+ Time GetCompressedBlockAckTimeout () const;
+ /**
+ * Return CTS timeout of this MacLow.
+ *
+ * \return CTS timeout
+ */
+ Time GetCtsTimeout (void) const;
+ /**
+ * Return Short Interframe Space (SIFS) of this MacLow.
+ *
+ * \return SIFS
+ */
+ Time GetSifs (void) const;
+ /**
+ * Return slot duration of this MacLow.
+ *
+ * \return slot duration
+ */
+ Time GetSlotTime (void) const;
+ /**
+ * Return PCF Interframe Space (PIFS) of this MacLow.
+ *
+ * \return PIFS
+ */
+ Time GetPifs (void) const;
+ /**
+ * Return Reduced Interframe Space (RIFS) of this MacLow.
+ *
+ * \return RIFS
+ */
+ Time GetRifs (void) const;
+ /**
+ * Return the Basic Service Set Identification.
+ *
+ * \return BSSID
+ */
+ Mac48Address GetBssid (void) const;
+ /**
+ * Check if MacLow is operating in promiscuous mode.
+ *
+ * \return true if MacLow is operating in promiscuous mode,
+ * false otherwise
+ */
+ bool IsPromisc (void) const;
+
+ /**
+ * \param callback the callback which receives every incoming packet.
+ *
+ * This callback typically forwards incoming packets to
+ * an instance of ns3::MacRxMiddle.
+ */
+ void SetRxCallback (Callback<void,Ptr<Packet>,const WifiMacHeader *> callback);
+ /**
+ * \param listener listen to NAV events for every incoming
+ * and outgoing packet.
+ */
+ void RegisterDcfListener (MacLowDcfListener *listener);
+
+ /**
+ * \param packet to send (does not include the 802.11 MAC header and checksum)
+ * \param hdr header associated to the packet to send.
+ * \param parameters transmission parameters of packet.
+ * \return the transmission time that includes the time for the next packet transmission
+ *
+ * This transmission time includes the time required for
+ * the next packet transmission if one was selected.
+ */
+ Time CalculateTransmissionTime (Ptr<const Packet> packet,
+ const WifiMacHeader* hdr,
+ const MacLowTransmissionParameters& parameters) const;
+
+ /**
+ * \param packet packet to send
+ * \param hdr 802.11 header for packet to send
+ * \param parameters the transmission parameters to use for this packet.
+ * \param listener listen to transmission events.
+ *
+ * Start the transmission of the input packet and notify the listener
+ * of transmission events.
+ */
+ virtual void StartTransmission (Ptr<const Packet> packet,
+ const WifiMacHeader* hdr,
+ MacLowTransmissionParameters parameters,
+ MacLowTransmissionListener *listener);
+
+ /**
+ * \param packet packet received
+ * \param rxSnr snr of packet received
+ * \param txVector TXVECTOR of packet received
+ * \param preamble type of preamble used for the packet received
+ * \param ampduSubframe true if this MPDU is part of an A-MPDU
+ *
+ * This method is typically invoked by the lower PHY layer to notify
+ * the MAC layer that a packet was successfully received.
+ */
+ void ReceiveOk (Ptr<Packet> packet, double rxSnr, WifiTxVector txVector, WifiPreamble preamble, bool ampduSubframe);
+ /**
+ * \param packet packet received.
+ * \param rxSnr snr of packet received.
+ *
+ * This method is typically invoked by the lower PHY layer to notify
+ * the MAC layer that a packet was unsuccessfully received.
+ */
+ void ReceiveError (Ptr<const Packet> packet, double rxSnr);
+ /**
+ * \param duration switching delay duration.
+ *
+ * This method is typically invoked by the PhyMacLowListener to notify
+ * the MAC layer that a channel switching occured. When a channel switching
+ * occurs, pending MAC transmissions (RTS, CTS, DATA and ACK) are cancelled.
+ */
+ void NotifySwitchingStartNow (Time duration);
+ /**
+ * This method is typically invoked by the PhyMacLowListener to notify
+ * the MAC layer that the device has been put into sleep mode. When the device is put
+ * into sleep mode, pending MAC transmissions (RTS, CTS, DATA and ACK) are cancelled.
+ */
+ void NotifySleepNow (void);
+ /**
+ * \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::RegularWifiMac
+ * when the STA (which may be non-AP in ESS, or in an IBSS) has
+ * received an ADDBA Request frame and is transmitting an ADDBA
+ * Response frame. At this point MacLow must allocate buffers to
+ * collect all correctly received packets belonging to the category
+ * for which Block Ack was negotiated.
+ */
+ void CreateBlockAckAgreement (const MgtAddBaResponseHeader *respHdr,
+ Mac48Address originator,
+ uint16_t startingSeq);
+ /**
+ * \param originator Address of peer participating 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 AcIndex ac, MacLowAggregationCapableTransmissionListener *listener);
+ /**
+ * \param packet the packet to be aggregated. If the aggregation is succesfull, it corresponds either to the first data packet that will be aggregated or to the BAR that will be piggybacked at the end of the A-MPDU.
+ * \param hdr the WifiMacHeader for the packet.
+ * \return the A-MPDU packet if aggregation is successfull, the input packet otherwise
+ *
+ * This function adds the packets that will be added to an A-MPDU to an aggregate queue
+ *
+ */
+ Ptr<Packet> AggregateToAmpdu (Ptr<const Packet> packet, const WifiMacHeader hdr);
+ /**
+ * \param aggregatedPacket which is the current A-MPDU
+ * \param rxSnr snr of packet received
+ * \param txVector TXVECTOR of packet received
+ * \param preamble type of preamble used for the packet received
+ *
+ * This function de-aggregates an A-MPDU and decide if each MPDU is received correctly or not
+ *
+ */
+ void DeaggregateAmpduAndReceive (Ptr<Packet> aggregatedPacket, double rxSnr, WifiTxVector txVector, WifiPreamble preamble);
+ /**
+ * \param peekedPacket the packet to be aggregated
+ * \param peekedHdr the WifiMacHeader for the packet.
+ * \param aggregatedPacket the current A-MPDU
+ * \param size the size of a piggybacked block ack request
+ * \return false if the given packet can be added to an A-MPDU, true otherwise
+ *
+ * This function decides if a given packet can be added to an A-MPDU or not
+ *
+ */
+ bool StopMpduAggregation (Ptr<const Packet> peekedPacket, WifiMacHeader peekedHdr, Ptr<Packet> aggregatedPacket, uint16_t size) const;
+ /**
+ *
+ * This function is called to flush the aggregate queue, which is used for A-MPDU
+ *
+ */
+ void FlushAggregateQueue (void);
+
+ /** an overload of FlushAggregateQueue
+ * this function will check the destination address of packets in the aggregate queue, before flushing it.
+ * if the destination address is the same as that of given as parameter, the function flushes the aggregate
+ * queue, otherwise it does no operation.
+ * \param destAddress the given destination address, to be compared with that of packets in the aggregate queue
+ */
+
+ void FlushAggregateQueue (Mac48Address destAddress);
+
+protected:
+ /**
+ * Return a TXVECTOR for the DATA frame given the destination.
+ * The function consults WifiRemoteStationManager, which controls the rate
+ * to different destinations.
+ *
+ * \param packet the packet being asked for TXVECTOR
+ * \param hdr the WifiMacHeader
+ * \return TXVECTOR for the given packet
+ */
+ virtual WifiTxVector GetDataTxVector (Ptr<const Packet> packet, const WifiMacHeader *hdr) const;
+private:
+ /**
+ * Cancel all scheduled events. Called before beginning a transmission
+ * or switching channel.
+ */
+ void CancelAllEvents (void);
+ /**
+ * Return the total ACK size (including FCS trailer).
+ *
+ * \return the total ACK size
+ */
+ uint32_t GetAckSize (void) const;
+ /**
+ * Return the total Block ACK size (including FCS trailer).
+ *
+ * \param type the Block ACK type
+ * \return the total Block ACK size
+ */
+ uint32_t GetBlockAckSize (enum BlockAckType type) const;
+ /**
+ * Return the total RTS size (including FCS trailer).
+ *
+ * \return the total RTS size
+ */
+ uint32_t GetRtsSize (void) const;
+ /**
+ * Return the total CTS size (including FCS trailer).
+ *
+ * \return the total CTS size
+ */
+ uint32_t GetCtsSize (void) const;
+ /**
+ * Return the total size of the packet after WifiMacHeader and FCS trailer
+ * have been added.
+ *
+ * \param packet the packet to be encapsulated with WifiMacHeader and FCS trailer
+ * \param hdr the WifiMacHeader
+ * \return the total packet size
+ */
+ uint32_t GetSize (Ptr<const Packet> packet, const WifiMacHeader *hdr) const;
+ /**
+ * Forward the packet down to WifiPhy for transmission. This is called for the entire A-MPDu when MPDU aggregation is used.
+ *
+ * \param packet
+ * \param hdr
+ * \param txVector
+ * \param preamble
+ */
+ void ForwardDown (Ptr<const Packet> packet, const WifiMacHeader *hdr,
+ WifiTxVector txVector, WifiPreamble preamble);
+ /**
+ * Forward the packet down to WifiPhy for transmission. This is called for each MPDU when MPDU aggregation is used.
+ *
+ * \param packet
+ * \param hdr
+ * \param txVector
+ * \param preamble
+ * \param packetType
+ * \param mpduReferenceNumber
+ */
+ void SendPacket (Ptr<const Packet> packet, WifiTxVector txVector, WifiPreamble preamble, uint8_t packetType, uint32_t mpduReferenceNumber);
+ /**
+ * Return a TXVECTOR for the RTS frame given the destination.
+ * The function consults WifiRemoteStationManager, which controls the rate
+ * to different destinations.
+ *
+ * \param packet the packet being asked for RTS TXVECTOR
+ * \param hdr the WifiMacHeader
+ * \return TXVECTOR for the RTS of the given packet
+ */
+ WifiTxVector GetRtsTxVector (Ptr<const Packet> packet, const WifiMacHeader *hdr) const;
+ /**
+ * Return a TXVECTOR for the CTS frame given the destination and the mode of the RTS
+ * used by the sender.
+ * The function consults WifiRemoteStationManager, which controls the rate
+ * to different destinations.
+ *
+ * \param to the MAC address of the CTS receiver
+ * \param rtsTxMode the mode of the RTS used by the sender
+ * \return TXVECTOR for the CTS
+ */
+ WifiTxVector GetCtsTxVector (Mac48Address to, WifiMode rtsTxMode) const;
+ /**
+ * Return a TXVECTOR for the ACK frame given the destination and the mode of the DATA
+ * used by the sender.
+ * The function consults WifiRemoteStationManager, which controls the rate
+ * to different destinations.
+ *
+ * \param to the MAC address of the ACK receiver
+ * \param dataTxMode the mode of the DATA used by the sender
+ * \return TXVECTOR for the ACK
+ */
+ WifiTxVector GetAckTxVector (Mac48Address to, WifiMode dataTxMode) const;
+ /**
+ * Return a TXVECTOR for the Block ACK frame given the destination and the mode of the DATA
+ * used by the sender.
+ * The function consults WifiRemoteStationManager, which controls the rate
+ * to different destinations.
+ *
+ * \param to the MAC address of the Block ACK receiver
+ * \param dataTxMode the mode of the DATA used by the sender
+ * \return TXVECTOR for the Block ACK
+ */
+ WifiTxVector GetBlockAckTxVector (Mac48Address to, WifiMode dataTxMode) const;
+ /**
+ * Return a TXVECTOR for the CTS-to-self frame.
+ * The function consults WifiRemoteStationManager, which controls the rate
+ * to different destinations.
+ *
+ * \param packet the packet that requires CTS-to-self
+ * \param hdr the Wifi header of the packet
+ * \return TXVECTOR for the CTS-to-self operation
+ */
+ WifiTxVector GetCtsToSelfTxVector (Ptr<const Packet> packet, const WifiMacHeader *hdr) const;
+ /**
+ * Return a TXVECTOR for the CTS frame given the destination and the mode of the RTS
+ * used by the sender.
+ * The function consults WifiRemoteStationManager, which controls the rate
+ * to different destinations.
+ *
+ * \param to the MAC address of the CTS receiver
+ * \param rtsTxMode the mode of the RTS used by the sender
+ * \return TXVECTOR for the CTS
+ */
+ WifiTxVector GetCtsTxVectorForRts (Mac48Address to, WifiMode rtsTxMode) const;
+ /**
+ * Return a TXVECTOR for the Block ACK frame given the destination and the mode of the DATA
+ * used by the sender.
+ * The function consults WifiRemoteStationManager, which controls the rate
+ * to different destinations.
+ *
+ * \param to the MAC address of the Block ACK receiver
+ * \param dataTxMode the mode of the DATA used by the sender
+ * \return TXVECTOR for the Block ACK
+ */
+ WifiTxVector GetAckTxVectorForData (Mac48Address to, WifiMode dataTxMode) const;
+ /**
+ * Return the time required to transmit the CTS (including preamble and FCS).
+ *
+ * \param ctsTxVector
+ * \return the time required to transmit the CTS (including preamble and FCS)
+ */
+ Time GetCtsDuration (WifiTxVector ctsTxVector) const;
+ /**
+ * Return the time required to transmit the CTS to the specified address
+ * given the TXVECTOR of the RTS (including preamble and FCS).
+ *
+ * \param to
+ * \param rtsTxVector
+ * \return the time required to transmit the CTS (including preamble and FCS)
+ */
+ Time GetCtsDuration (Mac48Address to, WifiTxVector rtsTxVector) const;
+ /**
+ * Return the time required to transmit the ACK (including preamble and FCS).
+ *
+ * \param ackTxVector
+ * \return the time required to transmit the ACK (including preamble and FCS)
+ */
+ Time GetAckDuration (WifiTxVector ackTxVector) const;
+ /**
+ * Return the time required to transmit the ACK to the specified address
+ * given the TXVECTOR of the DATA (including preamble and FCS).
+ *
+ * \param to
+ * \param dataTxVector
+ * \return the time required to transmit the ACK (including preamble and FCS)
+ */
+ Time GetAckDuration (Mac48Address to, WifiTxVector dataTxVector) const;
+ /**
+ * Return the time required to transmit the Block ACK to the specified address
+ * given the TXVECTOR of the BAR (including preamble and FCS).
+ *
+ * \param to
+ * \param dataTxVector
+ * \param type the Block ACK type
+ * \return the time required to transmit the Block ACK (including preamble and FCS)
+ */
+ Time GetBlockAckDuration (Mac48Address to, WifiTxVector blockAckReqTxVector, enum BlockAckType type) const;
+ /**
+ * Check if the current packet should be sent with a RTS protection.
+ *
+ * \return true if RTS protection should be used,
+ * false otherwise
+ */
+ bool NeedRts (void);
+ /**
+ * Check if CTS-to-self mechanism should be used for the current packet.
+ *
+ * \return true if CTS-to-self mechanism should be used for the current packet,
+ * false otherwise
+ */
+ bool NeedCtsToSelf (void);
+
+ Time CalculateOverallTxTime (Ptr<const Packet> packet,
+ const WifiMacHeader* hdr,
+ const MacLowTransmissionParameters &params) const;
+ void NotifyNav (Ptr<const Packet> packet,const WifiMacHeader &hdr, WifiPreamble preamble);
+ /**
+ * Reset NAV with the given duration.
+ *
+ * \param duration
+ */
+ void DoNavResetNow (Time duration);
+ /**
+ * Start NAV with the given duration.
+ *
+ * \param duration
+ * \return true if NAV is resetted
+ */
+ bool DoNavStartNow (Time duration);
+ /**
+ * Check if NAV is zero.
+ *
+ * \return true if NAV is zero,
+ * false otherwise
+ */
+ bool IsNavZero (void) const;
+ /**
+ * Notify DcfManager (via DcfListener) that
+ * ACK timer should be started for the given
+ * duration.
+ *
+ * \param duration
+ */
+ void NotifyAckTimeoutStartNow (Time duration);
+ /**
+ * Notify DcfManager (via DcfListener) that
+ * ACK timer should be resetted.
+ */
+ void NotifyAckTimeoutResetNow ();
+ /**
+ * Notify DcfManager (via DcfListener) that
+ * CTS timer should be started for the given
+ * duration.
+ *
+ * \param duration
+ */
+ void NotifyCtsTimeoutStartNow (Time duration);
+ /**
+ * Notify DcfManager (via DcfListener) that
+ * CTS timer should be resetted.
+ */
+ void NotifyCtsTimeoutResetNow ();
+ /**
+ * Reset NAV after CTS was missed when the NAV was
+ * setted with RTS.
+ *
+ * \param rtsEndRxTime
+ */
+ void NavCounterResetCtsMissed (Time rtsEndRxTime);
+ /* Event handlers */
+ /**
+ * Event handler when normal ACK timeout occurs.
+ */
+ void NormalAckTimeout (void);
+ /**
+ * Event handler when fast ACK timeout occurs (idle).
+ */
+ void FastAckTimeout (void);
+ /**
+ * Event handler when super fast ACK timeout occurs.
+ */
+ void SuperFastAckTimeout (void);
+ /**
+ * Event handler when fast ACK timeout occurs (busy).
+ */
+ void FastAckFailedTimeout (void);
+ /**
+ * Event handler when block ACK timeout occurs.
+ */
+ void BlockAckTimeout (void);
+ /**
+ * Event handler when CTS timeout occurs.
+ */
+ void CtsTimeout (void);
+ /**
+ * Send CTS for a CTS-to-self mechanism.
+ */
+ void SendCtsToSelf (void);
+ /**
+ * Send CTS after receiving RTS.
+ *
+ * \param source
+ * \param duration
+ * \param rtsTxVector
+ * \param rtsSnr
+ */
+ void SendCtsAfterRts (Mac48Address source, Time duration, WifiTxVector rtsTxVector, double rtsSnr);
+ /**
+ * Send ACK after receiving DATA.
+ *
+ * \param source
+ * \param duration
+ * \param dataTxMode
+ * \param dataSnr
+ */
+ void SendAckAfterData (Mac48Address source, Time duration, WifiMode dataTxMode, double dataSnr);
+ /**
+ * Send DATA after receiving CTS.
+ *
+ * \param source
+ * \param duration
+ */
+ void SendDataAfterCts (Mac48Address source, Time duration);
+ /**
+ * Event handler that is usually scheduled to fired at the appropriate time
+ * after completing transmissions.
+ */
+ void WaitSifsAfterEndTx (void);
+ /**
+ * A transmission that does not require an ACK has completed.
+ */
+ void EndTxNoAck (void);
+ /**
+ * Send RTS to begin RTS-CTS-DATA-ACK transaction.
+ */
+ void SendRtsForPacket (void);
+ /**
+ * Send DATA packet, which can be DATA-ACK or
+ * RTS-CTS-DATA-ACK transaction.
+ */
+ void SendDataPacket (void);
+ /**
+ * Start a DATA timer by scheduling appropriate
+ * ACK timeout.
+ *
+ * \param dataTxVector
+ */
+ void StartDataTxTimers (WifiTxVector dataTxVector);
+
+ virtual void DoDispose (void);
+
+ /**
+ * \param packet packet to check
+ * \param hdr 802.11 header for packet to check
+ *
+ * Returns Tid of different packet types
+ */
+ uint8_t GetTid (Ptr<const Packet> packet, const WifiMacHeader hdr) const;
+ /**
+ * \param originator Address of peer participating in Block Ack mechanism.
+ * \param tid TID for which Block Ack was created.
+ * \param seq Starting sequence control
+ *
+ * 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 participating 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 or missing MSDU.
+ * See section 9.10.4 in IEEE 802.11 standard for more details.
+ */
+ void RxCompleteBufferedPacketsUntilFirstLost (Mac48Address originator, uint8_t tid);
+ /**
+ * \param seq MPDU sequence number
+ * \param winstart sequence number window start
+ * \param winsize the size of the sequence number window (currently default is 64)
+ * This method checks if the MPDU's sequence number is inside the scoreboard boundaries or not
+ */
+ bool IsInWindow (uint16_t seq, uint16_t winstart, uint16_t winsize);
+ /**
+ * This method updates the reorder buffer and the scoreboard when an MPDU is received in an HT station
+ * and sotres the MPDU if needed when an MPDU is received in an non-HT Station (implements HT
+ * immediate block Ack)
+ */
+ bool ReceiveMpdu (Ptr<Packet> packet, WifiMacHeader hdr);
+ /**
+ * 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.
+ *
+ * \param reqHdr
+ * \param originator
+ * \param duration
+ * \param blockAckReqTxMode
+ */
+ void SendBlockAckAfterBlockAckRequest (const CtrlBAckRequestHeader reqHdr, Mac48Address originator,
+ Time duration, WifiMode blockAckReqTxMode);
+ /**
+ * Invoked after an A-MPDU has been received. Looks for corresponding
+ * block ack agreement and creates block ack bitmap on a received packets basis.
+ */
+ void SendBlockAckAfterAmpdu (uint8_t tid, Mac48Address originator,
+ Time duration, WifiTxVector blockAckReqTxVector);
+ /**
+ * This method creates block ack frame with header equals to <i>blockAck</i> and start its transmission.
+ *
+ * \param blockAck
+ * \param originator
+ * \param immediate
+ * \param duration
+ * \param blockAckReqTxMode
+ */
+ 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 IEEE 802.11e for more details.
+ *
+ * \param agreement
+ */
+ void ResetBlockAckInactivityTimerIfNeeded (BlockAckAgreement &agreement);
+
+ /**
+ * Set up WifiPhy listener for this MacLow.
+ *
+ * \param phy the WifiPhy this MacLow is connected to
+ */
+ void SetupPhyMacLowListener (Ptr<WifiPhy> phy);
+ /**
+ * Remove current WifiPhy listener for this MacLow.
+ *
+ * \param phy the WifiPhy this MacLow is connected to
+ */
+ void RemovePhyMacLowListener (Ptr<WifiPhy> phy);
+ /**
+ * Checks if the given packet will be aggregated to an A-MPDU or not
+ *
+ * \param packet packet to check whether it can be aggregated in an A-MPDU
+ * \param hdr 802.11 header for packet to check whether it can be aggregated in an A-MPDU
+ *
+ */
+ bool IsAmpdu (Ptr<const Packet> packet, const WifiMacHeader hdr);
+ /**
+ * Insert in a temporary queue.
+ * It is only used with a RTS/CTS exchange for an A-MPDU transmission.
+ */
+ void InsertInTxQueue (Ptr<const Packet> packet, const WifiMacHeader &hdr, Time tStamp);
+ /**
+ * Perform MSDU aggregation for a given MPDU in an A-MPDU
+ *
+ * \param packet packet picked for aggregation
+ * \param hdr 802.11 header for packet picked for aggregation
+ * \param tstamp timestamp
+ * \param currentAmpduPacket current A-MPDU packet
+ * \param blockAckSize size of the piggybacked block ack request
+ *
+ * \return the aggregate if MSDU aggregation succeeded, 0 otherwise
+ */
+ Ptr<Packet> PerformMsduAggregation (Ptr<const Packet> packet, WifiMacHeader *hdr, Time *tstamp, Ptr<Packet> currentAmpduPacket, uint16_t blockAckSize);
+
+ Ptr<WifiPhy> m_phy; //!< Pointer to WifiPhy (actually send/receives frames)
+ Ptr<WifiRemoteStationManager> m_stationManager; //!< Pointer to WifiRemoteStationManager (rate control)
+ MacLowRxCallback m_rxCallback; //!< Callback to pass packet up
+
+ /**
+ * A struct for packet, Wifi header, and timestamp.
+ */
+ typedef struct
+ {
+ Ptr<const Packet> packet;
+ WifiMacHeader hdr;
+ Time timestamp;
+ } Item;
+
+ /**
+ * typedef for an iterator for a list of MacLowDcfListener.
+ */
+ typedef std::vector<MacLowDcfListener *>::const_iterator DcfListenersCI;
+ /**
+ * typedef for a list of MacLowDcfListener.
+ */
+ typedef std::vector<MacLowDcfListener *> DcfListeners;
+ DcfListeners m_dcfListeners; //!< List of MacLowDcfListener (pass events to Dcf)
+
+ EventId m_normalAckTimeoutEvent; //!< Normal ACK timeout event
+ EventId m_fastAckTimeoutEvent; //!< Fast ACK timeout event
+ EventId m_superFastAckTimeoutEvent; //!< Super fast ACK timeout event
+ EventId m_fastAckFailedTimeoutEvent; //!< Fast ACK failed timeout event
+ EventId m_blockAckTimeoutEvent; //!< Block ACK timeout event
+ EventId m_ctsTimeoutEvent; //!< CTS timeout event
+ EventId m_sendCtsEvent; //!< Event to send CTS
+ EventId m_sendAckEvent; //!< Event to send ACK
+ EventId m_sendDataEvent; //!< Event to send DATA
+ EventId m_waitSifsEvent; //!< Wait for SIFS event
+ EventId m_endTxNoAckEvent; //!< Event for finishing transmission that does not require ACK
+ EventId m_navCounterResetCtsMissed; //!< Event to reset NAV when CTS is not received
+ EventId m_waitRifsEvent; //!< Wait for RIFS event
+
+ Ptr<MpduAggregator> m_mpduAggregator; //!<
+
+ Ptr<Packet> m_currentPacket; //!< Current packet transmitted/to be transmitted
+ WifiMacHeader m_currentHdr; //!< Header of the current packet
+ MacLowTransmissionParameters m_txParams; //!< Transmission parameters of the current packet
+ MacLowTransmissionListener *m_listener; //!< Transmission listener for the current packet
+ Mac48Address m_self; //!< Address of this MacLow (Mac48Address)
+ Mac48Address m_bssid; //!< BSSID address (Mac48Address)
+ Time m_ackTimeout; //!< ACK timeout duration
+ Time m_basicBlockAckTimeout; //!< Basic block ACK timeout duration
+ Time m_compressedBlockAckTimeout; //!< Compressed block ACK timeout duration
+ Time m_ctsTimeout; //!< CTS timeout duration
+ Time m_sifs; //!< Short Interframe Space (SIFS) duration
+ Time m_slotTime; //!< Slot duration
+ Time m_pifs; //!< PCF Interframe Space (PIFS) duration
+ Time m_rifs; //!< Reduced Interframe Space (RIFS) duration
+
+ Time m_lastNavStart; //!< The time when the latest NAV started
+ Time m_lastNavDuration; //!< The duration of the latest NAV
+
+ bool m_promisc; //!< Flag if the device is operating in promiscuous mode
+ bool m_ampdu; //!< Flag if the current transmission involves an A-MPDU
+
+ class PhyMacLowListener * m_phyMacLowListener; //!< Listener needed to monitor when a channel switching occurs.
+
+ /*
+ * 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;
+
+ typedef std::map<AgreementKey, BlockAckCache> BlockAckCaches;
+ typedef std::map<AgreementKey, BlockAckCache>::iterator BlockAckCachesI;
+
+ Agreements m_bAckAgreements;
+ BlockAckCaches m_bAckCaches;
+
+ typedef std::map<AcIndex, MacLowAggregationCapableTransmissionListener*> QueueListeners;
+ QueueListeners m_edcaListeners;
+ bool m_ctsToSelfSupported; //!< Flag whether CTS-to-self is supported
+ uint8_t m_sentMpdus; //!< Number of transmitted MPDUs in an A-MPDU that have not been acknowledged yet
+ Ptr<WifiMacQueue> m_aggregateQueue; //!< Queue used for MPDU aggregation
+ WifiTxVector m_currentTxVector; //!< TXVECTOR used for the current packet transmission
+ bool m_receivedAtLeastOneMpdu; //!< Flag whether an MPDU has already been successfully received while receiving an A-MPDU
+ std::vector<Item> m_txPackets; //!< Contain temporary items to be sent with the next A-MPDU transmission, once RTS/CTS exchange has succeeded. It is not used in other cases.
+ uint32_t m_mpduReferenceNumber; //!< A-MPDU reference number to identify all subframes belonging to the same A-MPDU
+
+#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW
+ Mac48Address m_lastmpduFrom;
+#endif
+};
+
+} //namespace ns3
+
+#endif /* MAC_LOW_H */
diff --git a/emu-radio/ns3-patch/wifi/model/minstrel-ht-wifi-manager.cc b/emu-radio/ns3-patch/wifi/model/minstrel-ht-wifi-manager.cc
new file mode 100644
index 00000000..ff773004
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/minstrel-ht-wifi-manager.cc
@@ -0,0 +1,1127 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2015 Ghada Badawy
+ *
+ * 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: Ghada Badawy <gbadawy@gmail.com>
+ *
+ * Some Comments:
+ *
+ * 1) Segment Size is declared for completeness but not used because it has
+ * to do more with the requirement of the specific hardware.
+ *
+ * 2) By default, Minstrel applies the multi-rate retry(the core of Minstrel
+ * algorithm). Otherwise, please use ConstantRateWifiManager instead.
+ *
+ * 3) 40Mhz can't fall back to 20MHz
+ *
+ * reference: http://lwn.net/Articles/376765/
+ */
+
+#include "minstrel-ht-wifi-manager.h"
+#include "wifi-phy.h"
+#include "ns3/random-variable-stream.h"
+#include "ns3/simulator.h"
+#include "ns3/log.h"
+#include "ns3/uinteger.h"
+#include "ns3/double.h"
+#include "ns3/wifi-mac.h"
+#include "ns3/assert.h"
+#include <vector>
+
+//newly added
+#include "ns3/ht-wifi-mac-helper.h"
+
+#define Min(a,b) ((a < b) ? a : b)
+
+
+
+
+namespace ns3 {
+
+ NS_LOG_COMPONENT_DEFINE ("MinstrelHtWifiManager");
+
+struct MinstrelHtWifiRemoteStation : public WifiRemoteStation
+{
+ void DisposeStation ();
+ Time m_nextStatsUpdate; ///< 10 times every second
+
+ /**
+ * To keep track of the current position in the our random sample table
+ * going row by row from 1st column until the 10th column(Minstrel defines 10)
+ * then we wrap back to the row 1 col 1.
+ * note: there are many other ways to do this.
+ */
+ uint32_t m_col, m_index;
+ uint32_t m_maxTpRate; ///< the current throughput rate
+ uint32_t m_maxTpRate2; ///< second highest throughput rate
+ uint32_t m_maxProbRate; ///< rate with highest prob of success
+ uint8_t m_maxTpStreams; ///< number of streams for max TP
+ uint8_t m_maxTp2Streams;///< number of streams for max TP2
+ uint8_t m_maxProbStreams;
+
+ int m_packetCount; ///< total number of packets as of now
+ int m_sampleCount; ///< how many packets we have sample so far
+
+ bool m_isSampling; ///< a flag to indicate we are currently sampling
+ uint32_t m_sampleRate; ///< current sample rate
+ bool m_sampleRateSlower; ///< a flag to indicate sample rate is slower
+ uint32_t m_currentRate; ///< current rate we are using
+ uint32_t m_sampleGroup; ///< the group that the sample rate belong to
+ uint8_t m_sampleStreams; ///< the number of streams to use with the sample rate
+
+ uint32_t m_shortRetry; ///< short retries such as control packts
+ uint32_t m_longRetry; ///< long retries such as data packets
+ uint32_t m_retry; ///< total retries short + long
+ uint32_t m_err; ///< retry errors
+ uint32_t m_txrate; ///< current transmit rate
+ uint8_t m_txstreams; ///<current transmit streams
+
+ bool m_initialized; ///< for initializing tables
+
+ // MinstrelRate m_minstrelTable; ///< minstrel table
+ HtSampleRate m_sampleTable; ///< sample table
+ McsGroup m_mcsTable; ///< MCS groups table
+
+ //added by zeng
+ bool m_isNewPacketSent;
+ uint32_t m_txrateToUse;
+};
+
+void
+MinstrelHtWifiRemoteStation::DisposeStation ()
+{
+ std::vector<std::vector<uint32_t> >().swap(m_sampleTable);
+ for (uint8_t j=0; j< m_mcsTable.size();j++)
+ std::vector<struct HtRateInfo>().swap(m_mcsTable[j].m_minstrelTable);
+ std::vector<struct GroupInfo> ().swap(m_mcsTable);
+
+}
+
+NS_OBJECT_ENSURE_REGISTERED (MinstrelHtWifiManager);
+
+TypeId
+MinstrelHtWifiManager::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::MinstrelHtWifiManager")
+ .SetParent<WifiRemoteStationManager> ()
+ .AddConstructor<MinstrelHtWifiManager> ()
+ .AddAttribute ("UpdateStatistics",
+ "The interval between updating statistics table ",
+ TimeValue (Seconds (0.1)),
+ MakeTimeAccessor (&MinstrelHtWifiManager::m_updateStats),
+ MakeTimeChecker ())
+ .AddAttribute ("LookAroundRate",
+ "the percentage to try other rates",
+ DoubleValue (10),
+ MakeDoubleAccessor (&MinstrelHtWifiManager::m_lookAroundRate),
+ MakeDoubleChecker<double> ())
+ .AddAttribute ("EWMA",
+ "EWMA level",
+ DoubleValue (75),
+ MakeDoubleAccessor (&MinstrelHtWifiManager::m_ewmaLevel),
+ MakeDoubleChecker<double> ())
+ .AddAttribute ("SegmentSize",
+ "The largest allowable segment size packet",
+ DoubleValue (6000),
+ MakeDoubleAccessor (&MinstrelHtWifiManager::m_segmentSize),
+ MakeDoubleChecker <double> ())
+ .AddAttribute ("SampleColumn",
+ "The number of columns used for sampling",
+ DoubleValue (10),
+ MakeDoubleAccessor (&MinstrelHtWifiManager::m_sampleCol),
+ MakeDoubleChecker <double> ())
+ .AddAttribute ("PacketLength",
+ "The packet length used for calculating mode TxTime",
+ DoubleValue (65536),
+ MakeDoubleAccessor (&MinstrelHtWifiManager::m_pktLen),
+ MakeDoubleChecker <double> ())
+ .AddTraceSource ("RateChange",
+ "The transmission rate has changed",
+ MakeTraceSourceAccessor (&MinstrelHtWifiManager::m_rateChange),
+ "ns3::MinstrelHtWifiManager::RateChangeTracedCallback")
+ ;
+ return tid;
+}
+
+MinstrelHtWifiManager::MinstrelHtWifiManager ()
+{
+ m_nsupported = 0;
+}
+
+MinstrelHtWifiManager::~MinstrelHtWifiManager ()
+{
+ m_calcTxTime.clear();
+}
+
+void
+MinstrelHtWifiManager::SetupPhy (Ptr<WifiPhy> phy)
+{
+ //8
+ uint32_t nModes = phy->GetNMcs ();
+ for (uint32_t i = 0; i < nModes; i++)
+ {
+ //WifiMode mode = phy->GetMode (i);
+
+ StringValue DataRate = HtWifiMacHelper::DataRateForMcs (i);
+ WifiTxVector txvector;
+ txvector.SetMode(WifiMode(DataRate.Get()));
+ txvector.SetTxPowerLevel(0);
+ txvector.SetShortGuardInterval(phy->GetGuardInterval());
+ txvector.SetNss(1);
+ txvector.SetNess(0);
+ //txvector.SetStbc(phy->GetStbc());
+ txvector.SetStbc(false);
+ WifiPreamble preamble;
+ if (HasHtSupported())
+ preamble= WIFI_PREAMBLE_HT_MF;
+ else
+ preamble= WIFI_PREAMBLE_LONG;
+ AddCalcTxTime (txvector.GetMode(), phy->CalculateTxDuration (m_pktLen, txvector, preamble, phy->GetFrequency(),0,0));
+ }
+ WifiRemoteStationManager::SetupPhy (phy);
+}
+
+Time
+MinstrelHtWifiManager::GetCalcTxTime (WifiMode mode) const
+{
+
+ for (TxTime::const_iterator i = m_calcTxTime.begin (); i != m_calcTxTime.end (); i++)
+ {
+ if (mode == i->second)
+ {
+ return i->first;
+ }
+ }
+ NS_ASSERT (false);
+ return Seconds (0);
+}
+
+void
+MinstrelHtWifiManager::AddCalcTxTime (WifiMode mode, Time t)
+{
+ m_calcTxTime.push_back (std::make_pair (t, mode));
+}
+
+WifiRemoteStation *
+MinstrelHtWifiManager::DoCreateStation (void) const
+{
+ MinstrelHtWifiRemoteStation *station = new MinstrelHtWifiRemoteStation ();
+
+ station->m_nextStatsUpdate = Simulator::Now () + m_updateStats;
+ station->m_col = 0;
+ station->m_index = 0;
+ station->m_maxTpRate = 0;
+ station->m_maxTpRate2 = 0;
+ station->m_maxProbRate = 0;
+ station->m_packetCount = 0;
+ station->m_sampleCount = 0;
+ station->m_isSampling = false;
+ station->m_sampleRate = 0;
+ station->m_sampleRateSlower = false;
+ station->m_currentRate = 0;
+ station->m_shortRetry = 0;
+ station->m_longRetry = 0;
+ station->m_retry = 0;
+ station->m_err = 0;
+ station->m_txrate = 0;
+ station->m_initialized = false;
+ station->m_sampleGroup = 0;
+ station->m_txstreams = 1;
+ station->m_maxTpStreams = 1;
+ station->m_maxTp2Streams = 1;
+ station->m_maxProbStreams = 1;
+ station->m_sampleStreams = 1;
+
+ //added by zeng
+ station->m_isNewPacketSent=false;
+ station->m_txrateToUse = 0;
+
+
+ return station;
+}
+
+void
+MinstrelHtWifiManager::CheckInit (MinstrelHtWifiRemoteStation *station)
+{
+ if (!station->m_initialized && GetNMcsSupported (station) > 1)
+ {
+ // Note: we appear to be doing late initialization of the table
+ // to make sure that the set of supported rates has been initialized
+ // before we perform our own initialization.
+ m_nsupported = GetNMcsSupported(station);
+ //NOTE: to be fixed later, it is hard coded now
+ m_nGroups=1;
+ station->m_mcsTable = McsGroup (m_nGroups);
+ station->m_sampleTable = HtSampleRate (8, std::vector<uint32_t> (m_sampleCol));
+ InitSampleTable (station);
+ RateInit (station);
+ station->m_initialized = true;
+
+ }
+}
+
+void
+MinstrelHtWifiManager::DoReportRxOk (WifiRemoteStation *st,
+ double rxSnr, WifiMode txMode)
+{
+ NS_LOG_DEBUG ("DoReportRxOk m_txrate=" << txMode);
+}
+
+void
+MinstrelHtWifiManager::DoReportRtsFailed (WifiRemoteStation *st)
+{
+ MinstrelHtWifiRemoteStation *station = (MinstrelHtWifiRemoteStation *)st;
+ NS_LOG_DEBUG ("DoReportRtsFailed m_txrate=" << station->m_txrate);
+
+ station->m_shortRetry++;
+}
+
+void
+MinstrelHtWifiManager::DoReportRtsOk (WifiRemoteStation *st, double ctsSnr, WifiMode ctsMode, double rtsSnr)
+{
+ NS_LOG_DEBUG ("self=" << st << " rts ok");
+}
+
+void
+MinstrelHtWifiManager::DoReportFinalRtsFailed (WifiRemoteStation *st)
+{
+ MinstrelHtWifiRemoteStation *station = (MinstrelHtWifiRemoteStation *)st;
+ NS_LOG_DEBUG ("Final RTS failed");
+ UpdateRetry (station);
+ station->m_err++;
+}
+
+uint32_t
+MinstrelHtWifiManager::GetRateId(uint32_t rate)
+{
+ uint32_t id;
+ id = rate % 8;
+ return id;
+}
+uint32_t
+MinstrelHtWifiManager::GetGroupId(uint32_t rate, WifiRemoteStation *st, uint8_t txstreams)
+{
+ uint32_t id;
+ //we have 2 groups if we have SGI else we only have 1 group for 40 or 20MHZ channel BW
+ //NOTE: to be fixed later, it is hard coded now
+ id=0;
+ return id;
+}
+
+void
+MinstrelHtWifiManager::DoReportDataFailed (WifiRemoteStation *st)
+{
+ MinstrelHtWifiRemoteStation *station = (MinstrelHtWifiRemoteStation *)st;
+ /**
+ *
+ * Retry Chain table is implemented here
+ *
+ * Try | LOOKAROUND RATE | NORMAL RATE
+ * | random < best | random > best |
+ * --------------------------------------------------------------
+ * 1 | Best throughput | Random rate | Best throughput
+ * 2 | Random rate | Best throughput | Next best throughput
+ * 3 | Best probability | Best probability | Best probability
+ * 4 | Lowest Baserate | Lowest baserate | Lowest baserate
+ *
+ * Note: For clarity, multiple blocks of if's and else's are used
+ * After a failing 7 times, DoReportFinalDataFailed will be called
+ */
+
+ CheckInit (station);
+ if (!station->m_initialized)
+ {
+ return;
+ }
+
+ //******************
+// if(!station->m_isNewPacketSent)//if a new packet is not sent yet, don't update the counter and txrate, the idea is to view all AMPDU packets in one A-MPDU as one packet.
+// return;
+
+ station->m_longRetry++;
+ uint32_t rateid = GetRateId (station->m_txrate);
+ uint32_t groupid = GetGroupId (station->m_txrate,station,station->m_txstreams);
+ uint32_t maxtprateid = GetRateId (station->m_maxTpRate);
+ uint32_t maxtpgroupid = GetGroupId (station->m_maxTpRate,station,station->m_maxTpStreams);
+ uint32_t maxtp2rateid = GetRateId (station->m_maxTpRate2);
+ uint32_t maxtp2groupid = GetGroupId (station->m_maxTpRate2,station,station->m_maxTp2Streams);
+ uint32_t samplerateid = GetRateId (station->m_sampleRate);
+ uint32_t samplegroupid = GetGroupId (station->m_sampleRate,station,station->m_sampleStreams);
+
+ station->m_mcsTable[groupid].m_minstrelTable[rateid].numRateAttempt++; // for some reason kept track at FinalDataFail!!!
+
+ NS_LOG_DEBUG ("DoReportDataFailed " << station << "\t rate " << station->m_txrate << "\tlongRetry \t" << station->m_longRetry);
+
+
+ /// for normal rate, we're not currently sampling random rates
+ if (!station->m_isSampling)
+ {
+ /// use best throughput rate
+ if (station->m_longRetry < station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount)
+ {
+ NS_LOG_DEBUG ("Not Sampling use the same rate again");
+ station->m_txrateToUse = station->m_maxTpRate; ///< there's still a few retries left
+ }
+
+ /// use second best throughput rate
+ else if (station->m_longRetry <= ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("Not Sampling use the Max TP2");
+ station->m_txrateToUse = station->m_maxTpRate2;
+ }
+
+ /// use best probability rate
+ else if (station->m_longRetry <= ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[maxtp2groupid].m_minstrelTable[maxtp2rateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("Not Sampling use Max Prob");
+ station->m_txrateToUse = station->m_maxProbRate;
+ }
+
+ /// use lowest base rate
+ else if (station->m_longRetry > ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[maxtp2groupid].m_minstrelTable[maxtp2rateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("Not Sampling use MCS0");
+ station->m_txrateToUse = 0;
+ }
+ }
+
+ /// for look-around rate, we're currently sampling random rates
+ else
+ {
+ /// current sampling rate is slower than the current best rate
+ if (station->m_sampleRateSlower)
+ {
+ /// use best throughput rate
+ if (station->m_longRetry < station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount)
+ {
+ NS_LOG_DEBUG ("Sampling use the same rate again");
+ station->m_txrateToUse = station->m_maxTpRate;///< there are a few retries left
+ }
+
+ /// use random rate
+ else if (station->m_longRetry <= ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("Sampling use the sample rate");
+ station->m_txrateToUse = station->m_sampleRate;
+ }
+
+ /// use max probability rate
+ else if (station->m_longRetry <= ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[samplegroupid].m_minstrelTable[samplerateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount ))
+ {
+ NS_LOG_DEBUG ("Sampling use Max prob");
+ station->m_txrateToUse = station->m_maxProbRate;
+ }
+
+ /// use lowest base rate
+ else if (station->m_longRetry > ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[samplegroupid].m_minstrelTable[samplerateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("Sampling use MCS0");
+ station->m_txrateToUse = 0;
+ }
+ }
+
+ /// current sampling rate is better than current best rate
+ else
+ {
+ /// use random rate
+ if (station->m_longRetry < station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount)
+ {
+ NS_LOG_DEBUG ("Sampling use the same sample rate");
+ station->m_txrateToUse = station->m_sampleRate; ///< keep using it
+ }
+
+ /// use the best rate
+ else if (station->m_longRetry <= ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[samplegroupid].m_minstrelTable[samplerateid].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("Sampling use the MaxTP rate");
+ station->m_txrateToUse = station->m_maxTpRate;
+ }
+
+ /// use the best probability rate
+ else if (station->m_longRetry <= ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount +
+ station->m_mcsTable[samplegroupid].m_minstrelTable[samplerateid].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("Sampling use the MaxProb rate");
+ station->m_txrateToUse =station->m_maxProbRate;
+ }
+
+ /// use the lowest base rate
+ else if (station->m_longRetry > ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount +
+ station->m_mcsTable[samplegroupid].m_minstrelTable[samplerateid].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("Sampling use the MCS0");
+ station->m_txrateToUse = 0;
+ }
+ }
+ }
+ NS_LOG_DEBUG ("Txrate = " << station->m_txrateToUse );
+
+ //****************
+// station->m_isNewPacketSent=false;
+}
+
+void
+MinstrelHtWifiManager::DoReportDataOk (WifiRemoteStation *st,
+ double ackSnr, WifiMode ackMode, double dataSnr)
+{
+ MinstrelHtWifiRemoteStation *station = (MinstrelHtWifiRemoteStation *) st;
+ station->m_isSampling = false;
+ station->m_sampleRateSlower = false;
+
+ CheckInit (station);
+ if (!station->m_initialized)
+ {
+ return;
+ }
+
+ //******************
+// if(!station->m_isNewPacketSent)//if a new packet is not sent yet, don't update the counter and txrate, the idea is to view all AMPDU packets in one A-MPDU as one packet.
+// return;
+
+ uint32_t rateid = GetRateId(station->m_txrate);
+ uint32_t groupid = GetGroupId(station->m_txrate,station, station->m_txstreams);
+ station->m_mcsTable[groupid].m_minstrelTable[rateid].numRateSuccess++;
+ station->m_mcsTable[groupid].m_minstrelTable[rateid].numRateAttempt++;
+
+ UpdateRetry (station);
+
+ //station->m_minstrelTable[station->m_txrate].numRateAttempt += station->m_retry;
+ station->m_packetCount++;
+
+ if (m_nsupported >= 1)
+ {
+ station->m_txrateToUse = FindRate (station);
+ }
+ NS_LOG_DEBUG ("Data OK - Txrate = " << station->m_txrate );
+
+ //****************
+// station->m_isNewPacketSent=false;
+}
+
+void
+MinstrelHtWifiManager::DoReportFinalDataFailed (WifiRemoteStation *st)
+{
+ MinstrelHtWifiRemoteStation *station = (MinstrelHtWifiRemoteStation *) st;
+ NS_LOG_DEBUG ("DoReportFinalDataFailed m_txrate=" << station->m_txrate);
+
+ //******************
+// if(!station->m_isNewPacketSent)//if a new packet is not sent yet, don't update the counter and txrate, the idea is to view all AMPDU packets in one A-MPDU as one packet.
+// return;
+
+ station->m_isSampling = false;
+ station->m_sampleRateSlower = false;
+
+ UpdateRetry (station);
+
+ CheckInit (station);
+ if (!station->m_initialized)
+ {
+ return;
+ }
+
+ uint32_t rateid = GetRateId(station->m_txrate);
+ uint32_t groupid = GetGroupId(station->m_txrate,station,station->m_txstreams );
+ station->m_mcsTable[groupid].m_minstrelTable[rateid].numRateAttempt++;
+ station->m_err++;
+
+ if (m_nsupported >= 1)
+ {
+ station->m_txrateToUse = FindRate (station);
+ }
+ NS_LOG_DEBUG ("Txrate = " << station->m_txrate );
+
+ //****************
+// station->m_isNewPacketSent=false;
+}
+
+void
+MinstrelHtWifiManager::UpdateRetry (MinstrelHtWifiRemoteStation *station)
+{
+ station->m_retry = station->m_shortRetry + station->m_longRetry;
+ station->m_shortRetry = 0;
+ station->m_longRetry = 0;
+}
+
+WifiTxVector
+MinstrelHtWifiManager::DoGetDataTxVector (WifiRemoteStation *st,
+ uint32_t size)
+{
+ MinstrelHtWifiRemoteStation *station = (MinstrelHtWifiRemoteStation *) st;
+ station->m_txrate=station->m_txrateToUse;
+
+ if (!station->m_isSampling)
+ {
+ m_rateChange (station->m_txrate, station->m_state->m_address);
+ }
+
+ if (!station->m_initialized)
+ {
+
+ CheckInit (station);
+ if (!station->m_initialized)
+ {
+ station->m_txrate = 0;
+ }
+ else
+ {
+ /// start the rate at half way
+ station->m_txrate = m_nsupported / 2;
+ }
+ }
+
+ //****************
+// station->m_isNewPacketSent=true;
+ NS_LOG_DEBUG ("DoGetDataMode m_txrate=" << station->m_txrate << " m_nsupported " << m_nsupported);
+ UpdateStats (station);
+ //if station->txrate == something then this is a 2x2 stream
+ return WifiTxVector (GetMcsSupported (station, station->m_txrate), GetDefaultTxPowerLevel (), st->m_slrc, GetShortGuardInterval (st), 1, 0, GetChannelWidth (st), GetAggregation (st), false);
+}
+
+WifiTxVector
+MinstrelHtWifiManager::DoGetRtsTxVector (WifiRemoteStation *st)
+{
+ MinstrelHtWifiRemoteStation *station = (MinstrelHtWifiRemoteStation *) st;
+ station->m_txrate=station->m_txrateToUse;
+ NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << station->m_txrate);
+
+ //****************
+// station->m_isNewPacketSent=true;
+ return WifiTxVector (GetMcsSupported (station, 0), GetDefaultTxPowerLevel (), st->m_ssrc, GetShortGuardInterval (st), 1, 0, GetChannelWidth (st), GetAggregation (st), false);
+}
+
+bool
+MinstrelHtWifiManager::DoNeedDataRetransmission (WifiRemoteStation *st, Ptr<const Packet> packet, bool normally)
+{
+ MinstrelHtWifiRemoteStation *station = (MinstrelHtWifiRemoteStation *)st;
+ uint32_t maxprobrateid = GetRateId (station->m_maxProbRate);
+ uint32_t maxprobgroupid = GetGroupId (station->m_maxProbRate,station, station->m_maxProbStreams);
+ uint32_t maxtprateid = GetRateId (station->m_maxTpRate);
+ uint32_t maxtpgroupid = GetGroupId (station->m_maxTpRate,station,station->m_maxTpStreams );
+ uint32_t maxtp2rateid = GetRateId (station->m_maxTpRate2);
+ uint32_t maxtp2groupid = GetGroupId (station->m_maxTpRate2,station,station->m_maxTp2Streams);
+ uint32_t samplerateid = GetRateId (station->m_sampleRate);
+ uint32_t samplegroupid = GetGroupId (station->m_sampleRate,station,station->m_sampleStreams);
+
+ CheckInit (station);
+ if (!station->m_initialized)
+ {
+ return normally;
+ }
+
+ if (!station->m_isSampling)
+ {
+ if (station->m_longRetry > (station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount +
+ station->m_mcsTable[maxtp2groupid].m_minstrelTable[maxtp2rateid].adjustedRetryCount +
+ station->m_mcsTable[maxprobgroupid].m_minstrelTable[maxprobrateid].adjustedRetryCount +
+ station->m_mcsTable[0].m_minstrelTable[0].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("No re-transmission allowed" );
+ return false;
+ }
+ else
+ {
+ NS_LOG_DEBUG ("Re-tranmsit" );
+ return true;
+ }
+ }
+ else
+ {
+ if (station->m_longRetry > (station->m_mcsTable[samplegroupid].m_minstrelTable[samplerateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount +
+ station->m_mcsTable[maxprobgroupid].m_minstrelTable[maxprobrateid].adjustedRetryCount +
+ station->m_mcsTable[0].m_minstrelTable[0].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("No re-transmission allowed" );
+ return false;
+ }
+ else
+ {
+ NS_LOG_DEBUG ("Re-tranmsit" );
+ return true;
+ }
+ }
+}
+
+bool
+MinstrelHtWifiManager::IsLowLatency (void) const
+{
+ return true;
+}
+uint8_t
+MinstrelHtWifiManager::GetStreams (uint32_t groupId, MinstrelHtWifiRemoteStation *station)
+{
+ uint8_t nstreams = 1;
+ if (GetShortGuardInterval(station) && m_nGroups > 2)
+ {
+ //SGI is supported and we have more than one stream
+ if (groupId > 2) //group 0 and 1 are SGI and LGI 1 stream
+ nstreams = 2;
+ }
+ else if (!GetShortGuardInterval(station) && m_nGroups > 1)
+ {
+ //SGI is not supported and we have more than one stream
+ if (groupId == 1)
+ nstreams = 2;
+ }
+ return nstreams;
+}
+uint32_t
+MinstrelHtWifiManager::GetNextSample (MinstrelHtWifiRemoteStation *station)
+{
+ uint32_t sampleindex;
+ uint32_t bitrate;
+ sampleindex = station->m_sampleTable[station->m_mcsTable[station->m_sampleGroup].m_index][station->m_mcsTable[station->m_sampleGroup].m_col];
+ bitrate = GetTxRate(station->m_sampleGroup,sampleindex);
+ station->m_mcsTable[station->m_sampleGroup].m_index++;
+ station->m_sampleStreams = GetStreams (station->m_sampleGroup, station);
+ station->m_sampleGroup++;
+ /// bookeeping for m_index and m_col variables
+ station->m_sampleGroup %= m_nGroups;
+ if (station->m_mcsTable[station->m_sampleGroup].m_index > 6)
+ {
+ station->m_mcsTable[station->m_sampleGroup].m_index = 0;
+ station->m_mcsTable[station->m_sampleGroup].m_col++;
+ if (station->m_mcsTable[station->m_sampleGroup].m_col >= m_sampleCol)
+ {
+ station->m_mcsTable[station->m_sampleGroup].m_col = 0;
+ }
+ }
+ NS_LOG_DEBUG ("Next Sample is " << bitrate );
+ return bitrate;
+}
+
+uint32_t
+MinstrelHtWifiManager::FindRate (MinstrelHtWifiRemoteStation *station)
+{
+ NS_LOG_DEBUG ("FindRate " << "packet=" << station->m_packetCount );
+
+ if ((station->m_sampleCount + station->m_packetCount) == 0)
+ {
+ return 0;
+ }
+
+ uint32_t idx;
+
+ /// for determining when to try a sample rate
+ Ptr<UniformRandomVariable> coinFlip = CreateObject<UniformRandomVariable> ();
+ coinFlip->SetAttribute ("Min", DoubleValue (0));
+ coinFlip->SetAttribute ("Max", DoubleValue (100));
+
+ /**
+ * if we are below the target of look around rate percentage, look around
+ * note: do it randomly by flipping a coin instead sampling
+ * all at once until it reaches the look around rate
+ */
+ if ( (((100 * station->m_sampleCount) / (station->m_sampleCount + station->m_packetCount )) < m_lookAroundRate)
+ && ((int)coinFlip->GetValue ()) % 2 == 1 )
+ {
+ NS_LOG_DEBUG ("Sampling");
+ /// now go through the table and find an index rate
+ idx = GetNextSample (station);
+ NS_LOG_DEBUG ("Sampling rate = " << idx);
+
+ /**
+ * This if condition is used to make sure that we don't need to use
+ * the sample rate it is the same as our current rate
+ */
+ if (idx != station->m_maxTpRate && idx != station->m_txrate)
+ {
+
+ /// start sample count
+ station->m_sampleCount++;
+
+ /// set flag that we are currently sampling
+ station->m_isSampling = true;
+
+ /// bookeeping for resetting stuff
+ if (station->m_packetCount >= 10000)
+ {
+ station->m_sampleCount = 0;
+ station->m_packetCount = 0;
+ }
+
+ /// error check
+ if (idx >= m_nsupported)
+ {
+ NS_LOG_DEBUG ("ALERT!!! ERROR");
+ }
+
+ /// set the rate that we're currently sampling
+ station->m_sampleRate = idx;
+
+ if (station->m_sampleRate == station->m_maxTpRate)
+ {
+ station->m_sampleRate = station->m_maxTpRate2;
+ }
+
+ /// is this rate slower than the current best rate
+ uint32_t idxgroupid = GetGroupId(idx,station, station-> m_sampleStreams);
+ uint32_t idxrateid = GetRateId(idx);
+ uint32_t maxTpgroupid = GetGroupId(station->m_maxTpRate,station,station->m_maxTpStreams);
+ uint32_t maxTprateid = GetRateId(station->m_maxTpRate);
+ station->m_sampleRateSlower =
+ (station->m_mcsTable[idxgroupid].m_minstrelTable[idxrateid].perfectTxTime > station->m_mcsTable[maxTpgroupid].m_minstrelTable[maxTprateid].perfectTxTime);
+
+ /// using the best rate instead
+ if (station->m_sampleRateSlower)
+ {
+ idx = station->m_maxTpRate;
+ }
+ }
+
+ }
+
+ /// continue using the best rate
+ else
+ {
+ idx = station->m_maxTpRate;
+ }
+
+
+ NS_LOG_DEBUG ("FindRate " << "sample rate=" << idx);
+
+ return idx;
+}
+uint32_t
+MinstrelHtWifiManager::GetTxRate(uint32_t groupid, uint32_t index)
+{
+ uint32_t rate;
+ //Group 0 for LGI group 1 for SGI
+ //rate = (groupid*8)+ index;
+ rate=index%8;//to avoid MCS_index >7 to happen
+ return rate;
+}
+void
+MinstrelHtWifiManager::UpdateStats (MinstrelHtWifiRemoteStation *station)
+{
+ if (Simulator::Now () < station->m_nextStatsUpdate)
+ {
+ return;
+ }
+
+ if (!station->m_initialized)
+ {
+ return;
+ }
+ NS_LOG_DEBUG ("Updating stats=" << this);
+
+ station->m_nextStatsUpdate = Simulator::Now () + m_updateStats;
+
+ Time txTime;
+ uint32_t tempProb;
+
+
+ //update throughput and emwa for each rate inside each group
+ for (uint32_t j=0 ; j <m_nGroups ; j++)
+ {
+ for (uint32_t i = 0; i < 8; i++)
+ {
+
+ /// calculate the perfect tx time for this rate
+ txTime = station->m_mcsTable[j].m_minstrelTable[i].perfectTxTime;
+
+ /// just for initialization
+ if (txTime.GetMicroSeconds () == 0)
+ {
+ txTime = Seconds (1);
+ }
+
+ NS_LOG_DEBUG (i << " " << GetMcsSupported (station, GetTxRate(j,i)) <<
+ "\t attempt=" << station->m_mcsTable[j].m_minstrelTable[i].numRateAttempt <<
+ "\t success=" << station->m_mcsTable[j].m_minstrelTable[i].numRateSuccess);
+
+ /// if we've attempted something
+ if (station->m_mcsTable[j].m_minstrelTable[i].numRateAttempt)
+ {
+ /**
+ * calculate the probability of success
+ * assume probability scales from 0 to 18000
+ */
+ tempProb = (station->m_mcsTable[j].m_minstrelTable[i].numRateSuccess * 18000) / station->m_mcsTable[j].m_minstrelTable[i].numRateAttempt;
+
+ /// bookeeping
+ station->m_mcsTable[j].m_minstrelTable[i].prob = tempProb;
+
+ /// ewma probability (cast for gcc 3.4 compatibility)
+ tempProb = static_cast<uint32_t> (((tempProb * (100 - m_ewmaLevel)) + (station->m_mcsTable[j].m_minstrelTable[i].ewmaProb * m_ewmaLevel) ) / 100);
+
+ station->m_mcsTable[j].m_minstrelTable[i].ewmaProb = tempProb;
+
+ /// calculating throughput
+ station->m_mcsTable[j].m_minstrelTable[i].throughput = tempProb * (1000000 / txTime.GetMicroSeconds ());
+
+ }
+
+ /// bookeeping
+ station->m_mcsTable[j].m_minstrelTable[i].numRateSuccess = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].numRateAttempt = 0;
+
+ /// Sample less often below 10% and above 95% of success
+ if ((station->m_mcsTable[j].m_minstrelTable[i].ewmaProb > 17100) || (station->m_mcsTable[j].m_minstrelTable[i].ewmaProb < 1800))
+ {
+ /**
+ * retry count denotes the number of retries permitted for each rate
+ * # retry_count/2
+ */
+
+ if (station->m_mcsTable[j].m_minstrelTable[i].adjustedRetryCount > 2)
+ {
+ station->m_mcsTable[j].m_minstrelTable[i].adjustedRetryCount = 2;
+ }
+ else
+ {
+ station->m_mcsTable[j].m_minstrelTable[i].adjustedRetryCount = station->m_mcsTable[j].m_minstrelTable[i].retryCount;
+ }
+ }
+ else
+ {
+ station->m_mcsTable[j].m_minstrelTable[i].adjustedRetryCount = station->m_mcsTable[j].m_minstrelTable[i].retryCount;
+ }
+
+ /// if it's 0 allow one retry limit
+ if (station->m_mcsTable[j].m_minstrelTable[i].adjustedRetryCount == 0)
+ {
+ station->m_mcsTable[j].m_minstrelTable[i].adjustedRetryCount = 1;
+ }
+ }
+ }
+
+ //for each group get the max tp and maxtp2
+ uint32_t max_prob = 0, index_max_prob = 0, max_tp = 0, index_max_tp = 0, index_max_tp2 = 0;
+ uint32_t index_max_prob_streams =1, index_max_tp_streams =1 , index_max_tp2_streams =1;
+ for (uint32_t j = 0; j <m_nGroups; j++)
+ {
+ max_prob = 0;
+ index_max_prob = 0;
+ max_tp = 0;
+ index_max_tp = 0;
+ index_max_tp2 = 0;
+ /// go find max throughput, second maximum throughput, high probability succ
+ for (uint32_t i = 0; i < 8; i++)
+ {
+ NS_LOG_DEBUG ("throughput" << station->m_mcsTable[j].m_minstrelTable[i].throughput <<
+ "\n ewma" << station->m_mcsTable[j].m_minstrelTable[i].ewmaProb);
+
+ if (max_tp < station->m_mcsTable[j].m_minstrelTable[i].throughput)
+ {
+ index_max_tp = i;
+ max_tp = station->m_mcsTable[j].m_minstrelTable[i].throughput;
+ }
+
+ if (max_prob < station->m_mcsTable[j].m_minstrelTable[i].ewmaProb)
+ {
+ index_max_prob = i;
+ max_prob = station->m_mcsTable[j].m_minstrelTable[i].ewmaProb;
+ }
+ }
+
+ max_tp = 0;
+ /// find the second highest max
+ for (uint32_t i = 0; i <8; i++)
+ {
+ if ((i != index_max_tp) && (max_tp < station->m_mcsTable[j].m_minstrelTable[i].throughput))
+ {
+ index_max_tp2 = i;
+ max_tp = station->m_mcsTable[j].m_minstrelTable[i].throughput;
+ }
+ }
+
+ station->m_mcsTable[j].m_maxTpRate = index_max_tp;
+ station->m_mcsTable[j].m_maxTpRate2 = index_max_tp2;
+ station->m_mcsTable[j].m_maxProbRate = index_max_prob;
+ }
+
+ max_prob = 0;
+ index_max_prob = 0;
+ max_tp = 0;
+ index_max_tp = 0;
+ index_max_tp2 = 0;
+// get the maxtp and maxtp2 from all groups
+ for (uint32_t j = 0; j < m_nGroups; j++)
+ {
+ /// go find max throughput, second maximum throughput, high probability succ
+
+ if (max_tp < station->m_mcsTable[j].m_minstrelTable[station->m_mcsTable[j].m_maxTpRate].throughput)
+ {
+ index_max_tp = GetTxRate(j, station->m_mcsTable[j].m_maxTpRate);
+ max_tp = station->m_mcsTable[j].m_minstrelTable[station->m_mcsTable[j].m_maxTpRate].throughput;
+ index_max_tp_streams = GetStreams (j, station);
+ }
+
+ if (max_prob < station->m_mcsTable[j].m_minstrelTable[station->m_mcsTable[j].m_maxProbRate].ewmaProb)
+ {
+ index_max_prob = GetTxRate(j,station->m_mcsTable[j].m_maxProbRate);
+ max_prob = station->m_mcsTable[j].m_minstrelTable[station->m_mcsTable[j].m_maxProbRate].ewmaProb;
+ index_max_prob_streams = GetStreams (j, station);
+ }
+}
+ max_tp = 0;
+ /// find the second highest max
+ for (uint32_t i = 0; i <m_nGroups; i++)
+ {
+ if ((GetTxRate(i,station->m_mcsTable[i].m_maxTpRate) != index_max_tp) && (max_tp < station->m_mcsTable[i].m_minstrelTable[station->m_mcsTable[i].m_maxTpRate].throughput))
+ {
+ //finds if another group maxtp is better than the max tp2
+ index_max_tp2 = GetTxRate(i,station->m_mcsTable[i].m_maxTpRate);
+ max_tp = station->m_mcsTable[i].m_minstrelTable[station->m_mcsTable[i].m_maxTpRate].throughput;
+ index_max_tp2_streams = GetStreams (i, station);
+ }
+ if (max_tp < station->m_mcsTable[i].m_minstrelTable[station->m_mcsTable[i].m_maxTpRate2].throughput)
+ {
+ //find if another group maxtp2 is better than maxtp2
+ index_max_tp2 = GetTxRate(i,station->m_mcsTable[i].m_maxTpRate2);
+ max_tp = station->m_mcsTable[i].m_minstrelTable[station->m_mcsTable[i].m_maxTpRate2].throughput;
+ index_max_tp2_streams = GetStreams (i, station);
+ }
+ }
+
+
+ station->m_maxTpRate = index_max_tp;
+ station->m_maxTpStreams = index_max_tp_streams;
+ station->m_maxTpRate2 = index_max_tp2;
+ station->m_maxTp2Streams = index_max_tp2_streams;
+ station->m_maxProbRate = index_max_prob;
+ station->m_maxProbStreams = index_max_prob_streams;
+ station->m_currentRate = index_max_tp;
+
+ ///if the max tp rate is bigger than the current rate and uses the same number of streams
+ if ((index_max_tp > station->m_txrate) &&(index_max_tp_streams >= station->m_txstreams) )
+ {
+ station->m_txrate = index_max_tp;
+ station->m_txstreams = index_max_tp_streams;
+ }
+
+ NS_LOG_DEBUG ("max tp=" << index_max_tp << "\nmax tp2=" << index_max_tp2 << "\nmax prob=" << index_max_prob);
+
+ /// reset it
+ //RateInit (station);
+}
+
+void
+MinstrelHtWifiManager::RateInit (MinstrelHtWifiRemoteStation *station)
+{
+ NS_LOG_DEBUG ("RateInit=" << station);
+
+ for (uint32_t j = 0; j < m_nGroups; j++)
+ {
+ //should include MCS
+ station->m_mcsTable[j].m_minstrelTable = HtMinstrelRate (m_nsupported/m_nGroups);
+ station->m_mcsTable[j].m_col = 0;
+ station->m_mcsTable[j].m_index = 0;
+ for (uint32_t i = 0; i < 8; i++)
+ {
+ station->m_mcsTable[j].m_minstrelTable[i].numRateAttempt = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].numRateSuccess = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].prob = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].ewmaProb = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].prevNumRateAttempt = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].prevNumRateSuccess = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].successHist = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].attemptHist = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].throughput = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].perfectTxTime = GetCalcTxTime (GetMcsSupported (station, GetTxRate(j,i)));
+ station->m_mcsTable[j].m_minstrelTable[i].retryCount = 1;
+ station->m_mcsTable[j].m_minstrelTable[i].adjustedRetryCount = 1;
+ }
+ }
+}
+
+void
+MinstrelHtWifiManager::InitSampleTable (MinstrelHtWifiRemoteStation *station)
+{
+ NS_LOG_DEBUG ("InitSampleTable=" << this);
+
+ station->m_col = station->m_index = 0;
+
+ /// for off-seting to make rates fall between 0 and numrates
+ uint32_t numSampleRates = 8;
+
+ uint32_t newIndex;
+ for (uint32_t col = 0; col < m_sampleCol; col++)
+ {
+ for (uint32_t i = 0; i < numSampleRates; i++ )
+ {
+
+ /**
+ * The next two lines basically tries to generate a random number
+ * between 0 and the number of available rates
+ */
+ Ptr<UniformRandomVariable> uv = CreateObject<UniformRandomVariable> ();
+ uv->SetAttribute ("Min", DoubleValue (0));
+ uv->SetAttribute ("Max", DoubleValue (numSampleRates));
+
+ newIndex = (i + (uint32_t)uv->GetValue ()) % numSampleRates;
+
+ /// this loop is used for filling in other uninitilized places
+ while (station->m_sampleTable[newIndex][col] != 0)
+ {
+ newIndex = (newIndex + 1) % 8;
+ }
+ station->m_sampleTable[newIndex][col] = i;
+
+ }
+ }
+}
+
+void
+MinstrelHtWifiManager::PrintSampleTable (MinstrelHtWifiRemoteStation *station)
+{
+ NS_LOG_DEBUG ("PrintSampleTable=" << station);
+
+ uint32_t numSampleRates = 8;
+ for (uint32_t i = 0; i < numSampleRates; i++)
+ {
+ for (uint32_t j = 0; j < m_sampleCol; j++)
+ {
+ std::cout << station->m_sampleTable[i][j] << "\t";
+ }
+ std::cout << std::endl;
+ }
+}
+
+void
+MinstrelHtWifiManager::PrintTable (MinstrelHtWifiRemoteStation *station)
+{
+ NS_LOG_DEBUG ("PrintTable=" << station);
+ for (uint32_t j = 0; j < m_nGroups; j++)
+ {
+ for (uint32_t i = 0; i < 8; i++)
+ {
+ std::cout << "index(" << i << ") = " << station->m_mcsTable[j].m_minstrelTable[i].perfectTxTime << "\n";
+ }
+ }
+}
+
+} // namespace ns3
+
+
+
+
+
+
diff --git a/emu-radio/ns3-patch/wifi/model/minstrel-ht-wifi-manager.h b/emu-radio/ns3-patch/wifi/model/minstrel-ht-wifi-manager.h
new file mode 100644
index 00000000..6ea064fa
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/minstrel-ht-wifi-manager.h
@@ -0,0 +1,202 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2015 Ghada Badawy
+ *
+ * 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: Ghada Badawy <gbadawy@gmail.com>
+ *
+ * modified by zeng <zengxuan123456@gmail.com>
+ * NOTE: currently the spatial stream used are hard coded to 1*1, because only 1 spatial
+ * stream is supported for 802.11n
+ */
+
+
+
+#ifndef MINSTREL_HT_WIFI_MANAGER_H
+#define MINSTREL_HT_WIFI_MANAGER_H
+
+#include "wifi-remote-station-manager.h"
+#include "wifi-mode.h"
+#include "ns3/nstime.h"
+#include <vector>
+#include <map>
+#include <deque>
+
+
+namespace ns3 {
+
+struct MinstrelHtWifiRemoteStation;
+
+/**
+ * A struct to contain all information related to a data rate
+ */
+struct HtRateInfo
+{
+ /**
+ * Perfect transmission time calculation, or frame calculation
+ * Given a bit rate and a packet length n bytes
+ */
+ Time perfectTxTime;
+
+
+ uint32_t retryCount; ///< retry limit
+ uint32_t adjustedRetryCount; ///< adjust the retry limit for this rate
+ uint32_t numRateAttempt; ///< how many number of attempts so far
+ uint32_t numRateSuccess; ///< number of successful pkts
+ uint32_t prob; ///< (# pkts success )/(# total pkts)
+
+ /**
+ * EWMA calculation
+ * ewma_prob =[prob *(100 - ewma_level) + (ewma_prob_old * ewma_level)]/100
+ */
+ uint32_t ewmaProb;
+
+ uint32_t prevNumRateAttempt; ///< from last rate
+ uint32_t prevNumRateSuccess; ///< from last rate
+ uint64_t successHist; ///< aggregate of all successes
+ uint64_t attemptHist; ///< aggregate of all attempts
+ uint32_t throughput; ///< throughput of a rate
+};
+
+/**
+ * Data structure for a Minstrel Rate table
+ * A vector of a struct RateInfo
+ */
+typedef std::vector<struct HtRateInfo> HtMinstrelRate;
+
+struct GroupInfo
+{
+ /**
+ * MCS rates are divided into groups based on the number of streams and flags that they use
+ */
+ uint8_t m_col; ///< sample table column
+ uint8_t m_index; ///<sample table index
+ uint32_t m_maxTpRate; ///< Rate the has max throughput for this group
+ uint32_t m_maxTpRate2;///< Rate the has second max throughput for this group
+ uint32_t m_maxProbRate;///< Rate the has highest success probability for this group
+ HtMinstrelRate m_minstrelTable; ///< Information about rates member in this group
+
+};
+
+/**
+ * Data structure for a MCS group table
+ * A vector of a Minstrel Rate Table
+ */
+typedef std::vector<struct GroupInfo> McsGroup;
+
+/**
+ * Data structure for a Sample Rate table
+ * A vector of a vector uint32_t
+ */
+typedef std::vector<std::vector<uint32_t> > HtSampleRate;
+
+
+/**
+ * \author Ghada Badawy
+ * \brief Implementation of Minstrel HT Rate Control Algorithm
+ * \ingroup wifi
+ *
+ * http://lwn.net/Articles/376765/
+ */
+class MinstrelHtWifiManager : public WifiRemoteStationManager
+{
+
+public:
+ static TypeId GetTypeId (void);
+ MinstrelHtWifiManager ();
+ virtual ~MinstrelHtWifiManager ();
+
+ virtual void SetupPhy (Ptr<WifiPhy> phy);
+
+ typedef void (*RateChangeTracedCallback)(const uint64_t rate, const Mac48Address remoteAddress);
+
+private:
+ // overriden from base class
+ virtual WifiRemoteStation * DoCreateStation (void) const;
+ virtual void DoReportRxOk (WifiRemoteStation *station,
+ double rxSnr, WifiMode txMode);
+ virtual void DoReportRtsFailed (WifiRemoteStation *station);
+ virtual void DoReportDataFailed (WifiRemoteStation *station);
+ virtual void DoReportRtsOk (WifiRemoteStation *station,
+ double ctsSnr, WifiMode ctsMode, double rtsSnr);
+ virtual void DoReportDataOk (WifiRemoteStation *station,
+ double ackSnr, WifiMode ackMode, double dataSnr);
+ virtual void DoReportFinalRtsFailed (WifiRemoteStation *station);
+ virtual void DoReportFinalDataFailed (WifiRemoteStation *station);
+ virtual WifiTxVector DoGetDataTxVector (WifiRemoteStation *station, uint32_t size);
+ virtual WifiTxVector DoGetRtsTxVector (WifiRemoteStation *station);
+
+ virtual bool DoNeedDataRetransmission (WifiRemoteStation *st, Ptr<const Packet> packet, bool normally);
+
+
+ virtual bool IsLowLatency (void) const;
+
+
+ /// for estimating the TxTime of a packet with a given mode
+ Time GetCalcTxTime (WifiMode mode) const;
+ void AddCalcTxTime (WifiMode mode, Time t);
+
+ /// update the number of retries and reset accordingly
+ void UpdateRetry (MinstrelHtWifiRemoteStation *station);
+
+ /// getting the next sample from Sample Table
+ uint32_t GetNextSample (MinstrelHtWifiRemoteStation *station);
+
+ /// find a rate to use from Minstrel Table
+ uint32_t FindRate (MinstrelHtWifiRemoteStation *station);
+
+ /// updating the Minstrel Table every 1/10 seconds
+ void UpdateStats (MinstrelHtWifiRemoteStation *station);
+
+ /// initialize Minstrel Table
+ void RateInit (MinstrelHtWifiRemoteStation *station);
+
+ /// initialize Sample Table
+ void InitSampleTable (MinstrelHtWifiRemoteStation *station);
+
+ /// printing Sample Table
+ void PrintSampleTable (MinstrelHtWifiRemoteStation *station);
+
+ /// printing Minstrel Table
+ void PrintTable (MinstrelHtWifiRemoteStation *station);
+
+ void CheckInit (MinstrelHtWifiRemoteStation *station); ///< check for initializations
+
+ uint32_t GetRateId(uint32_t rate);
+
+ uint32_t GetGroupId(uint32_t rate, WifiRemoteStation *st, uint8_t txstreams);
+ uint32_t GetTxRate(uint32_t groupid, uint32_t index);
+ uint8_t GetStreams (uint32_t groupId, MinstrelHtWifiRemoteStation *station);
+
+ typedef std::vector<std::pair<Time,WifiMode> > TxTime;
+
+
+ TxTime m_calcTxTime; ///< to hold all the calculated TxTime for all modes
+ Time m_updateStats; ///< how frequent do we calculate the stats(1/10 seconds)
+ double m_lookAroundRate; ///< the % to try other rates than our current rate
+ double m_ewmaLevel; ///< exponential weighted moving average
+ uint32_t m_segmentSize; ///< largest allowable segment size
+ uint32_t m_sampleCol; ///< number of sample columns
+ uint32_t m_pktLen; ///< packet length used for calculate mode TxTime
+ uint32_t m_nsupported; ///< modes supported
+ uint8_t m_nGroups;///<hold the number of different MCS groups that the STA has if the STA supports 40MHz then it only uses 40MHz rates no switching between 20 and 40MHz rates
+
+ TracedCallback<uint64_t, Mac48Address> m_rateChange;
+};
+
+} // namespace ns3
+
+#endif /* MINSTREL_HT_WIFI_MANAGER_H */
+
diff --git a/emu-radio/ns3-patch/wifi/model/originator-block-ack-agreement.cc b/emu-radio/ns3-patch/wifi/model/originator-block-ack-agreement.cc
new file mode 100644
index 00000000..93543c6a
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/originator-block-ack-agreement.cc
@@ -0,0 +1,111 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009, 2010 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
+ *
+ * Authors: Mirko Banchi <mk.banchi@gmail.com>
+ * Tommaso Pecorella <tommaso.pecorella@unifi.it>
+ */
+
+#include "originator-block-ack-agreement.h"
+
+namespace ns3 {
+
+OriginatorBlockAckAgreement::OriginatorBlockAckAgreement ()
+ : BlockAckAgreement (),
+ m_state (PENDING),
+ m_sentMpdus (0),
+ m_needBlockAckReq (false)
+{
+}
+
+OriginatorBlockAckAgreement::OriginatorBlockAckAgreement (Mac48Address recipient, uint8_t tid)
+ : BlockAckAgreement (recipient, tid),
+ m_state (PENDING),
+ m_sentMpdus (0),
+ m_needBlockAckReq (false)
+{
+}
+
+OriginatorBlockAckAgreement::~OriginatorBlockAckAgreement ()
+{
+ //NS_LOG_FUNCTION (this);
+
+ //std::cout<<"destructor for OriginatorBlockAckAgreement is called, destroy event is canceled, destroy agreement with="<<m_peer<<"\n";
+ m_OriginatorInactivityEvent.Cancel ();
+}
+
+void
+OriginatorBlockAckAgreement::SetState (enum State state)
+{
+ m_state = state;
+ if (state == INACTIVE)
+ {
+ m_needBlockAckReq = false;
+ 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 (uint16_t nextSeqNumber)
+{
+ NS_ASSERT (m_sentMpdus < m_bufferSize);
+ m_sentMpdus++;
+ uint16_t delta = (nextSeqNumber - m_startingSeq + 4096) % 4096;
+ uint16_t min = m_bufferSize < 64 ? m_bufferSize : 64;
+ if (delta >= min || m_sentMpdus == m_bufferSize)
+ {
+ m_needBlockAckReq = true;
+ }
+}
+
+bool
+OriginatorBlockAckAgreement::IsBlockAckRequestNeeded (void) const
+{
+ return m_needBlockAckReq;
+}
+
+void
+OriginatorBlockAckAgreement::CompleteExchange (void)
+{
+ m_needBlockAckReq = false;
+ m_sentMpdus = 0;
+}
+
+} //namespace ns3
diff --git a/emu-radio/ns3-patch/wifi/model/originator-block-ack-agreement.h b/emu-radio/ns3-patch/wifi/model/originator-block-ack-agreement.h
new file mode 100644
index 00000000..1bc93cad
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/originator-block-ack-agreement.h
@@ -0,0 +1,155 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009, 2010 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>
+ * Author: Tommaso Pecorella <tommaso.pecorella@unifi.it>
+ */
+#ifndef ORIGINATOR_BLOCK_ACK_AGREEMENT_H
+#define ORIGINATOR_BLOCK_ACK_AGREEMENT_H
+
+#include "block-ack-agreement.h"
+
+namespace ns3 {
+
+/**
+ * \ingroup wifi
+ * Maintains the state and information about transmitted 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 transmitted
+ * 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::BlockAckManager). 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 agreement'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);
+ /**
+ * Check if the current state of this agreement is PENDING.
+ *
+ * \return true if the current state of this agreement is PENDING,
+ * false otherwise
+ */
+ bool IsPending (void) const;
+ /**
+ * Check if the current state of this agreement is ESTABLISHED.
+ *
+ * \return true if the current state of this agreement is ESTABLISHED,
+ * false otherwise
+ */
+ bool IsEstablished (void) const;
+ /**
+ * Check if the current state of this agreement is INACTIVE.
+ *
+ * \return true if the current state of this agreement is INACTIVE,
+ * false otherwise
+ */
+ bool IsInactive (void) const;
+ /**
+ * Check if the current state of this agreement is UNSUCCESSFUL.
+ *
+ * \return true if the current state of this agreement is UNSUCCESSFUL,
+ * false otherwise
+ */
+ bool IsUnsuccessful (void) const;
+ /**
+ * Notifies a packet's transmission with ack policy Block Ack.
+ *
+ * \param nextSeqNumber
+ */
+ void NotifyMpduTransmission (uint16_t nextSeqNumber);
+ /**
+ * 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.
+ *
+ * \return true if all packets for which a block ack was negotiated have been transmitted,
+ * false otherwise
+ */
+ bool IsBlockAckRequestNeeded (void) const;
+ void CompleteExchange (void);
+
+
+private:
+ enum State m_state;
+ uint16_t m_sentMpdus;
+ bool m_needBlockAckReq;
+
+ //+++++++++
+ EventId m_OriginatorInactivityEvent;
+};
+
+} //namespace ns3
+
+#endif /* ORIGINATOR_BLOCK_ACK_AGREEMENT_H */
diff --git a/emu-radio/ns3-patch/wifi/model/regular-wifi-mac.cc b/emu-radio/ns3-patch/wifi/model/regular-wifi-mac.cc
new file mode 100644
index 00000000..9c0e83d6
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/regular-wifi-mac.cc
@@ -0,0 +1,780 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * 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: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "regular-wifi-mac.h"
+#include "ns3/log.h"
+#include "ns3/boolean.h"
+#include "ns3/pointer.h"
+#include "ns3/uinteger.h"
+#include "ns3/trace-source-accessor.h"
+#include "mac-rx-middle.h"
+#include "mac-tx-middle.h"
+#include "mac-low.h"
+#include "dcf.h"
+#include "dcf-manager.h"
+#include "wifi-phy.h"
+#include "msdu-aggregator.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("RegularWifiMac");
+
+NS_OBJECT_ENSURE_REGISTERED (RegularWifiMac);
+
+RegularWifiMac::RegularWifiMac ()
+{
+ NS_LOG_FUNCTION (this);
+ m_rxMiddle = new MacRxMiddle ();
+ m_rxMiddle->SetForwardCallback (MakeCallback (&RegularWifiMac::Receive, this));
+
+ m_txMiddle = new MacTxMiddle ();
+
+ m_low = CreateObject<MacLow> ();
+ m_low->SetRxCallback (MakeCallback (&MacRxMiddle::Receive, m_rxMiddle));
+
+ m_dcfManager = new DcfManager ();
+ m_dcfManager->SetupLowListener (m_low);
+
+ m_dca = CreateObject<DcaTxop> ();
+ m_dca->SetLow (m_low);
+ m_dca->SetManager (m_dcfManager);
+ m_dca->SetTxMiddle (m_txMiddle);
+ m_dca->SetTxOkCallback (MakeCallback (&RegularWifiMac::TxOk, this));
+ m_dca->SetTxFailedCallback (MakeCallback (&RegularWifiMac::TxFailed, this));
+
+ //Construct the EDCAFs. The ordering is important - highest
+ //priority (Table 9-1 UP-to-AC mapping; IEEE 802.11-2012) must be created
+ //first.
+ SetupEdcaQueue (AC_VO);
+ SetupEdcaQueue (AC_VI);
+ SetupEdcaQueue (AC_BE);
+ SetupEdcaQueue (AC_BK);
+}
+
+RegularWifiMac::~RegularWifiMac ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+void
+RegularWifiMac::DoInitialize ()
+{
+ NS_LOG_FUNCTION (this);
+ m_dca->Initialize ();
+
+ for (EdcaQueues::iterator i = m_edca.begin (); i != m_edca.end (); ++i)
+ {
+ i->second->Initialize ();
+ }
+}
+
+void
+RegularWifiMac::DoDispose ()
+{
+ NS_LOG_FUNCTION (this);
+ delete m_rxMiddle;
+ m_rxMiddle = 0;
+
+ delete m_txMiddle;
+ m_txMiddle = 0;
+
+ delete m_dcfManager;
+ m_dcfManager = 0;
+
+ m_low->Dispose ();
+ m_low = 0;
+
+ m_phy = 0;
+ m_stationManager = 0;
+
+ m_dca->Dispose ();
+ m_dca = 0;
+
+ for (EdcaQueues::iterator i = m_edca.begin (); i != m_edca.end (); ++i)
+ {
+ i->second = 0;
+ }
+}
+
+void
+RegularWifiMac::SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> stationManager)
+{
+ NS_LOG_FUNCTION (this << stationManager);
+ m_stationManager = stationManager;
+ m_stationManager->SetHtSupported (GetHtSupported ());
+ m_stationManager->SetVhtSupported (GetVhtSupported ());
+ m_low->SetWifiRemoteStationManager (stationManager);
+
+ m_dca->SetWifiRemoteStationManager (stationManager);
+
+ for (EdcaQueues::iterator i = m_edca.begin (); i != m_edca.end (); ++i)
+ {
+ i->second->SetWifiRemoteStationManager (stationManager);
+ }
+}
+
+Ptr<WifiRemoteStationManager>
+RegularWifiMac::GetWifiRemoteStationManager () const
+{
+ return m_stationManager;
+}
+
+void
+RegularWifiMac::SetupEdcaQueue (enum AcIndex ac)
+{
+ NS_LOG_FUNCTION (this << ac);
+
+ //Our caller shouldn't be attempting to setup a queue that is
+ //already configured.
+ NS_ASSERT (m_edca.find (ac) == m_edca.end ());
+
+ Ptr<EdcaTxopN> edca = CreateObject<EdcaTxopN> ();
+ edca->SetLow (m_low);
+ edca->SetManager (m_dcfManager);
+ edca->SetTxMiddle (m_txMiddle);
+ edca->SetTxOkCallback (MakeCallback (&RegularWifiMac::TxOk, this));
+ edca->SetTxFailedCallback (MakeCallback (&RegularWifiMac::TxFailed, this));
+ edca->SetAccessCategory (ac);
+ edca->CompleteConfig ();
+ m_edca.insert (std::make_pair (ac, edca));
+}
+
+void
+RegularWifiMac::SetTypeOfStation (TypeOfStation type)
+{
+ NS_LOG_FUNCTION (this << type);
+ for (EdcaQueues::iterator i = m_edca.begin (); i != m_edca.end (); ++i)
+ {
+ i->second->SetTypeOfStation (type);
+ }
+}
+
+Ptr<DcaTxop>
+RegularWifiMac::GetDcaTxop () const
+{
+ return m_dca;
+}
+
+Ptr<EdcaTxopN>
+RegularWifiMac::GetVOQueue () const
+{
+ return m_edca.find (AC_VO)->second;
+}
+
+Ptr<EdcaTxopN>
+RegularWifiMac::GetVIQueue () const
+{
+ return m_edca.find (AC_VI)->second;
+}
+
+Ptr<EdcaTxopN>
+RegularWifiMac::GetBEQueue () const
+{
+ return m_edca.find (AC_BE)->second;
+}
+
+Ptr<EdcaTxopN>
+RegularWifiMac::GetBKQueue () const
+{
+ return m_edca.find (AC_BK)->second;
+}
+
+void
+RegularWifiMac::SetWifiPhy (Ptr<WifiPhy> phy)
+{
+ NS_LOG_FUNCTION (this << phy);
+ m_phy = phy;
+ m_dcfManager->SetupPhyListener (phy);
+ m_low->SetPhy (phy);
+}
+
+Ptr<WifiPhy>
+RegularWifiMac::GetWifiPhy (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_phy;
+}
+
+void
+RegularWifiMac::ResetWifiPhy (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_low->ResetPhy ();
+ m_dcfManager->RemovePhyListener (m_phy);
+ m_phy = 0;
+}
+
+void
+RegularWifiMac::SetForwardUpCallback (ForwardUpCallback upCallback)
+{
+ NS_LOG_FUNCTION (this);
+ m_forwardUp = upCallback;
+}
+
+void
+RegularWifiMac::SetLinkUpCallback (Callback<void> linkUp)
+{
+ NS_LOG_FUNCTION (this);
+ m_linkUp = linkUp;
+}
+
+void
+RegularWifiMac::SetLinkDownCallback (Callback<void> linkDown)
+{
+ NS_LOG_FUNCTION (this);
+ m_linkDown = linkDown;
+}
+
+void
+RegularWifiMac::SetQosSupported (bool enable)
+{
+ NS_LOG_FUNCTION (this);
+ m_qosSupported = enable;
+}
+
+bool
+RegularWifiMac::GetQosSupported () const
+{
+ return m_qosSupported;
+}
+
+void
+RegularWifiMac::SetHtSupported (bool enable)
+{
+ NS_LOG_FUNCTION (this);
+ m_htSupported = enable;
+}
+
+bool
+RegularWifiMac::GetVhtSupported () const
+{
+ return m_vhtSupported;
+}
+
+void
+RegularWifiMac::SetVhtSupported (bool enable)
+{
+ NS_LOG_FUNCTION (this);
+ m_vhtSupported = enable;
+}
+
+bool
+RegularWifiMac::GetHtSupported () const
+{
+ return m_htSupported;
+}
+
+void
+RegularWifiMac::SetCtsToSelfSupported (bool enable)
+{
+ NS_LOG_FUNCTION (this);
+ m_low->SetCtsToSelfSupported (enable);
+}
+
+bool
+RegularWifiMac::GetCtsToSelfSupported () const
+{
+ return m_low->GetCtsToSelfSupported ();
+}
+
+void
+RegularWifiMac::SetSlot (Time slotTime)
+{
+ NS_LOG_FUNCTION (this << slotTime);
+ m_dcfManager->SetSlot (slotTime);
+ m_low->SetSlotTime (slotTime);
+}
+
+Time
+RegularWifiMac::GetSlot (void) const
+{
+ return m_low->GetSlotTime ();
+}
+
+void
+RegularWifiMac::SetSifs (Time sifs)
+{
+ NS_LOG_FUNCTION (this << sifs);
+ m_dcfManager->SetSifs (sifs);
+ m_low->SetSifs (sifs);
+}
+
+Time
+RegularWifiMac::GetSifs (void) const
+{
+ return m_low->GetSifs ();
+}
+
+void
+RegularWifiMac::SetEifsNoDifs (Time eifsNoDifs)
+{
+ NS_LOG_FUNCTION (this << eifsNoDifs);
+ m_dcfManager->SetEifsNoDifs (eifsNoDifs);
+}
+
+Time
+RegularWifiMac::GetEifsNoDifs (void) const
+{
+ return m_dcfManager->GetEifsNoDifs ();
+}
+
+void
+RegularWifiMac::SetRifs (Time rifs)
+{
+ NS_LOG_FUNCTION (this << rifs);
+ m_low->SetRifs (rifs);
+}
+
+Time
+RegularWifiMac::GetRifs (void) const
+{
+ return m_low->GetRifs ();
+}
+
+void
+RegularWifiMac::SetPifs (Time pifs)
+{
+ NS_LOG_FUNCTION (this << pifs);
+ m_low->SetPifs (pifs);
+}
+
+Time
+RegularWifiMac::GetPifs (void) const
+{
+ return m_low->GetPifs ();
+}
+
+void
+RegularWifiMac::SetAckTimeout (Time ackTimeout)
+{
+ NS_LOG_FUNCTION (this << ackTimeout);
+ m_low->SetAckTimeout (ackTimeout);
+}
+
+Time
+RegularWifiMac::GetAckTimeout (void) const
+{
+ return m_low->GetAckTimeout ();
+}
+
+void
+RegularWifiMac::SetCtsTimeout (Time ctsTimeout)
+{
+ NS_LOG_FUNCTION (this << ctsTimeout);
+ m_low->SetCtsTimeout (ctsTimeout);
+}
+
+Time
+RegularWifiMac::GetCtsTimeout (void) const
+{
+ return m_low->GetCtsTimeout ();
+}
+
+void
+RegularWifiMac::SetBasicBlockAckTimeout (Time blockAckTimeout)
+{
+ NS_LOG_FUNCTION (this << blockAckTimeout);
+ m_low->SetBasicBlockAckTimeout (blockAckTimeout);
+}
+
+Time
+RegularWifiMac::GetBasicBlockAckTimeout (void) const
+{
+ return m_low->GetBasicBlockAckTimeout ();
+}
+
+void
+RegularWifiMac::SetCompressedBlockAckTimeout (Time blockAckTimeout)
+{
+ NS_LOG_FUNCTION (this << blockAckTimeout);
+ m_low->SetCompressedBlockAckTimeout (blockAckTimeout);
+}
+
+Time
+RegularWifiMac::GetCompressedBlockAckTimeout (void) const
+{
+ return m_low->GetCompressedBlockAckTimeout ();
+}
+
+void
+RegularWifiMac::SetAddress (Mac48Address address)
+{
+ NS_LOG_FUNCTION (this << address);
+ m_low->SetAddress (address);
+}
+
+Mac48Address
+RegularWifiMac::GetAddress (void) const
+{
+ return m_low->GetAddress ();
+}
+
+void
+RegularWifiMac::SetSsid (Ssid ssid)
+{
+ NS_LOG_FUNCTION (this << ssid);
+ m_ssid = ssid;
+}
+
+Ssid
+RegularWifiMac::GetSsid (void) const
+{
+ return m_ssid;
+}
+
+void
+RegularWifiMac::SetBssid (Mac48Address bssid)
+{
+ NS_LOG_FUNCTION (this << bssid);
+ m_low->SetBssid (bssid);
+}
+
+Mac48Address
+RegularWifiMac::GetBssid (void) const
+{
+ return m_low->GetBssid ();
+}
+
+void
+RegularWifiMac::SetPromisc (void)
+{
+ m_low->SetPromisc ();
+}
+
+void
+RegularWifiMac::Enqueue (Ptr<const Packet> packet,
+ Mac48Address to, Mac48Address from)
+{
+ //We expect RegularWifiMac subclasses which do support forwarding (e.g.,
+ //AP) to override this method. Therefore, we throw a fatal error if
+ //someone tries to invoke this method on a class which has not done
+ //this.
+ NS_FATAL_ERROR ("This MAC entity (" << this << ", " << GetAddress ()
+ << ") does not support Enqueue() with from address");
+}
+
+bool
+RegularWifiMac::SupportsSendFrom (void) const
+{
+ return false;
+}
+
+void
+RegularWifiMac::ForwardUp (Ptr<Packet> packet, Mac48Address from, Mac48Address to)
+{
+ NS_LOG_FUNCTION (this << packet << from);
+ m_forwardUp (packet, from, to);
+}
+
+void
+RegularWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
+{
+ NS_LOG_FUNCTION (this << packet << hdr);
+
+ Mac48Address to = hdr->GetAddr1 ();
+ Mac48Address from = hdr->GetAddr2 ();
+
+ //We don't know how to deal with any frame that is not addressed to
+ //us (and odds are there is nothing sensible we could do anyway),
+ //so we ignore such frames.
+ //
+ //The derived class may also do some such filtering, but it doesn't
+ //hurt to have it here too as a backstop.
+ if (to != GetAddress ())
+ {
+ return;
+ }
+
+ if (hdr->IsMgt () && hdr->IsAction ())
+ {
+ //There is currently only any reason for Management Action
+ //frames to be flying about if we are a QoS STA.
+ NS_ASSERT (m_qosSupported);
+
+ WifiActionHeader actionHdr;
+ packet->RemoveHeader (actionHdr);
+
+ switch (actionHdr.GetCategory ())
+ {
+ case WifiActionHeader::BLOCK_ACK:
+
+ switch (actionHdr.GetAction ().blockAck)
+ {
+ case WifiActionHeader::BLOCK_ACK_ADDBA_REQUEST:
+ {
+ MgtAddBaRequestHeader reqHdr;
+ packet->RemoveHeader (reqHdr);
+
+ //We've received an ADDBA Request. Our policy here is
+ //to automatically accept it, so we get the ADDBA
+ //Response on it's way immediately.
+ SendAddBaResponse (&reqHdr, from);
+ //This frame is now completely dealt with, so we're done.
+ return;
+ }
+ case WifiActionHeader::BLOCK_ACK_ADDBA_RESPONSE:
+ {
+ MgtAddBaResponseHeader respHdr;
+ packet->RemoveHeader (respHdr);
+
+ //We've received an ADDBA Response. We assume that it
+ //indicates success after an ADDBA Request we have
+ //sent (we could, in principle, check this, but it
+ //seems a waste given the level of the current model)
+ //and act by locally establishing the agreement on
+ //the appropriate queue.
+ AcIndex ac = QosUtilsMapTidToAc (respHdr.GetTid ());
+ m_edca[ac]->GotAddBaResponse (&respHdr, from);
+ //This frame is now completely dealt with, so we're done.
+ return;
+ }
+ case WifiActionHeader::BLOCK_ACK_DELBA:
+ {
+ MgtDelBaHeader delBaHdr;
+ packet->RemoveHeader (delBaHdr);
+
+ if (delBaHdr.IsByOriginator ())
+ {
+ //This DELBA frame was sent by the originator, so
+ //this means that an ingoing established
+ //agreement exists in MacLow and we need to
+ //destroy it.
+ m_low->DestroyBlockAckAgreement (from, delBaHdr.GetTid ());
+ }
+ else
+ {
+ //We must have been the originator. We need to
+ //tell the correct queue that the agreement has
+ //been torn down
+ AcIndex ac = QosUtilsMapTidToAc (delBaHdr.GetTid ());
+ m_edca[ac]->GotDelBaFrame (&delBaHdr, from);
+ }
+ //This frame is now completely dealt with, so we're done.
+ return;
+ }
+ default:
+ NS_FATAL_ERROR ("Unsupported Action field in Block Ack Action frame");
+ return;
+ }
+ default:
+ NS_FATAL_ERROR ("Unsupported Action frame received");
+ return;
+ }
+ }
+ NS_FATAL_ERROR ("Don't know how to handle frame (type=" << hdr->GetType ());
+}
+
+void
+RegularWifiMac::DeaggregateAmsduAndForward (Ptr<Packet> aggregatedPacket,
+ const WifiMacHeader *hdr)
+{
+ MsduAggregator::DeaggregatedMsdus packets =
+ MsduAggregator::Deaggregate (aggregatedPacket);
+
+ for (MsduAggregator::DeaggregatedMsdusCI i = packets.begin ();
+ i != packets.end (); ++i)
+ {
+ ForwardUp ((*i).first, (*i).second.GetSourceAddr (),
+ (*i).second.GetDestinationAddr ());
+ }
+}
+
+void
+RegularWifiMac::SendAddBaResponse (const MgtAddBaRequestHeader *reqHdr,
+ Mac48Address originator)
+{
+ NS_LOG_FUNCTION (this);
+ WifiMacHeader hdr;
+ hdr.SetAction ();
+ hdr.SetAddr1 (originator);
+ hdr.SetAddr2 (GetAddress ());
+ hdr.SetAddr3 (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);
+#ifdef WITH_MORE_FIX_TO_BA_IN_REGULAR_MAC
+ //added by zeng:
+ //destory the old aggreement in case it exists
+ m_low->DestroyBlockAckAgreement( originator, reqHdr->GetTid ());
+#endif
+
+ //We need to notify our MacLow object as it will have to buffer all
+ //correctly received packets for this Block Ack session
+ m_low->CreateBlockAckAgreement (&respHdr, originator,
+ reqHdr->GetStartingSequence ());
+
+ //It is unclear which queue this frame should go into. For now we
+ //bung it into the queue corresponding to the TID for which we are
+ //establishing an agreement, and push it to the head.
+ m_edca[QosUtilsMapTidToAc (reqHdr->GetTid ())]->PushFront (packet, hdr);
+}
+
+TypeId
+RegularWifiMac::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::RegularWifiMac")
+ .SetParent<WifiMac> ()
+ .SetGroupName ("Wifi")
+ .AddAttribute ("QosSupported",
+ "This Boolean attribute is set to enable 802.11e/WMM-style QoS support at this STA",
+ BooleanValue (false),
+ MakeBooleanAccessor (&RegularWifiMac::SetQosSupported,
+ &RegularWifiMac::GetQosSupported),
+ MakeBooleanChecker ())
+ .AddAttribute ("HtSupported",
+ "This Boolean attribute is set to enable 802.11n support at this STA",
+ BooleanValue (false),
+ MakeBooleanAccessor (&RegularWifiMac::SetHtSupported,
+ &RegularWifiMac::GetHtSupported),
+ MakeBooleanChecker ())
+ .AddAttribute ("VhtSupported",
+ "This Boolean attribute is set to enable 802.11ac support at this STA",
+ BooleanValue (false),
+ MakeBooleanAccessor (&RegularWifiMac::SetVhtSupported,
+ &RegularWifiMac::GetVhtSupported),
+ MakeBooleanChecker ())
+ .AddAttribute ("CtsToSelfSupported",
+ "Use CTS to Self when using a rate that is not in the basic set rate",
+ BooleanValue (false),
+ MakeBooleanAccessor (&RegularWifiMac::SetCtsToSelfSupported,
+ &RegularWifiMac::GetCtsToSelfSupported),
+ MakeBooleanChecker ())
+ .AddAttribute ("DcaTxop", "The DcaTxop object",
+ PointerValue (),
+ MakePointerAccessor (&RegularWifiMac::GetDcaTxop),
+ MakePointerChecker<DcaTxop> ())
+ .AddAttribute ("VO_EdcaTxopN",
+ "Queue that manages packets belonging to AC_VO access class",
+ PointerValue (),
+ MakePointerAccessor (&RegularWifiMac::GetVOQueue),
+ MakePointerChecker<EdcaTxopN> ())
+ .AddAttribute ("VI_EdcaTxopN",
+ "Queue that manages packets belonging to AC_VI access class",
+ PointerValue (),
+ MakePointerAccessor (&RegularWifiMac::GetVIQueue),
+ MakePointerChecker<EdcaTxopN> ())
+ .AddAttribute ("BE_EdcaTxopN",
+ "Queue that manages packets belonging to AC_BE access class",
+ PointerValue (),
+ MakePointerAccessor (&RegularWifiMac::GetBEQueue),
+ MakePointerChecker<EdcaTxopN> ())
+ .AddAttribute ("BK_EdcaTxopN",
+ "Queue that manages packets belonging to AC_BK access class",
+ PointerValue (),
+ MakePointerAccessor (&RegularWifiMac::GetBKQueue),
+ MakePointerChecker<EdcaTxopN> ())
+ .AddTraceSource ("TxOkHeader",
+ "The header of successfully transmitted packet",
+ MakeTraceSourceAccessor (&RegularWifiMac::m_txOkCallback),
+ "ns3::WifiMacHeader::TracedCallback")
+ .AddTraceSource ("TxErrHeader",
+ "The header of unsuccessfully transmitted packet",
+ MakeTraceSourceAccessor (&RegularWifiMac::m_txErrCallback),
+ "ns3::WifiMacHeader::TracedCallback")
+ ;
+ return tid;
+}
+
+void
+RegularWifiMac::FinishConfigureStandard (enum WifiPhyStandard standard)
+{
+ uint32_t cwmin;
+ uint32_t cwmax;
+
+ switch (standard)
+ {
+ case WIFI_PHY_STANDARD_holland:
+ case WIFI_PHY_STANDARD_80211a:
+ case WIFI_PHY_STANDARD_80211g:
+ case WIFI_PHY_STANDARD_80211_10MHZ:
+ case WIFI_PHY_STANDARD_80211_5MHZ:
+ case WIFI_PHY_STANDARD_80211n_5GHZ:
+ case WIFI_PHY_STANDARD_80211n_2_4GHZ:
+ case WIFI_PHY_STANDARD_80211ac:
+ cwmin = 15;
+ cwmax = 1023;
+ break;
+ case WIFI_PHY_STANDARD_80211b:
+ cwmin = 31;
+ cwmax = 1023;
+ break;
+ default:
+ NS_FATAL_ERROR ("Unsupported WifiPhyStandard in RegularWifiMac::FinishConfigureStandard ()");
+ }
+
+ //The special value of AC_BE_NQOS which exists in the Access
+ //Category enumeration allows us to configure plain old DCF.
+ ConfigureDcf (m_dca, cwmin, cwmax, AC_BE_NQOS);
+
+ //Now we configure the EDCA functions
+ for (EdcaQueues::iterator i = m_edca.begin (); i != m_edca.end (); ++i)
+ {
+ ConfigureDcf (i->second, cwmin, cwmax, i->first);
+ }
+}
+
+void
+RegularWifiMac::TxOk (const WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this << hdr);
+ m_txOkCallback (hdr);
+}
+
+void
+RegularWifiMac::TxFailed (const WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this << hdr);
+ m_txErrCallback (hdr);
+}
+
+} //namespace ns3
diff --git a/emu-radio/ns3-patch/wifi/model/regular-wifi-mac.h b/emu-radio/ns3-patch/wifi/model/regular-wifi-mac.h
new file mode 100644
index 00000000..3059f60d
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/regular-wifi-mac.h
@@ -0,0 +1,480 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * 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: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#ifndef REGULAR_WIFI_MAC_H
+#define REGULAR_WIFI_MAC_H
+
+#include "ns3/wifi-mac.h"
+#include "dca-txop.h"
+#include "edca-txop-n.h"
+#include "wifi-remote-station-manager.h"
+#include "ssid.h"
+#include "qos-utils.h"
+#include <map>
+
+#define WITH_MORE_FIX_TO_BA_IN_REGULAR_MAC 1
+
+namespace ns3 {
+
+class Dcf;
+class MacLow;
+class MacRxMiddle;
+class MacTxMiddle;
+class DcfManager;
+
+/**
+ * \brief base class for all MAC-level wifi objects.
+ * \ingroup wifi
+ *
+ * This class encapsulates all the low-level MAC functionality
+ * DCA, EDCA, etc) and all the high-level MAC functionality
+ * (association/disassociation state machines).
+ *
+ */
+class RegularWifiMac : public WifiMac
+{
+public:
+ static TypeId GetTypeId (void);
+
+ RegularWifiMac ();
+ virtual ~RegularWifiMac ();
+
+ /**
+ * \param slotTime the slot duration
+ */
+ void SetSlot (Time slotTime);
+ /**
+ * \param sifs the sifs duration
+ */
+ void SetSifs (Time sifs);
+ /**
+ * \param eifsNoDifs the duration of an EIFS minus DIFS.
+ *
+ * This value is used to calculate the EIFS depending
+ * on AIFSN.
+ */
+ void SetEifsNoDifs (Time eifsNoDifs);
+ /**
+ * \param pifs the pifs duration.
+ */
+ void SetPifs (Time pifs);
+ /**
+ * \param rifs the rifs duration.
+ */
+ void SetRifs (Time rifs);
+ /**
+ * \param ctsTimeout the duration of a CTS timeout.
+ */
+ void SetCtsTimeout (Time ctsTimeout);
+ /**
+ * \param ackTimeout the duration of an ACK timeout.
+ */
+ void SetAckTimeout (Time ackTimeout);
+
+ Time GetRifs (void) const;
+ /**
+ * \return the current PIFS duration.
+ */
+ Time GetPifs (void) const;
+ /**
+ * \return the current SIFS duration.
+ */
+ Time GetSifs (void) const;
+ /**
+ * \return the current slot duration.
+ */
+ Time GetSlot (void) const;
+ /**
+ * \return the current EIFS minus DIFS duration
+ */
+ Time GetEifsNoDifs (void) const;
+ /**
+ * \return the current CTS timeout duration.
+ */
+ Time GetCtsTimeout (void) const;
+ /**
+ * \return the current ACK timeout duration.
+ */
+ Time GetAckTimeout (void) const;
+
+ /**
+ * Enable or disable CTS-to-self feature.
+ *
+ * \param enable true if CTS-to-self is to be supported,
+ * false otherwise
+ */
+ void SetCtsToSelfSupported (bool enable);
+
+ /**
+ * Return whether the device supports CTS-to-self
+ * capability.
+ *
+ * \return true if CTS-to-self is supported,
+ * false otherwise.
+ */
+ bool GetCtsToSelfSupported () const;
+ /**
+ * \return the MAC address associated to this MAC layer.
+ */
+ virtual Mac48Address GetAddress (void) const;
+ /**
+ * \return the ssid which this MAC layer is going to try to stay in.
+ */
+ virtual Ssid GetSsid (void) const;
+ /**
+ * \param address the current address of this MAC layer.
+ */
+ virtual void SetAddress (Mac48Address address);
+ /**
+ * \param ssid the current ssid of this MAC layer.
+ */
+ virtual void SetSsid (Ssid ssid);
+ /**
+ * \param bssid the BSSID of the network that this device belongs to.
+ */
+ virtual void SetBssid (Mac48Address bssid);
+ /**
+ * \return the bssid of the network this device belongs to.
+ */
+ virtual Mac48Address GetBssid (void) const;
+ /**
+ * \brief Sets the interface in promiscuous mode.
+ *
+ * Enables promiscuous mode on the interface. Note that any further
+ * filtering on the incoming frame path may affect the overall
+ * behavior.
+ */
+ virtual void SetPromisc (void);
+
+ /**
+ * \param packet the packet to send.
+ * \param to the address to which the packet should be sent.
+ * \param from the address from which the packet should be sent.
+ *
+ * The packet should be enqueued in a tx queue, and should be
+ * dequeued as soon as the channel access function determines that
+ * access is granted to this MAC. The extra parameter "from" allows
+ * this device to operate in a bridged mode, forwarding received
+ * frames without altering the source address.
+ */
+ virtual void Enqueue (Ptr<const Packet> packet, Mac48Address to, Mac48Address from);
+
+ virtual bool SupportsSendFrom (void) const;
+
+ /**
+ * \param packet the packet to send.
+ * \param to the address to which the packet should be sent.
+ *
+ * The packet should be enqueued in a tx queue, and should be
+ * dequeued as soon as the channel access function determines that
+ * access is granted to this MAC.
+ */
+ virtual void Enqueue (Ptr<const Packet> packet, Mac48Address to) = 0;
+ /**
+ * \param phy the physical layer attached to this MAC.
+ */
+ virtual void SetWifiPhy (Ptr<WifiPhy> phy);
+ /**
+ * \return the physical layer attached to this MAC.
+ */
+ virtual Ptr<WifiPhy> GetWifiPhy (void) const;
+ /**
+ * removes attached WifiPhy device from this MAC.
+ */
+ virtual void ResetWifiPhy (void);
+ /**
+ * \param stationManager the station manager attached to this MAC.
+ */
+ virtual void SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> stationManager);
+ /**
+ * \return the station manager attached to this MAC.
+ */
+ virtual Ptr<WifiRemoteStationManager> GetWifiRemoteStationManager (void) const;
+
+ /**
+ * This type defines the callback of a higher layer that a
+ * WifiMac(-derived) object invokes to pass a packet up the stack.
+ *
+ * \param packet the packet that has been received.
+ * \param from the MAC address of the device that sent the packet.
+ * \param to the MAC address ot the device that the packet is destined for.
+ */
+ typedef Callback<void, Ptr<Packet>, Mac48Address, Mac48Address> ForwardUpCallback;
+ /**
+ * \param upCallback the callback to invoke when a packet must be
+ * forwarded up the stack.
+ */
+ virtual void SetForwardUpCallback (ForwardUpCallback upCallback);
+ /**
+ * \param linkUp the callback to invoke when the link becomes up.
+ */
+ virtual void SetLinkUpCallback (Callback<void> linkUp);
+ /**
+ * \param linkDown the callback to invoke when the link becomes down.
+ */
+ virtual void SetLinkDownCallback (Callback<void> linkDown);
+
+ /* Next functions are not pure virtual 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;
+
+
+protected:
+ virtual void DoInitialize ();
+ virtual void DoDispose ();
+
+ MacRxMiddle *m_rxMiddle; //!< RX middle (de-fragmentation etc.)
+ MacTxMiddle *m_txMiddle; //!< TX middle (aggregation etc.)
+ Ptr<MacLow> m_low; //!< MacLow (RTS, CTS, DATA, ACK etc.)
+ DcfManager *m_dcfManager; //!< DCF manager (access to channel)
+ Ptr<WifiPhy> m_phy; //!< Wifi PHY
+
+ Ptr<WifiRemoteStationManager> m_stationManager; //!< Remote station manager (rate control, RTS/CTS/fragmentation thresholds etc.)
+
+ ForwardUpCallback m_forwardUp; //!< Callback to forward packet up the stack
+ Callback<void> m_linkUp; //!< Callback when a link is up
+ Callback<void> m_linkDown; //!< Callback when a link is down
+
+ Ssid m_ssid; //!< Service Set ID (SSID)
+
+ /** This holds a pointer to the DCF instance for this WifiMac - used
+ for transmission of frames to non-QoS peers. */
+ Ptr<DcaTxop> m_dca;
+
+ /** This type defines a mapping between an Access Category index,
+ and a pointer to the corresponding channel access function */
+ typedef std::map<AcIndex, Ptr<EdcaTxopN> > EdcaQueues;
+
+ /** This is a map from Access Category index to the corresponding
+ channel access function */
+ EdcaQueues m_edca;
+
+ /**
+ * Accessor for the DCF object
+ *
+ * \return a smart pointer to DcaTxop
+ */
+ Ptr<DcaTxop> GetDcaTxop (void) const;
+
+ /**
+ * Accessor for the AC_VO channel access function
+ *
+ * \return a smart pointer to EdcaTxopN
+ */
+ Ptr<EdcaTxopN> GetVOQueue (void) const;
+ /**
+ * Accessor for the AC_VI channel access function
+ *
+ * \return a smart pointer to EdcaTxopN
+ */
+ Ptr<EdcaTxopN> GetVIQueue (void) const;
+ /**
+ * Accessor for the AC_BE channel access function
+ *
+ * \return a smart pointer to EdcaTxopN
+ */
+ Ptr<EdcaTxopN> GetBEQueue (void) const;
+ /**
+ * Accessor for the AC_BK channel access function
+ *
+ * \return a smart pointer to EdcaTxopN
+ */
+ Ptr<EdcaTxopN> GetBKQueue (void) const;
+
+ /**
+ * \param standard the phy standard to be used
+ *
+ * This method is called by ns3::WifiMac::ConfigureStandard to
+ * complete the configuration process for a requested phy standard.
+ *
+ * This method may be overriden by a derived class (e.g., in order
+ * to apply DCF or EDCA parameters specific to the usage model it is
+ * dealing with), in which case the reimplementation may choose to
+ * deal with certain values in the WifiPhyStandard enumeration, and
+ * chain up to this implementation to deal with the remainder.
+ */
+ virtual void FinishConfigureStandard (enum WifiPhyStandard standard);
+
+ /**
+ * This method is invoked by a subclass to specify what type of
+ * station it is implementing. This is something that the channel
+ * access functions (instantiated within this class as EdcaTxopN's)
+ * need to know.
+ *
+ * \param type the type of station.
+ */
+ void SetTypeOfStation (TypeOfStation type);
+
+ /**
+ * This method acts as the MacRxMiddle receive callback and is
+ * invoked to notify us that a frame has been received. The
+ * implementation is intended to capture logic that is going to be
+ * common to all (or most) derived classes. Specifically, handling
+ * of Block Ack managment frames is dealt with here.
+ *
+ * This method will need, however, to be overriden by derived
+ * classes so that they can perform their data handling before
+ * invoking the base version.
+ *
+ * \param packet the packet that has been received.
+ * \param hdr a pointer to the MAC header of the received frame.
+ */
+ virtual void Receive (Ptr<Packet> packet, const WifiMacHeader *hdr);
+ /**
+ * The packet we sent was successfully received by the receiver
+ * (i.e. we received an ACK from the receiver).
+ *
+ * \param hdr the header of the packet that we successfully sent
+ */
+ virtual void TxOk (const WifiMacHeader &hdr);
+ /**
+ * The packet we sent was successfully received by the receiver
+ * (i.e. we did not receive an ACK from the receiver).
+ *
+ * \param hdr the header of the packet that we failed to sent
+ */
+ virtual void TxFailed (const WifiMacHeader &hdr);
+
+ /**
+ * Forward the packet up to the device.
+ *
+ * \param packet the packet that we are forwarding up to the device
+ * \param from the address of the source
+ * \param to the address of the destination
+ */
+ void ForwardUp (Ptr<Packet> packet, Mac48Address from, Mac48Address to);
+
+ /**
+ * This method can be called to de-aggregate an A-MSDU and forward
+ * the constituent packets up the stack.
+ *
+ * \param aggregatedPacket the Packet containing the A-MSDU.
+ * \param hdr a pointer to the MAC header for \c aggregatedPacket.
+ */
+ virtual void DeaggregateAmsduAndForward (Ptr<Packet> aggregatedPacket,
+ const WifiMacHeader *hdr);
+
+ /**
+ * This method can be called to accept a received ADDBA Request. An
+ * ADDBA Response will be constructed and queued for transmission.
+ *
+ * \param reqHdr a pointer to the received ADDBA Request header.
+ * \param originator the MAC address of the originator.
+ */
+ virtual void SendAddBaResponse (const MgtAddBaRequestHeader *reqHdr,
+ Mac48Address originator);
+
+ /**
+ * This Boolean is set \c true iff this WifiMac is to model
+ * 802.11e/WMM style Quality of Service. It is exposed through the
+ * attribute system.
+ *
+ * At the moment, this flag is the sole selection between QoS and
+ * non-QoS operation for the STA (whether IBSS, AP, or
+ * non-AP). Ultimately, we will want a QoS-enabled STA to be able to
+ * fall back to non-QoS operation with a non-QoS peer. This'll
+ * require further intelligence - i.e., per-association QoS
+ * state. Having a big switch seems like a good intermediate stage,
+ * however.
+ */
+ bool m_qosSupported;
+
+ /**
+ * Enable or disable QoS support for the device.
+ *
+ * \param enable whether QoS is supported
+ */
+ void SetQosSupported (bool enable);
+ /**
+ * Return whether the device supports QoS.
+ *
+ * \return true if QoS is supported, false otherwise
+ */
+ bool GetQosSupported () const;
+
+ /**
+ * This Boolean is set \c true iff this WifiMac is to model
+ * 802.11n. It is exposed through the attribute system.
+ *
+ * At the moment, this flag is the sole selection between HT and
+ * non-HT operation for the STA (whether IBSS, AP, or
+ * non-AP). Ultimately, we will want a HT-enabled STA to be able to
+ * fall back to non-HT operation with a non-HT peer. This'll
+ * require further intelligence - i.e., per-association HT
+ * state. Having a big switch seems like a good intermediate stage,
+ * however.
+ */
+ bool m_htSupported;
+
+ /**
+ * Enable or disable HT support for the device.
+ *
+ * \param enable whether HT is supported
+ */
+ void SetHtSupported (bool enable);
+ /**
+ * Return whether the device supports HT.
+ *
+ * \return true if HT is supported, false otherwise
+ */
+ bool GetHtSupported () const;
+
+ /**
+ * This Boolean is set \c true iff this WifiMac is to model
+ * 802.11ac. It is exposed through the attribute system.
+ */
+ bool m_vhtSupported;
+ /**
+ * Enable or disable HT support for the device.
+ *
+ * \param enable whether VHT is supported
+ */
+ void SetVhtSupported (bool enable);
+ /**
+ * Return whether the device supports VHT.
+ *
+ * \return true if VHT is supported, false otherwise
+ */
+ bool GetVhtSupported () const;
+
+
+private:
+ RegularWifiMac (const RegularWifiMac &);
+ RegularWifiMac & operator= (const RegularWifiMac &);
+
+ /**
+ * This method is a private utility invoked to configure the channel
+ * access function for the specified Access Category.
+ *
+ * \param ac the Access Category index of the queue to initialise.
+ */
+ void SetupEdcaQueue (enum AcIndex ac);
+
+ TracedCallback<const WifiMacHeader &> m_txOkCallback;
+ TracedCallback<const WifiMacHeader &> m_txErrCallback;
+};
+
+} //namespace ns3
+
+#endif /* REGULAR_WIFI_MAC_H */
diff --git a/emu-radio/ns3-patch/wifi/model/sta-wifi-mac.cc b/emu-radio/ns3-patch/wifi/model/sta-wifi-mac.cc
new file mode 100644
index 00000000..be5e9f2d
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/sta-wifi-mac.cc
@@ -0,0 +1,1085 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006, 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
+ *
+ * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Mirko Banchi <mk.banchi@gmail.com>
+ */
+
+#include "sta-wifi-mac.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ns3/string.h"
+#include "ns3/pointer.h"
+#include "ns3/boolean.h"
+#include "ns3/trace-source-accessor.h"
+#include "qos-tag.h"
+#include "mac-low.h"
+#include "dcf-manager.h"
+#include "mac-rx-middle.h"
+#include "mac-tx-middle.h"
+#include "wifi-mac-header.h"
+#include "msdu-aggregator.h"
+#include "amsdu-subframe-header.h"
+#include "mgt-headers.h"
+#include "ht-capabilities.h"
+#include "vht-capabilities.h"
+
+//added:+++++
+#include "yans-wifi-phy.h"
+#include "ap-info-collection.h"
+//for removing packets for old AP
+#include "wifi-mac-queue.h"
+
+
+#define MAX_NUM_PROBEREQ 4
+#define HYSTERESIS_THRESHOLD 4
+//end++++++++++
+
+/*
+ * The state machine for this STA is:
+ -------------- -----------
+ | Associated | <-------------------- -------> | Refused |
+ -------------- \ / -----------
+ \ \ /
+ \ ----------------- -----------------------------
+ \-> | Beacon Missed | --> | Wait Association Response |
+ ----------------- -----------------------------
+ \ ^
+ \ |
+ \ -----------------------
+ \-> | Wait Probe Response |
+ -----------------------
+ */
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("StaWifiMac");
+
+NS_OBJECT_ENSURE_REGISTERED (StaWifiMac);
+
+TypeId
+StaWifiMac::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::StaWifiMac")
+ .SetParent<RegularWifiMac> ()
+ .SetGroupName ("Wifi")
+ .AddConstructor<StaWifiMac> ()
+ .AddAttribute ("ProbeRequestTimeout", "The interval between two consecutive probe request attempts.",
+ TimeValue (Seconds (0.05)),
+ MakeTimeAccessor (&StaWifiMac::m_probeRequestTimeout),
+ MakeTimeChecker ())
+ .AddAttribute ("AssocRequestTimeout", "The interval between two consecutive assoc request attempts.",
+ TimeValue (Seconds (0.5)),
+ MakeTimeAccessor (&StaWifiMac::m_assocRequestTimeout),
+ MakeTimeChecker ())
+ .AddAttribute ("MaxMissedBeacons",
+ "Number of beacons which much be consecutively missed before "
+ "we attempt to restart association.",
+ UintegerValue (10),
+ MakeUintegerAccessor (&StaWifiMac::m_maxMissedBeacons),
+ MakeUintegerChecker<uint32_t> ())
+ .AddAttribute ("ActiveProbing",
+ "If true, we send probe requests. If false, we don't."
+ "NOTE: if more than one STA in your simulation is using active probing, "
+ "you should enable it at a different simulation time for each STA, "
+ "otherwise all the STAs will start sending probes at the same time resulting in collisions. "
+ "See bug 1060 for more info.",
+ BooleanValue (false),
+ MakeBooleanAccessor (&StaWifiMac::SetActiveProbing, &StaWifiMac::GetActiveProbing),
+ MakeBooleanChecker ())
+ .AddTraceSource ("Assoc", "Associated with an access point.",
+ MakeTraceSourceAccessor (&StaWifiMac::m_assocLogger),
+ "ns3::Mac48Address::TracedCallback")
+ .AddTraceSource ("DeAssoc", "Association with an access point lost.",
+ MakeTraceSourceAccessor (&StaWifiMac::m_deAssocLogger),
+ "ns3::Mac48Address::TracedCallback")
+ ;
+ return tid;
+}
+
+StaWifiMac::StaWifiMac ()
+ : m_state (BEACON_MISSED),
+ m_probeRequestEvent (),
+ m_assocRequestEvent (),
+ m_beaconWatchdogEnd (Seconds (0.0))
+ ,m_isSelectingAP(false)
+ ,m_currentRssi(0.0)
+ ,m_packetCounts(0)
+ ,m_probeRequestCount(0)
+ ,m_isEverAssoicated(true)
+{
+ NS_LOG_FUNCTION (this);
+
+ //Let the lower layers know that we are acting as a non-AP STA in
+ //an infrastructure BSS.
+ SetTypeOfStation (STA);
+}
+
+StaWifiMac::~StaWifiMac ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+void
+StaWifiMac::SetMaxMissedBeacons (uint32_t missed)
+{
+ NS_LOG_FUNCTION (this << missed);
+ m_maxMissedBeacons = missed;
+}
+
+void
+StaWifiMac::SetProbeRequestTimeout (Time timeout)
+{
+ NS_LOG_FUNCTION (this << timeout);
+ m_probeRequestTimeout = timeout;
+}
+
+void
+StaWifiMac::SetAssocRequestTimeout (Time timeout)
+{
+ NS_LOG_FUNCTION (this << timeout);
+ m_assocRequestTimeout = timeout;
+}
+
+void
+StaWifiMac::StartActiveAssociation (void)
+{
+ NS_LOG_FUNCTION (this);
+ TryToEnsureAssociated ();
+}
+
+void
+StaWifiMac::SetActiveProbing (bool enable)
+{
+ NS_LOG_FUNCTION (this << enable);
+ if (enable)
+ {
+ Simulator::ScheduleNow (&StaWifiMac::TryToEnsureAssociated, this);
+ }
+ else
+ {
+ m_probeRequestEvent.Cancel ();
+ }
+ m_activeProbing = enable;
+}
+
+bool StaWifiMac::GetActiveProbing (void) const
+{
+ return m_activeProbing;
+}
+
+void
+StaWifiMac::SendProbeRequest (void)
+{
+// std::cout<<Simulator::Now().ToDouble(Time::S)<<", send probe request="<<m_probeRequestCount <<"\n";
+
+ NS_LOG_FUNCTION (this);
+ WifiMacHeader hdr;
+ hdr.SetProbeReq ();
+ hdr.SetAddr1 (Mac48Address::GetBroadcast ());
+ hdr.SetAddr2 (GetAddress ());
+ hdr.SetAddr3 (Mac48Address::GetBroadcast ());
+ hdr.SetDsNotFrom ();
+ hdr.SetDsNotTo ();
+ Ptr<Packet> packet = Create<Packet> ();
+ MgtProbeRequestHeader probe;
+ probe.SetSsid (GetSsid ());
+ probe.SetSupportedRates (GetSupportedRates ());
+ if (m_htSupported || m_vhtSupported)
+ {
+ probe.SetHtCapabilities (GetHtCapabilities ());
+ hdr.SetNoOrder ();
+ }
+ if (m_vhtSupported)
+ {
+ probe.SetVhtCapabilities (GetVhtCapabilities ());
+ }
+ packet->AddHeader (probe);
+
+ //The standard is not clear on the correct queue for management
+ //frames if we are a QoS AP. The approach taken here is to always
+ //use the DCF for these regardless of whether we have a QoS
+ //association or not.
+ m_dca->Queue (packet, hdr);
+
+
+}
+
+void
+StaWifiMac::SendAssociationRequest (void)
+{
+// std::cout<<Simulator::Now().ToDouble(Time::S)<<", send assoc request to="<<GetBssid ()<<"by="<<GetAddress ()<<"\n";
+
+ NS_LOG_FUNCTION (this << GetBssid ());
+ WifiMacHeader hdr;
+ hdr.SetAssocReq ();
+ hdr.SetAddr1 (GetBssid ());
+ hdr.SetAddr2 (GetAddress ());
+ hdr.SetAddr3 (GetBssid ());
+ hdr.SetDsNotFrom ();
+ hdr.SetDsNotTo ();
+ Ptr<Packet> packet = Create<Packet> ();
+ MgtAssocRequestHeader assoc;
+ assoc.SetSsid (GetSsid ());
+ assoc.SetSupportedRates (GetSupportedRates ());
+ if (m_htSupported || m_vhtSupported)
+ {
+ assoc.SetHtCapabilities (GetHtCapabilities ());
+ hdr.SetNoOrder ();
+ }
+ if (m_vhtSupported)
+ {
+ assoc.SetVhtCapabilities (GetVhtCapabilities ());
+ }
+ packet->AddHeader (assoc);
+
+ //The standard is not clear on the correct queue for management
+ //frames if we are a QoS AP. The approach taken here is to always
+ //use the DCF for these regardless of whether we have a QoS
+ //association or not.
+ m_dca->Queue (packet, hdr);
+
+ if (m_assocRequestEvent.IsRunning ())
+ {
+ m_assocRequestEvent.Cancel ();
+ }
+ m_assocRequestEvent = Simulator::Schedule (m_assocRequestTimeout,
+ &StaWifiMac::AssocRequestTimeout, this);
+}
+
+void
+StaWifiMac::sendDissassociationRequest (void)
+{
+// std::cout<<Simulator::Now().ToDouble(Time::S)<<", send assoc request to="<<GetBssid ()<<"by="<<GetAddress ()<<"\n";
+
+ NS_LOG_FUNCTION (this << GetBssid ());
+ WifiMacHeader hdr;
+ hdr.SetType(WIFI_MAC_MGT_DISASSOCIATION);
+ hdr.SetAddr1 (GetBssid ());
+ hdr.SetAddr2 (GetAddress ());
+ hdr.SetAddr3 (GetBssid ());
+ hdr.SetDsNotFrom ();
+ hdr.SetDsNotTo ();
+ Ptr<Packet> packet = Create<Packet> ();
+
+ //The standard is not clear on the correct queue for management
+ //frames if we are a QoS AP. The approach taken here is to always
+ //use the DCF for these regardless of whether we have a QoS
+ //association or not.
+ m_dca->Queue (packet, hdr);
+
+
+}
+
+void
+StaWifiMac::TryToEnsureAssociated (void)
+{
+ NS_LOG_FUNCTION (this);
+ switch (m_state)
+ {
+ case ASSOCIATED:
+ return;
+ break;
+ case WAIT_PROBE_RESP:
+ /* we have sent a probe request earlier so we
+ do not need to re-send a probe request immediately.
+ We just need to wait until probe-request-timeout
+ or until we get a probe response
+ */
+ break;
+ case BEACON_MISSED:
+ /* we were associated but we missed a bunch of beacons
+ * so we should assume we are not associated anymore.
+ * We try to initiate a probe request now.
+ */
+ m_linkDown ();
+ if (m_activeProbing)
+ {
+ SetState (WAIT_PROBE_RESP);
+ if (m_probeRequestEvent.IsRunning ())
+ {
+ m_probeRequestEvent.Cancel ();
+ }
+ m_probeRequestEvent = Simulator::Schedule (m_probeRequestTimeout,
+ &StaWifiMac::ProbeRequestTimeout, this);
+ if(m_isEverAssoicated)
+ {
+ sendBurstOfProbeRequest ();
+ }
+ else
+ {
+ SendProbeRequest();
+ }
+ }
+ break;
+ case WAIT_ASSOC_RESP:
+ /* we have sent an assoc request so we do not need to
+ re-send an assoc request right now. We just need to
+ wait until either assoc-request-timeout or until
+ we get an assoc response.
+ */
+ break;
+ case REFUSED:
+ /* we have sent an assoc request and received a negative
+ assoc resp. We wait until someone restarts an
+ association with a given ssid.
+ */
+ break;
+ }
+}
+
+void
+StaWifiMac::AssocRequestTimeout (void)
+{
+ NS_LOG_FUNCTION (this);
+ //SetState (WAIT_ASSOC_RESP);
+ //std::cout<<Simulator::Now().ToDouble(Time::S)<<", assoc request timed out" <<"\n";
+ //SendAssociationRequest ();
+
+ SetState(BEACON_MISSED);
+ TryToEnsureAssociated();
+}
+
+void
+StaWifiMac::ProbeRequestTimeout (void)
+{
+ NS_LOG_FUNCTION (this);
+
+
+ if (m_probeRequestBurstEvent.IsRunning ())
+ {
+ m_probeRequestBurstEvent.Cancel ();
+ }
+ m_probeRequestCount=0;
+
+ if(!m_isSelectingAP)//no response has been received before timeout
+ {
+ SetState (WAIT_PROBE_RESP);
+ if (m_probeRequestEvent.IsRunning ())
+ {
+ m_probeRequestEvent.Cancel ();
+ }
+ m_probeRequestEvent = Simulator::Schedule (m_probeRequestTimeout,
+ &StaWifiMac::ProbeRequestTimeout, this);
+ sendBurstOfProbeRequest ();
+ }
+ else
+ {
+
+ //destroy all block ack agreement with old AP (by pretending to receive a delba frame from AP).
+ //clean up packets for the old AP in the meanwhile
+ cleanUpPacketsAndAgreementsWithOldAp();
+
+ SetState (WAIT_ASSOC_RESP);
+ double candidateRssi=-1.0;
+ SupportedRates rates;
+
+ ApInfoCollection::iterator it;
+ for(it=m_apInfos.begin();it!=m_apInfos.end();it++)
+ {
+ if(it->getAverageRssi()>candidateRssi)
+ {
+ candidateRssi=it->getAverageRssi();
+ m_delayFromProbResp=it->getDelayFromProbResp();
+ SetBssid(it->getBssid());
+ rates=it->getSupportedRates();
+ }
+ }
+
+ //++++++++++++
+ //remove obsolete remote station states if exists, before reassoicate to the station
+ // m_stationManager->RemoveStation(GetBssid());
+ //++++++++++++++
+
+ loadSupportedRatesOfAp(rates,GetBssid());
+ //RestartBeaconWatchdog (delayFromProbResp);
+ SendAssociationRequest ();
+ }
+
+}
+
+void
+StaWifiMac::MissedBeacons (void)
+{
+ NS_LOG_FUNCTION (this);
+ if (m_beaconWatchdogEnd > Simulator::Now ())
+ {
+ if (m_beaconWatchdog.IsRunning ())
+ {
+ m_beaconWatchdog.Cancel ();
+ }
+ m_beaconWatchdog = Simulator::Schedule (m_beaconWatchdogEnd - Simulator::Now (),
+ &StaWifiMac::MissedBeacons, this);
+ return;
+ }
+ NS_LOG_DEBUG ("beacon missed");
+// std::cout<<Simulator::Now().ToDouble(Time::S)<<", beacon missed"<<"\n";
+
+
+#ifdef WITH_HYSTERESIS_HANDOVER_TRIGGER
+ m_currentApRrssiMeasures.clear();
+ m_candidadteApRssiMeasures.clear();
+#endif
+ SetState (BEACON_MISSED);
+ //disassociate from old AP
+ sendDissassociationRequest();
+ TryToEnsureAssociated ();
+}
+
+void
+StaWifiMac::RestartBeaconWatchdog (Time delay)
+{
+ NS_LOG_FUNCTION (this << delay);
+ m_beaconWatchdogEnd = std::max (Simulator::Now () + delay, m_beaconWatchdogEnd);
+ if (Simulator::GetDelayLeft (m_beaconWatchdog) < delay
+ && m_beaconWatchdog.IsExpired ())
+ {
+ NS_LOG_DEBUG ("really restart watchdog.");
+ m_beaconWatchdog = Simulator::Schedule (delay, &StaWifiMac::MissedBeacons, this);
+ }
+}
+
+bool
+StaWifiMac::IsAssociated (void) const
+{
+ return m_state == ASSOCIATED;
+}
+
+bool
+StaWifiMac::IsWaitAssocResp (void) const
+{
+ return m_state == WAIT_ASSOC_RESP;
+}
+
+void
+StaWifiMac::Enqueue (Ptr<const Packet> packet, Mac48Address to)
+{
+ NS_LOG_FUNCTION (this << packet << to);
+ if (!IsAssociated ())
+ {
+ NotifyTxDrop (packet);
+ TryToEnsureAssociated ();
+ return;
+ }
+ WifiMacHeader hdr;
+
+ //If we are not a QoS AP then we definitely want to use AC_BE to
+ //transmit the packet. A TID of zero will map to AC_BE (through \c
+ //QosUtilsMapTidToAc()), so we use that as our default here.
+ uint8_t tid = 0;
+
+ //For now, an AP that supports QoS does not support non-QoS
+ //associations, and vice versa. In future the AP model should
+ //support simultaneously associated QoS and non-QoS STAs, at which
+ //point there will need to be per-association QoS state maintained
+ //by the association state machine, and consulted here.
+ if (m_qosSupported)
+ {
+ hdr.SetType (WIFI_MAC_QOSDATA);
+ hdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK);
+ hdr.SetQosNoEosp ();
+ hdr.SetQosNoAmsdu ();
+ //Transmission of multiple frames in the same TXOP is not
+ //supported for now
+ hdr.SetQosTxopLimit (0);
+
+ //Fill in the QoS control field in the MAC header
+ tid = QosUtilsGetTidForPacket (packet);
+ //Any value greater than 7 is invalid and likely indicates that
+ //the packet had no QoS tag, so we revert to zero, which'll
+ //mean that AC_BE is used.
+ if (tid > 7)
+ {
+ tid = 0;
+ }
+ hdr.SetQosTid (tid);
+ }
+ else
+ {
+ hdr.SetTypeData ();
+ }
+ if (m_htSupported || m_vhtSupported)
+ {
+ hdr.SetNoOrder ();
+ }
+
+ hdr.SetAddr1 (GetBssid ());
+ hdr.SetAddr2 (m_low->GetAddress ());
+ hdr.SetAddr3 (to);
+ hdr.SetDsNotFrom ();
+ hdr.SetDsTo ();
+
+ if (m_qosSupported)
+ {
+ //Sanity check that the TID is valid
+ NS_ASSERT (tid < 8);
+ m_edca[QosUtilsMapTidToAc (tid)]->Queue (packet, hdr);
+ }
+ else
+ {
+ m_dca->Queue (packet, hdr);
+ }
+}
+
+void
+StaWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
+{
+ NS_LOG_FUNCTION (this << packet << hdr);
+ NS_ASSERT (!hdr->IsCtl ());
+ if (hdr->GetAddr3 () == GetAddress ())
+ {
+ NS_LOG_LOGIC ("packet sent by us.");
+ return;
+ }
+ else if (hdr->GetAddr1 () != GetAddress ()
+ && !hdr->GetAddr1 ().IsGroup ())
+ {
+ NS_LOG_LOGIC ("packet is not for us");
+ NotifyRxDrop (packet);
+ return;
+ }
+ else if (hdr->IsData ())
+ {
+ if (!IsAssociated ())
+ {
+ NS_LOG_LOGIC ("Received data frame while not associated: ignore");
+ NotifyRxDrop (packet);
+ return;
+ }
+ if (!(hdr->IsFromDs () && !hdr->IsToDs ()))
+ {
+ NS_LOG_LOGIC ("Received data frame not from the DS: ignore");
+ NotifyRxDrop (packet);
+ return;
+ }
+ if (hdr->GetAddr2 () != GetBssid ())
+ {
+ NS_LOG_LOGIC ("Received data frame not from the BSS we are associated with: ignore");
+ NotifyRxDrop (packet);
+ return;
+ }
+//here the rssi could be measured +++++++++++++++++++++++
+//end+++++++++++++++++++
+ if (hdr->IsQosData ())
+ {
+ if (hdr->IsQosAmsdu ())
+ {
+ NS_ASSERT (hdr->GetAddr3 () == GetBssid ());
+ DeaggregateAmsduAndForward (packet, hdr);
+ packet = 0;
+ }
+ else
+ {
+ ForwardUp (packet, hdr->GetAddr3 (), hdr->GetAddr1 ());
+ }
+ }
+ else
+ {
+ ForwardUp (packet, hdr->GetAddr3 (), hdr->GetAddr1 ());
+ }
+ return;
+ }
+ else if (hdr->IsProbeReq ()
+ || hdr->IsAssocReq ())
+ {
+ //This is a frame aimed at an AP, so we can safely ignore it.
+ NotifyRxDrop (packet);
+ return;
+ }
+ else if (hdr->IsBeacon ())
+ {
+ MgtBeaconHeader beacon;
+ packet->RemoveHeader (beacon);
+ bool goodBeacon = false;
+ if (GetSsid ().IsBroadcast ()
+ || beacon.GetSsid ().IsEqual (GetSsid ()))
+ {
+ goodBeacon = true;
+ }
+ SupportedRates rates = beacon.GetSupportedRates ();
+ for (uint32_t i = 0; i < m_phy->GetNBssMembershipSelectors (); i++)
+ {
+ uint32_t selector = m_phy->GetBssMembershipSelector (i);
+ if (!rates.IsSupportedRate (selector))
+ {
+ goodBeacon = false;
+ }
+ }
+
+#ifdef WITH_HYSTERESIS_HANDOVER_TRIGGER
+ ///background scanning, measuring current or candidate AP beacon's rssi in the same channel
+ if(goodBeacon && IsAssociated ())
+ {
+ RssiTag t;
+ double rssi;
+ if (packet->PeekPacketTag (t))
+ {
+ rssi=t.Get();
+ }
+ else
+ {
+ std::cout<<"ERROR:cannot find Rssi for beacon\n";
+ exit(1);
+ }
+ if(hdr->GetAddr3 ()==GetBssid ()) //beacon from current AP
+ {
+ m_currentApRrssiMeasures.setBssid(GetBssid ());
+ m_currentApRrssiMeasures.addRssi(rssi);
+ }
+ else//beacon from a candidate AP
+ {
+ RssiMeasureInfoCollection::iterator it;
+ for(it=m_candidadteApRssiMeasures.begin();it!=m_candidadteApRssiMeasures.end();it++)
+ {
+ if(it->getBssid()==hdr->GetAddr3 ()) //find a record for this AP, old candidate AP
+ break;
+ }
+ if(it==m_candidadteApRssiMeasures.end()) // new candidate AP
+ {
+ RssiMeasureInfo newApRssiMeasure(hdr->GetAddr3 ());
+ newApRssiMeasure.addRssi(rssi);
+ m_candidadteApRssiMeasures.push_back(newApRssiMeasure);
+ }
+ else//old AP
+ {
+ it->addRssi(rssi);//ad rssi sample
+ double avgRssi=it->getAverageRssi();
+ double currentApavgRssi=m_currentApRrssiMeasures.getAverageRssi();
+ if(avgRssi!=-1 && currentApavgRssi!=-1 && avgRssi/currentApavgRssi >HYSTERESIS_THRESHOLD)//check if we have at least 4 samples
+ {
+ m_currentApRrssiMeasures.clear();
+ m_candidadteApRssiMeasures.clear();
+ m_beaconWatchdog.Cancel();
+ //std::cout<<"NOTE: handover is triggered by Hysteresis algorithm\n";
+
+// SetState(BEACON_MISSED);
+// TryToEnsureAssociated();
+
+ //swith to the ap we find:
+ cleanUpPacketsAndAgreementsWithOldAp();
+
+ //disassociate with old AP
+ sendDissassociationRequest();
+
+ //switch:
+ SetState (WAIT_ASSOC_RESP);
+ SetBssid(hdr->GetAddr3 ());
+ loadSupportedRatesOfAp(rates,GetBssid());
+ m_sendAssocReqEvent=Simulator::Schedule (Time("0.024s"),
+ &StaWifiMac::SendAssociationRequest, this);
+ return;
+ }
+ }
+ }
+ }
+#endif
+ if ((IsWaitAssocResp () || IsAssociated ()) && hdr->GetAddr3 () != GetBssid ())
+ {
+ goodBeacon = false;
+ }
+ if(m_activeProbing)
+ {
+
+ if (goodBeacon && IsAssociated ())
+ {
+//here the rssi could be measured +++++++++++++++++++++++
+//end+++++++++++++++++++
+ Time delay = MicroSeconds (beacon.GetBeaconIntervalUs () * m_maxMissedBeacons);
+ RestartBeaconWatchdog (delay);
+ SetBssid (hdr->GetAddr3 ());
+// std::cout<<Simulator::Now().ToDouble(Time::S)<<", received beacon, restart watchdog" <<"\n";
+ }
+ }
+ else
+ {
+ if (goodBeacon)
+ {
+ Time delay = MicroSeconds (beacon.GetBeaconIntervalUs () * m_maxMissedBeacons);
+ RestartBeaconWatchdog (delay);
+ SetBssid (hdr->GetAddr3 ());
+ }
+ if (goodBeacon && m_state == BEACON_MISSED)
+ {
+ SetState (WAIT_ASSOC_RESP);
+ SendAssociationRequest ();
+ }
+ }
+
+ return;
+ }
+ else if (hdr->IsProbeResp ())
+ {
+ if (m_state == WAIT_PROBE_RESP)
+ {
+ MgtProbeResponseHeader probeResp;
+ packet->RemoveHeader (probeResp);
+ if (!probeResp.GetSsid ().IsEqual (GetSsid ()))
+ {
+ //not a probe resp for our ssid.
+ return;
+ }
+ SupportedRates rates = probeResp.GetSupportedRates ();
+ for (uint32_t i = 0; i < m_phy->GetNBssMembershipSelectors (); i++)
+ {
+ uint32_t selector = m_phy->GetBssMembershipSelector (i);
+ if (!rates.IsSupportedRate (selector))
+ {
+ return;
+ }
+ }
+//added++++++++++++++++++++++++++
+
+ if(!m_isSelectingAP)
+ {
+ m_isSelectingAP=true;
+ }
+
+ //std::cout<<Simulator::Now().ToDouble(Time::S)<<", received probe response from="<<hdr->GetAddr3 () <<"\n";
+
+ RssiTag t;
+
+ if (packet->PeekPacketTag (t))
+ {
+ double rssi=t.Get();
+ Time delayFromProbResp=MicroSeconds (probeResp.GetBeaconIntervalUs () * m_maxMissedBeacons);
+ Mac48Address bssid=hdr->GetAddr3 ();
+ ApInfoCollection::iterator it;
+ for(it=m_apInfos.begin();it!=m_apInfos.end();it++)
+ {
+ if(it->getBssid()==bssid)
+ break;
+ }
+ if(it!=m_apInfos.end())
+ {
+ it->addRssi(rssi);
+ }
+ else
+ {
+ ApInfo newApInfo(bssid,delayFromProbResp,rssi,rates);
+ m_apInfos.push_back(newApInfo);
+ }
+ }
+ else
+ {
+ std::cout<<"cannot find RSSi TAG for probe response\n";
+ exit(1);
+ }
+
+ //---------------end-------------------------
+
+ }
+ return;
+ }
+ else if (hdr->IsAssocResp ())
+ {
+ if (m_state == WAIT_ASSOC_RESP)
+ {
+ MgtAssocResponseHeader assocResp;
+ packet->RemoveHeader (assocResp);
+ if (m_assocRequestEvent.IsRunning ())
+ {
+ m_assocRequestEvent.Cancel ();
+ }
+#ifdef WITH_HYSTERESIS_HANDOVER_TRIGGER
+ if(m_sendAssocReqEvent.IsRunning ())
+ {
+ m_sendAssocReqEvent.Cancel ();
+ }
+#endif
+ if (assocResp.GetStatusCode ().IsSuccess ())
+ {
+ SetState (ASSOCIATED);
+ //added++++++++
+if(m_activeProbing)
+ {
+ m_isSelectingAP=false;
+
+
+ m_currentRssi=0;
+ m_packetCounts=0;
+
+
+ //ap info becomes unuseful:
+ m_apInfos.clear();
+ if(!m_isEverAssoicated)
+ m_isEverAssoicated=true;
+
+ RestartBeaconWatchdog (m_delayFromProbResp);
+// std::cout<<Simulator::Now().ToDouble(Time::S)<<", assoc completed"<<m_probeRequestCount <<"\n";
+ }
+ //+++end+++++++
+ NS_LOG_DEBUG ("assoc completed");
+ SupportedRates rates = assocResp.GetSupportedRates ();
+ if (m_htSupported)
+ {
+ HtCapabilities htcapabilities = assocResp.GetHtCapabilities ();
+ m_stationManager->AddStationHtCapabilities (hdr->GetAddr2 (),htcapabilities);
+ }
+ if (m_vhtSupported)
+ {
+ VhtCapabilities vhtcapabilities = assocResp.GetVhtCapabilities ();
+ m_stationManager->AddStationVhtCapabilities (hdr->GetAddr2 (), vhtcapabilities);
+ }
+
+ for (uint32_t i = 0; i < m_phy->GetNModes (); i++)
+ {
+ WifiMode mode = m_phy->GetMode (i);
+ if (rates.IsSupportedRate (mode.GetDataRate (m_phy->GetChannelWidth (), false, 1)))
+ {
+ m_stationManager->AddSupportedMode (hdr->GetAddr2 (), mode);
+ if (rates.IsBasicRate (mode.GetDataRate (m_phy->GetChannelWidth (), false, 1)))
+ {
+ m_stationManager->AddBasicMode (mode);
+ }
+ }
+ }
+ if (m_htSupported)
+ {
+ HtCapabilities htcapabilities = assocResp.GetHtCapabilities ();
+ for (uint32_t i = 0; i < m_phy->GetNMcs (); i++)
+ {
+ WifiMode mcs = m_phy->GetMcs (i);
+ if (mcs.GetModulationClass () == WIFI_MOD_CLASS_HT && htcapabilities.IsSupportedMcs (mcs.GetMcsValue ()))
+ {
+ m_stationManager->AddSupportedMcs (hdr->GetAddr2 (), mcs);
+ //here should add a control to add basic MCS when it is implemented
+ }
+ }
+ }
+ if (m_vhtSupported)
+ {
+ VhtCapabilities vhtcapabilities = assocResp.GetVhtCapabilities ();
+ for (uint32_t i = 0; i < m_phy->GetNMcs (); i++)
+ {
+ WifiMode mcs = m_phy->GetMcs (i);
+ if (mcs.GetModulationClass () == WIFI_MOD_CLASS_VHT && vhtcapabilities.IsSupportedTxMcs (mcs.GetMcsValue ()))
+ {
+ m_stationManager->AddSupportedMcs (hdr->GetAddr2 (), mcs);
+ //here should add a control to add basic MCS when it is implemented
+ }
+ }
+ }
+ if (!m_linkUp.IsNull ())
+ {
+ m_linkUp ();
+ }
+ }
+ else
+ {
+ NS_LOG_DEBUG ("assoc refused");
+ SetState (REFUSED);
+ }
+ }
+
+ return;
+ }
+
+ //Invoke the receive handler of our parent class to deal with any
+ //other frames. Specifically, this will handle Block Ack-related
+ //Management Action frames.
+ RegularWifiMac::Receive (packet, hdr);
+}
+
+SupportedRates
+StaWifiMac::GetSupportedRates (void) const
+{
+ SupportedRates rates;
+ if (m_htSupported || m_vhtSupported)
+ {
+ for (uint32_t i = 0; i < m_phy->GetNBssMembershipSelectors (); i++)
+ {
+ rates.SetBasicRate (m_phy->GetBssMembershipSelector (i));
+ }
+ }
+ for (uint32_t i = 0; i < m_phy->GetNModes (); i++)
+ {
+ WifiMode mode = m_phy->GetMode (i);
+ rates.AddSupportedRate (mode.GetDataRate (m_phy->GetChannelWidth (), false, 1));
+ }
+ return rates;
+}
+
+HtCapabilities
+StaWifiMac::GetHtCapabilities (void) const
+{
+ HtCapabilities capabilities;
+ capabilities.SetHtSupported (1);
+ if (m_htSupported)
+ {
+ capabilities.SetLdpc (m_phy->GetLdpc ());
+ capabilities.SetSupportedChannelWidth (m_phy->GetChannelWidth () == 40);
+ capabilities.SetShortGuardInterval20 (m_phy->GetGuardInterval ());
+ capabilities.SetShortGuardInterval40 (m_phy->GetChannelWidth () == 40 && m_phy->GetGuardInterval ());
+ capabilities.SetGreenfield (m_phy->GetGreenfield ());
+ capabilities.SetMaxAmsduLength (1); //hardcoded for now (TBD)
+ capabilities.SetLSigProtectionSupport (!m_phy->GetGreenfield ());
+ capabilities.SetMaxAmpduLength (3); //hardcoded for now (TBD)
+ uint64_t maxSupportedRate = 0; //in bit/s
+ for (uint8_t i = 0; i < m_phy->GetNMcs (); i++)
+ {
+ WifiMode mcs = m_phy->GetMcs (i);
+ capabilities.SetRxMcsBitmask (mcs.GetMcsValue ());
+ if (mcs.GetDataRate (m_phy->GetGuardInterval (), m_phy->GetGuardInterval (), 1) > maxSupportedRate)
+ {
+ maxSupportedRate = mcs.GetDataRate (m_phy->GetGuardInterval (), m_phy->GetGuardInterval (), 1);
+ }
+ }
+ capabilities.SetRxHighestSupportedDataRate (maxSupportedRate / 1e6); //in Mbit/s
+ capabilities.SetTxMcsSetDefined (m_phy->GetNMcs () > 0);
+ capabilities.SetTxMaxNSpatialStreams (m_phy->GetNumberOfTransmitAntennas ());
+ }
+ return capabilities;
+}
+
+VhtCapabilities
+StaWifiMac::GetVhtCapabilities (void) const
+{
+ VhtCapabilities capabilities;
+ capabilities.SetVhtSupported (1);
+ if (m_vhtSupported)
+ {
+ if (m_phy->GetChannelWidth () == 160)
+ {
+ capabilities.SetSupportedChannelWidthSet (1);
+ }
+ else
+ {
+ capabilities.SetSupportedChannelWidthSet (0);
+ }
+ capabilities.SetMaxMpduLength (2); //hardcoded for now (TBD)
+ capabilities.SetRxLdpc (m_phy->GetLdpc ());
+ capabilities.SetShortGuardIntervalFor80Mhz ((m_phy->GetChannelWidth () == 80) && m_phy->GetGuardInterval ());
+ capabilities.SetShortGuardIntervalFor160Mhz ((m_phy->GetChannelWidth () == 160) && m_phy->GetGuardInterval ());
+ capabilities.SetMaxAmpduLengthExponent (7); //hardcoded for now (TBD)
+ uint8_t maxMcs = 0;
+ for (uint8_t i = 0; i < m_phy->GetNMcs (); i++)
+ {
+ WifiMode mcs = m_phy->GetMcs (i);
+ if (mcs.GetMcsValue () > maxMcs)
+ {
+ maxMcs = mcs.GetMcsValue ();
+ }
+ }
+ capabilities.SetRxMcsMap (maxMcs, 1); //Only 1 SS is currently supported
+ capabilities.SetTxMcsMap (maxMcs, 1); //Only 1 SS is currently supported
+ }
+ return capabilities;
+}
+
+void
+StaWifiMac::SetState (MacState value)
+{
+ if (value == ASSOCIATED
+ && m_state != ASSOCIATED)
+ {
+ m_assocLogger (GetBssid ());
+ }
+ else if (value != ASSOCIATED
+ && m_state == ASSOCIATED)
+ {
+ m_deAssocLogger (GetBssid ());
+ }
+ m_state = value;
+}
+
+void
+StaWifiMac::sendBurstOfProbeRequest()
+{
+ SendProbeRequest();
+ m_probeRequestCount++;
+ if(m_probeRequestCount >= MAX_NUM_PROBEREQ)
+ return;
+ else
+ m_probeRequestBurstEvent=Simulator::Schedule ((m_probeRequestTimeout-Time("0.02s"))/(MAX_NUM_PROBEREQ-1),
+ &StaWifiMac::sendBurstOfProbeRequest, this);
+}
+
+void
+StaWifiMac::loadSupportedRatesOfAp(SupportedRates rates, Mac48Address bssid)
+{
+ for (uint32_t i = 0; i < m_phy->GetNModes (); i++)
+ {
+ WifiMode mode = m_phy->GetMode (i);
+ if (rates.IsSupportedRate (mode.GetDataRate (m_phy->GetChannelWidth (), false, 1)))
+ {
+ m_stationManager->AddSupportedMode (bssid, mode);
+ if (rates.IsBasicRate (mode.GetDataRate (m_phy->GetChannelWidth (), false, 1)))
+ {
+ m_stationManager->AddBasicMode (mode);
+ }
+ }
+ }
+}
+
+void
+StaWifiMac::cleanUpPacketsAndAgreementsWithOldAp()
+{
+
+ //destroy all block ack agreement with old AP (by pretending to receive a delba frame from AP).
+ //clean up packets for the old AP in the meanwhile
+ for(uint8_t tid=0; tid<=7;tid++)
+ {
+ MgtDelBaHeader delbaHdr;
+ delbaHdr.SetTid (tid);
+ AcIndex ac = QosUtilsMapTidToAc (tid);
+ m_edca[ac]->GotDelBaFrame(&delbaHdr, GetBssid());
+// //also destroy aggreement at mac low immediately:
+ m_low->DestroyBlockAckAgreement (GetBssid(), tid);
+
+ WifiMacHeader dequeuedHdr;
+
+ //for edca:
+ Ptr<WifiMacQueue > edcaQueue=m_edca[ac]->GetEdcaQueue ();
+
+ Ptr<const Packet> dequeuedPacket = edcaQueue->DequeueByTidAndAddress (&dequeuedHdr, tid,
+ WifiMacHeader::ADDR1,
+ GetBssid());
+// int count=0;
+ while (dequeuedPacket != 0)
+ {
+// count++;
+ dequeuedPacket = edcaQueue->DequeueByTidAndAddress (&dequeuedHdr, tid,
+ WifiMacHeader::ADDR1,
+ GetBssid());
+ }
+
+// if(count!=0)
+// std::cout<<"EDCA "<<count<<"\n";
+
+// count=0;
+ // for dca
+ Ptr<WifiMacQueue > dcaQueue=m_dca->GetQueue ();
+ dequeuedPacket = dcaQueue->DequeueByTidAndAddress (&dequeuedHdr, tid,
+ WifiMacHeader::ADDR1,
+ GetBssid());
+
+ while (dequeuedPacket != 0)
+ {
+// count++;
+ dequeuedPacket = dcaQueue->DequeueByTidAndAddress (&dequeuedHdr, tid,
+ WifiMacHeader::ADDR1,
+ GetBssid());
+ }
+// if(count!=0)
+// std::cout<<"DCA "<<count<<"\n";
+
+ }
+}
+
+
+} //namespace ns3
diff --git a/emu-radio/ns3-patch/wifi/model/sta-wifi-mac.h b/emu-radio/ns3-patch/wifi/model/sta-wifi-mac.h
new file mode 100644
index 00000000..7b931c53
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/sta-wifi-mac.h
@@ -0,0 +1,238 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006, 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
+ *
+ * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Mirko Banchi <mk.banchi@gmail.com>
+ */
+#ifndef STA_WIFI_MAC_H
+#define STA_WIFI_MAC_H
+
+#include "regular-wifi-mac.h"
+#include "ns3/event-id.h"
+#include "ns3/packet.h"
+#include "ns3/traced-callback.h"
+#include "supported-rates.h"
+#include "amsdu-subframe-header.h"
+
+//added+++++++++
+#include "ap-info-collection.h"
+
+#define WITH_HYSTERESIS_HANDOVER_TRIGGER 1
+
+namespace ns3 {
+
+class MgtAddBaRequestHeader;
+
+/**
+ * \ingroup wifi
+ *
+ * The Wifi MAC high model for a non-AP STA in a BSS.
+ */
+class StaWifiMac : public RegularWifiMac
+{
+public:
+ static TypeId GetTypeId (void);
+
+ StaWifiMac ();
+ virtual ~StaWifiMac ();
+
+ /**
+ * \param packet the packet to send.
+ * \param to the address to which the packet should be sent.
+ *
+ * The packet should be enqueued in a tx queue, and should be
+ * dequeued as soon as the channel access function determines that
+ * access is granted to this MAC.
+ */
+ virtual void Enqueue (Ptr<const Packet> packet, Mac48Address to);
+
+ /**
+ * \param missed the number of beacons which must be missed
+ * before a new association sequence is started.
+ */
+ void SetMaxMissedBeacons (uint32_t missed);
+ /**
+ * \param timeout
+ *
+ * If no probe response is received within the specified
+ * timeout, the station sends a new probe request.
+ */
+ void SetProbeRequestTimeout (Time timeout);
+ /**
+ * \param timeout
+ *
+ * If no association response is received within the specified
+ * timeout, the station sends a new association request.
+ */
+ void SetAssocRequestTimeout (Time timeout);
+
+ /**
+ * Start an active association sequence immediately.
+ */
+ void StartActiveAssociation (void);
+
+
+private:
+ /**
+ * The current MAC state of the STA.
+ */
+ enum MacState
+ {
+ ASSOCIATED,
+ WAIT_PROBE_RESP,
+ WAIT_ASSOC_RESP,
+ BEACON_MISSED,
+ REFUSED
+ };
+
+ /**
+ * Enable or disable active probing.
+ *
+ * \param enable enable or disable active probing
+ */
+ void SetActiveProbing (bool enable);
+ /**
+ * Return whether active probing is enabled.
+ *
+ * \return true if active probing is enabled, false otherwise
+ */
+ bool GetActiveProbing (void) const;
+
+ virtual void Receive (Ptr<Packet> packet, const WifiMacHeader *hdr);
+
+ /**
+ * Forward a probe request packet to the DCF. The standard is not clear on the correct
+ * queue for management frames if QoS is supported. We always use the DCF.
+ */
+ void SendProbeRequest (void);
+ /**
+ * Forward an association request packet to the DCF. The standard is not clear on the correct
+ * queue for management frames if QoS is supported. We always use the DCF.
+ */
+ void SendAssociationRequest (void);
+ /**
+ * Try to ensure that we are associated with an AP by taking an appropriate action
+ * depending on the current association status.
+ */
+ void TryToEnsureAssociated (void);
+ /**
+ * This method is called after the association timeout occurred. We switch the state to
+ * WAIT_ASSOC_RESP and re-send an association request.
+ */
+ void AssocRequestTimeout (void);
+ /**
+ * This method is called after the probe request timeout occurred. We switch the state to
+ * WAIT_PROBE_RESP and re-send a probe request.
+ */
+ void ProbeRequestTimeout (void);
+ /**
+ * Return whether we are associated with an AP.
+ *
+ * \return true if we are associated with an AP, false otherwise
+ */
+ bool IsAssociated (void) const;
+ /**
+ * Return whether we are waiting for an association response from an AP.
+ *
+ * \return true if we are waiting for an association response from an AP, false otherwise
+ */
+ bool IsWaitAssocResp (void) const;
+ /**
+ * This method is called after we have not received a beacon from the AP
+ */
+ void MissedBeacons (void);
+ /**
+ * Restarts the beacon timer.
+ *
+ * \param delay the delay before the watchdog fires
+ */
+ void RestartBeaconWatchdog (Time delay);
+ /**
+ * Return an instance of SupportedRates that contains all rates that we support
+ * including HT rates.
+ *
+ * \return SupportedRates all rates that we support
+ */
+ SupportedRates GetSupportedRates (void) const;
+ /**
+ * Set the current MAC state.
+ *
+ * \param value the new state
+ */
+ void SetState (enum MacState value);
+ /**
+ * Return the HT capability of the current AP.
+ *
+ * \return the HT capability that we support
+ */
+ HtCapabilities GetHtCapabilities (void) const;
+ /**
+ * Return the VHT capability of the current AP.
+ *
+ * \return the VHT capability that we support
+ */
+ VhtCapabilities GetVhtCapabilities (void) const;
+
+ enum MacState m_state;
+ Time m_probeRequestTimeout;
+ Time m_assocRequestTimeout;
+ EventId m_probeRequestEvent;
+ EventId m_assocRequestEvent;
+ EventId m_beaconWatchdog;
+ Time m_beaconWatchdogEnd;
+ uint32_t m_maxMissedBeacons;
+ bool m_activeProbing;
+
+ TracedCallback<Mac48Address> m_assocLogger;
+ TracedCallback<Mac48Address> m_deAssocLogger;
+
+ //********for selecting AP********
+ bool m_isSelectingAP;
+ double m_currentRssi;
+ int m_packetCounts;
+ Time m_delayFromProbResp;
+
+ ApInfoCollection m_apInfos;
+ int m_probeRequestCount;
+
+ bool m_isEverAssoicated;
+ void sendBurstOfProbeRequest();
+ EventId m_probeRequestBurstEvent;
+ EventId m_initialEvent;
+
+ void loadSupportedRatesOfAp(SupportedRates rates, Mac48Address bssid);
+
+ void cleanUpPacketsAndAgreementsWithOldAp();
+
+ void sendDissassociationRequest();
+ //******************************
+
+#ifdef WITH_HYSTERESIS_HANDOVER_TRIGGER
+ //for triggering wifi handover
+ RssiMeasureInfo m_currentApRrssiMeasures;
+ RssiMeasureInfoCollection m_candidadteApRssiMeasures;
+
+ EventId m_sendAssocReqEvent;
+
+#endif
+
+};
+
+} //namespace ns3
+
+#endif /* STA_WIFI_MAC_H */
diff --git a/emu-radio/ns3-patch/wifi/model/wifi-phy.cc b/emu-radio/ns3-patch/wifi/model/wifi-phy.cc
new file mode 100644
index 00000000..11ab5aae
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/wifi-phy.cc
@@ -0,0 +1,1570 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005,2006 INRIA
+ *
+ * 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
+ *
+ * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Sébastien Deronne <sebastien.deronne@gmail.com>
+ */
+
+#include "wifi-phy.h"
+#include "wifi-mode.h"
+#include "wifi-channel.h"
+#include "wifi-preamble.h"
+#include "ns3/simulator.h"
+#include "ns3/packet.h"
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/double.h"
+#include "ns3/uinteger.h"
+#include "ns3/enum.h"
+#include "ns3/trace-source-accessor.h"
+#include <cmath>
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("WifiPhy");
+
+/****************************************************************
+ * This destructor is needed.
+ ****************************************************************/
+
+WifiPhyListener::~WifiPhyListener ()
+{
+}
+
+/****************************************************************
+ * The actual WifiPhy class
+ ****************************************************************/
+
+NS_OBJECT_ENSURE_REGISTERED (WifiPhy);
+
+TypeId
+WifiPhy::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::WifiPhy")
+ .SetParent<Object> ()
+ .SetGroupName ("Wifi")
+ .AddTraceSource ("PhyTxBegin",
+ "Trace source indicating a packet "
+ "has begun transmitting over the channel medium",
+ MakeTraceSourceAccessor (&WifiPhy::m_phyTxBeginTrace),
+ "ns3::Packet::TracedCallback")
+ .AddTraceSource ("PhyTxEnd",
+ "Trace source indicating a packet "
+ "has been completely transmitted over the channel. "
+ "NOTE: the only official WifiPhy implementation "
+ "available to this date (YansWifiPhy) never fires "
+ "this trace source.",
+ MakeTraceSourceAccessor (&WifiPhy::m_phyTxEndTrace),
+ "ns3::Packet::TracedCallback")
+ .AddTraceSource ("PhyTxDrop",
+ "Trace source indicating a packet "
+ "has been dropped by the device during transmission",
+ MakeTraceSourceAccessor (&WifiPhy::m_phyTxDropTrace),
+ "ns3::Packet::TracedCallback")
+ .AddTraceSource ("PhyRxBegin",
+ "Trace source indicating a packet "
+ "has begun being received from the channel medium "
+ "by the device",
+ MakeTraceSourceAccessor (&WifiPhy::m_phyRxBeginTrace),
+ "ns3::Packet::TracedCallback")
+ .AddTraceSource ("PhyRxEnd",
+ "Trace source indicating a packet "
+ "has been completely received from the channel medium "
+ "by the device",
+ MakeTraceSourceAccessor (&WifiPhy::m_phyRxEndTrace),
+ "ns3::Packet::TracedCallback")
+ .AddTraceSource ("PhyRxDrop",
+ "Trace source indicating a packet "
+ "has been dropped by the device during reception",
+ MakeTraceSourceAccessor (&WifiPhy::m_phyRxDropTrace),
+ "ns3::Packet::TracedCallback")
+ .AddTraceSource ("MonitorSnifferRx",
+ "Trace source simulating a wifi device in monitor mode "
+ "sniffing all received frames",
+ MakeTraceSourceAccessor (&WifiPhy::m_phyMonitorSniffRxTrace),
+ "ns3::WifiPhy::MonitorSnifferRxTracedCallback")
+ .AddTraceSource ("MonitorSnifferTx",
+ "Trace source simulating the capability of a wifi device "
+ "in monitor mode to sniff all frames being transmitted",
+ MakeTraceSourceAccessor (&WifiPhy::m_phyMonitorSniffTxTrace),
+ "ns3::WifiPhy::MonitorSnifferTxTracedCallback")
+ ;
+ return tid;
+}
+
+WifiPhy::WifiPhy ()
+{
+ NS_LOG_FUNCTION (this);
+ m_totalAmpduSize = 0;
+ m_totalAmpduNumSymbols = 0;
+}
+
+WifiPhy::~WifiPhy ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+WifiMode
+WifiPhy::GetHtPlcpHeaderMode (WifiMode payloadMode)
+{
+ return WifiPhy::GetHtMcs0 ();
+}
+
+WifiMode
+WifiPhy::GetVhtPlcpHeaderMode (WifiMode payloadMode)
+{
+ return WifiPhy::GetVhtMcs0 ();
+}
+
+Time
+WifiPhy::GetPlcpHtTrainingSymbolDuration (WifiPreamble preamble, WifiTxVector txVector)
+{
+ uint8_t Ndltf, Neltf;
+ //We suppose here that STBC = 0.
+ //If STBC > 0, we need a different mapping between Nss and Nltf (IEEE 802.11n-2012 standard, page 1682).
+ if (txVector.GetNss () < 3)
+ {
+ Ndltf = txVector.GetNss ();
+ }
+ else if (txVector.GetNss () < 5)
+ {
+ Ndltf = 4;
+ }
+ else if (txVector.GetNss () < 7)
+ {
+ Ndltf = 6;
+ }
+ else
+ {
+ Ndltf = 8;
+ }
+
+ if (txVector.GetNess () < 3)
+ {
+ Neltf = txVector.GetNess ();
+ }
+ else
+ {
+ Neltf = 4;
+ }
+
+ switch (preamble)
+ {
+ case WIFI_PREAMBLE_HT_MF:
+ return MicroSeconds (4 + (4 * Ndltf) + (4 * Neltf));
+ case WIFI_PREAMBLE_HT_GF:
+ return MicroSeconds ((4 * Ndltf) + (4 * Neltf));
+ case WIFI_PREAMBLE_VHT:
+ return MicroSeconds (4 + (4 * Ndltf));
+ default:
+ //no training for non HT
+ return MicroSeconds (0);
+ }
+}
+
+Time
+WifiPhy::GetPlcpHtSigHeaderDuration (WifiPreamble preamble)
+{
+ switch (preamble)
+ {
+ case WIFI_PREAMBLE_HT_MF:
+ case WIFI_PREAMBLE_HT_GF:
+ //HT-SIG
+ return MicroSeconds (8);
+ default:
+ //no HT-SIG for non HT
+ return MicroSeconds (0);
+ }
+}
+
+Time
+WifiPhy::GetPlcpVhtSigA1Duration (WifiPreamble preamble)
+{
+ switch (preamble)
+ {
+ case WIFI_PREAMBLE_VHT:
+ //VHT-SIG-A1
+ return MicroSeconds (4);
+ default:
+ // no VHT-SIG-A1 for non VHT
+ return MicroSeconds (0);
+ }
+}
+
+Time
+WifiPhy::GetPlcpVhtSigA2Duration (WifiPreamble preamble)
+{
+ switch (preamble)
+ {
+ case WIFI_PREAMBLE_VHT:
+ //VHT-SIG-A2
+ return MicroSeconds (4);
+ default:
+ // no VHT-SIG-A2 for non VHT
+ return MicroSeconds (0);
+ }
+}
+
+Time
+WifiPhy::GetPlcpVhtSigBDuration (WifiPreamble preamble)
+{
+ switch (preamble)
+ {
+ case WIFI_PREAMBLE_VHT:
+ //VHT-SIG-B
+ return MicroSeconds (4);
+ default:
+ // no VHT-SIG-B for non VHT
+ return MicroSeconds (0);
+ }
+}
+
+WifiMode
+WifiPhy::GetPlcpHeaderMode (WifiMode payloadMode, WifiPreamble preamble, WifiTxVector txVector)
+{
+ switch (payloadMode.GetModulationClass ())
+ {
+ case WIFI_MOD_CLASS_OFDM:
+ case WIFI_MOD_CLASS_HT:
+ case WIFI_MOD_CLASS_VHT:
+ switch (txVector.GetChannelWidth ())
+ {
+ case 5000000:
+ return WifiPhy::GetOfdmRate1_5MbpsBW5MHz ();
+ case 10000000:
+ return WifiPhy::GetOfdmRate3MbpsBW10MHz ();
+ case 20000000:
+ case 40000000:
+ case 80000000:
+ case 160000000:
+ default:
+ //(Section 18.3.2 "PLCP frame format"; IEEE Std 802.11-2012)
+ //actually this is only the first part of the PlcpHeader,
+ //because the last 16 bits of the PlcpHeader are using the
+ //same mode of the payload
+ return WifiPhy::GetOfdmRate6Mbps ();
+ }
+ case WIFI_MOD_CLASS_ERP_OFDM:
+ return WifiPhy::GetErpOfdmRate6Mbps ();
+ case WIFI_MOD_CLASS_DSSS:
+ case WIFI_MOD_CLASS_HR_DSSS:
+ if (preamble == WIFI_PREAMBLE_LONG)
+ {
+ //(Section 16.2.3 "PLCP field definitions" and Section 17.2.2.2 "Long PPDU format"; IEEE Std 802.11-2012)
+ return WifiPhy::GetDsssRate1Mbps ();
+ }
+ else //WIFI_PREAMBLE_SHORT
+ {
+ //(Section 17.2.2.3 "Short PPDU format"; IEEE Std 802.11-2012)
+ return WifiPhy::GetDsssRate2Mbps ();
+ }
+ default:
+ NS_FATAL_ERROR ("unsupported modulation class");
+ return WifiMode ();
+ }
+}
+
+Time
+WifiPhy::GetPlcpHeaderDuration (WifiTxVector txVector, WifiPreamble preamble)
+{
+ if (preamble == WIFI_PREAMBLE_NONE)
+ {
+ return MicroSeconds (0);
+ }
+ switch (txVector.GetMode ().GetModulationClass ())
+ {
+ case WIFI_MOD_CLASS_OFDM:
+ {
+ switch (txVector.GetChannelWidth ())
+ {
+ case 20000000:
+ default:
+ //(Section 18.3.3 "PLCP preamble (SYNC))" and Figure 18-4 "OFDM training structure"; IEEE Std 802.11-2012)
+ //also (Section 18.3.2.4 "Timing related parameters" Table 18-5 "Timing-related parameters"; IEEE Std 802.11-2012)
+ //We return the duration of the SIGNAL field only, since the
+ //SERVICE field (which strictly speaking belongs to the PLCP
+ //header, see Section 18.3.2 and Figure 18-1) is sent using the
+ //payload mode.
+ return MicroSeconds (4);
+ case 10000000:
+ //(Section 18.3.2.4 "Timing related parameters" Table 18-5 "Timing-related parameters"; IEEE Std 802.11-2012)
+ return MicroSeconds (8);
+ case 5000000:
+ //(Section 18.3.2.4 "Timing related parameters" Table 18-5 "Timing-related parameters"; IEEE Std 802.11-2012)
+ return MicroSeconds (16);
+ }
+ }
+ case WIFI_MOD_CLASS_HT:
+ {
+ //L-SIG
+ //IEEE 802.11n Figure 20.1
+ switch (preamble)
+ {
+ case WIFI_PREAMBLE_HT_MF:
+ default:
+ return MicroSeconds (4);
+ case WIFI_PREAMBLE_HT_GF:
+ return MicroSeconds (0);
+ }
+ }
+ case WIFI_MOD_CLASS_VHT:
+ case WIFI_MOD_CLASS_ERP_OFDM:
+ return MicroSeconds (4);
+ case WIFI_MOD_CLASS_DSSS:
+ case WIFI_MOD_CLASS_HR_DSSS:
+ if (preamble == WIFI_PREAMBLE_SHORT)
+ {
+ //(Section 17.2.2.3 "Short PPDU format" and Figure 17-2 "Short PPDU format"; IEEE Std 802.11-2012)
+ return MicroSeconds (24);
+ }
+ else //WIFI_PREAMBLE_LONG
+ {
+ //(Section 17.2.2.2 "Long PPDU format" and Figure 17-1 "Short PPDU format"; IEEE Std 802.11-2012)
+ return MicroSeconds (48);
+ }
+ default:
+ NS_FATAL_ERROR ("unsupported modulation class");
+ return MicroSeconds (0);
+ }
+}
+
+Time
+WifiPhy::GetPlcpPreambleDuration (WifiTxVector txVector, WifiPreamble preamble)
+{
+ if (preamble == WIFI_PREAMBLE_NONE)
+ {
+ return MicroSeconds (0);
+ }
+ switch (txVector.GetMode ().GetModulationClass ())
+ {
+ case WIFI_MOD_CLASS_OFDM:
+ {
+ switch (txVector.GetChannelWidth ())
+ {
+ case 20000000:
+ default:
+ //(Section 18.3.3 "PLCP preamble (SYNC))" Figure 18-4 "OFDM training structure"
+ //also Section 18.3.2.3 "Modulation-dependent parameters" Table 18-4 "Modulation-dependent parameters"; IEEE Std 802.11-2012)
+ return MicroSeconds (16);
+ case 10000000:
+ //(Section 18.3.3 "PLCP preamble (SYNC))" Figure 18-4 "OFDM training structure"
+ //also Section 18.3.2.3 "Modulation-dependent parameters" Table 18-4 "Modulation-dependent parameters"; IEEE Std 802.11-2012)
+ return MicroSeconds (32);
+ case 5000000:
+ //(Section 18.3.3 "PLCP preamble (SYNC))" Figure 18-4 "OFDM training structure"
+ //also Section 18.3.2.3 "Modulation-dependent parameters" Table 18-4 "Modulation-dependent parameters"; IEEE Std 802.11-2012)
+ return MicroSeconds (64);
+ }
+ }
+ case WIFI_MOD_CLASS_VHT:
+ case WIFI_MOD_CLASS_HT:
+ //IEEE 802.11n Figure 20.1 the training symbols before L_SIG or HT_SIG
+ return MicroSeconds (16);
+ case WIFI_MOD_CLASS_ERP_OFDM:
+ return MicroSeconds (16);
+ case WIFI_MOD_CLASS_DSSS:
+ case WIFI_MOD_CLASS_HR_DSSS:
+ if (preamble == WIFI_PREAMBLE_SHORT)
+ {
+ //(Section 17.2.2.3 "Short PPDU format)" Figure 17-2 "Short PPDU format"; IEEE Std 802.11-2012)
+ return MicroSeconds (72);
+ }
+ else //WIFI_PREAMBLE_LONG
+ {
+ //(Section 17.2.2.2 "Long PPDU format)" Figure 17-1 "Long PPDU format"; IEEE Std 802.11-2012)
+ return MicroSeconds (144);
+ }
+ default:
+ NS_FATAL_ERROR ("unsupported modulation class");
+ return MicroSeconds (0);
+ }
+}
+
+Time
+WifiPhy::GetPayloadDuration (uint32_t size, WifiTxVector txVector, WifiPreamble preamble, double frequency, uint8_t packetType, uint8_t incFlag)
+{
+ WifiMode payloadMode = txVector.GetMode ();
+ NS_LOG_FUNCTION (size << payloadMode);
+
+ switch (payloadMode.GetModulationClass ())
+ {
+ case WIFI_MOD_CLASS_OFDM:
+ case WIFI_MOD_CLASS_ERP_OFDM:
+ {
+ //(Section 18.3.2.4 "Timing related parameters" Table 18-5 "Timing-related parameters"; IEEE Std 802.11-2012
+ //corresponds to T_{SYM} in the table)
+ Time symbolDuration;
+
+ switch (txVector.GetChannelWidth ())
+ {
+ case 20000000:
+ default:
+ symbolDuration = MicroSeconds (4);
+ break;
+ case 10000000:
+ symbolDuration = MicroSeconds (8);
+ break;
+ case 5000000:
+ symbolDuration = MicroSeconds (16);
+ break;
+ }
+
+ //(Section 18.3.2.3 "Modulation-dependent parameters" Table 18-4 "Modulation-dependent parameters"; IEEE Std 802.11-2012)
+ //corresponds to N_{DBPS} in the table
+ double numDataBitsPerSymbol = payloadMode.GetDataRate (txVector.GetChannelWidth (), 0, 1) * symbolDuration.GetNanoSeconds () / 1e9;
+//*********probably needs to be added*******************
+double numSymbols;
+
+ if (packetType == 1 && preamble != WIFI_PREAMBLE_NONE)
+ {
+ //First packet in an A-MPDU
+//probably needs to be added************************
+ numSymbols = ((16 + size * 8.0 + 6) / numDataBitsPerSymbol);
+ if (incFlag == 1)
+ {
+ m_totalAmpduSize += size;
+ m_totalAmpduNumSymbols += numSymbols;
+ }
+ }
+ else if (packetType == 1 && preamble == WIFI_PREAMBLE_NONE)
+ {
+ //consecutive packets in an A-MPDU
+ numSymbols = ((size * 8.0) / numDataBitsPerSymbol);
+ if (incFlag == 1)
+ {
+ m_totalAmpduSize += size;
+ m_totalAmpduNumSymbols += numSymbols;
+ }
+ }
+ else if (packetType == 2 && preamble == WIFI_PREAMBLE_NONE)
+ {
+ //last packet in an A-MPDU
+ uint32_t totalAmpduSize = m_totalAmpduSize + size;
+ numSymbols = lrint (ceil ((16 + totalAmpduSize * 8.0 + 6) / numDataBitsPerSymbol));
+ NS_ASSERT (m_totalAmpduNumSymbols <= numSymbols);
+ numSymbols -= m_totalAmpduNumSymbols;
+ if (incFlag == 1)
+ {
+ m_totalAmpduSize = 0;
+ m_totalAmpduNumSymbols = 0;
+ }
+ }
+ else if (packetType == 0 && preamble != WIFI_PREAMBLE_NONE)
+ {
+ //Not an A-MPDU
+ numSymbols = lrint (ceil ((16 + size * 8.0 + 6.0) / numDataBitsPerSymbol));
+ }
+ else
+ {
+ NS_FATAL_ERROR ("Wrong combination of preamble and packet type");
+ }
+
+ //Add signal extension for ERP PHY
+ if (payloadMode.GetModulationClass () == WIFI_MOD_CLASS_ERP_OFDM)
+ {
+//**********probably needs to be added**********************
+ return NanoSeconds (numSymbols * symbolDuration.GetNanoSeconds ()) + MicroSeconds (6);
+ }
+ else
+ {
+ return NanoSeconds (numSymbols * symbolDuration.GetNanoSeconds ());
+ }
+ }
+ case WIFI_MOD_CLASS_HT:
+ case WIFI_MOD_CLASS_VHT:
+ {
+ Time symbolDuration;
+ double m_Stbc;
+ //if short GI data rate is used then symbol duration is 3.6us else symbol duration is 4us
+ //In the future has to create a stationmanager that only uses these data rates if sender and reciever support GI
+ if (txVector.IsShortGuardInterval ())
+ {
+ symbolDuration = NanoSeconds (3600);
+ }
+ else
+ {
+ symbolDuration = MicroSeconds (4);
+ }
+
+ if (txVector.IsStbc ())
+ {
+ m_Stbc = 2;
+ }
+ else
+ {
+ m_Stbc = 1;
+ }
+
+ //check tables 20-35 and 20-36 in the .11n standard to get cases when nes = 2
+ //check tables 22-30 to 22-61 in the .11ac standard to get cases when nes > 1
+ double Nes;
+ if (txVector.GetChannelWidth () == 160
+ && (payloadMode.GetUniqueName () == "VhtMcs7" || payloadMode.GetUniqueName () == "VhtMcs8" || payloadMode.GetUniqueName () == "VhtMcs9"))
+ {
+ Nes = 2;
+ }
+ else
+ {
+ Nes = 1;
+ }
+
+ //IEEE Std 802.11n, section 20.3.11, equation (20-32)
+ double numDataBitsPerSymbol = payloadMode.GetDataRate (txVector.GetChannelWidth (), txVector.IsShortGuardInterval (), 1) * txVector.GetNss () * symbolDuration.GetNanoSeconds () / 1e9;
+//probably needs to be added***********
+double numSymbols;
+
+ if (packetType == 1 && preamble != WIFI_PREAMBLE_NONE)
+ {
+ //First packet in an A-MPDU
+//probably needs to be added*****************
+ numSymbols = (m_Stbc * (16 + size * 8.0 + 6 * Nes) / (m_Stbc * numDataBitsPerSymbol));
+ if (incFlag == 1)
+ {
+ m_totalAmpduSize += size;
+ m_totalAmpduNumSymbols += numSymbols;
+ }
+ }
+ else if (packetType == 1 && preamble == WIFI_PREAMBLE_NONE)
+ {
+ //consecutive packets in an A-MPDU
+ numSymbols = m_Stbc * ((size * 8.0 ) / (m_Stbc * numDataBitsPerSymbol));
+ if (incFlag == 1)
+ {
+ m_totalAmpduSize += size;
+ m_totalAmpduNumSymbols += numSymbols;
+ }
+ }
+ else if (packetType == 2 && preamble == WIFI_PREAMBLE_NONE)
+ {
+ //last packet in an A-MPDU
+ uint32_t totalAmpduSize = m_totalAmpduSize + size;
+ numSymbols = lrint (m_Stbc * ceil ((16 + totalAmpduSize * 8.0 + 6 * Nes) / (m_Stbc * numDataBitsPerSymbol)));
+ NS_ASSERT (m_totalAmpduNumSymbols <= numSymbols);
+ numSymbols -= m_totalAmpduNumSymbols;
+ if (incFlag == 1)
+ {
+ m_totalAmpduSize = 0;
+ m_totalAmpduNumSymbols = 0;
+ }
+ }
+ else if (packetType == 0 && preamble != WIFI_PREAMBLE_NONE)
+ {
+ //Not an A-MPDU
+ numSymbols = lrint (m_Stbc * ceil ((16 + size * 8.0 + 6.0 * Nes) / (m_Stbc * numDataBitsPerSymbol)));
+ }
+ else
+ {
+ NS_FATAL_ERROR ("Wrong combination of preamble and packet type");
+ }
+
+ if (payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HT && frequency >= 2400 && frequency <= 2500 && ((packetType == 0 && preamble != WIFI_PREAMBLE_NONE) || (packetType == 2 && preamble == WIFI_PREAMBLE_NONE))) //at 2.4 GHz
+ {
+//*******************************************
+ return NanoSeconds (numSymbols * symbolDuration.GetNanoSeconds ()) + MicroSeconds (6);
+ }
+ else //at 5 GHz
+ {
+ return NanoSeconds (numSymbols * symbolDuration.GetNanoSeconds ());
+ }
+ }
+ case WIFI_MOD_CLASS_DSSS:
+ case WIFI_MOD_CLASS_HR_DSSS:
+ //(Section 17.2.3.6 "Long PLCP LENGTH field"; IEEE Std 802.11-2012)
+ NS_LOG_LOGIC (" size=" << size
+ << " mode=" << payloadMode
+ << " rate=" << payloadMode.GetDataRate (22, 0, 1));
+ return MicroSeconds (lrint (ceil ((size * 8.0) / (payloadMode.GetDataRate (22, 0, 1) / 1.0e6))));
+ default:
+ NS_FATAL_ERROR ("unsupported modulation class");
+ return MicroSeconds (0);
+ }
+}
+
+Time
+WifiPhy::CalculatePlcpPreambleAndHeaderDuration (WifiTxVector txVector, WifiPreamble preamble)
+{
+ Time duration = GetPlcpPreambleDuration (txVector, preamble)
+ + GetPlcpHeaderDuration (txVector, preamble)
+ + GetPlcpHtSigHeaderDuration (preamble)
+ + GetPlcpVhtSigA1Duration (preamble)
+ + GetPlcpVhtSigA2Duration (preamble)
+ + GetPlcpHtTrainingSymbolDuration (preamble, txVector)
+ + GetPlcpVhtSigBDuration (preamble);
+ return duration;
+}
+
+Time
+WifiPhy::CalculateTxDuration (uint32_t size, WifiTxVector txVector, WifiPreamble preamble, double frequency, uint8_t packetType, uint8_t incFlag)
+{
+ Time duration = CalculatePlcpPreambleAndHeaderDuration (txVector, preamble)
+ + GetPayloadDuration (size, txVector, preamble, frequency, packetType, incFlag);
+ return duration;
+}
+
+void
+WifiPhy::NotifyTxBegin (Ptr<const Packet> packet)
+{
+ m_phyTxBeginTrace (packet);
+}
+
+void
+WifiPhy::NotifyTxEnd (Ptr<const Packet> packet)
+{
+ m_phyTxEndTrace (packet);
+}
+
+void
+WifiPhy::NotifyTxDrop (Ptr<const Packet> packet)
+{
+ m_phyTxDropTrace (packet);
+}
+
+void
+WifiPhy::NotifyRxBegin (Ptr<const Packet> packet)
+{
+ m_phyRxBeginTrace (packet);
+}
+
+void
+WifiPhy::NotifyRxEnd (Ptr<const Packet> packet)
+{
+ m_phyRxEndTrace (packet);
+}
+
+void
+WifiPhy::NotifyRxDrop (Ptr<const Packet> packet)
+{
+ m_phyRxDropTrace (packet);
+}
+
+void
+WifiPhy::NotifyMonitorSniffRx (Ptr<const Packet> packet, uint16_t channelFreqMhz, uint16_t channelNumber, uint32_t rate, WifiPreamble preamble, WifiTxVector txVector, struct mpduInfo aMpdu, struct signalNoiseDbm signalNoise)
+{
+ m_phyMonitorSniffRxTrace (packet, channelFreqMhz, channelNumber, rate, preamble, txVector, aMpdu, signalNoise);
+}
+
+void
+WifiPhy::NotifyMonitorSniffTx (Ptr<const Packet> packet, uint16_t channelFreqMhz, uint16_t channelNumber, uint32_t rate, WifiPreamble preamble, WifiTxVector txVector, struct mpduInfo aMpdu)
+{
+ m_phyMonitorSniffTxTrace (packet, channelFreqMhz, channelNumber, rate, preamble, txVector, aMpdu);
+}
+
+
+// Clause 15 rates (DSSS)
+
+WifiMode
+WifiPhy::GetDsssRate1Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("DsssRate1Mbps",
+ WIFI_MOD_CLASS_DSSS,
+ true,
+ WIFI_CODE_RATE_UNDEFINED,
+ 2);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetDsssRate2Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("DsssRate2Mbps",
+ WIFI_MOD_CLASS_DSSS,
+ true,
+ WIFI_CODE_RATE_UNDEFINED,
+ 4);
+ return mode;
+}
+
+
+// Clause 18 rates (HR/DSSS)
+
+WifiMode
+WifiPhy::GetDsssRate5_5Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("DsssRate5_5Mbps",
+ WIFI_MOD_CLASS_HR_DSSS,
+ true,
+ WIFI_CODE_RATE_UNDEFINED,
+ 16);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetDsssRate11Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("DsssRate11Mbps",
+ WIFI_MOD_CLASS_HR_DSSS,
+ true,
+ WIFI_CODE_RATE_UNDEFINED,
+ 256);
+ return mode;
+}
+
+
+// Clause 19.5 rates (ERP-OFDM)
+
+WifiMode
+WifiPhy::GetErpOfdmRate6Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("ErpOfdmRate6Mbps",
+ WIFI_MOD_CLASS_ERP_OFDM,
+ true,
+ WIFI_CODE_RATE_1_2,
+ 2);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetErpOfdmRate9Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("ErpOfdmRate9Mbps",
+ WIFI_MOD_CLASS_ERP_OFDM,
+ false,
+ WIFI_CODE_RATE_3_4,
+ 2);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetErpOfdmRate12Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("ErpOfdmRate12Mbps",
+ WIFI_MOD_CLASS_ERP_OFDM,
+ true,
+ WIFI_CODE_RATE_1_2,
+ 4);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetErpOfdmRate18Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("ErpOfdmRate18Mbps",
+ WIFI_MOD_CLASS_ERP_OFDM,
+ false,
+ WIFI_CODE_RATE_3_4,
+ 4);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetErpOfdmRate24Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("ErpOfdmRate24Mbps",
+ WIFI_MOD_CLASS_ERP_OFDM,
+ true,
+ WIFI_CODE_RATE_1_2,
+ 16);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetErpOfdmRate36Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("ErpOfdmRate36Mbps",
+ WIFI_MOD_CLASS_ERP_OFDM,
+ false,
+ WIFI_CODE_RATE_3_4,
+ 16);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetErpOfdmRate48Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("ErpOfdmRate48Mbps",
+ WIFI_MOD_CLASS_ERP_OFDM,
+ false,
+ WIFI_CODE_RATE_2_3,
+ 64);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetErpOfdmRate54Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("ErpOfdmRate54Mbps",
+ WIFI_MOD_CLASS_ERP_OFDM,
+ false,
+ WIFI_CODE_RATE_3_4,
+ 64);
+ return mode;
+}
+
+
+// Clause 17 rates (OFDM)
+
+WifiMode
+WifiPhy::GetOfdmRate6Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate6Mbps",
+ WIFI_MOD_CLASS_OFDM,
+ true,
+ WIFI_CODE_RATE_1_2,
+ 2);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate9Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate9Mbps",
+ WIFI_MOD_CLASS_OFDM,
+ false,
+ WIFI_CODE_RATE_3_4,
+ 2);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate12Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate12Mbps",
+ WIFI_MOD_CLASS_OFDM,
+ true,
+ WIFI_CODE_RATE_1_2,
+ 4);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate18Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate18Mbps",
+ WIFI_MOD_CLASS_OFDM,
+ false,
+ WIFI_CODE_RATE_3_4,
+ 4);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate24Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate24Mbps",
+ WIFI_MOD_CLASS_OFDM,
+ true,
+ WIFI_CODE_RATE_1_2,
+ 16);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate36Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate36Mbps",
+ WIFI_MOD_CLASS_OFDM,
+ false,
+ WIFI_CODE_RATE_3_4,
+ 16);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate48Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate48Mbps",
+ WIFI_MOD_CLASS_OFDM,
+ false,
+ WIFI_CODE_RATE_2_3,
+ 64);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate54Mbps ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate54Mbps",
+ WIFI_MOD_CLASS_OFDM,
+ false,
+ WIFI_CODE_RATE_3_4,
+ 64);
+ return mode;
+}
+
+
+// 10 MHz channel rates
+
+WifiMode
+WifiPhy::GetOfdmRate3MbpsBW10MHz ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate3MbpsBW10MHz",
+ WIFI_MOD_CLASS_OFDM,
+ true,
+ WIFI_CODE_RATE_1_2,
+ 2);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate4_5MbpsBW10MHz ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate4_5MbpsBW10MHz",
+ WIFI_MOD_CLASS_OFDM,
+ false,
+ WIFI_CODE_RATE_3_4,
+ 2);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate6MbpsBW10MHz ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate6MbpsBW10MHz",
+ WIFI_MOD_CLASS_OFDM,
+ true,
+ WIFI_CODE_RATE_1_2,
+ 4);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate9MbpsBW10MHz ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate9MbpsBW10MHz",
+ WIFI_MOD_CLASS_OFDM,
+ false,
+ WIFI_CODE_RATE_3_4,
+ 4);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate12MbpsBW10MHz ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate12MbpsBW10MHz",
+ WIFI_MOD_CLASS_OFDM,
+ true,
+ WIFI_CODE_RATE_1_2,
+ 16);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate18MbpsBW10MHz ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate18MbpsBW10MHz",
+ WIFI_MOD_CLASS_OFDM,
+ false,
+ WIFI_CODE_RATE_3_4,
+ 16);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate24MbpsBW10MHz ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate24MbpsBW10MHz",
+ WIFI_MOD_CLASS_OFDM,
+ false,
+ WIFI_CODE_RATE_2_3,
+ 64);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate27MbpsBW10MHz ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate27MbpsBW10MHz",
+ WIFI_MOD_CLASS_OFDM,
+ false,
+ WIFI_CODE_RATE_3_4,
+ 64);
+ return mode;
+}
+
+
+// 5 MHz channel rates
+
+WifiMode
+WifiPhy::GetOfdmRate1_5MbpsBW5MHz ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate1_5MbpsBW5MHz",
+ WIFI_MOD_CLASS_OFDM,
+ true,
+ WIFI_CODE_RATE_1_2,
+ 2);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate2_25MbpsBW5MHz ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate2_25MbpsBW5MHz",
+ WIFI_MOD_CLASS_OFDM,
+ false,
+ WIFI_CODE_RATE_3_4,
+ 2);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate3MbpsBW5MHz ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate3MbpsBW5MHz",
+ WIFI_MOD_CLASS_OFDM,
+ true,
+ WIFI_CODE_RATE_1_2,
+ 4);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate4_5MbpsBW5MHz ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate4_5MbpsBW5MHz",
+ WIFI_MOD_CLASS_OFDM,
+ false,
+ WIFI_CODE_RATE_3_4,
+ 4);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate6MbpsBW5MHz ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate6MbpsBW5MHz",
+ WIFI_MOD_CLASS_OFDM,
+ true,
+ WIFI_CODE_RATE_1_2,
+ 16);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate9MbpsBW5MHz ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate9MbpsBW5MHz",
+ WIFI_MOD_CLASS_OFDM,
+ false,
+ WIFI_CODE_RATE_3_4,
+ 16);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate12MbpsBW5MHz ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate12MbpsBW5MHz",
+ WIFI_MOD_CLASS_OFDM,
+ false,
+ WIFI_CODE_RATE_2_3,
+ 64);
+ return mode;
+}
+
+WifiMode
+WifiPhy::GetOfdmRate13_5MbpsBW5MHz ()
+{
+ static WifiMode mode =
+ WifiModeFactory::CreateWifiMode ("OfdmRate13_5MbpsBW5MHz",
+ WIFI_MOD_CLASS_OFDM,
+ false,
+ WIFI_CODE_RATE_3_4,
+ 64);
+ return mode;
+}
+
+
+// Clause 20
+
+WifiMode
+WifiPhy::GetHtMcs0 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs0", 0, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs1 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs1", 1, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs2 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs2", 2, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs3 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs3", 3, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs4 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs4", 4, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs5 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs5", 5, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs6 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs6", 6, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs7 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs7", 7, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs8 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs8", 8, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs9 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs9", 9, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs10 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs10", 10, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs11 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs11", 11, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs12 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs12", 12, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs13 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs13", 13, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs14 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs14", 14, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs15 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs15", 15, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs16 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs16", 16, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs17 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs17", 17, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs18 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs18", 18, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs19 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs19", 19, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs20 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs20", 20, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs21 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs21", 21, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs22 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs22", 22, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs23 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs23", 23, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs24 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs24", 24, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs25 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs25", 25, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs26 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs26", 26, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs27 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs27", 27, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs28 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs28", 28, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs29 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs29", 29, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs30 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs30", 30, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetHtMcs31 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("HtMcs31", 31, WIFI_MOD_CLASS_HT);
+ return mcs;
+}
+
+
+// Clause 22
+
+WifiMode
+WifiPhy::GetVhtMcs0 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("VhtMcs0", 0, WIFI_MOD_CLASS_VHT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetVhtMcs1 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("VhtMcs1", 1, WIFI_MOD_CLASS_VHT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetVhtMcs2 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("VhtMcs2", 2, WIFI_MOD_CLASS_VHT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetVhtMcs3 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("VhtMcs3", 3, WIFI_MOD_CLASS_VHT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetVhtMcs4 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("VhtMcs4", 4, WIFI_MOD_CLASS_VHT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetVhtMcs5 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("VhtMcs5", 5, WIFI_MOD_CLASS_VHT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetVhtMcs6 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("VhtMcs6", 6, WIFI_MOD_CLASS_VHT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetVhtMcs7 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("VhtMcs7", 7, WIFI_MOD_CLASS_VHT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetVhtMcs8 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("VhtMcs8", 8, WIFI_MOD_CLASS_VHT);
+ return mcs;
+}
+
+WifiMode
+WifiPhy::GetVhtMcs9 ()
+{
+ static WifiMode mcs =
+ WifiModeFactory::CreateWifiMcs ("VhtMcs9", 9, WIFI_MOD_CLASS_VHT);
+ return mcs;
+}
+
+std::ostream& operator<< (std::ostream& os, enum WifiPhy::State state)
+{
+ switch (state)
+ {
+ case WifiPhy::IDLE:
+ return (os << "IDLE");
+ case WifiPhy::CCA_BUSY:
+ return (os << "CCA_BUSY");
+ case WifiPhy::TX:
+ return (os << "TX");
+ case WifiPhy::RX:
+ return (os << "RX");
+ case WifiPhy::SWITCHING:
+ return (os << "SWITCHING");
+ case WifiPhy::SLEEP:
+ return (os << "SLEEP");
+ default:
+ NS_FATAL_ERROR ("Invalid WifiPhy state");
+ return (os << "INVALID");
+ }
+}
+
+} //namespace ns3
+
+namespace {
+
+static class Constructor
+{
+public:
+ Constructor ()
+ {
+ ns3::WifiPhy::GetDsssRate1Mbps ();
+ ns3::WifiPhy::GetDsssRate2Mbps ();
+ ns3::WifiPhy::GetDsssRate5_5Mbps ();
+ ns3::WifiPhy::GetDsssRate11Mbps ();
+ ns3::WifiPhy::GetErpOfdmRate6Mbps ();
+ ns3::WifiPhy::GetErpOfdmRate9Mbps ();
+ ns3::WifiPhy::GetErpOfdmRate12Mbps ();
+ ns3::WifiPhy::GetErpOfdmRate18Mbps ();
+ ns3::WifiPhy::GetErpOfdmRate24Mbps ();
+ ns3::WifiPhy::GetErpOfdmRate36Mbps ();
+ ns3::WifiPhy::GetErpOfdmRate48Mbps ();
+ ns3::WifiPhy::GetErpOfdmRate54Mbps ();
+ ns3::WifiPhy::GetOfdmRate6Mbps ();
+ ns3::WifiPhy::GetOfdmRate9Mbps ();
+ ns3::WifiPhy::GetOfdmRate12Mbps ();
+ ns3::WifiPhy::GetOfdmRate18Mbps ();
+ ns3::WifiPhy::GetOfdmRate24Mbps ();
+ ns3::WifiPhy::GetOfdmRate36Mbps ();
+ ns3::WifiPhy::GetOfdmRate48Mbps ();
+ ns3::WifiPhy::GetOfdmRate54Mbps ();
+ ns3::WifiPhy::GetOfdmRate3MbpsBW10MHz ();
+ ns3::WifiPhy::GetOfdmRate4_5MbpsBW10MHz ();
+ ns3::WifiPhy::GetOfdmRate6MbpsBW10MHz ();
+ ns3::WifiPhy::GetOfdmRate9MbpsBW10MHz ();
+ ns3::WifiPhy::GetOfdmRate12MbpsBW10MHz ();
+ ns3::WifiPhy::GetOfdmRate18MbpsBW10MHz ();
+ ns3::WifiPhy::GetOfdmRate24MbpsBW10MHz ();
+ ns3::WifiPhy::GetOfdmRate27MbpsBW10MHz ();
+ ns3::WifiPhy::GetOfdmRate1_5MbpsBW5MHz ();
+ ns3::WifiPhy::GetOfdmRate2_25MbpsBW5MHz ();
+ ns3::WifiPhy::GetOfdmRate3MbpsBW5MHz ();
+ ns3::WifiPhy::GetOfdmRate4_5MbpsBW5MHz ();
+ ns3::WifiPhy::GetOfdmRate6MbpsBW5MHz ();
+ ns3::WifiPhy::GetOfdmRate9MbpsBW5MHz ();
+ ns3::WifiPhy::GetOfdmRate12MbpsBW5MHz ();
+ ns3::WifiPhy::GetOfdmRate13_5MbpsBW5MHz ();
+ ns3::WifiPhy::GetHtMcs0 ();
+ ns3::WifiPhy::GetHtMcs1 ();
+ ns3::WifiPhy::GetHtMcs2 ();
+ ns3::WifiPhy::GetHtMcs3 ();
+ ns3::WifiPhy::GetHtMcs4 ();
+ ns3::WifiPhy::GetHtMcs5 ();
+ ns3::WifiPhy::GetHtMcs6 ();
+ ns3::WifiPhy::GetHtMcs7 ();
+ ns3::WifiPhy::GetHtMcs8 ();
+ ns3::WifiPhy::GetHtMcs9 ();
+ ns3::WifiPhy::GetHtMcs10 ();
+ ns3::WifiPhy::GetHtMcs11 ();
+ ns3::WifiPhy::GetHtMcs12 ();
+ ns3::WifiPhy::GetHtMcs13 ();
+ ns3::WifiPhy::GetHtMcs14 ();
+ ns3::WifiPhy::GetHtMcs15 ();
+ ns3::WifiPhy::GetHtMcs16 ();
+ ns3::WifiPhy::GetHtMcs17 ();
+ ns3::WifiPhy::GetHtMcs18 ();
+ ns3::WifiPhy::GetHtMcs19 ();
+ ns3::WifiPhy::GetHtMcs20 ();
+ ns3::WifiPhy::GetHtMcs21 ();
+ ns3::WifiPhy::GetHtMcs22 ();
+ ns3::WifiPhy::GetHtMcs23 ();
+ ns3::WifiPhy::GetHtMcs24 ();
+ ns3::WifiPhy::GetHtMcs25 ();
+ ns3::WifiPhy::GetHtMcs26 ();
+ ns3::WifiPhy::GetHtMcs27 ();
+ ns3::WifiPhy::GetHtMcs28 ();
+ ns3::WifiPhy::GetHtMcs29 ();
+ ns3::WifiPhy::GetHtMcs30 ();
+ ns3::WifiPhy::GetHtMcs31 ();
+ ns3::WifiPhy::GetVhtMcs0 ();
+ ns3::WifiPhy::GetVhtMcs1 ();
+ ns3::WifiPhy::GetVhtMcs2 ();
+ ns3::WifiPhy::GetVhtMcs3 ();
+ ns3::WifiPhy::GetVhtMcs4 ();
+ ns3::WifiPhy::GetVhtMcs5 ();
+ ns3::WifiPhy::GetVhtMcs6 ();
+ ns3::WifiPhy::GetVhtMcs7 ();
+ ns3::WifiPhy::GetVhtMcs8 ();
+ ns3::WifiPhy::GetVhtMcs9 ();
+ }
+} g_constructor;
+
+}
diff --git a/emu-radio/ns3-patch/wifi/model/wifi-phy.h b/emu-radio/ns3-patch/wifi/model/wifi-phy.h
new file mode 100644
index 00000000..bc739de1
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/wifi-phy.h
@@ -0,0 +1,1326 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005,2006 INRIA
+ *
+ * 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
+ *
+ * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Sébastien Deronne <sebastien.deronne@gmail.com>
+ */
+
+#ifndef WIFI_PHY_H
+#define WIFI_PHY_H
+
+#include <stdint.h>
+#include "ns3/callback.h"
+#include "ns3/packet.h"
+#include "ns3/object.h"
+#include "ns3/nstime.h"
+#include "ns3/ptr.h"
+#include "wifi-mode.h"
+#include "wifi-preamble.h"
+#include "wifi-phy-standard.h"
+#include "ns3/traced-callback.h"
+#include "wifi-tx-vector.h"
+
+namespace ns3 {
+
+class WifiChannel;
+class NetDevice;
+
+struct signalNoiseDbm
+{
+ double signal; //in dBm
+ double noise; //in dBm
+};
+
+struct mpduInfo
+{
+ uint8_t packetType;
+ uint32_t referenceNumber;
+};
+
+/**
+ * \brief receive notifications about phy events.
+ */
+class WifiPhyListener
+{
+public:
+ virtual ~WifiPhyListener ();
+
+ /**
+ * \param duration the expected duration of the packet reception.
+ *
+ * We have received the first bit of a packet. We decided
+ * that we could synchronize on this packet. It does not mean
+ * we will be able to successfully receive completely the
+ * whole packet. It means that we will report a BUSY status until
+ * one of the following happens:
+ * - NotifyRxEndOk
+ * - NotifyRxEndError
+ * - NotifyTxStart
+ */
+ virtual void NotifyRxStart (Time duration) = 0;
+ /**
+ * We have received the last bit of a packet for which
+ * NotifyRxStart was invoked first and, the packet has
+ * been successfully received.
+ */
+ virtual void NotifyRxEndOk (void) = 0;
+ /**
+ * We have received the last bit of a packet for which
+ * NotifyRxStart was invoked first and, the packet has
+ * _not_ been successfully received.
+ */
+ virtual void NotifyRxEndError (void) = 0;
+ /**
+ * \param duration the expected transmission duration.
+ * \param txPowerDbm the nominal tx power in dBm
+ *
+ * We are about to send the first bit of the packet.
+ * We do not send any event to notify the end of
+ * transmission. Listeners should assume that the
+ * channel implicitely reverts to the idle state
+ * unless they have received a cca busy report.
+ */
+ virtual void NotifyTxStart (Time duration, double txPowerDbm) = 0;
+ /**
+ * \param duration the expected busy duration.
+ *
+ * This method does not really report a real state
+ * change as opposed to the other methods in this class.
+ * It merely reports that, unless the medium is reported
+ * busy through NotifyTxStart or NotifyRxStart/End,
+ * it will be busy as defined by the currently selected
+ * CCA mode.
+ *
+ * Typical client code which wants to have a clear picture
+ * of the CCA state will need to keep track of the time at
+ * which the last NotifyCcaBusyStart method is called and
+ * what duration it reported.
+ */
+ virtual void NotifyMaybeCcaBusyStart (Time duration) = 0;
+ /**
+ * \param duration the expected channel switching duration.
+ *
+ * We do not send any event to notify the end of
+ * channel switching. Listeners should assume that the
+ * channel implicitely reverts to the idle or busy states.
+ */
+ virtual void NotifySwitchingStart (Time duration) = 0;
+ /**
+ * Notify listeners that we went to sleep
+ */
+ virtual void NotifySleep (void) = 0;
+ /**
+ * Notify listeners that we woke up
+ */
+ virtual void NotifyWakeup (void) = 0;
+};
+
+
+/**
+ * \brief 802.11 PHY layer model
+ * \ingroup wifi
+ *
+ */
+class WifiPhy : public Object
+{
+public:
+ /**
+ * The state of the PHY layer.
+ */
+ enum State
+ {
+ /**
+ * The PHY layer is IDLE.
+ */
+ IDLE,
+ /**
+ * The PHY layer has sense the medium busy through the CCA mechanism
+ */
+ CCA_BUSY,
+ /**
+ * The PHY layer is sending a packet.
+ */
+ TX,
+ /**
+ * The PHY layer is receiving a packet.
+ */
+ RX,
+ /**
+ * The PHY layer is switching to other channel.
+ */
+ SWITCHING,
+ /**
+ * The PHY layer is sleeping.
+ */
+ SLEEP
+ };
+
+ /**
+ * arg1: packet received successfully
+ * arg2: snr of packet
+ * arg3: TXVECTOR of packet
+ * arg4: type of preamble used for packet.
+ */
+ typedef Callback<void, Ptr<Packet>, double, WifiTxVector, enum WifiPreamble> RxOkCallback;
+ /**
+ * arg1: packet received unsuccessfully
+ * arg2: snr of packet
+ */
+ typedef Callback<void, Ptr<const Packet>, double> RxErrorCallback;
+
+ static TypeId GetTypeId (void);
+
+ WifiPhy ();
+ virtual ~WifiPhy ();
+
+ /**
+ * Return the minimum available transmission power level (dBm).
+ *
+ * \return the minimum available transmission power level in dBm
+ */
+ virtual double GetTxPowerStart (void) const = 0;
+ /**
+ * Return the maximum available transmission power level (dBm).
+ *
+ * \return the maximum available transmission power level in dBm
+ */
+ virtual double GetTxPowerEnd (void) const = 0;
+ /**
+ * \return the number of tx power levels available for this PHY.
+ */
+ virtual uint32_t GetNTxPower (void) const = 0;
+
+ /**
+ * \param callback the callback to invoke
+ * upon successful packet reception.
+ */
+ virtual void SetReceiveOkCallback (RxOkCallback callback) = 0;
+ /**
+ * \param callback the callback to invoke
+ * upon erroneous packet reception.
+ */
+ virtual void SetReceiveErrorCallback (RxErrorCallback callback) = 0;
+
+ /**
+ * \param packet the packet to send
+ * \param txVector the TXVECTOR that has tx parameters such as mode, the transmission mode to use to send
+ * this packet, and txPowerLevel, a power level to use to send this packet. The real transmission
+ * power is calculated as txPowerMin + txPowerLevel * (txPowerMax - txPowerMin) / nTxLevels
+ * \param preamble the type of preamble to use to send this packet.
+ * \param packetType the type of the packet 0 is not A-MPDU, 1 is a MPDU that is part of an A-MPDU and 2 is the last MPDU in an A-MPDU
+ * \param mpduReferenceNumber the A-MPDU reference number (must be a different value for each A-MPDU but the same for each subframe within one A-MPDU)
+ */
+ virtual void SendPacket (Ptr<const Packet> packet, WifiTxVector txVector, enum WifiPreamble preamble, uint8_t packetType, uint32_t mpduReferenceNumber) = 0;
+
+ /**
+ * \param listener the new listener
+ *
+ * Add the input listener to the list of objects to be notified of
+ * PHY-level events.
+ */
+ virtual void RegisterListener (WifiPhyListener *listener) = 0;
+ /**
+ * \param listener the listener to be unregistered
+ *
+ * Remove the input listener from the list of objects to be notified of
+ * PHY-level events.
+ */
+ virtual void UnregisterListener (WifiPhyListener *listener) = 0;
+
+ /**
+ * Put in sleep mode.
+ */
+ virtual void SetSleepMode (void) = 0;
+ /**
+ * Resume from sleep mode.
+ */
+ virtual void ResumeFromSleep (void) = 0;
+
+ /**
+ * \return true of the current state of the PHY layer is WifiPhy::IDLE, false otherwise.
+ */
+ virtual bool IsStateIdle (void) = 0;
+ /**
+ * \return true of the current state of the PHY layer is WifiPhy::CCA_BUSY, false otherwise.
+ */
+ virtual bool IsStateCcaBusy (void) = 0;
+ /**
+ * \return true of the current state of the PHY layer is not WifiPhy::IDLE, false otherwise.
+ */
+ virtual bool IsStateBusy (void) = 0;
+ /**
+ * \return true of the current state of the PHY layer is WifiPhy::RX, false otherwise.
+ */
+ virtual bool IsStateRx (void) = 0;
+ /**
+ * \return true of the current state of the PHY layer is WifiPhy::TX, false otherwise.
+ */
+ virtual bool IsStateTx (void) = 0;
+ /**
+ * \return true of the current state of the PHY layer is WifiPhy::SWITCHING, false otherwise.
+ */
+ virtual bool IsStateSwitching (void) = 0;
+ /**
+ * \return true if the current state of the PHY layer is WifiPhy::SLEEP, false otherwise.
+ */
+ virtual bool IsStateSleep (void) = 0;
+ /**
+ * \return the amount of time since the current state has started.
+ */
+ virtual Time GetStateDuration (void) = 0;
+ /**
+ * \return the predicted delay until this PHY can become WifiPhy::IDLE.
+ *
+ * The PHY will never become WifiPhy::IDLE _before_ the delay returned by
+ * this method but it could become really idle later.
+ */
+ virtual Time GetDelayUntilIdle (void) = 0;
+
+ /**
+ * Return the start time of the last received packet.
+ *
+ * \return the start time of the last received packet
+ */
+ virtual Time GetLastRxStartTime (void) const = 0;
+
+ /**
+ * \param size the number of bytes in the packet to send
+ * \param txVector the TXVECTOR used for the transmission of this packet
+ * \param preamble the type of preamble to use for this packet.
+ * \param frequency the channel center frequency (MHz)
+ * \param packetType the type of the packet 0 is not A-MPDU, 1 is a MPDU that is part of an A-MPDU and 2 is the last MPDU in an A-MPDU
+ * \param incFlag this flag is used to indicate that the static variables need to be update or not. This function is called a couple of times for the same packet so static variables should not be increased each time.
+ *
+ * \return the total amount of time this PHY will stay busy for the transmission of these bytes.
+ */
+ Time CalculateTxDuration (uint32_t size, WifiTxVector txVector, enum WifiPreamble preamble, double frequency, uint8_t packetType, uint8_t incFlag);
+
+ /**
+ * \param txVector the transmission parameters used for this packet
+ * \param preamble the type of preamble to use for this packet.
+ *
+ * \return the total amount of time this PHY will stay busy for the transmission of the PLCP preamble and PLCP header.
+ */
+ Time CalculatePlcpPreambleAndHeaderDuration (WifiTxVector txVector, enum WifiPreamble preamble);
+
+ /**
+ * \param preamble the type of preamble
+ * \param txVector the transmission parameters used for this packet
+ *
+ * \return the training symbol duration
+ */
+ static Time GetPlcpHtTrainingSymbolDuration (WifiPreamble preamble, WifiTxVector txVector);
+ /**
+ * \param payloadMode the WifiMode use for the transmission of the payload
+ *
+ * \return the WifiMode used for the transmission of the HT-SIG and the HT training fields
+ * in Mixed Format and greenfield format PLCP header
+ */
+ static WifiMode GetHtPlcpHeaderMode (WifiMode payloadMode);
+ /**
+ * \param payloadMode the WifiMode use for the transmission of the payload
+ *
+ * \return the WifiMode used for the transmission of the VHT-STF, VHT-LTF and VHT-SIG-B fields
+ */
+ static WifiMode GetVhtPlcpHeaderMode (WifiMode payloadMode);
+ /**
+ * \param preamble the type of preamble
+ *
+ * \return the duration of the HT-SIG in Mixed Format and greenfield format PLCP header
+ */
+ static Time GetPlcpHtSigHeaderDuration (WifiPreamble preamble);
+ /**
+ * \param preamble the type of preamble
+ *
+ * \return the duration of the VHT-SIG-A1 in PLCP header
+ */
+ static Time GetPlcpVhtSigA1Duration (WifiPreamble preamble);
+ /**
+ * \param preamble the type of preamble
+ *
+ * \return the duration of the VHT-SIG-A2 in PLCP header
+ */
+ static Time GetPlcpVhtSigA2Duration (WifiPreamble preamble);
+ /**
+ * \param preamble the type of preamble
+ *
+ * \return the duration of the VHT-SIG-B in PLCP header
+ */
+ static Time GetPlcpVhtSigBDuration (WifiPreamble preamble);
+ /**
+ * \param payloadMode the WifiMode use for the transmission of the payload
+ * \param preamble the type of preamble
+ * \param txVector the transmission parameters used for this packet
+ *
+ * \return the WifiMode used for the transmission of the PLCP header
+ */
+ static WifiMode GetPlcpHeaderMode (WifiMode payloadMode, WifiPreamble preamble, WifiTxVector txVector);
+ /**
+ * \param txVector the transmission parameters used for this packet
+ * \param preamble the type of preamble
+ *
+ * \return the duration of the PLCP header
+ */
+ static Time GetPlcpHeaderDuration (WifiTxVector txVector, WifiPreamble preamble);
+ /**
+ * \param txVector the transmission parameters used for this packet
+ * \param preamble the type of preamble
+ *
+ * \return the duration of the PLCP preamble
+ */
+ static Time GetPlcpPreambleDuration (WifiTxVector txVector, WifiPreamble preamble);
+ /**
+ * \param size the number of bytes in the packet to send
+ * \param txVector the TXVECTOR used for the transmission of this packet
+ * \param preamble the type of preamble to use for this packet
+ * \param frequency the channel center frequency (MHz)
+ * \param packetType the type of the packet (0 is not A-MPDU, 1 is a MPDU that is part of an A-MPDU and 2 is the last MPDU in an A-MPDU)
+ * \param incFlag this flag is used to indicate that the static variables need to be update or not. This function is called a couple of times for the same packet so static variables should not be increased each time
+ *
+ * \return the duration of the payload
+ */
+ Time GetPayloadDuration (uint32_t size, WifiTxVector txVector, WifiPreamble preamble, double frequency, uint8_t packetType, uint8_t incFlag);
+
+ /**
+ * The WifiPhy::GetNModes() and WifiPhy::GetMode() methods are used
+ * (e.g., by a WifiRemoteStationManager) to determine the set of
+ * transmission/reception modes that this WifiPhy(-derived class)
+ * can support - a set of WifiMode objects which we call the
+ * DeviceRateSet, and which is stored as WifiPhy::m_deviceRateSet.
+ *
+ * It is important to note that the DeviceRateSet is a superset (not
+ * necessarily proper) of the OperationalRateSet (which is
+ * logically, if not actually, a property of the associated
+ * WifiRemoteStationManager), which itself is a superset (again, not
+ * necessarily proper) of the BSSBasicRateSet.
+ *
+ * \return the number of transmission modes supported by this PHY.
+ *
+ * \sa WifiPhy::GetMode()
+ */
+ virtual uint32_t GetNModes (void) const = 0;
+ /**
+ * The WifiPhy::GetNModes() and WifiPhy::GetMode() methods are used
+ * (e.g., by a WifiRemoteStationManager) to determine the set of
+ * transmission/reception modes that this WifiPhy(-derived class)
+ * can support - a set of WifiMode objects which we call the
+ * DeviceRateSet, and which is stored as WifiPhy::m_deviceRateSet.
+ *
+ * It is important to note that the DeviceRateSet is a superset (not
+ * necessarily proper) of the OperationalRateSet (which is
+ * logically, if not actually, a property of the associated
+ * WifiRemoteStationManager), which itself is a superset (again, not
+ * necessarily proper) of the BSSBasicRateSet.
+ *
+ * \param mode index in array of supported modes
+ *
+ * \return the mode whose index is specified.
+ *
+ * \sa WifiPhy::GetNModes()
+ */
+ virtual WifiMode GetMode (uint32_t mode) const = 0;
+ /**
+ * Check if the given WifiMode is supported by the PHY.
+ *
+ * \param mode the wifi mode to check
+ *
+ * \return true if the given mode is supported,
+ * false otherwise
+ */
+ virtual bool IsModeSupported (WifiMode mode) const = 0;
+
+ /**
+ * \param txMode the transmission mode
+ * \param ber the probability of bit error rate
+ *
+ * \return the minimum snr which is required to achieve
+ * the requested ber for the specified transmission mode. (W/W)
+ */
+ virtual double CalculateSnr (WifiMode txMode, double ber) const = 0;
+
+ /**
+ * The WifiPhy::NBssMembershipSelectors() method is used
+ * (e.g., by a WifiRemoteStationManager) to determine the set of
+ * transmission/reception modes that this WifiPhy(-derived class)
+ * can support - a set of WifiMode objects which we call the
+ * BssMembershipSelectorSet, and which is stored as WifiPhy::m_bssMembershipSelectorSet.
+ *
+ * \return the memebership selector whose index is specified.
+ */
+ virtual uint32_t GetNBssMembershipSelectors (void) const = 0;
+ /**
+ * The WifiPhy::BssMembershipSelector() method is used
+ * (e.g., by a WifiRemoteStationManager) to determine the set of
+ * transmission/reception modes that this WifiPhy(-derived class)
+ * can support - a set of WifiMode objects which we call the
+ * BssMembershipSelectorSet, and which is stored as WifiPhy::m_bssMembershipSelectorSet.
+ *
+ * \param selector index in array of supported memberships
+ *
+ * \return the memebership selector whose index is specified.
+ */
+ virtual uint32_t GetBssMembershipSelector (uint32_t selector) const = 0;
+ /**
+ * The WifiPhy::GetMembershipSelectorModes() method is used
+ * (e.g., by a WifiRemoteStationManager) to determine the set of
+ * transmission/reception modes that this WifiPhy(-derived class)
+ * can support - a set of WifiMode objects which we call the
+ * BssMembershipSelectorSet, and which is stored as WifiPhy::m_bssMembershipSelectorSet.
+ *
+ * \param selector index in array of supported memberships
+ *
+ * \return a WifiModeList that contains the WifiModes associrated with the selected index.
+ *
+ * \sa WifiPhy::GetMembershipSelectorModes()
+ */
+ virtual WifiModeList GetMembershipSelectorModes (uint32_t selector) = 0;
+ /**
+ * The WifiPhy::GetNMcs() method is used
+ * (e.g., by a WifiRemoteStationManager) to determine the set of
+ * transmission/reception MCS indexes that this WifiPhy(-derived class)
+ * can support - a set of MCS indexes which we call the
+ * DeviceMcsSet, and which is stored as WifiPhy::m_deviceMcsSet.
+ *
+ * \return the MCS index whose index is specified.
+ */
+ virtual uint8_t GetNMcs (void) const = 0;
+ /**
+ * The WifiPhy::GetMcs() method is used
+ * (e.g., by a WifiRemoteStationManager) to determine the set of
+ * transmission/reception MCS indexes that this WifiPhy(-derived class)
+ * can support - a set of MCS indexes which we call the
+ * DeviceMcsSet, and which is stored as WifiPhy::m_deviceMcsSet.
+ *
+ * \param mcs index in array of supported MCS
+ *
+ * \return the MCS index whose index is specified.
+ */
+ virtual WifiMode GetMcs (uint8_t mcs) const = 0;
+
+ /**
+ * \brief Set channel number.
+ *
+ * Channel center frequency = Channel starting frequency + 5 MHz * (nch - 1)
+ *
+ * where Starting channel frequency is standard-dependent, see SetStandard()
+ * as defined in (Section 18.3.8.4.2 "Channel numbering"; IEEE Std 802.11-2012).
+ *
+ * \param id the channel number
+ */
+ virtual void SetChannelNumber (uint16_t id) = 0;
+ /**
+ * Return current channel number.
+ *
+ * \return the current channel number
+ */
+ virtual uint16_t GetChannelNumber (void) const = 0;
+ /**
+ * \return the required time for channel switch operation of this WifiPhy
+ */
+ virtual Time GetChannelSwitchDelay (void) const = 0;
+
+ /**
+ * Configure the PHY-level parameters for different Wi-Fi standard.
+ *
+ * \param standard the Wi-Fi standard
+ */
+ virtual void ConfigureStandard (enum WifiPhyStandard standard) = 0;
+
+ /**
+ * Return the WifiChannel this WifiPhy is connected to.
+ *
+ * \return the WifiChannel this WifiPhy is connected to
+ */
+ virtual Ptr<WifiChannel> GetChannel (void) const = 0;
+
+ /**
+ * Return a WifiMode for DSSS at 1Mbps.
+ *
+ * \return a WifiMode for DSSS at 1Mbps
+ */
+ static WifiMode GetDsssRate1Mbps ();
+ /**
+ * Return a WifiMode for DSSS at 2Mbps.
+ *
+ * \return a WifiMode for DSSS at 2Mbps
+ */
+ static WifiMode GetDsssRate2Mbps ();
+ /**
+ * Return a WifiMode for DSSS at 5.5Mbps.
+ *
+ * \return a WifiMode for DSSS at 5.5Mbps
+ */
+ static WifiMode GetDsssRate5_5Mbps ();
+ /**
+ * Return a WifiMode for DSSS at 11Mbps.
+ *
+ * \return a WifiMode for DSSS at 11Mbps
+ */
+ static WifiMode GetDsssRate11Mbps ();
+ /**
+ * Return a WifiMode for ERP-OFDM at 6Mbps.
+ *
+ * \return a WifiMode for ERP-OFDM at 6Mbps
+ */
+ static WifiMode GetErpOfdmRate6Mbps ();
+ /**
+ * Return a WifiMode for ERP-OFDM at 9Mbps.
+ *
+ * \return a WifiMode for ERP-OFDM at 9Mbps
+ */
+ static WifiMode GetErpOfdmRate9Mbps ();
+ /**
+ * Return a WifiMode for ERP-OFDM at 12Mbps.
+ *
+ * \return a WifiMode for ERP-OFDM at 12Mbps
+ */
+ static WifiMode GetErpOfdmRate12Mbps ();
+ /**
+ * Return a WifiMode for ERP-OFDM at 18Mbps.
+ *
+ * \return a WifiMode for ERP-OFDM at 18Mbps
+ */
+ static WifiMode GetErpOfdmRate18Mbps ();
+ /**
+ * Return a WifiMode for ERP-OFDM at 24Mbps.
+ *
+ * \return a WifiMode for ERP-OFDM at 24Mbps
+ */
+ static WifiMode GetErpOfdmRate24Mbps ();
+ /**
+ * Return a WifiMode for ERP-OFDM at 36Mbps.
+ *
+ * \return a WifiMode for ERP-OFDM at 36Mbps
+ */
+ static WifiMode GetErpOfdmRate36Mbps ();
+ /**
+ * Return a WifiMode for ERP-OFDM at 48Mbps.
+ *
+ * \return a WifiMode for ERP-OFDM at 48Mbps
+ */
+ static WifiMode GetErpOfdmRate48Mbps ();
+ /**
+ * Return a WifiMode for ERP-OFDM at 54Mbps.
+ *
+ * \return a WifiMode for ERP-OFDM at 54Mbps
+ */
+ static WifiMode GetErpOfdmRate54Mbps ();
+ /**
+ * Return a WifiMode for OFDM at 6Mbps.
+ *
+ * \return a WifiMode for OFDM at 6Mbps
+ */
+ static WifiMode GetOfdmRate6Mbps ();
+ /**
+ * Return a WifiMode for OFDM at 9Mbps.
+ *
+ * \return a WifiMode for OFDM at 9Mbps
+ */
+ static WifiMode GetOfdmRate9Mbps ();
+ /**
+ * Return a WifiMode for OFDM at 12Mbps.
+ *
+ * \return a WifiMode for OFDM at 12Mbps
+ */
+ static WifiMode GetOfdmRate12Mbps ();
+ /**
+ * Return a WifiMode for OFDM at 18Mbps.
+ *
+ * \return a WifiMode for OFDM at 18Mbps
+ */
+ static WifiMode GetOfdmRate18Mbps ();
+ /**
+ * Return a WifiMode for OFDM at 24Mbps.
+ *
+ * \return a WifiMode for OFDM at 24Mbps
+ */
+ static WifiMode GetOfdmRate24Mbps ();
+ /**
+ * Return a WifiMode for OFDM at 36Mbps.
+ *
+ * \return a WifiMode for OFDM at 36Mbps
+ */
+ static WifiMode GetOfdmRate36Mbps ();
+ /**
+ * Return a WifiMode for OFDM at 48Mbps.
+ *
+ * \return a WifiMode for OFDM at 48Mbps
+ */
+ static WifiMode GetOfdmRate48Mbps ();
+ /**
+ * Return a WifiMode for OFDM at 54Mbps.
+ *
+ * \return a WifiMode for OFDM at 54Mbps
+ */
+ static WifiMode GetOfdmRate54Mbps ();
+ /**
+ * Return a WifiMode for OFDM at 3Mbps with 10MHz channel spacing.
+ *
+ * \return a WifiMode for OFDM at 3Mbps with 10MHz channel spacing
+ */
+ static WifiMode GetOfdmRate3MbpsBW10MHz ();
+ /**
+ * Return a WifiMode for OFDM at 4.5Mbps with 10MHz channel spacing.
+ *
+ * \return a WifiMode for OFDM at 4.5Mbps with 10MHz channel spacing
+ */
+ static WifiMode GetOfdmRate4_5MbpsBW10MHz ();
+ /**
+ * Return a WifiMode for OFDM at 6Mbps with 10MHz channel spacing.
+ *
+ * \return a WifiMode for OFDM at 6Mbps with 10MHz channel spacing
+ */
+ static WifiMode GetOfdmRate6MbpsBW10MHz ();
+ /**
+ * Return a WifiMode for OFDM at 9Mbps with 10MHz channel spacing.
+ *
+ * \return a WifiMode for OFDM at 9Mbps with 10MHz channel spacing
+ */
+ static WifiMode GetOfdmRate9MbpsBW10MHz ();
+ /**
+ * Return a WifiMode for OFDM at 12Mbps with 10MHz channel spacing.
+ *
+ * \return a WifiMode for OFDM at 12Mbps with 10MHz channel spacing
+ */
+ static WifiMode GetOfdmRate12MbpsBW10MHz ();
+ /**
+ * Return a WifiMode for OFDM at 18Mbps with 10MHz channel spacing.
+ *
+ * \return a WifiMode for OFDM at 18Mbps with 10MHz channel spacing
+ */
+ static WifiMode GetOfdmRate18MbpsBW10MHz ();
+ /**
+ * Return a WifiMode for OFDM at 24Mbps with 10MHz channel spacing.
+ *
+ * \return a WifiMode for OFDM at 24Mbps with 10MHz channel spacing
+ */
+ static WifiMode GetOfdmRate24MbpsBW10MHz ();
+ /**
+ * Return a WifiMode for OFDM at 27Mbps with 10MHz channel spacing.
+ *
+ * \return a WifiMode for OFDM at 27Mbps with 10MHz channel spacing
+ */
+ static WifiMode GetOfdmRate27MbpsBW10MHz ();
+ /**
+ * Return a WifiMode for OFDM at 1.5Mbps with 5MHz channel spacing.
+ *
+ * \return a WifiMode for OFDM at 1.5Mbps with 5MHz channel spacing
+ */
+ static WifiMode GetOfdmRate1_5MbpsBW5MHz ();
+ /**
+ * Return a WifiMode for OFDM at 2.25Mbps with 5MHz channel spacing.
+ *
+ * \return a WifiMode for OFDM at 2.25Mbps with 5MHz channel spacing
+ */
+ static WifiMode GetOfdmRate2_25MbpsBW5MHz ();
+ /**
+ * Return a WifiMode for OFDM at 3Mbps with 5MHz channel spacing.
+ *
+ * \return a WifiMode for OFDM at 3Mbps with 5MHz channel spacing
+ */
+ static WifiMode GetOfdmRate3MbpsBW5MHz ();
+ /**
+ * Return a WifiMode for OFDM at 4.5Mbps with 5MHz channel spacing.
+ *
+ * \return a WifiMode for OFDM at 4.5Mbps with 5MHz channel spacing
+ */
+ static WifiMode GetOfdmRate4_5MbpsBW5MHz ();
+ /**
+ * Return a WifiMode for OFDM at 6Mbps with 5MHz channel spacing.
+ *
+ * \return a WifiMode for OFDM at 6Mbps with 5MHz channel spacing
+ */
+ static WifiMode GetOfdmRate6MbpsBW5MHz ();
+ /**
+ * Return a WifiMode for OFDM at 9Mbps with 5MHz channel spacing.
+ *
+ * \return a WifiMode for OFDM at 9Mbps with 5MHz channel spacing
+ */
+ static WifiMode GetOfdmRate9MbpsBW5MHz ();
+ /**
+ * Return a WifiMode for OFDM at 12Mbps with 5MHz channel spacing.
+ *
+ * \return a WifiMode for OFDM at 12Mbps with 5MHz channel spacing
+ */
+ static WifiMode GetOfdmRate12MbpsBW5MHz ();
+ /**
+ * Return a WifiMode for OFDM at 13.5Mbps with 5MHz channel spacing.
+ *
+ * \return a WifiMode for OFDM at 13.5Mbps with 5MHz channel spacing
+ */
+ static WifiMode GetOfdmRate13_5MbpsBW5MHz ();
+
+ /**
+ * Return MCS 0 from HT MCS values.
+ *
+ * \return MCS 0 from HT MCS values
+ */
+ static WifiMode GetHtMcs0 ();
+ /**
+ * Return MCS 1 from HT MCS values.
+ *
+ * \return MCS 1 from HT MCS values
+ */
+ static WifiMode GetHtMcs1 ();
+ /**
+ * Return MCS 2 from HT MCS values.
+ *
+ * \return MCS 2 from HT MCS values
+ */
+ static WifiMode GetHtMcs2 ();
+ /**
+ * Return MCS 3 from HT MCS values.
+ *
+ * \return MCS 3 from HT MCS values
+ */
+ static WifiMode GetHtMcs3 ();
+ /**
+ * Return MCS 4 from HT MCS values.
+ *
+ * \return MCS 4 from HT MCS values
+ */
+ static WifiMode GetHtMcs4 ();
+ /**
+ * Return MCS 5 from HT MCS values.
+ *
+ * \return MCS 5 from HT MCS values
+ */
+ static WifiMode GetHtMcs5 ();
+ /**
+ * Return MCS 6 from HT MCS values.
+ *
+ * \return MCS 6 from HT MCS values
+ */
+ static WifiMode GetHtMcs6 ();
+ /**
+ * Return MCS 7 from HT MCS values.
+ *
+ * \return MCS 7 from HT MCS values
+ */
+ static WifiMode GetHtMcs7 ();
+ /**
+ * Return MCS 8 from HT MCS values.
+ *
+ * \return MCS 8 from HT MCS values
+ */
+ static WifiMode GetHtMcs8 ();
+ /**
+ * Return MCS 9 from HT MCS values.
+ *
+ * \return MCS 9 from HT MCS values
+ */
+ static WifiMode GetHtMcs9 ();
+ /**
+ * Return MCS 10 from HT MCS values.
+ *
+ * \return MCS 10 from HT MCS values
+ */
+ static WifiMode GetHtMcs10 ();
+ /**
+ * Return MCS 11 from HT MCS values.
+ *
+ * \return MCS 11 from HT MCS values
+ */
+ static WifiMode GetHtMcs11 ();
+ /**
+ * Return MCS 12 from HT MCS values.
+ *
+ * \return MCS 12 from HT MCS values
+ */
+ static WifiMode GetHtMcs12 ();
+ /**
+ * Return MCS 13 from HT MCS values.
+ *
+ * \return MCS 13 from HT MCS values
+ */
+ static WifiMode GetHtMcs13 ();
+ /**
+ * Return MCS 14 from HT MCS values.
+ *
+ * \return MCS 14 from HT MCS values
+ */
+ static WifiMode GetHtMcs14 ();
+ /**
+ * Return MCS 15 from HT MCS values.
+ *
+ * \return MCS 15 from HT MCS values
+ */
+ static WifiMode GetHtMcs15 ();
+ /**
+ * Return MCS 16 from HT MCS values.
+ *
+ * \return MCS 16 from HT MCS values
+ */
+ static WifiMode GetHtMcs16 ();
+ /**
+ * Return MCS 17 from HT MCS values.
+ *
+ * \return MCS 17 from HT MCS values
+ */
+ static WifiMode GetHtMcs17 ();
+ /**
+ * Return MCS 18 from HT MCS values.
+ *
+ * \return MCS 18 from HT MCS values
+ */
+ static WifiMode GetHtMcs18 ();
+ /**
+ * Return MCS 19 from HT MCS values.
+ *
+ * \return MCS 19 from HT MCS values
+ */
+ static WifiMode GetHtMcs19 ();
+ /**
+ * Return MCS 20 from HT MCS values.
+ *
+ * \return MCS 20 from HT MCS values
+ */
+ static WifiMode GetHtMcs20 ();
+ /**
+ * Return MCS 21 from HT MCS values.
+ *
+ * \return MCS 21 from HT MCS values
+ */
+ static WifiMode GetHtMcs21 ();
+ /**
+ * Return MCS 22 from HT MCS values.
+ *
+ * \return MCS 22 from HT MCS values
+ */
+ static WifiMode GetHtMcs22 ();
+ /**
+ * Return MCS 23 from HT MCS values.
+ *
+ * \return MCS 23 from HT MCS values
+ */
+ static WifiMode GetHtMcs23 ();
+ /**
+ * Return MCS 24 from HT MCS values.
+ *
+ * \return MCS 24 from HT MCS values
+ */
+ static WifiMode GetHtMcs24 ();
+ /**
+ * Return MCS 25 from HT MCS values.
+ *
+ * \return MCS 25 from HT MCS values
+ */
+ static WifiMode GetHtMcs25 ();
+ /**
+ * Return MCS 26 from HT MCS values.
+ *
+ * \return MCS 26 from HT MCS values
+ */
+ static WifiMode GetHtMcs26 ();
+ /**
+ * Return MCS 27 from HT MCS values.
+ *
+ * \return MCS 27 from HT MCS values
+ */
+ static WifiMode GetHtMcs27 ();
+ /**
+ * Return MCS 28 from HT MCS values.
+ *
+ * \return MCS 28 from HT MCS values
+ */
+ static WifiMode GetHtMcs28 ();
+ /**
+ * Return MCS 29 from HT MCS values.
+ *
+ * \return MCS 29 from HT MCS values
+ */
+ static WifiMode GetHtMcs29 ();
+ /**
+ * Return MCS 30 from HT MCS values.
+ *
+ * \return MCS 30 from HT MCS values
+ */
+ static WifiMode GetHtMcs30 ();
+ /**
+ * Return MCS 31 from HT MCS values.
+ *
+ * \return MCS 31 from HT MCS values
+ */
+ static WifiMode GetHtMcs31 ();
+
+ /**
+ * Return MCS 0 from VHT MCS values.
+ *
+ * \return MCS 0 from VHT MCS values
+ */
+ static WifiMode GetVhtMcs0 ();
+ /**
+ * Return MCS 1 from VHT MCS values.
+ *
+ * \return MCS 1 from VHT MCS values
+ */
+ static WifiMode GetVhtMcs1 ();
+ /**
+ * Return MCS 2 from VHT MCS values.
+ *
+ * \return MCS 2 from VHT MCS values
+ */
+ static WifiMode GetVhtMcs2 ();
+ /**
+ * Return MCS 3 from VHT MCS values.
+ *
+ * \return MCS 3 from VHT MCS values
+ */
+ static WifiMode GetVhtMcs3 ();
+ /**
+ * Return MCS 4 from VHT MCS values.
+ *
+ * \return MCS 4 from VHT MCS values
+ */
+ static WifiMode GetVhtMcs4 ();
+ /**
+ * Return MCS 5 from VHT MCS values.
+ *
+ * \return MCS 5 from VHT MCS values
+ */
+ static WifiMode GetVhtMcs5 ();
+ /**
+ * Return MCS 6 from VHT MCS values.
+ *
+ * \return MCS 6 from VHT MCS values
+ */
+ static WifiMode GetVhtMcs6 ();
+ /**
+ * Return MCS 7 from VHT MCS values.
+ *
+ * \return MCS 7 from VHT MCS values
+ */
+ static WifiMode GetVhtMcs7 ();
+ /**
+ * Return MCS 8 from VHT MCS values.
+ *
+ * \return MCS 8 from VHT MCS values
+ */
+ static WifiMode GetVhtMcs8 ();
+ /**
+ * Return MCS 9 from VHT MCS values.
+ *
+ * \return MCS 9 from VHT MCS values
+ */
+ static WifiMode GetVhtMcs9 ();
+
+ /**
+ * Public method used to fire a PhyTxBegin trace.
+ * Implemented for encapsulation purposes.
+ *
+ * \param packet the packet being transmitted
+ */
+ void NotifyTxBegin (Ptr<const Packet> packet);
+ /**
+ * Public method used to fire a PhyTxEnd trace.
+ * Implemented for encapsulation purposes.
+ *
+ * \param packet the packet that was transmitted
+ */
+ void NotifyTxEnd (Ptr<const Packet> packet);
+ /**
+ * Public method used to fire a PhyTxDrop trace.
+ * Implemented for encapsulation purposes.
+ *
+ * \param packet the packet that was failed to transmitted
+ */
+ void NotifyTxDrop (Ptr<const Packet> packet);
+ /**
+ * Public method used to fire a PhyRxBegin trace.
+ * Implemented for encapsulation purposes.
+ *
+ * \param packet the packet being received
+ */
+ void NotifyRxBegin (Ptr<const Packet> packet);
+ /**
+ * Public method used to fire a PhyRxEnd trace.
+ * Implemented for encapsulation purposes.
+ *
+ * \param packet the packet received
+ */
+ void NotifyRxEnd (Ptr<const Packet> packet);
+ /**
+ * Public method used to fire a PhyRxDrop trace.
+ * Implemented for encapsulation purposes.
+ *
+ * \param packet the packet that was not successfully received
+ */
+ void NotifyRxDrop (Ptr<const Packet> packet);
+
+ /**
+ * Public method used to fire a MonitorSniffer trace for a wifi packet being received.
+ * Implemented for encapsulation purposes.
+ *
+ * \param packet the packet being received
+ * \param channelFreqMhz the frequency in MHz at which the packet is
+ * received. Note that in real devices this is normally the
+ * frequency to which the receiver is tuned, and this can be
+ * different than the frequency at which the packet was originally
+ * transmitted. This is because it is possible to have the receiver
+ * tuned on a given channel and still to be able to receive packets
+ * on a nearby channel.
+ * \param channelNumber the channel on which the packet is received
+ * \param rate the PHY data rate in units of 500kbps (i.e., the same
+ * units used both for the radiotap and for the prism header)
+ * \param preamble the preamble of the packet
+ * \param txVector the TXVECTOR that holds rx parameters
+ * \param aMpdu the type of the packet (0 is not A-MPDU, 1 is a MPDU that is part of an A-MPDU and 2 is the last MPDU in an A-MPDU)
+ * and the A-MPDU reference number (must be a different value for each A-MPDU but the same for each subframe within one A-MPDU)
+ * \param signalNoise signal power and noise power in dBm
+ */
+ void NotifyMonitorSniffRx (Ptr<const Packet> packet, uint16_t channelFreqMhz,
+ uint16_t channelNumber, uint32_t rate, WifiPreamble preamble,
+ WifiTxVector txVector, struct mpduInfo aMpdu, struct signalNoiseDbm signalNoise);
+
+ /**
+ * TracedCallback signature for monitor mode receive events.
+ *
+ *
+ * \param packet the packet being received
+ * \param channelFreqMhz the frequency in MHz at which the packet is
+ * received. Note that in real devices this is normally the
+ * frequency to which the receiver is tuned, and this can be
+ * different than the frequency at which the packet was originally
+ * transmitted. This is because it is possible to have the receiver
+ * tuned on a given channel and still to be able to receive packets
+ * on a nearby channel.
+ * \param channelNumber the channel on which the packet is received
+ * \param rate the PHY data rate in units of 500kbps (i.e., the same
+ * units used both for the radiotap and for the prism header)
+ * \param preamble the preamble of the packet
+ * \param txVector the TXVECTOR that holds rx parameters
+ * \param aMpdu the type of the packet (0 is not A-MPDU, 1 is a MPDU that is part of an A-MPDU and 2 is the last MPDU in an A-MPDU)
+ * and the A-MPDU reference number (must be a different value for each A-MPDU but the same for each subframe within one A-MPDU)
+ * \param signalNoise signal power and noise power in dBm
+ * \todo WifiTxVector should be passed by const reference because
+ * of its size.
+ */
+ typedef void (* MonitorSnifferRxCallback)(Ptr<const Packet> packet, uint16_t channelFreqMhz,
+ uint16_t channelNumber, uint32_t rate, WifiPreamble preamble,
+ WifiTxVector txVector, struct mpduInfo aMpdu,
+ struct signalNoiseDbm signalNoise);
+
+ /**
+ * Public method used to fire a MonitorSniffer trace for a wifi packet being transmitted.
+ * Implemented for encapsulation purposes.
+ *
+ * \param packet the packet being transmitted
+ * \param channelFreqMhz the frequency in MHz at which the packet is
+ * transmitted.
+ * \param channelNumber the channel on which the packet is transmitted
+ * \param rate the PHY data rate in units of 500kbps (i.e., the same
+ * units used both for the radiotap and for the prism header)
+ * \param preamble the preamble of the packet
+ * \param txVector the TXVECTOR that holds tx parameters
+ * \param aMpdu the type of the packet (0 is not A-MPDU, 1 is a MPDU that is part of an A-MPDU and 2 is the last MPDU in an A-MPDU)
+ * and the A-MPDU reference number (must be a different value for each A-MPDU but the same for each subframe within one A-MPDU)
+ */
+ void NotifyMonitorSniffTx (Ptr<const Packet> packet, uint16_t channelFreqMhz,
+ uint16_t channelNumber, uint32_t rate, WifiPreamble preamble,
+ WifiTxVector txVector, struct mpduInfo aMpdu);
+
+ /**
+ * TracedCallback signature for monitor mode transmit events.
+ *
+ * \param packet the packet being transmitted
+ * \param channelFreqMhz the frequency in MHz at which the packet is
+ * transmitted.
+ * \param channelNumber the channel on which the packet is transmitted
+ * \param rate the PHY data rate in units of 500kbps (i.e., the same
+ * units used both for the radiotap and for the prism header)
+ * \param preamble the preamble of the packet
+ * \param txVector the TXVECTOR that holds tx parameters
+ * \param aMpdu the type of the packet (0 is not A-MPDU, 1 is a MPDU that is part of an A-MPDU and 2 is the last MPDU in an A-MPDU)
+ * and the A-MPDU reference number (must be a different value for each A-MPDU but the same for each subframe within one A-MPDU)
+ * \todo WifiTxVector should be passed by const reference because
+ * of its size.
+ */
+ typedef void (* MonitorSnifferTxCallback)(const Ptr<const Packet> packet, uint16_t channelFreqMhz,
+ uint16_t channelNumber, uint32_t rate, WifiPreamble preamble,
+ WifiTxVector txVector, struct mpduInfo aMpdu);
+
+ /**
+ * Assign a fixed random variable stream number to the random variables
+ * used by this model. Return the number of streams (possibly zero) that
+ * have been assigned.
+ *
+ * \param stream first stream index to use
+ * \return the number of stream indices assigned by this model
+ */
+ virtual int64_t AssignStreams (int64_t stream) = 0;
+
+ /**
+ * \param freq the operating frequency on this node.
+ */
+ virtual void SetFrequency (uint32_t freq) = 0;
+ /**
+ * \return the operating frequency on this node
+ */
+ virtual uint32_t GetFrequency (void) const = 0;
+ /**
+ * \param tx the number of transmitters on this node.
+ */
+ virtual void SetNumberOfTransmitAntennas (uint32_t tx) = 0;
+ /**
+ * \return the number of transmit antenna on this device
+ */
+ virtual uint32_t GetNumberOfTransmitAntennas (void) const = 0;
+ /**
+ * \param rx the number of receivers on this node.
+ */
+ virtual void SetNumberOfReceiveAntennas (uint32_t rx) = 0;
+ /**
+ * \return the number of receivers on this node.
+ */
+ virtual uint32_t GetNumberOfReceiveAntennas (void) const = 0;
+ /**
+ * \param guardInterval Enable or disable short guard interval
+ */
+ virtual void SetGuardInterval (bool guardInterval) = 0;
+ /**
+ * \return true if short guard interval is supported, false otherwise
+ */
+ virtual bool GetGuardInterval (void) const = 0;
+ /**
+ * \param ldpc Enable or disable LDPC
+ */
+ virtual void SetLdpc (bool ldpc) = 0;
+ /**
+ * \return true if LDPC is supported, false otherwise
+ */
+ virtual bool GetLdpc (void) const = 0;
+ /**
+ * \param stbc Enable or disable STBC is supported
+ */
+ virtual void SetStbc (bool stbc) = 0;
+ /**
+ * \return true if STBC is supported, false otherwise
+ */
+ virtual bool GetStbc (void) const = 0;
+ /**
+ * \param greenfield Enable or disable GreenField
+ */
+ virtual void SetGreenfield (bool greenfield) = 0;
+ /**
+ * \return true if Greenfield is supported, false otherwise
+ */
+ virtual bool GetGreenfield (void) const = 0;
+ /**
+ * \return the channel width
+ */
+ virtual uint32_t GetChannelWidth (void) const = 0;
+ /**
+ * \param channelwidth channel width
+ */
+ virtual void SetChannelWidth (uint32_t channelwidth) = 0;
+
+
+private:
+ /**
+ * The trace source fired when a packet begins the transmission process on
+ * the medium.
+ *
+ * \see class CallBackTraceSource
+ */
+ TracedCallback<Ptr<const Packet> > m_phyTxBeginTrace;
+
+ /**
+ * The trace source fired when a packet ends the transmission process on
+ * the medium.
+ *
+ * \see class CallBackTraceSource
+ */
+ TracedCallback<Ptr<const Packet> > m_phyTxEndTrace;
+
+ /**
+ * The trace source fired when the phy layer drops a packet as it tries
+ * to transmit it.
+ *
+ * \see class CallBackTraceSource
+ */
+ TracedCallback<Ptr<const Packet> > m_phyTxDropTrace;
+
+ /**
+ * The trace source fired when a packet begins the reception process from
+ * the medium.
+ *
+ * \see class CallBackTraceSource
+ */
+ TracedCallback<Ptr<const Packet> > m_phyRxBeginTrace;
+
+ /**
+ * The trace source fired when a packet ends the reception process from
+ * the medium.
+ *
+ * \see class CallBackTraceSource
+ */
+ TracedCallback<Ptr<const Packet> > m_phyRxEndTrace;
+
+ /**
+ * The trace source fired when the phy layer drops a packet it has received.
+ *
+ * \see class CallBackTraceSource
+ */
+ TracedCallback<Ptr<const Packet> > m_phyRxDropTrace;
+
+ /**
+ * A trace source that emulates a wifi device in monitor mode
+ * sniffing a packet being received.
+ *
+ * As a reference with the real world, firing this trace
+ * corresponds in the madwifi driver to calling the function
+ * ieee80211_input_monitor()
+ *
+ * \see class CallBackTraceSource
+ * \todo WifiTxVector and signalNoiseDbm should be be passed as
+ * const references because of their sizes.
+ */
+ TracedCallback<Ptr<const Packet>, uint16_t, uint16_t, uint32_t,
+ WifiPreamble, WifiTxVector,
+ struct mpduInfo, struct signalNoiseDbm> m_phyMonitorSniffRxTrace;
+
+ /**
+ * A trace source that emulates a wifi device in monitor mode
+ * sniffing a packet being transmitted.
+ *
+ * As a reference with the real world, firing this trace
+ * corresponds in the madwifi driver to calling the function
+ * ieee80211_input_monitor()
+ *
+ * \see class CallBackTraceSource
+ * \todo WifiTxVector should be passed by const reference because
+ * of its size.
+ */
+ TracedCallback<Ptr<const Packet>, uint16_t, uint16_t, uint32_t,
+ WifiPreamble, WifiTxVector,
+ struct mpduInfo> m_phyMonitorSniffTxTrace;
+
+//*******probably need to be added***************
+ double m_totalAmpduNumSymbols; //!< Number of symbols previously transmitted for the MPDUs in an A-MPDU, used for the computation of the number of symbols needed for the last MPDU in the A-MPDU
+ uint32_t m_totalAmpduSize; //!< Total size of the previously transmitted MPDUs in an A-MPDU, used for the computation of the number of symbols needed for the last MPDU in the A-MPDU
+};
+
+/**
+ * \param os output stream
+ * \param state wifi state to stringify
+ * \return output stream
+ */
+std::ostream& operator<< (std::ostream& os, enum WifiPhy::State state);
+
+} //namespace ns3
+
+#endif /* WIFI_PHY_H */
diff --git a/emu-radio/ns3-patch/wifi/model/wifi-remote-station-manager.cc b/emu-radio/ns3-patch/wifi/model/wifi-remote-station-manager.cc
new file mode 100644
index 00000000..d1b6f016
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/wifi-remote-station-manager.cc
@@ -0,0 +1,1751 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005,2006,2007 INRIA
+ *
+ * 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: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include <iostream>
+#include "wifi-remote-station-manager.h"
+#include "ns3/simulator.h"
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/tag.h"
+#include "ns3/boolean.h"
+#include "ns3/double.h"
+#include "ns3/uinteger.h"
+#include "ns3/wifi-phy.h"
+#include "ns3/wifi-mac.h"
+#include "ns3/trace-source-accessor.h"
+#include "wifi-mac-header.h"
+#include "wifi-mac-trailer.h"
+
+/***************************************************************
+ * Packet Mode Tagger
+ ***************************************************************/
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("WifiRemoteStationManager");
+
+class HighLatencyDataTxVectorTag : public Tag
+{
+public:
+ HighLatencyDataTxVectorTag ();
+ HighLatencyDataTxVectorTag (WifiTxVector dataTxVector);
+ /**
+ * \returns the transmission mode to use to send this packet
+ */
+ WifiTxVector GetDataTxVector (void) const;
+
+ static TypeId GetTypeId (void);
+ virtual TypeId GetInstanceTypeId (void) const;
+ virtual uint32_t GetSerializedSize (void) const;
+ virtual void Serialize (TagBuffer i) const;
+ virtual void Deserialize (TagBuffer i);
+ virtual void Print (std::ostream &os) const;
+private:
+ WifiTxVector m_dataTxVector;
+};
+
+HighLatencyDataTxVectorTag::HighLatencyDataTxVectorTag ()
+{
+}
+
+HighLatencyDataTxVectorTag::HighLatencyDataTxVectorTag (WifiTxVector dataTxVector)
+ : m_dataTxVector (dataTxVector)
+{
+}
+
+WifiTxVector
+HighLatencyDataTxVectorTag::GetDataTxVector (void) const
+{
+ return m_dataTxVector;
+}
+
+TypeId
+HighLatencyDataTxVectorTag::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::HighLatencyDataTxVectorTag")
+ .SetParent<Tag> ()
+ .SetGroupName ("Wifi")
+ .AddConstructor<HighLatencyDataTxVectorTag> ()
+ ;
+ return tid;
+}
+
+TypeId
+HighLatencyDataTxVectorTag::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+
+uint32_t
+HighLatencyDataTxVectorTag::GetSerializedSize (void) const
+{
+ return sizeof (WifiTxVector);
+}
+
+void
+HighLatencyDataTxVectorTag::Serialize (TagBuffer i) const
+{
+ i.Write ((uint8_t *)&m_dataTxVector, sizeof (WifiTxVector));
+}
+
+void
+HighLatencyDataTxVectorTag::Deserialize (TagBuffer i)
+{
+ i.Read ((uint8_t *)&m_dataTxVector, sizeof (WifiTxVector));
+}
+
+void
+HighLatencyDataTxVectorTag::Print (std::ostream &os) const
+{
+ os << "Data=" << m_dataTxVector;
+}
+
+class HighLatencyRtsTxVectorTag : public Tag
+{
+public:
+ HighLatencyRtsTxVectorTag ();
+ HighLatencyRtsTxVectorTag (WifiTxVector rtsTxVector);
+ /**
+ * \returns the transmission mode to use to send the RTS prior to the
+ * transmission of the data packet itself.
+ */
+ WifiTxVector GetRtsTxVector (void) const;
+
+ static TypeId GetTypeId (void);
+ virtual TypeId GetInstanceTypeId (void) const;
+ virtual uint32_t GetSerializedSize (void) const;
+ virtual void Serialize (TagBuffer i) const;
+ virtual void Deserialize (TagBuffer i);
+ virtual void Print (std::ostream &os) const;
+private:
+ WifiTxVector m_rtsTxVector;
+};
+
+HighLatencyRtsTxVectorTag::HighLatencyRtsTxVectorTag ()
+{
+}
+
+HighLatencyRtsTxVectorTag::HighLatencyRtsTxVectorTag (WifiTxVector rtsTxVector)
+ : m_rtsTxVector (rtsTxVector)
+{
+}
+
+WifiTxVector
+HighLatencyRtsTxVectorTag::GetRtsTxVector (void) const
+{
+ return m_rtsTxVector;
+}
+
+TypeId
+HighLatencyRtsTxVectorTag::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::HighLatencyRtsTxVectorTag")
+ .SetParent<Tag> ()
+ .SetGroupName ("Wifi")
+ .AddConstructor<HighLatencyRtsTxVectorTag> ()
+ ;
+ return tid;
+}
+
+TypeId
+HighLatencyRtsTxVectorTag::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+
+uint32_t
+HighLatencyRtsTxVectorTag::GetSerializedSize (void) const
+{
+ return sizeof (WifiTxVector);
+}
+
+void
+HighLatencyRtsTxVectorTag::Serialize (TagBuffer i) const
+{
+ i.Write ((uint8_t *)&m_rtsTxVector, sizeof (WifiTxVector));
+}
+
+void
+HighLatencyRtsTxVectorTag::Deserialize (TagBuffer i)
+{
+ i.Read ((uint8_t *)&m_rtsTxVector, sizeof (WifiTxVector));
+}
+
+void
+HighLatencyRtsTxVectorTag::Print (std::ostream &os) const
+{
+ os << "Rts=" << m_rtsTxVector;
+}
+
+class HighLatencyCtsToSelfTxVectorTag : public Tag
+{
+public:
+ HighLatencyCtsToSelfTxVectorTag ();
+ HighLatencyCtsToSelfTxVectorTag (WifiTxVector ctsToSelfTxVector);
+ /**
+ * \returns the transmission mode to use for the CTS-to-self.
+ */
+ WifiTxVector GetCtsToSelfTxVector (void) const;
+
+ static TypeId GetTypeId (void);
+ virtual TypeId GetInstanceTypeId (void) const;
+ virtual uint32_t GetSerializedSize (void) const;
+ virtual void Serialize (TagBuffer i) const;
+ virtual void Deserialize (TagBuffer i);
+ virtual void Print (std::ostream &os) const;
+private:
+ WifiTxVector m_ctsToSelfTxVector;
+};
+
+HighLatencyCtsToSelfTxVectorTag::HighLatencyCtsToSelfTxVectorTag ()
+{
+}
+
+HighLatencyCtsToSelfTxVectorTag::HighLatencyCtsToSelfTxVectorTag (WifiTxVector ctsToSelfTxVector)
+ : m_ctsToSelfTxVector (ctsToSelfTxVector)
+{
+}
+
+WifiTxVector
+HighLatencyCtsToSelfTxVectorTag::GetCtsToSelfTxVector (void) const
+{
+ return m_ctsToSelfTxVector;
+}
+
+TypeId
+HighLatencyCtsToSelfTxVectorTag::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::HighLatencyCtsToSelfTxVectorTag")
+ .SetParent<Tag> ()
+ .SetGroupName ("Wifi")
+ .AddConstructor<HighLatencyCtsToSelfTxVectorTag> ()
+ ;
+ return tid;
+}
+
+TypeId
+HighLatencyCtsToSelfTxVectorTag::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+
+uint32_t
+HighLatencyCtsToSelfTxVectorTag::GetSerializedSize (void) const
+{
+ return sizeof (WifiTxVector);
+}
+
+void
+HighLatencyCtsToSelfTxVectorTag::Serialize (TagBuffer i) const
+{
+ i.Write ((uint8_t *)&m_ctsToSelfTxVector, sizeof (WifiTxVector));
+}
+
+void
+HighLatencyCtsToSelfTxVectorTag::Deserialize (TagBuffer i)
+{
+ i.Read ((uint8_t *)&m_ctsToSelfTxVector, sizeof (WifiTxVector));
+}
+
+void
+HighLatencyCtsToSelfTxVectorTag::Print (std::ostream &os) const
+{
+ os << "Cts To Self=" << m_ctsToSelfTxVector;
+}
+
+} //namespace ns3
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (WifiRemoteStationManager);
+
+TypeId
+WifiRemoteStationManager::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::WifiRemoteStationManager")
+ .SetParent<Object> ()
+ .SetGroupName ("Wifi")
+ .AddAttribute ("IsLowLatency", "If true, we attempt to modelize a so-called low-latency device: a device"
+ " where decisions about tx parameters can be made on a per-packet basis and feedback about the"
+ " transmission of each packet is obtained before sending the next. Otherwise, we modelize a "
+ " high-latency device, that is a device where we cannot update our decision about tx parameters"
+ " after every packet transmission.",
+ BooleanValue (true), //this value is ignored because there is no setter
+ MakeBooleanAccessor (&WifiRemoteStationManager::IsLowLatency),
+ MakeBooleanChecker ())
+ .AddAttribute ("MaxSsrc", "The maximum number of retransmission attempts for an RTS. This value"
+ " will not have any effect on some rate control algorithms.",
+ UintegerValue (7),
+ MakeUintegerAccessor (&WifiRemoteStationManager::m_maxSsrc),
+ MakeUintegerChecker<uint32_t> ())
+ .AddAttribute ("MaxSlrc", "The maximum number of retransmission attempts for a DATA packet. This value"
+ " will not have any effect on some rate control algorithms.",
+ UintegerValue (7),
+ MakeUintegerAccessor (&WifiRemoteStationManager::m_maxSlrc),
+ MakeUintegerChecker<uint32_t> ())
+ .AddAttribute ("RtsCtsThreshold", "If the size of the data packet + LLC header + MAC header + FCS trailer is bigger than "
+ "this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2012, Section 9.3.5. "
+ "This value will not have any effect on some rate control algorithms.",
+ UintegerValue (2346),
+ MakeUintegerAccessor (&WifiRemoteStationManager::m_rtsCtsThreshold),
+ MakeUintegerChecker<uint32_t> ())
+ .AddAttribute ("FragmentationThreshold", "If the size of the data packet + LLC header + MAC header + FCS trailer is bigger"
+ "than this value, we fragment it such that the size of the fragments are equal or smaller "
+ "than this value, as per IEEE Std. 802.11-2012, Section 9.5. "
+ "This value will not have any effect on some rate control algorithms.",
+ UintegerValue (2346),
+ MakeUintegerAccessor (&WifiRemoteStationManager::DoSetFragmentationThreshold,
+ &WifiRemoteStationManager::DoGetFragmentationThreshold),
+ MakeUintegerChecker<uint32_t> ())
+ .AddAttribute ("NonUnicastMode", "Wifi mode used for non-unicast transmissions.",
+ WifiModeValue (),
+ MakeWifiModeAccessor (&WifiRemoteStationManager::m_nonUnicastMode),
+ MakeWifiModeChecker ())
+ .AddAttribute ("DefaultTxPowerLevel", "Default power level to be used for transmissions. "
+ "This is the power level that is used by all those WifiManagers that do not"
+ "implement TX power control.",
+ UintegerValue (0),
+ MakeUintegerAccessor (&WifiRemoteStationManager::m_defaultTxPowerLevel),
+ MakeUintegerChecker<uint8_t> ())
+ .AddTraceSource ("MacTxRtsFailed",
+ "The transmission of a RTS by the MAC layer has failed",
+ MakeTraceSourceAccessor (&WifiRemoteStationManager::m_macTxRtsFailed),
+ "ns3::Mac48Address::TracedCallback")
+ .AddTraceSource ("MacTxDataFailed",
+ "The transmission of a data packet by the MAC layer has failed",
+ MakeTraceSourceAccessor (&WifiRemoteStationManager::m_macTxDataFailed),
+ "ns3::Mac48Address::TracedCallback")
+ .AddTraceSource ("MacTxFinalRtsFailed",
+ "The transmission of a RTS has exceeded the maximum number of attempts",
+ MakeTraceSourceAccessor (&WifiRemoteStationManager::m_macTxFinalRtsFailed),
+ "ns3::Mac48Address::TracedCallback")
+ .AddTraceSource ("MacTxFinalDataFailed",
+ "The transmission of a data packet has exceeded the maximum number of attempts",
+ MakeTraceSourceAccessor (&WifiRemoteStationManager::m_macTxFinalDataFailed),
+ "ns3::Mac48Address::TracedCallback")
+ ;
+ return tid;
+}
+
+WifiRemoteStationManager::WifiRemoteStationManager ()
+ : m_htSupported (false),
+ m_vhtSupported (false)
+{
+}
+
+WifiRemoteStationManager::~WifiRemoteStationManager ()
+{
+}
+
+void
+WifiRemoteStationManager::DoDispose (void)
+{
+ for (StationStates::const_iterator i = m_states.begin (); i != m_states.end (); i++)
+ {
+ delete (*i);
+ }
+ m_states.clear ();
+ for (Stations::const_iterator i = m_stations.begin (); i != m_stations.end (); i++)
+ {
+ delete (*i);
+ }
+ m_stations.clear ();
+}
+
+void
+WifiRemoteStationManager::SetupPhy (Ptr<WifiPhy> phy)
+{
+ //We need to track our PHY because it is the object that knows the
+ //full set of transmit rates that are supported. We need to know
+ //this in order to find the relevant mandatory rates when chosing a
+ //transmit rate for automatic control responses like
+ //acknowledgements.
+ m_wifiPhy = phy;
+ m_defaultTxMode = phy->GetMode (0);
+ if (HasHtSupported () || HasVhtSupported ())
+ {
+ m_defaultTxMcs = phy->GetMcs (0);
+ }
+ Reset ();
+}
+
+void
+WifiRemoteStationManager::SetupMac (Ptr<WifiMac> mac)
+{
+ //We need to track our MAC because it is the object that knows the
+ //full set of interframe spaces.
+ m_wifiMac = mac;
+ Reset ();
+}
+
+void
+WifiRemoteStationManager::SetHtSupported (bool enable)
+{
+ m_htSupported = enable;
+}
+
+void
+WifiRemoteStationManager::SetMaxSsrc (uint32_t maxSsrc)
+{
+ m_maxSsrc = maxSsrc;
+}
+
+void
+WifiRemoteStationManager::SetMaxSlrc (uint32_t maxSlrc)
+{
+ m_maxSlrc = maxSlrc;
+}
+
+void
+WifiRemoteStationManager::SetRtsCtsThreshold (uint32_t threshold)
+{
+ m_rtsCtsThreshold = threshold;
+}
+
+void
+WifiRemoteStationManager::SetFragmentationThreshold (uint32_t threshold)
+{
+ DoSetFragmentationThreshold (threshold);
+}
+
+bool
+WifiRemoteStationManager::HasHtSupported (void) const
+{
+ return m_htSupported;
+}
+
+void
+WifiRemoteStationManager::SetVhtSupported (bool enable)
+{
+ m_vhtSupported = enable;
+}
+
+bool
+WifiRemoteStationManager::HasVhtSupported (void) const
+{
+ return m_vhtSupported;
+}
+
+uint32_t
+WifiRemoteStationManager::GetMaxSsrc (void) const
+{
+ return m_maxSsrc;
+}
+
+uint32_t
+WifiRemoteStationManager::GetMaxSlrc (void) const
+{
+ return m_maxSlrc;
+}
+
+uint32_t
+WifiRemoteStationManager::GetRtsCtsThreshold (void) const
+{
+ return m_rtsCtsThreshold;
+}
+
+uint32_t
+WifiRemoteStationManager::GetFragmentationThreshold (void) const
+{
+ return DoGetFragmentationThreshold ();
+}
+
+void
+WifiRemoteStationManager::Reset (Mac48Address address)
+{
+ NS_LOG_FUNCTION (this << address);
+ NS_ASSERT (!address.IsGroup ());
+ WifiRemoteStationState *state = LookupState (address);
+ state->m_operationalRateSet.clear ();
+ state->m_operationalMcsSet.clear ();
+ AddSupportedMode (address, GetDefaultMode ());
+ AddSupportedMcs (address, GetDefaultMcs ());
+}
+
+void
+WifiRemoteStationManager::AddSupportedMode (Mac48Address address, WifiMode mode)
+{
+ NS_LOG_FUNCTION (this << address << mode);
+ NS_ASSERT (!address.IsGroup ());
+ WifiRemoteStationState *state = LookupState (address);
+ for (WifiModeListIterator i = state->m_operationalRateSet.begin (); i != state->m_operationalRateSet.end (); i++)
+ {
+ if ((*i) == mode)
+ {
+ //already in.
+ return;
+ }
+ }
+ state->m_operationalRateSet.push_back (mode);
+}
+
+void
+WifiRemoteStationManager::AddAllSupportedModes (Mac48Address address)
+{
+ NS_ASSERT (!address.IsGroup ());
+ WifiRemoteStationState *state = LookupState (address);
+ state->m_operationalRateSet.clear ();
+ for (uint32_t i = 0; i < m_wifiPhy->GetNModes (); i++)
+ {
+ state->m_operationalRateSet.push_back (m_wifiPhy->GetMode (i));
+ }
+}
+
+void
+WifiRemoteStationManager::AddSupportedMcs (Mac48Address address, WifiMode mcs)
+{
+ NS_LOG_FUNCTION (this << address << mcs);
+ NS_ASSERT (!address.IsGroup ());
+ WifiRemoteStationState *state = LookupState (address);
+ for (WifiModeListIterator i = state->m_operationalMcsSet.begin (); i != state->m_operationalMcsSet.end (); i++)
+ {
+ if ((*i) == mcs)
+ {
+ //already in.
+ return;
+ }
+ }
+ state->m_operationalMcsSet.push_back (mcs);
+}
+
+bool
+WifiRemoteStationManager::IsBrandNew (Mac48Address address) const
+{
+ if (address.IsGroup ())
+ {
+ return false;
+ }
+ return LookupState (address)->m_state == WifiRemoteStationState::BRAND_NEW;
+}
+
+std::vector<Mac48Address>
+WifiRemoteStationManager::GetRemoteAddresses() const
+{
+ std::vector<Mac48Address> remoteAddresses;
+
+
+ if( m_wifiMac->GetBssid() == m_wifiMac->GetAddress() )// as an AP
+ {
+ for (StationStates::const_iterator i = m_states.begin (); i != m_states.end (); i++)
+ {
+ if ((*i)->m_state == WifiRemoteStationState::GOT_ASSOC_TX_OK)// the station is associated
+ {
+ NS_LOG_DEBUG ("WifiRemoteStationManager::LookupState returning existing state");
+ remoteAddresses.push_back((*i)->m_address);
+ }
+ }
+ return remoteAddresses;
+
+ }
+ else
+ {
+ remoteAddresses.push_back(m_wifiMac->GetBssid());
+ return remoteAddresses;
+ }
+}
+
+bool
+WifiRemoteStationManager::IsAssociated (Mac48Address address) const
+{
+ if (address.IsGroup ())
+ {
+ return true;
+ }
+ return LookupState (address)->m_state == WifiRemoteStationState::GOT_ASSOC_TX_OK;
+}
+
+bool
+WifiRemoteStationManager::IsWaitAssocTxOk (Mac48Address address) const
+{
+ if (address.IsGroup ())
+ {
+ return false;
+ }
+ return LookupState (address)->m_state == WifiRemoteStationState::WAIT_ASSOC_TX_OK;
+}
+
+void
+WifiRemoteStationManager::RecordWaitAssocTxOk (Mac48Address address)
+{
+ NS_ASSERT (!address.IsGroup ());
+ LookupState (address)->m_state = WifiRemoteStationState::WAIT_ASSOC_TX_OK;
+ //added by zeng: to avoid bugs in association process
+ LookupState (address)->m_assocRespTxRetryCount=0;
+ //end
+}
+//added by zeng++++++++++++++
+void
+WifiRemoteStationManager::ReportGotAssocTxFailed (Mac48Address address)
+{
+ NS_ASSERT (!address.IsGroup ());
+ NS_LOG_DEBUG("association response not acked,retry="<<LookupState (address)->m_assocRespTxRetryCount);
+ LookupState (address)->m_assocRespTxRetryCount++;
+}
+
+bool
+WifiRemoteStationManager::NeedAssocRespRetransmission(Mac48Address address)
+{
+ return LookupState (address)->m_assocRespTxRetryCount < 3;
+}
+//end++++++++++++++++++
+void
+WifiRemoteStationManager::RecordGotAssocTxOk (Mac48Address address)
+{
+ NS_ASSERT (!address.IsGroup ());
+ LookupState (address)->m_state = WifiRemoteStationState::GOT_ASSOC_TX_OK;
+ //added by zeng: to avoid bugs in association process
+ LookupState (address)->m_assocRespTxRetryCount=0;
+ //end
+}
+
+void
+WifiRemoteStationManager::RecordGotAssocTxFailed (Mac48Address address)
+{
+ NS_ASSERT (!address.IsGroup ());
+ LookupState (address)->m_state = WifiRemoteStationState::DISASSOC;
+ //added by zeng: to avoid bugs in association process
+ LookupState (address)->m_assocRespTxRetryCount=0;
+ //end
+}
+
+void
+WifiRemoteStationManager::RecordDisassociated (Mac48Address address)
+{
+ NS_ASSERT (!address.IsGroup ());
+ LookupState (address)->m_state = WifiRemoteStationState::DISASSOC;
+}
+
+void
+WifiRemoteStationManager::PrepareForQueue (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet, uint32_t fullPacketSize)
+{
+ NS_LOG_FUNCTION (this << address << *header << packet << fullPacketSize);
+ if (IsLowLatency () || address.IsGroup ())
+ {
+ return;
+ }
+ WifiRemoteStation *station = Lookup (address, header);
+ WifiTxVector rts = DoGetRtsTxVector (station);
+ WifiTxVector data = DoGetDataTxVector (station, fullPacketSize);
+ WifiTxVector ctstoself = DoGetCtsToSelfTxVector ();
+ HighLatencyDataTxVectorTag datatag;
+ HighLatencyRtsTxVectorTag rtstag;
+ HighLatencyCtsToSelfTxVectorTag ctstoselftag;
+ //first, make sure that the tag is not here anymore.
+ ConstCast<Packet> (packet)->RemovePacketTag (datatag);
+ ConstCast<Packet> (packet)->RemovePacketTag (rtstag);
+ ConstCast<Packet> (packet)->RemovePacketTag (ctstoselftag);
+ datatag = HighLatencyDataTxVectorTag (data);
+ rtstag = HighLatencyRtsTxVectorTag (rts);
+ ctstoselftag = HighLatencyCtsToSelfTxVectorTag (ctstoself);
+ //and then, add it back
+ packet->AddPacketTag (datatag);
+ packet->AddPacketTag (rtstag);
+ packet->AddPacketTag (ctstoselftag);
+}
+
+WifiTxVector
+WifiRemoteStationManager::GetDataTxVector (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet, uint32_t fullPacketSize)
+{
+ NS_LOG_FUNCTION (this << address << *header << packet << fullPacketSize);
+ if (address.IsGroup ())
+ {
+ WifiTxVector v;
+ v.SetMode (GetNonUnicastMode ());
+ v.SetTxPowerLevel (m_defaultTxPowerLevel);
+ v.SetChannelWidth (m_wifiPhy->GetChannelWidth ());
+ v.SetShortGuardInterval (m_wifiPhy->GetGuardInterval ());
+ v.SetNss (1);
+ v.SetNess (0);
+ v.SetStbc (false);
+ return v;
+ }
+ if (!IsLowLatency ())
+ {
+ HighLatencyDataTxVectorTag datatag;
+ bool found;
+ found = ConstCast<Packet> (packet)->PeekPacketTag (datatag);
+ NS_ASSERT (found);
+ //cast found to void, to suppress 'found' set but not used
+ //compiler warning
+ (void) found;
+ return datatag.GetDataTxVector ();
+ }
+ return DoGetDataTxVector (Lookup (address, header), fullPacketSize);
+}
+
+WifiTxVector
+WifiRemoteStationManager::GetCtsToSelfTxVector (const WifiMacHeader *header,
+ Ptr<const Packet> packet)
+{
+ NS_LOG_FUNCTION (this << *header << packet);
+ if (!IsLowLatency ())
+ {
+ HighLatencyCtsToSelfTxVectorTag ctstoselftag;
+ bool found;
+ found = ConstCast<Packet> (packet)->PeekPacketTag (ctstoselftag);
+ NS_ASSERT (found);
+ //cast found to void, to suppress 'found' set but not used
+ //compiler warning
+ (void) found;
+ return ctstoselftag.GetCtsToSelfTxVector ();
+ }
+ return DoGetCtsToSelfTxVector ();
+}
+
+WifiTxVector
+WifiRemoteStationManager::DoGetCtsToSelfTxVector (void)
+{
+ return WifiTxVector (GetDefaultMode (),
+ GetDefaultTxPowerLevel (),
+ 0,
+ m_wifiPhy->GetChannelWidth (),
+ m_wifiPhy->GetGuardInterval (),
+ GetNumberOfTransmitAntennas (),
+ GetNumberOfTransmitAntennas (),
+ false,
+ false);
+}
+
+WifiTxVector
+WifiRemoteStationManager::GetRtsTxVector (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet)
+{
+ NS_LOG_FUNCTION (this << address << *header << packet);
+ NS_ASSERT (!address.IsGroup ());
+ if (!IsLowLatency ())
+ {
+ HighLatencyRtsTxVectorTag rtstag;
+ bool found;
+ found = ConstCast<Packet> (packet)->PeekPacketTag (rtstag);
+ NS_ASSERT (found);
+ //cast found to void, to suppress 'found' set but not used
+ //compiler warning
+ (void) found;
+ return rtstag.GetRtsTxVector ();
+ }
+ return DoGetRtsTxVector (Lookup (address, header));
+}
+
+void
+WifiRemoteStationManager::ReportRtsFailed (Mac48Address address, const WifiMacHeader *header)
+{
+ NS_LOG_FUNCTION (this << address << *header);
+ NS_ASSERT (!address.IsGroup ());
+ WifiRemoteStation *station = Lookup (address, header);
+ station->m_ssrc++;
+ m_macTxRtsFailed (address);
+ DoReportRtsFailed (station);
+}
+
+void
+WifiRemoteStationManager::ReportDataFailed (Mac48Address address, const WifiMacHeader *header)
+{
+ NS_LOG_FUNCTION (this << address << *header);
+ NS_ASSERT (!address.IsGroup ());
+ WifiRemoteStation *station = Lookup (address, header);
+ station->m_slrc++;
+ m_macTxDataFailed (address);
+ DoReportDataFailed (station);
+}
+
+void
+WifiRemoteStationManager::ReportRtsOk (Mac48Address address, const WifiMacHeader *header,
+ double ctsSnr, WifiMode ctsMode, double rtsSnr)
+{
+ NS_LOG_FUNCTION (this << address << *header << ctsSnr << ctsMode << rtsSnr);
+ NS_ASSERT (!address.IsGroup ());
+ WifiRemoteStation *station = Lookup (address, header);
+ station->m_state->m_info.NotifyTxSuccess (station->m_ssrc);
+ station->m_ssrc = 0;
+ DoReportRtsOk (station, ctsSnr, ctsMode, rtsSnr);
+}
+
+void
+WifiRemoteStationManager::ReportDataOk (Mac48Address address, const WifiMacHeader *header,
+ double ackSnr, WifiMode ackMode, double dataSnr)
+{
+ NS_LOG_FUNCTION (this << address << *header << ackSnr << ackMode << dataSnr);
+ NS_ASSERT (!address.IsGroup ());
+ WifiRemoteStation *station = Lookup (address, header);
+ station->m_state->m_info.NotifyTxSuccess (station->m_slrc);
+ station->m_slrc = 0;
+ DoReportDataOk (station, ackSnr, ackMode, dataSnr);
+}
+
+void
+WifiRemoteStationManager::ReportFinalRtsFailed (Mac48Address address, const WifiMacHeader *header)
+{
+ NS_LOG_FUNCTION (this << address << *header);
+ NS_ASSERT (!address.IsGroup ());
+ WifiRemoteStation *station = Lookup (address, header);
+ station->m_state->m_info.NotifyTxFailed ();
+ station->m_ssrc = 0;
+ m_macTxFinalRtsFailed (address);
+ DoReportFinalRtsFailed (station);
+}
+
+void
+WifiRemoteStationManager::ReportFinalDataFailed (Mac48Address address, const WifiMacHeader *header)
+{
+ NS_LOG_FUNCTION (this << address << *header);
+ NS_ASSERT (!address.IsGroup ());
+ WifiRemoteStation *station = Lookup (address, header);
+ station->m_state->m_info.NotifyTxFailed ();
+ station->m_slrc = 0;
+ m_macTxFinalDataFailed (address);
+ DoReportFinalDataFailed (station);
+}
+
+void
+WifiRemoteStationManager::ReportRxOk (Mac48Address address, const WifiMacHeader *header,
+ double rxSnr, WifiMode txMode)
+{
+ NS_LOG_FUNCTION (this << address << *header << rxSnr << txMode);
+ if (address.IsGroup ())
+ {
+ return;
+ }
+ WifiRemoteStation *station = Lookup (address, header);
+ DoReportRxOk (station, rxSnr, txMode);
+}
+
+bool
+WifiRemoteStationManager::NeedRts (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet)
+{
+ NS_LOG_FUNCTION (this << address << *header << packet);
+ if (address.IsGroup ())
+ {
+ return false;
+ }
+ bool normally = (packet->GetSize () + header->GetSize () + WIFI_MAC_FCS_LENGTH) > GetRtsCtsThreshold ();
+ return DoNeedRts (Lookup (address, header), packet, normally);
+}
+
+bool
+WifiRemoteStationManager::NeedCtsToSelf (WifiTxVector txVector)
+{
+ NS_LOG_FUNCTION (this << txVector);
+ WifiMode mode = txVector.GetMode ();
+ //search for the BSS Basic Rate set, if the used mode is in the basic set then there is no need for Cts To Self
+ for (WifiModeListIterator i = m_bssBasicRateSet.begin (); i != m_bssBasicRateSet.end (); i++)
+ {
+ if (mode == *i)
+ {
+ NS_LOG_DEBUG ("WifiRemoteStationManager::NeedCtsToSelf returning false");
+ return false;
+ }
+ }
+ if (HasHtSupported ())
+ {
+ //search for the BSS Basic MCS set, if the used mode is in the basic set then there is no need for Cts To Self
+ for (WifiModeListIterator i = m_bssBasicMcsSet.begin (); i != m_bssBasicMcsSet.end (); i++)
+ {
+ if (mode == *i)
+ {
+ NS_LOG_DEBUG ("WifiRemoteStationManager::NeedCtsToSelf returning false");
+ return false;
+ }
+ }
+ }
+ NS_LOG_DEBUG ("WifiRemoteStationManager::NeedCtsToSelf returning true");
+ return true;
+}
+
+bool
+WifiRemoteStationManager::NeedRtsRetransmission (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet)
+{
+ NS_LOG_FUNCTION (this << address << packet << *header);
+ NS_ASSERT (!address.IsGroup ());
+ WifiRemoteStation *station = Lookup (address, header);
+ bool normally = station->m_ssrc < GetMaxSsrc ();
+ NS_LOG_DEBUG ("WifiRemoteStationManager::NeedDataRetransmission count: " << station->m_ssrc << " result: " << std::boolalpha << normally);
+ return DoNeedRtsRetransmission (station, packet, normally);
+}
+
+bool
+WifiRemoteStationManager::NeedDataRetransmission (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet)
+{
+ NS_LOG_FUNCTION (this << address << packet << *header);
+ NS_ASSERT (!address.IsGroup ());
+ WifiRemoteStation *station = Lookup (address, header);
+ bool normally = station->m_slrc < GetMaxSlrc ();
+ NS_LOG_DEBUG ("WifiRemoteStationManager::NeedDataRetransmission count: " << station->m_slrc << " result: " << std::boolalpha << normally);
+ return DoNeedDataRetransmission (station, packet, normally);
+}
+
+bool
+WifiRemoteStationManager::NeedFragmentation (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet)
+{
+ NS_LOG_FUNCTION (this << address << packet << *header);
+ if (address.IsGroup ())
+ {
+ return false;
+ }
+ WifiRemoteStation *station = Lookup (address, header);
+ bool normally = (packet->GetSize () + header->GetSize () + WIFI_MAC_FCS_LENGTH) > GetFragmentationThreshold ();
+ NS_LOG_DEBUG ("WifiRemoteStationManager::NeedFragmentation result: " << std::boolalpha << normally);
+ return DoNeedFragmentation (station, packet, normally);
+}
+
+void
+WifiRemoteStationManager::DoSetFragmentationThreshold (uint32_t threshold)
+{
+ NS_LOG_FUNCTION (this << threshold);
+ if (threshold < 256)
+ {
+ /*
+ * ASN.1 encoding of the MAC and PHY MIB (256 ... 8000)
+ */
+ NS_LOG_WARN ("Fragmentation threshold should be larger than 256. Setting to 256.");
+ m_nextFragmentationThreshold = 256;
+ }
+ else
+ {
+ /*
+ * The length of each fragment shall be an even number of octets, except for the last fragment if an MSDU or
+ * MMPDU, which may be either an even or an odd number of octets.
+ */
+ if (threshold % 2 != 0)
+ {
+ NS_LOG_WARN ("Fragmentation threshold should be an even number. Setting to " << threshold - 1);
+ m_nextFragmentationThreshold = threshold - 1;
+ }
+ else
+ {
+ m_nextFragmentationThreshold = threshold;
+ }
+ }
+}
+
+void
+WifiRemoteStationManager::UpdateFragmentationThreshold (void)
+{
+ m_fragmentationThreshold = m_nextFragmentationThreshold;
+}
+
+uint32_t
+WifiRemoteStationManager::DoGetFragmentationThreshold (void) const
+{
+ return m_fragmentationThreshold;
+}
+
+uint32_t
+WifiRemoteStationManager::GetNFragments (const WifiMacHeader *header, Ptr<const Packet> packet)
+{
+ NS_LOG_FUNCTION (this << *header << packet);
+ //The number of bytes a fragment can support is (Threshold - WIFI_HEADER_SIZE - WIFI_FCS).
+ uint32_t nFragments = (packet->GetSize () / (GetFragmentationThreshold () - header->GetSize () - WIFI_MAC_FCS_LENGTH));
+
+ //If the size of the last fragment is not 0.
+ if ((packet->GetSize () % (GetFragmentationThreshold () - header->GetSize () - WIFI_MAC_FCS_LENGTH)) > 0)
+ {
+ nFragments++;
+ }
+ NS_LOG_DEBUG ("WifiRemoteStationManager::GetNFragments returning " << nFragments);
+ return nFragments;
+}
+
+uint32_t
+WifiRemoteStationManager::GetFragmentSize (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet, uint32_t fragmentNumber)
+{
+ NS_LOG_FUNCTION (this << address << *header << packet << fragmentNumber);
+ NS_ASSERT (!address.IsGroup ());
+ uint32_t nFragment = GetNFragments (header, packet);
+ if (fragmentNumber >= nFragment)
+ {
+ NS_LOG_DEBUG ("WifiRemoteStationManager::GetFragmentSize returning 0");
+ return 0;
+ }
+ //Last fragment
+ if (fragmentNumber == nFragment - 1)
+ {
+ uint32_t lastFragmentSize = packet->GetSize () - (fragmentNumber * (GetFragmentationThreshold () - header->GetSize () - WIFI_MAC_FCS_LENGTH));
+ NS_LOG_DEBUG ("WifiRemoteStationManager::GetFragmentSize returning " << lastFragmentSize);
+ return lastFragmentSize;
+ }
+ //All fragments but the last, the number of bytes is (Threshold - WIFI_HEADER_SIZE - WIFI_FCS).
+ else
+ {
+ uint32_t fragmentSize = GetFragmentationThreshold () - header->GetSize () - WIFI_MAC_FCS_LENGTH;
+ NS_LOG_DEBUG ("WifiRemoteStationManager::GetFragmentSize returning " << fragmentSize);
+ return fragmentSize;
+ }
+}
+
+uint32_t
+WifiRemoteStationManager::GetFragmentOffset (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet, uint32_t fragmentNumber)
+{
+ NS_LOG_FUNCTION (this << address << *header << packet << fragmentNumber);
+ NS_ASSERT (!address.IsGroup ());
+ NS_ASSERT (fragmentNumber < GetNFragments (header, packet));
+ uint32_t fragmentOffset = fragmentNumber * (GetFragmentationThreshold () - header->GetSize () - WIFI_MAC_FCS_LENGTH);
+ NS_LOG_DEBUG ("WifiRemoteStationManager::GetFragmentOffset returning " << fragmentOffset);
+ return fragmentOffset;
+}
+
+bool
+WifiRemoteStationManager::IsLastFragment (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet, uint32_t fragmentNumber)
+{
+ NS_LOG_FUNCTION (this << address << *header << packet << fragmentNumber);
+ NS_ASSERT (!address.IsGroup ());
+ bool isLast = fragmentNumber == (GetNFragments (header, packet) - 1);
+ NS_LOG_DEBUG ("WifiRemoteStationManager::IsLastFragment returning " << std::boolalpha << isLast);
+ return isLast;
+}
+
+WifiMode
+WifiRemoteStationManager::GetControlAnswerMode (Mac48Address address, WifiMode reqMode)
+{
+ /**
+ * The standard has relatively unambiguous rules for selecting a
+ * control response rate (the below is quoted from IEEE 802.11-2012,
+ * Section 9.7):
+ *
+ * To allow the transmitting STA to calculate the contents of the
+ * Duration/ID field, a STA responding to a received frame shall
+ * transmit its Control Response frame (either CTS or ACK), other
+ * than the BlockAck control frame, at the highest rate in the
+ * BSSBasicRateSet parameter that is less than or equal to the
+ * rate of the immediately previous frame in the frame exchange
+ * sequence (as defined in Annex G) and that is of the same
+ * modulation class (see Section 9.7.8) as the received frame...
+ */
+ NS_LOG_FUNCTION (this << address << reqMode);
+ WifiMode mode = GetDefaultMode ();
+ bool found = false;
+ //First, search the BSS Basic Rate set
+ for (WifiModeListIterator i = m_bssBasicRateSet.begin (); i != m_bssBasicRateSet.end (); i++)
+ {
+ if ((!found || i->GetPhyRate (m_wifiPhy->GetChannelWidth (), 0, 1) > mode.GetPhyRate (m_wifiPhy->GetChannelWidth (), 0, 1))
+ && (i->GetPhyRate (m_wifiPhy->GetChannelWidth (), 0, 1) <= reqMode.GetPhyRate (m_wifiPhy->GetChannelWidth (), 0, 1))
+ && (i->GetConstellationSize (1) <= reqMode.GetConstellationSize (1))
+ && ((i->GetModulationClass () == reqMode.GetModulationClass ())
+ || (reqMode.GetModulationClass () == WIFI_MOD_CLASS_HT)
+ || (reqMode.GetModulationClass () == WIFI_MOD_CLASS_VHT)))
+
+ {
+ mode = *i;
+ //We've found a potentially-suitable transmit rate, but we
+ //need to continue and consider all the basic rates before
+ //we can be sure we've got the right one.
+ found = true;
+ }
+ }
+ if (HasHtSupported () || HasVhtSupported ())
+ {
+ if (!found)
+ {
+ mode = GetDefaultMcs ();
+ for (WifiModeListIterator i = m_bssBasicMcsSet.begin (); i != m_bssBasicMcsSet.end (); i++)
+ {
+ if ((!found || i->GetPhyRate (m_wifiPhy->GetChannelWidth (), 0, 1) > mode.GetPhyRate (m_wifiPhy->GetChannelWidth (), 0, 1))
+ && i->GetPhyRate (m_wifiPhy->GetChannelWidth (), 0, 1) <= reqMode.GetPhyRate (m_wifiPhy->GetChannelWidth (), 0, 1))
+ //&& thismode.GetModulationClass () == reqMode.GetModulationClass ()) //TODO: check standard
+ {
+ mode = *i;
+ //We've found a potentially-suitable transmit rate, but we
+ //need to continue and consider all the basic rates before
+ //we can be sure we've got the right one.
+ found = true;
+ }
+ }
+ }
+ }
+ //If we found a suitable rate in the BSSBasicRateSet, then we are
+ //done and can return that mode.
+ if (found)
+ {
+ NS_LOG_DEBUG ("WifiRemoteStationManager::GetControlAnswerMode returning " << mode);
+ return mode;
+ }
+
+ /**
+ * If no suitable basic rate was found, we search the mandatory
+ * rates. The standard (IEEE 802.11-2007, Section 9.6) says:
+ *
+ * ...If no rate contained in the BSSBasicRateSet parameter meets
+ * these conditions, then the control frame sent in response to a
+ * received frame shall be transmitted at the highest mandatory
+ * rate of the PHY that is less than or equal to the rate of the
+ * received frame, and that is of the same modulation class as the
+ * received frame. In addition, the Control Response frame shall
+ * be sent using the same PHY options as the received frame,
+ * unless they conflict with the requirement to use the
+ * BSSBasicRateSet parameter.
+ *
+ * \todo Note that we're ignoring the last sentence for now, because
+ * there is not yet any manipulation here of PHY options.
+ */
+ for (uint32_t idx = 0; idx < m_wifiPhy->GetNModes (); idx++)
+ {
+ WifiMode thismode = m_wifiPhy->GetMode (idx);
+
+ /* If the rate:
+ *
+ * - is a mandatory rate for the PHY, and
+ * - is equal to or faster than our current best choice, and
+ * - is less than or equal to the rate of the received frame, and
+ * - is of the same modulation class as the received frame
+ *
+ * ...then it's our best choice so far.
+ */
+ if (thismode.IsMandatory ()
+ && (!found || thismode.GetPhyRate (m_wifiPhy->GetChannelWidth (), 0, 1) > mode.GetPhyRate (m_wifiPhy->GetChannelWidth (), 0, 1))
+ && (thismode.GetPhyRate (m_wifiPhy->GetChannelWidth (), 0, 1) <= reqMode.GetPhyRate (m_wifiPhy->GetChannelWidth (), 0, 1))
+ && (thismode.GetConstellationSize (1) <= reqMode.GetConstellationSize (1))
+ && ((thismode.GetModulationClass () == reqMode.GetModulationClass ())
+ || (reqMode.GetModulationClass () == WIFI_MOD_CLASS_HT)
+ || (reqMode.GetModulationClass () == WIFI_MOD_CLASS_HT)))
+
+ {
+ mode = thismode;
+ //As above; we've found a potentially-suitable transmit
+ //rate, but we need to continue and consider all the
+ //mandatory rates before we can be sure we've got the right one.
+ found = true;
+ }
+ }
+ if (HasHtSupported () || HasVhtSupported ())
+ {
+ for (uint32_t idx = 0; idx < m_wifiPhy->GetNMcs (); idx++)
+ {
+ WifiMode thismode = m_wifiPhy->GetMcs (idx);
+ if (thismode.IsMandatory ()
+ && (!found || thismode.GetPhyRate (m_wifiPhy->GetChannelWidth (), 0, 1) > mode.GetPhyRate (m_wifiPhy->GetChannelWidth (), 0, 1))
+ && thismode.GetPhyRate (m_wifiPhy->GetChannelWidth (), 0, 1) <= reqMode.GetPhyRate (m_wifiPhy->GetChannelWidth (), 0, 1))
+ //&& thismode.GetModulationClass () == reqMode.GetModulationClass ()) //TODO: check standard
+ {
+ mode = thismode;
+ //As above; we've found a potentially-suitable transmit
+ //rate, but we need to continue and consider all the
+ //mandatory rates before we can be sure we've got the right one.
+ found = true;
+ }
+
+ }
+ }
+
+ /**
+ * If we still haven't found a suitable rate for the response then
+ * someone has messed up the simulation config. This probably means
+ * that the WifiPhyStandard is not set correctly, or that a rate that
+ * is not supported by the PHY has been explicitly requested in a
+ * WifiRemoteStationManager (or descendant) configuration.
+ *
+ * Either way, it is serious - we can either disobey the standard or
+ * fail, and I have chosen to do the latter...
+ */
+ if (!found)
+ {
+ NS_FATAL_ERROR ("Can't find response rate for " << reqMode);
+ }
+
+ NS_LOG_DEBUG ("WifiRemoteStationManager::GetControlAnswerMode returning " << mode);
+ return mode;
+}
+
+WifiTxVector
+WifiRemoteStationManager::GetCtsTxVector (Mac48Address address, WifiMode rtsMode)
+{
+ NS_ASSERT (!address.IsGroup ());
+ WifiTxVector v;
+ v.SetMode (GetControlAnswerMode (address, rtsMode));
+ v.SetTxPowerLevel (DoGetCtsTxPowerLevel (address, v.GetMode ()));
+ v.SetChannelWidth (DoGetCtsTxChannelWidth (address, v.GetMode ()));
+ v.SetShortGuardInterval (DoGetCtsTxGuardInterval (address, v.GetMode ()));
+ v.SetNss (DoGetCtsTxNss (address, v.GetMode ()));
+ v.SetNess (DoGetCtsTxNess (address, v.GetMode ()));
+ v.SetStbc (DoGetCtsTxStbc (address, v.GetMode ()));
+ return v;
+}
+
+WifiTxVector
+WifiRemoteStationManager::GetAckTxVector (Mac48Address address, WifiMode dataMode)
+{
+ NS_ASSERT (!address.IsGroup ());
+ WifiTxVector v;
+ v.SetMode (GetControlAnswerMode (address, dataMode));
+ v.SetTxPowerLevel (DoGetAckTxPowerLevel (address, v.GetMode ()));
+ v.SetChannelWidth (DoGetAckTxChannelWidth (address, v.GetMode ()));
+ v.SetShortGuardInterval (DoGetAckTxGuardInterval (address, v.GetMode ()));
+ v.SetNss (DoGetAckTxNss (address, v.GetMode ()));
+ v.SetNess (DoGetAckTxNess (address, v.GetMode ()));
+ v.SetStbc (DoGetAckTxStbc (address, v.GetMode ()));
+ return v;
+}
+
+WifiTxVector
+WifiRemoteStationManager::GetBlockAckTxVector (Mac48Address address, WifiMode blockAckReqMode)
+{
+ NS_ASSERT (!address.IsGroup ());
+ WifiTxVector v;
+ v.SetMode (GetControlAnswerMode (address, blockAckReqMode));
+ v.SetTxPowerLevel (DoGetBlockAckTxPowerLevel (address, v.GetMode ()));
+ v.SetChannelWidth (DoGetBlockAckTxChannelWidth (address, v.GetMode ()));
+ v.SetShortGuardInterval (DoGetBlockAckTxGuardInterval (address, v.GetMode ()));
+ v.SetNss (DoGetBlockAckTxNss (address, v.GetMode ()));
+ v.SetNess (DoGetBlockAckTxNess (address, v.GetMode ()));
+ v.SetStbc (DoGetBlockAckTxStbc (address, v.GetMode ()));
+ return v;
+}
+
+uint8_t
+WifiRemoteStationManager::DoGetCtsTxPowerLevel (Mac48Address address, WifiMode ctsMode)
+{
+ return m_defaultTxPowerLevel;
+}
+
+uint32_t
+WifiRemoteStationManager::DoGetCtsTxChannelWidth (Mac48Address address, WifiMode ctsMode)
+{
+ return m_wifiPhy->GetChannelWidth ();
+}
+
+bool
+WifiRemoteStationManager::DoGetCtsTxGuardInterval (Mac48Address address, WifiMode ctsMode)
+{
+ return m_wifiPhy->GetGuardInterval ();
+}
+
+uint8_t
+WifiRemoteStationManager::DoGetCtsTxNss (Mac48Address address, WifiMode ctsMode)
+{
+ return 1;
+}
+
+uint8_t
+WifiRemoteStationManager::DoGetCtsTxNess (Mac48Address address, WifiMode ctsMode)
+{
+ return 0;
+}
+
+bool
+WifiRemoteStationManager::DoGetCtsTxStbc (Mac48Address address, WifiMode ctsMode)
+{
+ return m_wifiPhy->GetStbc ();
+}
+
+uint8_t
+WifiRemoteStationManager::DoGetAckTxPowerLevel (Mac48Address address, WifiMode ackMode)
+{
+ return m_defaultTxPowerLevel;
+}
+
+uint32_t
+WifiRemoteStationManager::DoGetAckTxChannelWidth (Mac48Address address, WifiMode ctsMode)
+{
+ return m_wifiPhy->GetChannelWidth ();
+}
+
+bool
+WifiRemoteStationManager::DoGetAckTxGuardInterval (Mac48Address address, WifiMode ackMode)
+{
+ return m_wifiPhy->GetGuardInterval ();
+}
+
+uint8_t
+WifiRemoteStationManager::DoGetAckTxNss (Mac48Address address, WifiMode ackMode)
+{
+ return 1;
+}
+
+uint8_t
+WifiRemoteStationManager::DoGetAckTxNess (Mac48Address address, WifiMode ackMode)
+{
+ return 0;
+}
+
+bool
+WifiRemoteStationManager::DoGetAckTxStbc (Mac48Address address, WifiMode ackMode)
+{
+ return m_wifiPhy->GetStbc ();
+}
+
+uint8_t
+WifiRemoteStationManager::DoGetBlockAckTxPowerLevel (Mac48Address address, WifiMode blockAckMode)
+{
+ return m_defaultTxPowerLevel;
+}
+
+uint32_t
+WifiRemoteStationManager::DoGetBlockAckTxChannelWidth (Mac48Address address, WifiMode ctsMode)
+{
+ return m_wifiPhy->GetChannelWidth ();
+}
+
+bool
+WifiRemoteStationManager::DoGetBlockAckTxGuardInterval (Mac48Address address, WifiMode blockAckMode)
+{
+ return m_wifiPhy->GetGuardInterval ();
+}
+
+uint8_t
+WifiRemoteStationManager::DoGetBlockAckTxNss (Mac48Address address, WifiMode blockAckMode)
+{
+ return 1;
+}
+
+uint8_t
+WifiRemoteStationManager::DoGetBlockAckTxNess (Mac48Address address, WifiMode blockAckMode)
+{
+ return 0;
+}
+
+bool
+WifiRemoteStationManager::DoGetBlockAckTxStbc (Mac48Address address, WifiMode blockAckMode)
+{
+ return m_wifiPhy->GetStbc ();
+}
+
+uint8_t
+WifiRemoteStationManager::GetDefaultTxPowerLevel (void) const
+{
+ return m_defaultTxPowerLevel;
+}
+
+WifiRemoteStationInfo
+WifiRemoteStationManager::GetInfo (Mac48Address address)
+{
+ WifiRemoteStationState *state = LookupState (address);
+ return state->m_info;
+}
+
+WifiRemoteStationState *
+WifiRemoteStationManager::LookupState (Mac48Address address) const
+{
+ NS_LOG_FUNCTION (this << address);
+ for (StationStates::const_iterator i = m_states.begin (); i != m_states.end (); i++)
+ {
+ if ((*i)->m_address == address)
+ {
+ NS_LOG_DEBUG ("WifiRemoteStationManager::LookupState returning existing state");
+ return (*i);
+ }
+ }
+ WifiRemoteStationState *state = new WifiRemoteStationState ();
+ state->m_state = WifiRemoteStationState::BRAND_NEW;
+ state->m_address = address;
+ state->m_operationalRateSet.push_back (GetDefaultMode ());
+ state->m_operationalMcsSet.push_back (GetDefaultMcs ());
+ state->m_channelWidth = m_wifiPhy->GetChannelWidth ();
+ state->m_shortGuardInterval = m_wifiPhy->GetGuardInterval ();
+ state->m_greenfield = m_wifiPhy->GetGreenfield ();
+ state->m_rx = 1;
+ state->m_tx = 1;
+ state->m_ness = 0;
+ state->m_aggregation = false;
+ state->m_stbc = false;
+ //added by zeng:
+ state->m_assocRespTxRetryCount=0;
+ //end
+ const_cast<WifiRemoteStationManager *> (this)->m_states.push_back (state);
+ NS_LOG_DEBUG ("WifiRemoteStationManager::LookupState returning new state");
+ return state;
+}
+
+WifiRemoteStation *
+WifiRemoteStationManager::Lookup (Mac48Address address, const WifiMacHeader *header) const
+{
+ uint8_t tid;
+ if (header->IsQosData ())
+ {
+ tid = header->GetQosTid ();
+ }
+ else
+ {
+ tid = 0;
+ }
+ return Lookup (address, tid);
+}
+
+WifiRemoteStation *
+WifiRemoteStationManager::Lookup (Mac48Address address, uint8_t tid) const
+{
+ NS_LOG_FUNCTION (this << address << (uint16_t)tid);
+ for (Stations::const_iterator i = m_stations.begin (); i != m_stations.end (); i++)
+ {
+ if ((*i)->m_tid == tid
+ && (*i)->m_state->m_address == address)
+ {
+ return (*i);
+ }
+ }
+ WifiRemoteStationState *state = LookupState (address);
+
+ WifiRemoteStation *station = DoCreateStation ();
+ station->m_state = state;
+ station->m_tid = tid;
+ station->m_ssrc = 0;
+ station->m_slrc = 0;
+ const_cast<WifiRemoteStationManager *> (this)->m_stations.push_back (station);
+ return station;
+}
+
+void
+WifiRemoteStationManager::AddStationHtCapabilities (Mac48Address from, HtCapabilities htCapabilities)
+{
+ //Used by all stations to record HT capabilities of remote stations
+ NS_LOG_FUNCTION (this << from << htCapabilities);
+ WifiRemoteStationState *state;
+ state = LookupState (from);
+ state->m_shortGuardInterval = htCapabilities.GetShortGuardInterval20 ();
+ if (htCapabilities.GetSupportedChannelWidth () == 1)
+ {
+ state->m_channelWidth = 40;
+ }
+ else
+ {
+ state->m_channelWidth = 20;
+ }
+ state->m_greenfield = htCapabilities.GetGreenfield ();
+}
+
+void
+WifiRemoteStationManager::AddStationVhtCapabilities (Mac48Address from, VhtCapabilities vhtCapabilities)
+{
+ //Used by all stations to record VHT capabilities of remote stations
+ NS_LOG_FUNCTION (this << from << vhtCapabilities);
+ WifiRemoteStationState *state;
+ state = LookupState (from);
+ if (vhtCapabilities.GetSupportedChannelWidthSet () == 1)
+ {
+ state->m_channelWidth = 160;
+ }
+ else
+ {
+ state->m_channelWidth = 80;
+ }
+ //This is a workaround to enable users to force a 20 or 40 MHz channel for a VHT-compliant device,
+ //since IEEE 802.11ac standard says that 20, 40 and 80 MHz channels are mandatory.
+ if (m_wifiPhy->GetChannelWidth () < state->m_channelWidth)
+ {
+ state->m_channelWidth = m_wifiPhy->GetChannelWidth ();
+ }
+}
+
+bool
+WifiRemoteStationManager::GetGreenfieldSupported (Mac48Address address) const
+{
+ return LookupState (address)->m_greenfield;
+}
+
+WifiMode
+WifiRemoteStationManager::GetDefaultMode (void) const
+{
+ return m_defaultTxMode;
+}
+
+WifiMode
+WifiRemoteStationManager::GetDefaultMcs (void) const
+{
+ return m_defaultTxMcs;
+}
+
+void
+WifiRemoteStationManager::Reset (void)
+{
+ NS_LOG_FUNCTION (this);
+ for (Stations::const_iterator i = m_stations.begin (); i != m_stations.end (); i++)
+ {
+ delete (*i);
+ }
+ m_stations.clear ();
+ m_bssBasicRateSet.clear ();
+ m_bssBasicRateSet.push_back (m_defaultTxMode);
+ m_bssBasicMcsSet.clear ();
+ m_bssBasicMcsSet.push_back (m_defaultTxMcs);
+ NS_ASSERT (m_defaultTxMode.IsMandatory ());
+}
+
+void
+WifiRemoteStationManager::RemoveStation (Mac48Address sta)
+{
+ NS_LOG_FUNCTION (sta);
+ for (Stations::iterator i = m_stations.begin (); i != m_stations.end (); i++)
+ {
+ if((*i)->m_state->m_address == sta )
+ {
+ delete (*i);
+ m_stations.erase(i);
+ break;
+ }
+ }
+}
+
+void
+WifiRemoteStationManager::AddBasicMode (WifiMode mode)
+{
+ NS_LOG_FUNCTION (this << mode);
+ if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT || mode.GetModulationClass () == WIFI_MOD_CLASS_VHT)
+ {
+ NS_FATAL_ERROR ("It is not allowed to add a (V)HT rate in the BSSBasicRateSet!");
+ }
+ for (uint32_t i = 0; i < GetNBasicModes (); i++)
+ {
+ if (GetBasicMode (i) == mode)
+ {
+ return;
+ }
+ }
+ m_bssBasicRateSet.push_back (mode);
+}
+
+uint32_t
+WifiRemoteStationManager::GetNBasicModes (void) const
+{
+ return m_bssBasicRateSet.size ();
+}
+
+WifiMode
+WifiRemoteStationManager::GetBasicMode (uint32_t i) const
+{
+ NS_ASSERT (i < m_bssBasicRateSet.size ());
+ return m_bssBasicRateSet[i];
+}
+
+void
+WifiRemoteStationManager::AddBasicMcs (WifiMode mcs)
+{
+ NS_LOG_FUNCTION (this << (uint32_t)mcs.GetMcsValue ());
+ for (uint32_t i = 0; i < GetNBasicMcs (); i++)
+ {
+ if (GetBasicMcs (i) == mcs)
+ {
+ return;
+ }
+ }
+ m_bssBasicMcsSet.push_back (mcs);
+}
+
+uint32_t
+WifiRemoteStationManager::GetNBasicMcs (void) const
+{
+ return m_bssBasicMcsSet.size ();
+}
+
+WifiMode
+WifiRemoteStationManager::GetBasicMcs (uint32_t i) const
+{
+ NS_ASSERT (i < m_bssBasicMcsSet.size ());
+ return m_bssBasicMcsSet[i];
+}
+
+WifiMode
+WifiRemoteStationManager::GetNonUnicastMode (void) const
+{
+ if (m_nonUnicastMode == WifiMode ())
+ {
+ return GetBasicMode (0);
+ }
+ else
+ {
+ return m_nonUnicastMode;
+ }
+}
+
+bool
+WifiRemoteStationManager::DoNeedRts (WifiRemoteStation *station,
+ Ptr<const Packet> packet, bool normally)
+{
+ return normally;
+}
+
+bool
+WifiRemoteStationManager::DoNeedRtsRetransmission (WifiRemoteStation *station,
+ Ptr<const Packet> packet, bool normally)
+{
+ return normally;
+}
+
+bool
+WifiRemoteStationManager::DoNeedDataRetransmission (WifiRemoteStation *station,
+ Ptr<const Packet> packet, bool normally)
+{
+ return normally;
+}
+
+bool
+WifiRemoteStationManager::DoNeedFragmentation (WifiRemoteStation *station,
+ Ptr<const Packet> packet, bool normally)
+{
+ return normally;
+}
+
+WifiMode
+WifiRemoteStationManager::GetSupported (const WifiRemoteStation *station, uint32_t i) const
+{
+ NS_ASSERT (i < GetNSupported (station));
+ return station->m_state->m_operationalRateSet[i];
+}
+
+WifiMode
+WifiRemoteStationManager::GetMcsSupported (const WifiRemoteStation *station, uint32_t i) const
+{
+ NS_ASSERT (i < GetNMcsSupported (station));
+ return station->m_state->m_operationalMcsSet[i];
+}
+
+uint32_t
+WifiRemoteStationManager::GetChannelWidth (const WifiRemoteStation *station) const
+{
+ return station->m_state->m_channelWidth;
+}
+
+bool
+WifiRemoteStationManager::GetShortGuardInterval (const WifiRemoteStation *station) const
+{
+ return station->m_state->m_shortGuardInterval;
+}
+
+bool
+WifiRemoteStationManager::GetGreenfield (const WifiRemoteStation *station) const
+{
+ return station->m_state->m_greenfield;
+}
+
+bool
+WifiRemoteStationManager::GetAggregation (const WifiRemoteStation *station) const
+{
+ return station->m_state->m_aggregation;
+}
+
+bool
+WifiRemoteStationManager::GetStbc (const WifiRemoteStation *station) const
+{
+ return station->m_state->m_stbc;
+}
+
+uint32_t
+WifiRemoteStationManager::GetNumberOfReceiveAntennas (const WifiRemoteStation *station) const
+{
+ return station->m_state->m_rx;
+}
+
+uint32_t
+WifiRemoteStationManager::GetNumberOfTransmitAntennas (const WifiRemoteStation *station) const
+{
+ return station->m_state->m_tx;
+}
+
+uint32_t
+WifiRemoteStationManager::GetNess (const WifiRemoteStation *station) const
+{
+ return station->m_state->m_ness;
+}
+
+uint32_t
+WifiRemoteStationManager::GetShortRetryCount (const WifiRemoteStation *station) const
+{
+ return station->m_ssrc;
+}
+
+Ptr<WifiPhy>
+WifiRemoteStationManager::GetPhy (void) const
+{
+ return m_wifiPhy;
+}
+
+Ptr<WifiMac>
+WifiRemoteStationManager::GetMac (void) const
+{
+ return m_wifiMac;
+}
+
+uint32_t
+WifiRemoteStationManager::GetLongRetryCount (const WifiRemoteStation *station) const
+{
+ return station->m_slrc;
+}
+
+uint32_t
+WifiRemoteStationManager::GetNSupported (const WifiRemoteStation *station) const
+{
+ return station->m_state->m_operationalRateSet.size ();
+}
+
+uint32_t
+WifiRemoteStationManager::GetNMcsSupported (const WifiRemoteStation *station) const
+{
+ return station->m_state->m_operationalMcsSet.size ();
+}
+
+void
+WifiRemoteStationManager::SetDefaultTxPowerLevel (uint8_t txPower)
+{
+ m_defaultTxPowerLevel = txPower;
+}
+
+uint32_t
+WifiRemoteStationManager::GetNumberOfTransmitAntennas (void)
+{
+ return m_wifiPhy->GetNumberOfTransmitAntennas ();
+}
+
+WifiRemoteStationInfo::WifiRemoteStationInfo ()
+ : m_memoryTime (Seconds (1.0)),
+ m_lastUpdate (Seconds (0.0)),
+ m_failAvg (0.0)
+{
+}
+
+double
+WifiRemoteStationInfo::CalculateAveragingCoefficient ()
+{
+ double retval = std::exp ((double)(m_lastUpdate.GetMicroSeconds () - Simulator::Now ().GetMicroSeconds ())
+ / (double)m_memoryTime.GetMicroSeconds ());
+ m_lastUpdate = Simulator::Now ();
+ return retval;
+}
+
+void
+WifiRemoteStationInfo::NotifyTxSuccess (uint32_t retryCounter)
+{
+ double coefficient = CalculateAveragingCoefficient ();
+ m_failAvg = (double)retryCounter / (1 + (double)retryCounter) * (1.0 - coefficient) + coefficient * m_failAvg;
+}
+
+void
+WifiRemoteStationInfo::NotifyTxFailed ()
+{
+ double coefficient = CalculateAveragingCoefficient ();
+ m_failAvg = (1.0 - coefficient) + coefficient * m_failAvg;
+}
+
+double
+WifiRemoteStationInfo::GetFrameErrorRate () const
+{
+ return m_failAvg;
+}
+
+WifiRemoteStation::~WifiRemoteStation ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+} //namespace ns3
diff --git a/emu-radio/ns3-patch/wifi/model/wifi-remote-station-manager.h b/emu-radio/ns3-patch/wifi/model/wifi-remote-station-manager.h
new file mode 100644
index 00000000..7889f093
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/wifi-remote-station-manager.h
@@ -0,0 +1,1177 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005,2006,2007 INRIA
+ *
+ * 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: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#ifndef WIFI_REMOTE_STATION_MANAGER_H
+#define WIFI_REMOTE_STATION_MANAGER_H
+
+#include <vector>
+#include <utility>
+#include "ns3/mac48-address.h"
+#include "ns3/traced-callback.h"
+#include "ns3/packet.h"
+#include "ns3/object.h"
+#include "ns3/nstime.h"
+#include "wifi-mode.h"
+#include "wifi-tx-vector.h"
+#include "ht-capabilities.h"
+#include "vht-capabilities.h"
+
+namespace ns3 {
+
+struct WifiRemoteStation;
+struct WifiRemoteStationState;
+class WifiPhy;
+class WifiMac;
+class WifiMacHeader;
+
+/**
+ * \brief Tid independent remote station statistics
+ *
+ * Structure is similar to struct sta_info in Linux kernel (see
+ * net/mac80211/sta_info.h)
+ */
+class WifiRemoteStationInfo
+{
+public:
+ WifiRemoteStationInfo ();
+ /**
+ * \brief Updates average frame error rate when data or RTS was transmitted successfully.
+ *
+ * \param retryCounter is slrc or ssrc value at the moment of success transmission.
+ */
+ void NotifyTxSuccess (uint32_t retryCounter);
+ /// Updates average frame error rate when final data or RTS has failed.
+ void NotifyTxFailed ();
+ /// Return frame error rate (probability that frame is corrupted due to transmission error).
+ double GetFrameErrorRate () const;
+private:
+ /**
+ * \brief Calculate averaging coefficient for frame error rate. Depends on time of the last update.
+ *
+ * \attention Calling this method twice gives different results,
+ * because it resets time of last update.
+ *
+ * \return average coefficient for frame error rate
+ */
+ double CalculateAveragingCoefficient ();
+ /// averaging coefficient depends on the memory time
+ Time m_memoryTime;
+ /// when last update has occured
+ Time m_lastUpdate;
+ /// moving percentage of failed frames
+ double m_failAvg;
+};
+
+/**
+ * \ingroup wifi
+ * \brief hold a list of per-remote-station state.
+ *
+ * \sa ns3::WifiRemoteStation.
+ */
+class WifiRemoteStationManager : public Object
+{
+public:
+ static TypeId GetTypeId (void);
+
+ WifiRemoteStationManager ();
+ virtual ~WifiRemoteStationManager ();
+
+ /**
+ * \return the address of AP (as station) or the addresses of stations (as AP)
+ */
+ std::vector<Mac48Address>
+ GetRemoteAddresses() const;
+
+ /**
+ * Set up PHY associated with this device since it is the object that
+ * knows the full set of transmit rates that are supported.
+ *
+ * \param phy the PHY of this device
+ */
+ virtual void SetupPhy (Ptr<WifiPhy> phy);
+ /**
+ * Set up MAC associated with this device since it is the object that
+ * knows the full set of timing parameters (e.g. IFS).
+ *
+ * \param phy the PHY of this device
+ */
+ virtual void SetupMac (Ptr<WifiMac> mac);
+
+ /**
+ * Return the maximum STA short retry count (SSRC).
+ *
+ * \return the maximum SSRC
+ */
+ uint32_t GetMaxSsrc (void) const;
+ /**
+ * Return the maximum STA long retry count (SLRC).
+ *
+ * \return the maximum SLRC
+ */
+ uint32_t GetMaxSlrc (void) const;
+ /**
+ * Return the RTS threshold.
+ *
+ * \return the RTS threshold
+ */
+ uint32_t GetRtsCtsThreshold (void) const;
+ /**
+ * Return the fragmentation threshold.
+ *
+ * \return the fragmentation threshold
+ */
+ uint32_t GetFragmentationThreshold (void) const;
+ /**
+ * Sets the maximum STA short retry count (SSRC).
+ *
+ * \param maxSsrc the maximum SSRC
+ */
+ void SetMaxSsrc (uint32_t maxSsrc);
+ /**
+ * Sets the maximum STA long retry count (SLRC).
+ *
+ * \param maxSlrc the maximum SLRC
+ */
+ void SetMaxSlrc (uint32_t maxSlrc);
+ /**
+ * Sets the RTS threshold.
+ *
+ * \param threshold the RTS threshold
+ */
+ void SetRtsCtsThreshold (uint32_t threshold);
+ /**
+ * Sets a fragmentation threshold. The method calls a private method
+ * DoSetFragmentationThreshold that checks the validity of the value given.
+ *
+ * \param threshold the fragmentation threshold
+ */
+ void SetFragmentationThreshold (uint32_t threshold);
+ /**
+ * Typically called to update the fragmentation threshold at the start of a new transmission.
+ * This avoid that the fragmentation threshold gets changed during a transmission (see bug 730).
+ */
+ void UpdateFragmentationThreshold (void);
+ /**
+ * Records HT capabilities of the remote station.
+ *
+ * \param from the address of the station being recorded
+ * \param htcapabilities the HT capabilities of the station
+ */
+ void AddStationHtCapabilities (Mac48Address from, HtCapabilities htcapabilities);
+ /**
+ * Records VHT capabilities of the remote station.
+ *
+ * \param from the address of the station being recorded
+ * \param vhtcapabilities the VHT capabilities of the station
+ */
+ void AddStationVhtCapabilities (Mac48Address from,VhtCapabilities vhtcapabilities);
+ /**
+ * Enable or disable HT capability support.
+ *
+ * \param enable enable or disable HT capability support
+ */
+ void SetHtSupported (bool enable);
+ /**
+ * Return whether the device has HT capability support enabled.
+ *
+ * \return true if HT capability support is enabled, false otherwise
+ */
+ bool HasHtSupported (void) const;
+ /**
+ * Enable or disable VHT capability support.
+ *
+ * \param enable enable or disable VHT capability support
+ */
+ void SetVhtSupported (bool enable);
+ /**
+ * Return whether the device has VHT capability support enabled.
+ *
+ * \return true if VHT capability support is enabled, false otherwise
+ */
+ bool HasVhtSupported (void) const;
+
+ /**
+ * Reset the station, invoked in a STA upon dis-association or in an AP upon reboot.
+ */
+ void Reset (void);
+
+ /**
+ * remove states related to a station, which are used to perform the selection of tx parameters
+ * on a per-packet basis.
+ */
+ void RemoveStation(Mac48Address sta);
+
+ /**
+ * Invoked in a STA upon association to store the set of rates which belong to the
+ * BSSBasicRateSet of the associated AP and which are supported locally.
+ * Invoked in an AP to configure the BSSBasicRateSet.
+ *
+ * \param mode the WifiMode to be added to the basic mode set
+ */
+ void AddBasicMode (WifiMode mode);
+ /**
+ * Return the default transmission mode.
+ *
+ * \return WifiMode the default transmission mode
+ */
+ WifiMode GetDefaultMode (void) const;
+ /**
+ * Return the number of basic modes we support.
+ *
+ * \return the number of basic modes we support
+ */
+ uint32_t GetNBasicModes (void) const;
+ /**
+ * Return a basic mode from the set of basic modes.
+ *
+ * \param i index of the basic mode in the basic mode set
+ *
+ * \return the basic mode at the given index
+ */
+ WifiMode GetBasicMode (uint32_t i) const;
+ /**
+ * Return whether the station supports Greenfield or not.
+ *
+ * \param address the address of the station
+ *
+ * \return true if Greenfield is supported by the station,
+ * false otherwise
+ */
+ bool GetGreenfieldSupported (Mac48Address address) const;
+ /**
+ * Add a given Modulation and Coding Scheme (MCS) index to
+ * the set of basic MCS.
+ *
+ * \param mcs the WifiMode to be added to the basic MCS set
+ */
+ void AddBasicMcs (WifiMode mcs);
+ /**
+ * Return the default Modulation and Coding Scheme (MCS) index.
+ *
+ * \return the default WifiMode
+ */
+ WifiMode GetDefaultMcs (void) const;
+ /**
+ * Return the number of basic MCS index.
+ *
+ * \return the number of basic MCS index
+ */
+ uint32_t GetNBasicMcs (void) const;
+ /**
+ * Return the MCS at the given <i>list</i> index.
+ *
+ * \param i the position in the list
+ *
+ * \return the basic mcs at the given list index
+ */
+ WifiMode GetBasicMcs (uint32_t i) const;
+ /**
+ * Record the MCS index supported by the station.
+ *
+ * \param address the address of the station
+ * \param mcs the WifiMode supported by the station
+ */
+ void AddSupportedMcs (Mac48Address address, WifiMode mcs);
+
+ /**
+ * Return a mode for non-unicast packets.
+ *
+ * \return WifiMode for non-unicast packets
+ */
+ WifiMode GetNonUnicastMode (void) const;
+
+ /**
+ * Invoked in an AP upon disassociation of a
+ * specific STA.
+ *
+ * \param address the address of the STA
+ */
+ void Reset (Mac48Address address);
+
+ /**
+ * Invoked in a STA or AP to store the set of
+ * modes supported by a destination which is
+ * also supported locally.
+ * The set of supported modes includes
+ * the BSSBasicRateSet.
+ *
+ * \param address the address of the station being recorded
+ * \param mode the WifiMode supports by the station
+ */
+ void AddSupportedMode (Mac48Address address, WifiMode mode);
+ /**
+ * Invoked in a STA or AP to store all of the modes supported
+ * by a destination which is also supported locally.
+ * The set of supported modes includes the BSSBasicRateSet.
+ *
+ * \param address the address of the station being recorded
+ */
+ void AddAllSupportedModes (Mac48Address address);
+
+ /**
+ * Return whether the station state is brand new.
+ *
+ * \param address the address of the station
+ *
+ * \return true if the state of the station is brand new,
+ * false otherwise
+ */
+ bool IsBrandNew (Mac48Address address) const;
+ /**
+ * Return whether the station associated.
+ *
+ * \param address the address of the station
+ *
+ * \return true if the station is associated,
+ * false otherwise
+ */
+ bool IsAssociated (Mac48Address address) const;
+ /**
+ * Return whether we are waiting for an ACK for
+ * the association response we sent.
+ *
+ * \param address the address of the station
+ *
+ * \return true if the station is associated,
+ * false otherwise
+ */
+ bool IsWaitAssocTxOk (Mac48Address address) const;
+ /**
+ * Records that we are waiting for an ACK for
+ * the association response we sent.
+ *
+ * \param address the address of the station
+ */
+ void RecordWaitAssocTxOk (Mac48Address address);
+
+//added by zeng+++++++++++++++++++++++++
+ /**
+ * : to avoid bugs in association process
+ * report to wifi remote station manager that
+ * an association response message tx failed(not acked)
+ * ensentailly it increments the retry counter for
+ * this association response
+ * the real retransmission time of this assoc response
+ * =max_retry_in_ap*max_retry_in_mac_low, where max_retry_in_ap
+ * is hardcoded to 2+1=3
+ * \param address the address of the station
+ */
+ void ReportGotAssocTxFailed (Mac48Address address);
+ /**
+ * check if needed to retransmit association response
+ * \param address the address of the station
+ */
+ bool NeedAssocRespRetransmission(Mac48Address address);
+//end++++++++++++++++++++++++++++++
+ /**
+ * Records that we got an ACK for
+ * the association response we sent.
+ *
+ * \param address the address of the station
+ */
+ void RecordGotAssocTxOk (Mac48Address address);
+ /**
+ * Records that we missed an ACK for
+ * the association response we sent.
+ *
+ * \param address the address of the station
+ */
+ void RecordGotAssocTxFailed (Mac48Address address);
+ /**
+ * Records that the STA was disassociated.
+ *
+ * \param address the address of the station
+ */
+ void RecordDisassociated (Mac48Address address);
+
+ /**
+ * \param address remote address
+ * \param header MAC header
+ * \param packet the packet to queue
+ * \param fullPacketSize the size of the packet after its 802.11 MAC header has been added.
+ *
+ * This method is typically invoked just before queuing a packet for transmission.
+ * It is a no-op unless the IsLowLatency attribute of the attached ns3::WifiRemoteStationManager
+ * is set to false, in which case, the tx parameters of the packet are calculated and stored in
+ * the packet as a tag. These tx parameters are later retrieved from GetDadaMode and GetRtsMode.
+ */
+ void PrepareForQueue (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet, uint32_t fullPacketSize);
+
+ /**
+ * \param address remote address
+ * \param header MAC header
+ * \param packet the packet to send
+ * \param fullPacketSize the size of the packet after its 802.11 MAC header has been added.
+ *
+ * \return the transmission mode to use to send this packet
+ */
+ WifiTxVector GetDataTxVector (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet, uint32_t fullPacketSize);
+ /**
+ * \param address remote address
+ * \param header MAC header
+ * \param packet the packet to send
+ *
+ * \return the transmission mode to use to send the RTS prior to the
+ * transmission of the data packet itself.
+ */
+ WifiTxVector GetRtsTxVector (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet);
+ /**
+ * \param header MAC header
+ * \param packet the packet to send
+ *
+ * \return the transmission mode to use to send the CTS-to-self prior to the
+ * transmission of the data packet itself.
+ */
+ WifiTxVector GetCtsToSelfTxVector (const WifiMacHeader *header,
+ Ptr<const Packet> packet);
+ /**
+ * Since CTS-to-self parameters are not dependent on the station,
+ * it is implemented in wifiremote station manager
+ *
+ * \return the transmission mode to use to send the CTS-to-self prior to the
+ * transmission of the data packet itself.
+ */
+ WifiTxVector DoGetCtsToSelfTxVector (void);
+
+ /**
+ * Should be invoked whenever the RtsTimeout associated to a transmission
+ * attempt expires.
+ *
+ * \param address the address of the receiver
+ * \param header MAC header of the DATA packet
+ */
+ void ReportRtsFailed (Mac48Address address, const WifiMacHeader *header);
+ /**
+ * Should be invoked whenever the AckTimeout associated to a transmission
+ * attempt expires.
+ *
+ * \param address the address of the receiver
+ * \param header MAC header of the DATA packet
+ */
+ void ReportDataFailed (Mac48Address address, const WifiMacHeader *header);
+ /**
+ * Should be invoked whenever we receive the Cts associated to an RTS
+ * we just sent. Note that we also get the SNR of the RTS we sent since
+ * the receiver put a SnrTag in the CTS.
+ *
+ * \param address the address of the receiver
+ * \param header MAC header of the DATA packet
+ * \param ctsSnr the SNR of the CTS we received
+ * \param ctsMode the WifiMode the receiver used to send the CTS
+ * \param rtsSnr the SNR of the RTS we sent
+ */
+ void ReportRtsOk (Mac48Address address, const WifiMacHeader *header,
+ double ctsSnr, WifiMode ctsMode, double rtsSnr);
+ /**
+ * Should be invoked whenever we receive the Ack associated to a data packet
+ * we just sent.
+ *
+ * \param address the address of the receiver
+ * \param header MAC header of the DATA packet
+ * \param ackSnr the SNR of the ACK we received
+ * \param ackMode the WifiMode the receiver used to send the ACK
+ * \param dataSnr the SNR of the DATA we sent
+ */
+ void ReportDataOk (Mac48Address address, const WifiMacHeader *header,
+ double ackSnr, WifiMode ackMode, double dataSnr);
+ /**
+ * Should be invoked after calling ReportRtsFailed if
+ * NeedRtsRetransmission returns false
+ *
+ * \param address the address of the receiver
+ * \param header MAC header of the DATA packet
+ */
+ void ReportFinalRtsFailed (Mac48Address address, const WifiMacHeader *header);
+ /**
+ * Should be invoked after calling ReportDataFailed if
+ * NeedDataRetransmission returns false
+ *
+ * \param address the address of the receiver
+ * \param header MAC header of the DATA packet
+ */
+ void ReportFinalDataFailed (Mac48Address address, const WifiMacHeader *header);
+
+ /**
+ * \param address remote address
+ * \param header MAC header
+ * \param rxSnr the snr of the packet received
+ * \param txMode the transmission mode used for the packet received.
+ *
+ * Should be invoked whenever a packet is successfully received.
+ */
+ void ReportRxOk (Mac48Address address, const WifiMacHeader *header,
+ double rxSnr, WifiMode txMode);
+
+ /**
+ * \param address remote address
+ * \param header MAC header
+ * \param packet the packet to send
+ *
+ * \return true if we want to use an RTS/CTS handshake for this
+ * packet before sending it, false otherwise.
+ */
+ bool NeedRts (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet);
+ /**
+ * Return if we need to do Cts-to-self before sending a DATA.
+ *
+ * \param txVector the TXVECTOR of the packet to be sent
+ *
+ * \return true if Cts-to-self is needed,
+ * false otherwise
+ */
+ bool NeedCtsToSelf (WifiTxVector txVector);
+
+ /**
+ * \param address remote address
+ * \param header MAC header
+ * \param packet the packet to send
+ *
+ * \return true if we want to restart a failed RTS/CTS handshake,
+ * false otherwise.
+ */
+ bool NeedRtsRetransmission (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet);
+ /**
+ * \param address remote address
+ * \param header MAC header
+ * \param packet the packet to send
+ *
+ * \return true if we want to resend a packet after a failed transmission attempt,
+ * false otherwise.
+ */
+ bool NeedDataRetransmission (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet);
+ /**
+ * \param address remote address
+ * \param header MAC header
+ * \param packet the packet to send
+ *
+ * \return true if this packet should be fragmented,
+ * false otherwise.
+ */
+ bool NeedFragmentation (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet);
+ /**
+ * \param address remote address
+ * \param header MAC header
+ * \param packet the packet to send
+ * \param fragmentNumber the fragment index of the next fragment to send (starts at zero).
+ *
+ * \return the size of the corresponding fragment.
+ */
+ uint32_t GetFragmentSize (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet, uint32_t fragmentNumber);
+ /**
+ * \param address remote address
+ * \param header MAC header
+ * \param packet the packet to send
+ * \param fragmentNumber the fragment index of the next fragment to send (starts at zero).
+ *
+ * \return the offset within the original packet where this fragment starts.
+ */
+ uint32_t GetFragmentOffset (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet, uint32_t fragmentNumber);
+ /**
+ * \param address remote address
+ * \param header MAC header
+ * \param packet the packet to send
+ * \param fragmentNumber the fragment index of the next fragment to send (starts at zero).
+ *
+ * \return true if this is the last fragment, false otherwise.
+ */
+ bool IsLastFragment (Mac48Address address, const WifiMacHeader *header,
+ Ptr<const Packet> packet, uint32_t fragmentNumber);
+
+ /**
+ * \param address remote address
+ * \param rtsMode the transmission mode used to send an RTS we just received
+ *
+ * \return the transmission mode to use for the CTS to complete the RTS/CTS handshake.
+ */
+ WifiTxVector GetCtsTxVector (Mac48Address address, WifiMode rtsMode);
+ /**
+ * \param address
+ * \param dataMode the transmission mode used to send an ACK we just received
+ *
+ * \return the transmission mode to use for the ACK to complete the data/ACK handshake.
+ */
+ WifiTxVector GetAckTxVector (Mac48Address address, WifiMode dataMode);
+ /**
+ * \param address
+ * \param dataMode the transmission mode used to send an ACK we just received
+ *
+ * \return the transmission mode to use for the ACK to complete the data/ACK handshake.
+ */
+ WifiTxVector GetBlockAckTxVector (Mac48Address address, WifiMode dataMode);
+ /**
+ * \return the default transmission power
+ */
+ uint8_t GetDefaultTxPowerLevel (void) const;
+ /**
+ * \param address of the remote station
+ *
+ * \return information regarding the remote station associated with the given address
+ */
+ WifiRemoteStationInfo GetInfo (Mac48Address address);
+ /**
+ * Set the default transmission power level
+ *
+ * \param txPower the default transmission power level
+ */
+ void SetDefaultTxPowerLevel (uint8_t txPower);
+ /**
+ * \return the number of transmit antennas supported by the phy layer
+ */
+ uint32_t GetNumberOfTransmitAntennas (void);
+
+ /**
+ * TracedCallback signature for power change events.
+ *
+ * \param [in] power The new power.
+ * \param [in] address The remote station MAC address.
+ */
+ typedef void (*PowerChangeTracedCallback)(uint8_t power, Mac48Address remoteAddress);
+
+ /**
+ * TracedCallback signature for rate change events.
+ *
+ * \param [in] rate The new rate.
+ * \param [in] address The remote station MAC address.
+ */
+ typedef void (*RateChangeTracedCallback)(uint32_t rate, Mac48Address remoteAddress);
+
+
+
+protected:
+ virtual void DoDispose (void);
+ /**
+ * Return whether mode associated with the specified station at the specified index.
+ *
+ * \param station the station being queried
+ * \param i the index
+ *
+ * \return WifiMode at the given index of the specified station
+ */
+ WifiMode GetSupported (const WifiRemoteStation *station, uint32_t i) const;
+ /**
+ * Return the number of modes supported by the given station.
+ *
+ * \param station the station being queried
+ *
+ * \return the number of modes supported by the given station
+ */
+ uint32_t GetNSupported (const WifiRemoteStation *station) const;
+ /**
+ * Return the WifiMode supported by the specified station at the specified index.
+ *
+ * \param station the station being queried
+ * \param i the index
+ *
+ * \return the WifiMode at the given index of the specified station
+ */
+ WifiMode GetMcsSupported (const WifiRemoteStation *station, uint32_t i) const;
+ /**
+ * Return the number of MCS supported by the given station.
+ *
+ * \param station the station being queried
+ *
+ * \return the number of MCS supported by the given station
+ */
+ uint32_t GetNMcsSupported (const WifiRemoteStation *station) const;
+ /**
+ * Return the channel width supported by the station.
+ *
+ * \param station the station being queried
+ *
+ * \return the channel width (in MHz) supported by the station
+ */
+ uint32_t GetChannelWidth (const WifiRemoteStation *station) const;
+ /**
+ * Return whether the given station supports short guard interval.
+ *
+ * \param station the station being queried
+ *
+ * \return true if the station supports short guard interval,
+ * false otherwise
+ */
+ bool GetShortGuardInterval (const WifiRemoteStation *station) const;
+ /**
+ * Return whether the given station supports A-MPDU.
+ *
+ * \param station the station being queried
+ *
+ * \return true if the station supports MPDU aggregation,
+ * false otherwise
+ */
+ bool GetAggregation (const WifiRemoteStation *station) const;
+ /**
+ * Return whether the given station supports space-time block coding (STBC).
+ *
+ * \param station the station being queried
+ *
+ * \return true if the station supports STBC,
+ * false otherwise
+ */
+ bool GetStbc (const WifiRemoteStation *station) const;
+ /**
+ * Return whether the station supports Greenfield or not.
+ *
+ * \param station the station being queried
+ *
+ * \return true if Greenfield is supported by the station,
+ * false otherwise
+ */
+ bool GetGreenfield (const WifiRemoteStation *station) const;
+ /**
+ * Return the number of receive antennas the station has.
+ *
+ * \param station the station being queried
+ *
+ * \return the number of receive antennas the station has
+ */
+ uint32_t GetNumberOfReceiveAntennas (const WifiRemoteStation *station) const;
+ /**
+ * Return the number of transmit antennas the station has.
+ *
+ * \param station the station being queried
+ *
+ * \return the number of transmit antennas the station has
+ */
+ uint32_t GetNumberOfTransmitAntennas (const WifiRemoteStation *station) const;
+ /**
+ * \returns the number of Ness the station has.
+ *
+ * \param station the station being queried
+ *
+ * \return the number of Ness the station has
+ */
+ uint32_t GetNess (const WifiRemoteStation *station) const;
+ /**
+ * Return the long retry limit of the given station.
+ *
+ * \param station the station being queried
+ *
+ * \return the long retry limit of the the station
+ */
+ uint32_t GetLongRetryCount (const WifiRemoteStation *station) const;
+ /**
+ * Return the short retry limit of the given station.
+ *
+ * \param station the station being queried
+ *
+ * \return the short retry limit of the the station
+ */
+ uint32_t GetShortRetryCount (const WifiRemoteStation *station) const;
+
+ /**
+ * Return the WifiPhy.
+ *
+ * \return WifiPhy
+ */
+ Ptr<WifiPhy> GetPhy (void) const;
+ /**
+ * Return the WifiMac.
+ *
+ * \return WifiMac
+ */
+ Ptr<WifiMac> GetMac (void) const;
+
+
+private:
+ /**
+ * \param station the station that we need to communicate
+ * \param packet the packet to send
+ * \param normally indicates whether the normal 802.11 rts enable mechanism would
+ * request that the rts is sent or not.
+ *
+ * \return true if we want to use an RTS/CTS handshake for this packet before sending it,
+ * false otherwise.
+ *
+ * Note: This method is called before a unicast packet is sent on the medium.
+ */
+ virtual bool DoNeedRts (WifiRemoteStation *station,
+ Ptr<const Packet> packet, bool normally);
+ /**
+ * \param station the station that we need to communicate
+ * \param packet the packet to send
+ * \param normally indicates whether the normal 802.11 rts enable mechanism would
+ * request that the rts is retransmitted or not.
+ *
+ * \return true if we want to restart a failed RTS/CTS handshake,
+ * false otherwise.
+ *
+ * Note: This method is called after an rts/cts handshake has been attempted
+ * and has failed.
+ */
+ virtual bool DoNeedRtsRetransmission (WifiRemoteStation *station,
+ Ptr<const Packet> packet, bool normally);
+ /**
+ * \param station the station that we need to communicate
+ * \param packet the packet to send
+ * \param normally indicates whether the normal 802.11 data retransmission mechanism
+ * would request that the data is retransmitted or not.
+ * \return true if we want to resend a packet after a failed transmission attempt,
+ * false otherwise.
+ *
+ * Note: This method is called after a unicast packet transmission has been attempted
+ * and has failed.
+ */
+ virtual bool DoNeedDataRetransmission (WifiRemoteStation *station,
+ Ptr<const Packet> packet, bool normally);
+ /**
+ * \param station the station that we need to communicate
+ * \param packet the packet to send
+ * \param normally indicates whether the normal 802.11 data fragmentation mechanism
+ * would request that the data packet is fragmented or not.
+ *
+ * \return true if this packet should be fragmented,
+ * false otherwise.
+ *
+ * Note: This method is called before sending a unicast packet.
+ */
+ virtual bool DoNeedFragmentation (WifiRemoteStation *station,
+ Ptr<const Packet> packet, bool normally);
+ /**
+ * \return whether this manager is a manager designed to work in low-latency environments.
+ *
+ * Note: In this context, low vs high latency is defined in <i>IEEE 802.11 Rate Adaptation:
+ * A Practical Approach</i>, by M. Lacage, M.H. Manshaei, and T. Turletti.
+ */
+ virtual bool IsLowLatency (void) const = 0;
+ /**
+ * \return a new station data structure
+ */
+ virtual WifiRemoteStation* DoCreateStation (void) const = 0;
+ /**
+ * \param station the station that we need to communicate
+ * \param size size of the packet or fragment we want to send
+ *
+ * \return the transmission mode to use to send a packet to the station
+ *
+ * Note: This method is called before sending a unicast packet or a fragment
+ * of a unicast packet to decide which transmission mode to use.
+ */
+ virtual WifiTxVector DoGetDataTxVector (WifiRemoteStation *station, uint32_t size) = 0;
+ /**
+ * \param station the station that we need to communicate
+ *
+ * \return the transmission mode to use to send an rts to the station
+ *
+ * Note: This method is called before sending an rts to a station
+ * to decide which transmission mode to use for the rts.
+ */
+ virtual WifiTxVector DoGetRtsTxVector (WifiRemoteStation *station) = 0;
+ /**
+ * \param address the address of the recipient of the CTS
+ * \param ctsMode the mode to be used for the CTS
+ *
+ * \return the power level to be used to send the CTS
+ */
+ virtual uint8_t DoGetCtsTxPowerLevel (Mac48Address address, WifiMode ctsMode);
+ /**
+ * \param address the address of the recipient of the ACK
+ * \param ackMode the mode to be used for the ACK
+ *
+ * \return the power level to be used to send the ACK
+ */
+ virtual uint8_t DoGetAckTxPowerLevel (Mac48Address address, WifiMode ackMode);
+ /**
+ * \param address the address of the recipient of the Block ACK
+ * \param blockAckMode the mode to be used for the Block ACK
+ *
+ * \return the power level to be used to send the Block ACK
+ */
+ virtual uint8_t DoGetBlockAckTxPowerLevel (Mac48Address address, WifiMode blockAckMode);
+
+ virtual uint32_t DoGetCtsTxChannelWidth (Mac48Address address, WifiMode ctsMode);
+ virtual bool DoGetCtsTxGuardInterval (Mac48Address address, WifiMode ctsMode);
+ virtual uint8_t DoGetCtsTxNss (Mac48Address address, WifiMode ctsMode);
+ virtual uint8_t DoGetCtsTxNess (Mac48Address address, WifiMode ctsMode);
+ virtual bool DoGetCtsTxStbc (Mac48Address address, WifiMode ctsMode);
+ virtual uint32_t DoGetAckTxChannelWidth (Mac48Address address, WifiMode ctsMode);
+ virtual bool DoGetAckTxGuardInterval (Mac48Address address, WifiMode ackMode);
+ virtual uint8_t DoGetAckTxNss (Mac48Address address, WifiMode ackMode);
+ virtual uint8_t DoGetAckTxNess (Mac48Address address, WifiMode ackMode);
+ virtual bool DoGetAckTxStbc (Mac48Address address, WifiMode ackMode);
+ virtual uint32_t DoGetBlockAckTxChannelWidth (Mac48Address address, WifiMode ctsMode);
+ virtual bool DoGetBlockAckTxGuardInterval (Mac48Address address, WifiMode blockAckMode);
+ virtual uint8_t DoGetBlockAckTxNss (Mac48Address address, WifiMode blockAckMode);
+ virtual uint8_t DoGetBlockAckTxNess (Mac48Address address, WifiMode blockAckMode);
+ virtual bool DoGetBlockAckTxStbc (Mac48Address address, WifiMode blockAckMode);
+
+ /**
+ * This method is a pure virtual method that must be implemented by the sub-class.
+ * This allows different types of WifiRemoteStationManager to respond differently,
+ *
+ * \param station the station that we failed to send RTS
+ */
+ virtual void DoReportRtsFailed (WifiRemoteStation *station) = 0;
+ /**
+ * This method is a pure virtual method that must be implemented by the sub-class.
+ * This allows different types of WifiRemoteStationManager to respond differently,
+ *
+ * \param station the station that we failed to send DATA
+ */
+ virtual void DoReportDataFailed (WifiRemoteStation *station) = 0;
+ /**
+ * This method is a pure virtual method that must be implemented by the sub-class.
+ * This allows different types of WifiRemoteStationManager to respond differently,
+ *
+ * \param station the station that we successfully sent RTS
+ * \param ctsSnr the SNR of the CTS we received
+ * \param ctsMode the WifiMode the receiver used to send the CTS
+ * \param rtsSnr the SNR of the RTS we sent
+ */
+ virtual void DoReportRtsOk (WifiRemoteStation *station,
+ double ctsSnr, WifiMode ctsMode, double rtsSnr) = 0;
+ /**
+ * This method is a pure virtual method that must be implemented by the sub-class.
+ * This allows different types of WifiRemoteStationManager to respond differently,
+ *
+ * \param station the station that we successfully sent RTS
+ * \param ackSnr the SNR of the ACK we received
+ * \param ackMode the WifiMode the receiver used to send the ACK
+ * \param dataSnr the SNR of the DATA we sent
+ */
+ virtual void DoReportDataOk (WifiRemoteStation *station,
+ double ackSnr, WifiMode ackMode, double dataSnr) = 0;
+ /**
+ * This method is a pure virtual method that must be implemented by the sub-class.
+ * This allows different types of WifiRemoteStationManager to respond differently,
+ *
+ * \param station the station that we failed to send RTS
+ */
+ virtual void DoReportFinalRtsFailed (WifiRemoteStation *station) = 0;
+ /**
+ * This method is a pure virtual method that must be implemented by the sub-class.
+ * This allows different types of WifiRemoteStationManager to respond differently,
+ *
+ * \param station the station that we failed to send DATA
+ */
+ virtual void DoReportFinalDataFailed (WifiRemoteStation *station) = 0;
+ /**
+ * This method is a pure virtual method that must be implemented by the sub-class.
+ * This allows different types of WifiRemoteStationManager to respond differently,
+ *
+ * \param station the station that sent the DATA to us
+ * \param rxSnr the SNR of the DATA we received
+ * \param txMode the WifiMode the sender used to send the DATA
+ */
+ virtual void DoReportRxOk (WifiRemoteStation *station,
+ double rxSnr, WifiMode txMode) = 0;
+
+ /**
+ * Return the state of the station associated with the given address.
+ *
+ * \param address the address of the station
+ * \return WifiRemoteStationState corresponding to the address
+ */
+ WifiRemoteStationState* LookupState (Mac48Address address) const;
+ /**
+ * Return the station associated with the given address and TID.
+ *
+ * \param address the address of the station
+ * \param tid the TID
+ *
+ * \return WifiRemoteStation corresponding to the address
+ */
+ WifiRemoteStation* Lookup (Mac48Address address, uint8_t tid) const;
+ /// Find a remote station by its remote address and TID taken from MAC header
+ /**
+ * Return the station associated with the given address and MAC header.
+ * It simply gets TID from the MAC header and calls Lookup with tid.
+ *
+ * \param address the address of the station
+ * \param header MAC header
+ *
+ * \return WifiRemoteStation corresponding to the address
+ */
+ WifiRemoteStation* Lookup (Mac48Address address, const WifiMacHeader *header) const;
+
+ WifiMode GetControlAnswerMode (Mac48Address address, WifiMode reqMode);
+
+ /**
+ * Actually sets the fragmentation threshold, it also checks the validity of
+ * the given threshold.
+ *
+ * \param threshold the fragmentation threshold
+ */
+ void DoSetFragmentationThreshold (uint32_t threshold);
+ /**
+ * Return the current fragmentation threshold
+ *
+ * \return the fragmentation threshold
+ */
+ uint32_t DoGetFragmentationThreshold (void) const;
+ /**
+ * Return the number of fragments needed for the given packet.
+ *
+ * \param header MAC header
+ * \param packet the packet to be fragmented
+ *
+ * \return the number of fragments needed
+ */
+ uint32_t GetNFragments (const WifiMacHeader *header, Ptr<const Packet> packet);
+
+ /**
+ * A vector of WifiRemoteStations
+ */
+ typedef std::vector <WifiRemoteStation *> Stations;
+ /**
+ * A vector of WifiRemoteStationStates
+ */
+ typedef std::vector <WifiRemoteStationState *> StationStates;
+
+ /**
+ * This is a pointer to the WifiPhy associated with this
+ * WifiRemoteStationManager that is set on call to
+ * WifiRemoteStationManager::SetupPhy(). Through this pointer the
+ * station manager can determine PHY characteristics, such as the
+ * set of all transmission rates that may be supported (the
+ * "DeviceRateSet").
+ */
+ Ptr<WifiPhy> m_wifiPhy;
+ /**
+ * This is a pointer to the WifiMac associated with this
+ * WifiRemoteStationManager that is set on call to
+ * WifiRemoteStationManager::SetupMac(). Through this pointer the
+ * station manager can determine MAC characteristics, such as the
+ * interframe spaces.
+ */
+ Ptr<WifiMac> m_wifiMac;
+
+ /**
+ * This member is the list of WifiMode objects that comprise the
+ * BSSBasicRateSet parameter. This list is constructed through calls
+ * to WifiRemoteStationManager::AddBasicMode(), and an API that
+ * allows external access to it is available through
+ * WifiRemoteStationManager::GetNBasicModes() and
+ * WifiRemoteStationManager::GetBasicMode().
+ */
+ WifiModeList m_bssBasicRateSet;
+ WifiModeList m_bssBasicMcsSet;
+
+ StationStates m_states; //!< States of known stations
+ Stations m_stations; //!< Information for each known stations
+
+ WifiMode m_defaultTxMode; //!< The default transmission mode
+ WifiMode m_defaultTxMcs; //!< The default transmission modulation-coding scheme (MCS)
+
+ bool m_htSupported; //!< Flag if HT capability is supported
+ bool m_vhtSupported; //!< Flag if VHT capability is supported
+ uint32_t m_maxSsrc; //!< Maximum STA short retry count (SSRC)
+ uint32_t m_maxSlrc; //!< Maximum STA long retry count (SLRC)
+ uint32_t m_rtsCtsThreshold; //!< Threshold for RTS/CTS
+ uint32_t m_fragmentationThreshold; //!< Current threshold for fragmentation
+ uint32_t m_nextFragmentationThreshold; //!< Threshold for fragmentation that will be used for the next transmission
+ uint8_t m_defaultTxPowerLevel; //!< Default tranmission power level
+ WifiMode m_nonUnicastMode; //!< Transmission mode for non-unicast DATA frames
+
+ /**
+ * The trace source fired when the transmission of a single RTS has failed
+ */
+ TracedCallback<Mac48Address> m_macTxRtsFailed;
+ /**
+ * The trace source fired when the transmission of a single data packet has failed
+ */
+ TracedCallback<Mac48Address> m_macTxDataFailed;
+ /**
+ * The trace source fired when the transmission of a RTS has
+ * exceeded the maximum number of attempts
+ */
+ TracedCallback<Mac48Address> m_macTxFinalRtsFailed;
+ /**
+ * The trace source fired when the transmission of a data packet has
+ * exceeded the maximum number of attempts
+ */
+ TracedCallback<Mac48Address> m_macTxFinalDataFailed;
+};
+
+/**
+ * A struct that holds information about each remote station.
+ */
+struct WifiRemoteStationState
+{
+ /**
+ * State of the station
+ */
+ enum
+ {
+ BRAND_NEW,
+ DISASSOC,
+ WAIT_ASSOC_TX_OK,
+ GOT_ASSOC_TX_OK
+ } m_state;
+
+ /**
+ * This member is the list of WifiMode objects that comprise the
+ * OperationalRateSet parameter for this remote station. This list
+ * is constructed through calls to
+ * WifiRemoteStationManager::AddSupportedMode(), and an API that
+ * allows external access to it is available through
+ * WifiRemoteStationManager::GetNSupported() and
+ * WifiRemoteStationManager::GetSupported().
+ */
+ WifiModeList m_operationalRateSet;
+ WifiModeList m_operationalMcsSet;
+ Mac48Address m_address; //!< Mac48Address of the remote station
+ WifiRemoteStationInfo m_info;
+
+ uint32_t m_channelWidth; //!< Channel width (in MHz) supported by the remote station
+ bool m_shortGuardInterval; //!< Flag if short guard interval is supported by the remote station
+ uint32_t m_rx; //!< Number of RX antennas of the remote station
+ uint32_t m_tx; //!< Number of TX antennas of the remote station
+ uint32_t m_ness; //!< Number of streams in beamforming of the remote station
+ bool m_stbc; //!< Flag if STBC is used by the remote station
+ bool m_aggregation; //!< Flag if MPDU aggregation is used by the remote station
+ bool m_greenfield; //!< Flag if green field is used by the remote station
+
+ //added by zeng:
+ uint32_t m_assocRespTxRetryCount;
+ //end
+};
+
+/**
+ * \brief hold per-remote-station state.
+ *
+ * The state in this class is used to keep track
+ * of association status if we are in an infrastructure
+ * network and to perform the selection of tx parameters
+ * on a per-packet basis.
+ *
+ * This class is typically subclassed and extended by
+ * rate control implementations
+ */
+struct WifiRemoteStation
+{
+ virtual ~WifiRemoteStation ();
+ WifiRemoteStationState *m_state; //!< Remote station state
+ uint32_t m_ssrc; //!< STA short retry count
+ uint32_t m_slrc; //!< STA long retry count
+ uint8_t m_tid; //!< traffic ID
+};
+
+} //namespace ns3
+
+#endif /* WIFI_REMOTE_STATION_MANAGER_H */
diff --git a/emu-radio/ns3-patch/wifi/model/yans-wifi-phy.cc b/emu-radio/ns3-patch/wifi/model/yans-wifi-phy.cc
new file mode 100644
index 00000000..dfc5323c
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/yans-wifi-phy.cc
@@ -0,0 +1,1390 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005,2006 INRIA
+ *
+ * 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
+ *
+ * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Ghada Badawy <gbadawy@gmail.com>
+ * Sébastien Deronne <sebastien.deronne@gmail.com>
+ */
+
+#include "yans-wifi-phy.h"
+#include "yans-wifi-channel.h"
+#include "wifi-mode.h"
+#include "wifi-preamble.h"
+#include "wifi-phy-state-helper.h"
+#include "error-rate-model.h"
+#include "ns3/simulator.h"
+#include "ns3/packet.h"
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/double.h"
+#include "ns3/uinteger.h"
+#include "ns3/enum.h"
+#include "ns3/pointer.h"
+#include "ns3/net-device.h"
+#include "ns3/trace-source-accessor.h"
+#include "ns3/boolean.h"
+#include "ns3/node.h"
+#include "ampdu-tag.h"
+#include <cmath>
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("YansWifiPhy");
+
+NS_OBJECT_ENSURE_REGISTERED (YansWifiPhy);
+
+TypeId
+RssiTag::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::RssiTag")
+ .SetParent<SnrTag> ()
+ .SetGroupName ("Wifi")
+ .AddConstructor<RssiTag> ()
+ .AddAttribute ("RSSI", "The RSSI of the last packet received",
+ DoubleValue (0.0),
+ MakeDoubleAccessor (&RssiTag::Get),
+ MakeDoubleChecker<double> ())
+ ;
+ return tid;
+}
+
+TypeId
+RssiTag::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+
+RssiTag::RssiTag()
+:SnrTag()
+{}
+
+RssiTag::RssiTag (double snr)
+:SnrTag(snr)
+{}
+
+TypeId
+YansWifiPhy::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::YansWifiPhy")
+ .SetParent<WifiPhy> ()
+ .SetGroupName ("Wifi")
+ .AddConstructor<YansWifiPhy> ()
+ .AddAttribute ("EnergyDetectionThreshold",
+ "The energy of a received signal should be higher than "
+ "this threshold (dbm) to allow the PHY layer to detect the signal.",
+ DoubleValue (-96.0),
+ MakeDoubleAccessor (&YansWifiPhy::SetEdThreshold,
+ &YansWifiPhy::GetEdThreshold),
+ MakeDoubleChecker<double> ())
+ .AddAttribute ("CcaMode1Threshold",
+ "The energy of a received signal should be higher than "
+ "this threshold (dbm) to allow the PHY layer to declare CCA BUSY state.",
+ DoubleValue (-99.0),
+ MakeDoubleAccessor (&YansWifiPhy::SetCcaMode1Threshold,
+ &YansWifiPhy::GetCcaMode1Threshold),
+ MakeDoubleChecker<double> ())
+ .AddAttribute ("TxGain",
+ "Transmission gain (dB).",
+ DoubleValue (1.0),
+ MakeDoubleAccessor (&YansWifiPhy::SetTxGain,
+ &YansWifiPhy::GetTxGain),
+ MakeDoubleChecker<double> ())
+ .AddAttribute ("RxGain",
+ "Reception gain (dB).",
+ DoubleValue (1.0),
+ MakeDoubleAccessor (&YansWifiPhy::SetRxGain,
+ &YansWifiPhy::GetRxGain),
+ MakeDoubleChecker<double> ())
+ .AddAttribute ("TxPowerLevels",
+ "Number of transmission power levels available between "
+ "TxPowerStart and TxPowerEnd included.",
+ UintegerValue (1),
+ MakeUintegerAccessor (&YansWifiPhy::m_nTxPower),
+ MakeUintegerChecker<uint32_t> ())
+ .AddAttribute ("TxPowerEnd",
+ "Maximum available transmission level (dbm).",
+ DoubleValue (16.0206),
+ MakeDoubleAccessor (&YansWifiPhy::SetTxPowerEnd,
+ &YansWifiPhy::GetTxPowerEnd),
+ MakeDoubleChecker<double> ())
+ .AddAttribute ("TxPowerStart",
+ "Minimum available transmission level (dbm).",
+ DoubleValue (16.0206),
+ MakeDoubleAccessor (&YansWifiPhy::SetTxPowerStart,
+ &YansWifiPhy::GetTxPowerStart),
+ MakeDoubleChecker<double> ())
+ .AddAttribute ("RxNoiseFigure",
+ "Loss (dB) in the Signal-to-Noise-Ratio due to non-idealities in the receiver."
+ " According to Wikipedia (http://en.wikipedia.org/wiki/Noise_figure), this is "
+ "\"the difference in decibels (dB) between"
+ " the noise output of the actual receiver to the noise output of an "
+ " ideal receiver with the same overall gain and bandwidth when the receivers "
+ " are connected to sources at the standard noise temperature T0 (usually 290 K)\".",
+ DoubleValue (7),
+ MakeDoubleAccessor (&YansWifiPhy::SetRxNoiseFigure,
+ &YansWifiPhy::GetRxNoiseFigure),
+ MakeDoubleChecker<double> ())
+ .AddAttribute ("State",
+ "The state of the PHY layer.",
+ PointerValue (),
+ MakePointerAccessor (&YansWifiPhy::m_state),
+ MakePointerChecker<WifiPhyStateHelper> ())
+ .AddAttribute ("ChannelSwitchDelay",
+ "Delay between two short frames transmitted on different frequencies.",
+ TimeValue (MicroSeconds (250)),
+ MakeTimeAccessor (&YansWifiPhy::m_channelSwitchDelay),
+ MakeTimeChecker ())
+ .AddAttribute ("ChannelNumber",
+ "Channel center frequency = Channel starting frequency + 5 MHz * nch.",
+ UintegerValue (1),
+ MakeUintegerAccessor (&YansWifiPhy::SetChannelNumber,
+ &YansWifiPhy::GetChannelNumber),
+ MakeUintegerChecker<uint16_t> ())
+ .AddAttribute ("Frequency",
+ "The operating frequency.",
+ UintegerValue (2407),
+ MakeUintegerAccessor (&YansWifiPhy::GetFrequency,
+ &YansWifiPhy::SetFrequency),
+ MakeUintegerChecker<uint32_t> ())
+ .AddAttribute ("Transmitters",
+ "The number of transmitters.",
+ UintegerValue (1),
+ MakeUintegerAccessor (&YansWifiPhy::GetNumberOfTransmitAntennas,
+ &YansWifiPhy::SetNumberOfTransmitAntennas),
+ MakeUintegerChecker<uint32_t> ())
+ .AddAttribute ("Receivers",
+ "The number of receivers.",
+ UintegerValue (1),
+ MakeUintegerAccessor (&YansWifiPhy::GetNumberOfReceiveAntennas,
+ &YansWifiPhy::SetNumberOfReceiveAntennas),
+ MakeUintegerChecker<uint32_t> ())
+ .AddAttribute ("ShortGuardEnabled",
+ "Whether or not short guard interval is enabled.",
+ BooleanValue (false),
+ MakeBooleanAccessor (&YansWifiPhy::GetGuardInterval,
+ &YansWifiPhy::SetGuardInterval),
+ MakeBooleanChecker ())
+ .AddAttribute ("LdpcEnabled",
+ "Whether or not LDPC is enabled.",
+ BooleanValue (false),
+ MakeBooleanAccessor (&YansWifiPhy::GetLdpc,
+ &YansWifiPhy::SetLdpc),
+ MakeBooleanChecker ())
+ .AddAttribute ("STBCEnabled",
+ "Whether or not STBC is enabled.",
+ BooleanValue (false),
+ MakeBooleanAccessor (&YansWifiPhy::GetStbc,
+ &YansWifiPhy::SetStbc),
+ MakeBooleanChecker ())
+ .AddAttribute ("GreenfieldEnabled",
+ "Whether or not Greenfield is enabled.",
+ BooleanValue (false),
+ MakeBooleanAccessor (&YansWifiPhy::GetGreenfield,
+ &YansWifiPhy::SetGreenfield),
+ MakeBooleanChecker ())
+ .AddAttribute ("ChannelWidth",
+ "Whether 5MHz, 10MHz, 20MHz, 22MHz, 40MHz, 80 MHz or 160 MHz.",
+ UintegerValue (20),
+ MakeUintegerAccessor (&YansWifiPhy::GetChannelWidth,
+ &YansWifiPhy::SetChannelWidth),
+ MakeUintegerChecker<uint32_t> ())
+ ;
+ return tid;
+}
+
+YansWifiPhy::YansWifiPhy ()
+ : m_initialized (false),
+ m_channelNumber (1),
+ m_endRxEvent (),
+ m_endPlcpRxEvent (),
+ m_channelStartingFrequency (0),
+ m_mpdusNum (0),
+ m_plcpSuccess (false)
+{
+ NS_LOG_FUNCTION (this);
+ m_random = CreateObject<UniformRandomVariable> ();
+ m_state = CreateObject<WifiPhyStateHelper> ();
+}
+
+YansWifiPhy::~YansWifiPhy ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+void
+YansWifiPhy::DoDispose (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_channel = 0;
+ m_deviceRateSet.clear ();
+ m_deviceMcsSet.clear ();
+ m_device = 0;
+ m_mobility = 0;
+ m_state = 0;
+}
+
+void
+YansWifiPhy::DoInitialize ()
+{
+ NS_LOG_FUNCTION (this);
+ m_initialized = true;
+}
+
+void
+YansWifiPhy::ConfigureStandard (enum WifiPhyStandard standard)
+{
+ NS_LOG_FUNCTION (this << standard);
+ switch (standard)
+ {
+ case WIFI_PHY_STANDARD_80211a:
+ Configure80211a ();
+ break;
+ case WIFI_PHY_STANDARD_80211b:
+ Configure80211b ();
+ break;
+ case WIFI_PHY_STANDARD_80211g:
+ Configure80211g ();
+ break;
+ case WIFI_PHY_STANDARD_80211_10MHZ:
+ Configure80211_10Mhz ();
+ break;
+ case WIFI_PHY_STANDARD_80211_5MHZ:
+ Configure80211_5Mhz ();
+ break;
+ case WIFI_PHY_STANDARD_holland:
+ ConfigureHolland ();
+ break;
+ case WIFI_PHY_STANDARD_80211n_2_4GHZ:
+ m_channelStartingFrequency = 2407;
+ Configure80211n ();
+ break;
+ case WIFI_PHY_STANDARD_80211n_5GHZ:
+ m_channelStartingFrequency = 5e3;
+ Configure80211n ();
+ break;
+ case WIFI_PHY_STANDARD_80211ac:
+ Configure80211ac ();
+ break;
+ default:
+ NS_ASSERT (false);
+ break;
+ }
+}
+
+void
+YansWifiPhy::SetRxNoiseFigure (double noiseFigureDb)
+{
+ NS_LOG_FUNCTION (this << noiseFigureDb);
+ m_interference.SetNoiseFigure (DbToRatio (noiseFigureDb));
+}
+
+void
+YansWifiPhy::SetTxPowerStart (double start)
+{
+ NS_LOG_FUNCTION (this << start);
+ m_txPowerBaseDbm = start;
+}
+
+void
+YansWifiPhy::SetTxPowerEnd (double end)
+{
+ NS_LOG_FUNCTION (this << end);
+ m_txPowerEndDbm = end;
+}
+
+void
+YansWifiPhy::SetNTxPower (uint32_t n)
+{
+ NS_LOG_FUNCTION (this << n);
+ m_nTxPower = n;
+}
+
+void
+YansWifiPhy::SetTxGain (double gain)
+{
+ NS_LOG_FUNCTION (this << gain);
+ m_txGainDb = gain;
+}
+
+void
+YansWifiPhy::SetRxGain (double gain)
+{
+ NS_LOG_FUNCTION (this << gain);
+ m_rxGainDb = gain;
+}
+
+void
+YansWifiPhy::SetEdThreshold (double threshold)
+{
+ NS_LOG_FUNCTION (this << threshold);
+ m_edThresholdW = DbmToW (threshold);
+}
+
+void
+YansWifiPhy::SetCcaMode1Threshold (double threshold)
+{
+ NS_LOG_FUNCTION (this << threshold);
+ m_ccaMode1ThresholdW = DbmToW (threshold);
+}
+
+void
+YansWifiPhy::SetErrorRateModel (Ptr<ErrorRateModel> rate)
+{
+ m_interference.SetErrorRateModel (rate);
+}
+
+void
+YansWifiPhy::SetDevice (Ptr<NetDevice> device)
+{
+ m_device = device;
+}
+
+void
+YansWifiPhy::SetMobility (Ptr<MobilityModel> mobility)
+{
+ m_mobility = mobility;
+}
+
+double
+YansWifiPhy::GetRxNoiseFigure (void) const
+{
+ return RatioToDb (m_interference.GetNoiseFigure ());
+}
+
+double
+YansWifiPhy::GetTxPowerStart (void) const
+{
+ return m_txPowerBaseDbm;
+}
+
+double
+YansWifiPhy::GetTxPowerEnd (void) const
+{
+ return m_txPowerEndDbm;
+}
+
+double
+YansWifiPhy::GetTxGain (void) const
+{
+ return m_txGainDb;
+}
+
+double
+YansWifiPhy::GetRxGain (void) const
+{
+ return m_rxGainDb;
+}
+
+double
+YansWifiPhy::GetEdThreshold (void) const
+{
+ return WToDbm (m_edThresholdW);
+}
+
+double
+YansWifiPhy::GetCcaMode1Threshold (void) const
+{
+ return WToDbm (m_ccaMode1ThresholdW);
+}
+
+Ptr<ErrorRateModel>
+YansWifiPhy::GetErrorRateModel (void) const
+{
+ return m_interference.GetErrorRateModel ();
+}
+
+Ptr<NetDevice>
+YansWifiPhy::GetDevice (void) const
+{
+ return m_device;
+}
+
+Ptr<MobilityModel>
+YansWifiPhy::GetMobility (void)
+{
+ if (m_mobility != 0)
+ {
+ return m_mobility;
+ }
+ else
+ {
+ return m_device->GetNode ()->GetObject<MobilityModel> ();
+ }
+}
+
+double
+YansWifiPhy::CalculateSnr (WifiMode txMode, double ber) const
+{
+ return m_interference.GetErrorRateModel ()->CalculateSnr (txMode, ber);
+}
+
+Ptr<WifiChannel>
+YansWifiPhy::GetChannel (void) const
+{
+ return m_channel;
+}
+
+void
+YansWifiPhy::SetChannel (Ptr<YansWifiChannel> channel)
+{
+ m_channel = channel;
+ m_channel->Add (this);
+}
+
+void
+YansWifiPhy::SetChannelNumber (uint16_t nch)
+{
+ if (!m_initialized)
+ {
+ //this is not channel switch, this is initialization
+ NS_LOG_DEBUG ("start at channel " << nch);
+ m_channelNumber = nch;
+ return;
+ }
+
+ NS_ASSERT (!IsStateSwitching ());
+ switch (m_state->GetState ())
+ {
+ case YansWifiPhy::RX:
+ NS_LOG_DEBUG ("drop packet because of channel switching while reception");
+ m_endPlcpRxEvent.Cancel ();
+ m_endRxEvent.Cancel ();
+ goto switchChannel;
+ break;
+ case YansWifiPhy::TX:
+ NS_LOG_DEBUG ("channel switching postponed until end of current transmission");
+ Simulator::Schedule (GetDelayUntilIdle (), &YansWifiPhy::SetChannelNumber, this, nch);
+ break;
+ case YansWifiPhy::CCA_BUSY:
+ case YansWifiPhy::IDLE:
+ goto switchChannel;
+ break;
+ case YansWifiPhy::SLEEP:
+ NS_LOG_DEBUG ("channel switching ignored in sleep mode");
+ break;
+ default:
+ NS_ASSERT (false);
+ break;
+ }
+
+ return;
+
+switchChannel:
+
+ NS_LOG_DEBUG ("switching channel " << m_channelNumber << " -> " << nch);
+ m_state->SwitchToChannelSwitching (m_channelSwitchDelay);
+ m_interference.EraseEvents ();
+ /*
+ * Needed here to be able to correctly sensed the medium for the first
+ * time after the switching. The actual switching is not performed until
+ * after m_channelSwitchDelay. Packets received during the switching
+ * state are added to the event list and are employed later to figure
+ * out the state of the medium after the switching.
+ */
+ m_channelNumber = nch;
+}
+
+uint16_t
+YansWifiPhy::GetChannelNumber (void) const
+{
+ return m_channelNumber;
+}
+
+Time
+YansWifiPhy::GetChannelSwitchDelay (void) const
+{
+ return m_channelSwitchDelay;
+}
+
+double
+YansWifiPhy::GetChannelFrequencyMhz () const
+{
+ return m_channelStartingFrequency + 5 * GetChannelNumber ();
+}
+
+void
+YansWifiPhy::SetSleepMode (void)
+{
+ NS_LOG_FUNCTION (this);
+ switch (m_state->GetState ())
+ {
+ case YansWifiPhy::TX:
+ NS_LOG_DEBUG ("setting sleep mode postponed until end of current transmission");
+ Simulator::Schedule (GetDelayUntilIdle (), &YansWifiPhy::SetSleepMode, this);
+ break;
+ case YansWifiPhy::RX:
+ NS_LOG_DEBUG ("setting sleep mode postponed until end of current reception");
+ Simulator::Schedule (GetDelayUntilIdle (), &YansWifiPhy::SetSleepMode, this);
+ break;
+ case YansWifiPhy::SWITCHING:
+ NS_LOG_DEBUG ("setting sleep mode postponed until end of channel switching");
+ Simulator::Schedule (GetDelayUntilIdle (), &YansWifiPhy::SetSleepMode, this);
+ break;
+ case YansWifiPhy::CCA_BUSY:
+ case YansWifiPhy::IDLE:
+ NS_LOG_DEBUG ("setting sleep mode");
+ m_state->SwitchToSleep ();
+ break;
+ case YansWifiPhy::SLEEP:
+ NS_LOG_DEBUG ("already in sleep mode");
+ break;
+ default:
+ NS_ASSERT (false);
+ break;
+ }
+}
+
+void
+YansWifiPhy::ResumeFromSleep (void)
+{
+ NS_LOG_FUNCTION (this);
+ switch (m_state->GetState ())
+ {
+ case YansWifiPhy::TX:
+ case YansWifiPhy::RX:
+ case YansWifiPhy::IDLE:
+ case YansWifiPhy::CCA_BUSY:
+ case YansWifiPhy::SWITCHING:
+ {
+ NS_LOG_DEBUG ("not in sleep mode, there is nothing to resume");
+ break;
+ }
+ case YansWifiPhy::SLEEP:
+ {
+ NS_LOG_DEBUG ("resuming from sleep mode");
+ Time delayUntilCcaEnd = m_interference.GetEnergyDuration (m_ccaMode1ThresholdW);
+ m_state->SwitchFromSleep (delayUntilCcaEnd);
+ break;
+ }
+ default:
+ {
+ NS_ASSERT (false);
+ break;
+ }
+ }
+}
+
+void
+YansWifiPhy::SetReceiveOkCallback (RxOkCallback callback)
+{
+ m_state->SetReceiveOkCallback (callback);
+}
+
+void
+YansWifiPhy::SetReceiveErrorCallback (RxErrorCallback callback)
+{
+ m_state->SetReceiveErrorCallback (callback);
+}
+
+void
+YansWifiPhy::StartReceivePreambleAndHeader (Ptr<Packet> packet,
+ double rxPowerDbm,
+ WifiTxVector txVector,
+ enum WifiPreamble preamble,
+ struct mpduInfo aMpdu, Time rxDuration)
+{
+ //This function should be later split to check separately whether plcp preamble and plcp header can be successfully received.
+ //Note: plcp preamble reception is not yet modeled.
+ NS_LOG_FUNCTION (this << packet << rxPowerDbm << txVector.GetMode () << preamble << (uint32_t)aMpdu.packetType);
+ AmpduTag ampduTag;
+ rxPowerDbm += m_rxGainDb;
+ double rxPowerW = DbmToW (rxPowerDbm);
+ Time endRx = Simulator::Now () + rxDuration;
+ Time preambleAndHeaderDuration = CalculatePlcpPreambleAndHeaderDuration (txVector, preamble);
+
+ Ptr<InterferenceHelper::Event> event;
+ event = m_interference.Add (packet->GetSize (),
+ txVector,
+ preamble,
+ rxDuration,
+ rxPowerW);
+
+ switch (m_state->GetState ())
+ {
+ case YansWifiPhy::SWITCHING:
+ NS_LOG_DEBUG ("drop packet because of channel switching");
+ NotifyRxDrop (packet);
+ m_plcpSuccess = false;
+ /*
+ * Packets received on the upcoming channel are added to the event list
+ * during the switching state. This way the medium can be correctly sensed
+ * when the device listens to the channel for the first time after the
+ * switching e.g. after channel switching, the channel may be sensed as
+ * busy due to other devices' tramissions started before the end of
+ * the switching.
+ */
+ if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ())
+ {
+ //that packet will be noise _after_ the completion of the
+ //channel switching.
+ goto maybeCcaBusy;
+ }
+ break;
+ case YansWifiPhy::RX:
+ NS_LOG_DEBUG ("drop packet because already in Rx (power=" <<
+ rxPowerW << "W)");
+ NotifyRxDrop (packet);
+ if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ())
+ {
+ //that packet will be noise _after_ the reception of the
+ //currently-received packet.
+ goto maybeCcaBusy;
+ }
+ break;
+ case YansWifiPhy::TX:
+ NS_LOG_DEBUG ("drop packet because already in Tx (power=" <<
+ rxPowerW << "W)");
+ NotifyRxDrop (packet);
+ if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ())
+ {
+ //that packet will be noise _after_ the transmission of the
+ //currently-transmitted packet.
+ goto maybeCcaBusy;
+ }
+ break;
+ case YansWifiPhy::CCA_BUSY:
+ case YansWifiPhy::IDLE:
+ if (rxPowerW > m_edThresholdW) //checked here, no need to check in the payload reception (current implementation assumes constant rx power over the packet duration)
+ {
+ if (preamble == WIFI_PREAMBLE_NONE && m_mpdusNum == 0)
+ {
+ NS_LOG_DEBUG ("drop packet because no preamble has been received");
+ NotifyRxDrop (packet);
+ goto maybeCcaBusy;
+ }
+ else if (preamble == WIFI_PREAMBLE_NONE && m_plcpSuccess == false) //A-MPDU reception fails
+ {
+ NS_LOG_DEBUG ("Drop MPDU because no plcp has been received");
+ NotifyRxDrop (packet);
+ goto maybeCcaBusy;
+ }
+ else if (preamble != WIFI_PREAMBLE_NONE && packet->PeekPacketTag (ampduTag) && m_mpdusNum == 0)
+ {
+ //received the first MPDU in an MPDU
+ m_mpdusNum = ampduTag.GetNoOfMpdus () - 1;
+ }
+ else if (preamble == WIFI_PREAMBLE_NONE && packet->PeekPacketTag (ampduTag) && m_mpdusNum > 0)
+ {
+ //received the other MPDUs that are part of the A-MPDU
+ if (ampduTag.GetNoOfMpdus () < m_mpdusNum)
+ {
+ NS_LOG_DEBUG ("Missing MPDU from the A-MPDU " << m_mpdusNum - ampduTag.GetNoOfMpdus ());
+ m_mpdusNum = ampduTag.GetNoOfMpdus ();
+ }
+ else
+ {
+ m_mpdusNum--;
+ }
+ }
+ else if (preamble != WIFI_PREAMBLE_NONE && m_mpdusNum > 0 )
+ {
+ NS_LOG_DEBUG ("Didn't receive the last MPDUs from an A-MPDU " << m_mpdusNum);
+ m_mpdusNum = 0;
+ }
+
+ NS_LOG_DEBUG ("sync to signal (power=" << rxPowerW << "W)");
+ //sync to signal
+ m_state->SwitchToRx (rxDuration);
+ NS_ASSERT (m_endPlcpRxEvent.IsExpired ());
+ NotifyRxBegin (packet);
+ m_interference.NotifyRxStart ();
+
+ if (preamble != WIFI_PREAMBLE_NONE)
+ {
+ NS_ASSERT (m_endPlcpRxEvent.IsExpired ());
+ m_endPlcpRxEvent = Simulator::Schedule (preambleAndHeaderDuration, &YansWifiPhy::StartReceivePacket, this,
+ packet, txVector, preamble, aMpdu, event);
+ }
+
+ NS_ASSERT (m_endRxEvent.IsExpired ());
+ m_endRxEvent = Simulator::Schedule (rxDuration, &YansWifiPhy::EndReceive, this,
+ packet, preamble, aMpdu, event);
+ }
+ else
+ {
+ NS_LOG_DEBUG ("drop packet because signal power too Small (" <<
+ rxPowerW << "<" << m_edThresholdW << ")");
+ NotifyRxDrop (packet);
+ m_plcpSuccess = false;
+ goto maybeCcaBusy;
+ }
+ break;
+ case YansWifiPhy::SLEEP:
+ NS_LOG_DEBUG ("drop packet because in sleep mode");
+ NotifyRxDrop (packet);
+ m_plcpSuccess = false;
+ break;
+ }
+
+ return;
+
+maybeCcaBusy:
+ //We are here because we have received the first bit of a packet and we are
+ //not going to be able to synchronize on it
+ //In this model, CCA becomes busy when the aggregation of all signals as
+ //tracked by the InterferenceHelper class is higher than the CcaBusyThreshold
+
+ Time delayUntilCcaEnd = m_interference.GetEnergyDuration (m_ccaMode1ThresholdW);
+ if (!delayUntilCcaEnd.IsZero ())
+ {
+ m_state->SwitchMaybeToCcaBusy (delayUntilCcaEnd);
+ }
+}
+
+void
+YansWifiPhy::StartReceivePacket (Ptr<Packet> packet,
+ WifiTxVector txVector,
+ enum WifiPreamble preamble,
+ struct mpduInfo aMpdu,
+ Ptr<InterferenceHelper::Event> event)
+{
+ NS_LOG_FUNCTION (this << packet << txVector.GetMode () << preamble << (uint32_t)aMpdu.packetType);
+ NS_ASSERT (IsStateRx ());
+ NS_ASSERT (m_endPlcpRxEvent.IsExpired ());
+ AmpduTag ampduTag;
+ WifiMode txMode = txVector.GetMode ();
+
+ struct InterferenceHelper::SnrPer snrPer;
+ snrPer = m_interference.CalculatePlcpHeaderSnrPer (event);
+
+ NS_LOG_DEBUG ("snr(dB)=" << RatioToDb (snrPer.snr) << ", per=" << snrPer.per);
+
+ if (m_random->GetValue () > snrPer.per) //plcp reception succeeded
+ {
+ if (IsModeSupported (txMode) || IsMcsSupported (txMode))
+ {
+ NS_LOG_DEBUG ("receiving plcp payload"); //endReceive is already scheduled
+ m_plcpSuccess = true;
+ }
+ else //mode is not allowed
+ {
+ NS_LOG_DEBUG ("drop packet because it was sent using an unsupported mode (" << txMode << ")");
+ NotifyRxDrop (packet);
+ m_plcpSuccess = false;
+ }
+ }
+ else //plcp reception failed
+ {
+ NS_LOG_DEBUG ("drop packet because plcp preamble/header reception failed");
+ NotifyRxDrop (packet);
+ m_plcpSuccess = false;
+ }
+}
+
+void
+YansWifiPhy::SendPacket (Ptr<const Packet> packet, WifiTxVector txVector, WifiPreamble preamble, uint8_t packetType, uint32_t mpduReferenceNumber)
+{
+ NS_LOG_FUNCTION (this << packet << txVector.GetMode () << txVector.GetMode ().GetDataRate (txVector.GetChannelWidth (), txVector.IsShortGuardInterval (), 1) << preamble << (uint32_t)txVector.GetTxPowerLevel () << (uint32_t)packetType);
+ /* Transmission can happen if:
+ * - we are syncing on a packet. It is the responsability of the
+ * MAC layer to avoid doing this but the PHY does nothing to
+ * prevent it.
+ * - we are idle
+ */
+ NS_ASSERT (!m_state->IsStateTx () && !m_state->IsStateSwitching ());
+
+ if (m_state->IsStateSleep ())
+ {
+ NS_LOG_DEBUG ("Dropping packet because in sleep mode");
+ NotifyTxDrop (packet);
+ return;
+ }
+
+ Time txDuration = CalculateTxDuration (packet->GetSize (), txVector, preamble, GetFrequency (), packetType, 1);
+ NS_ASSERT (txDuration > NanoSeconds (0));
+
+ if (m_state->IsStateRx ())
+ {
+ m_endPlcpRxEvent.Cancel ();
+ m_endRxEvent.Cancel ();
+ m_interference.NotifyRxEnd ();
+ }
+ NotifyTxBegin (packet);
+ uint32_t dataRate500KbpsUnits;
+ if (txVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT || txVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_VHT)
+ {
+ dataRate500KbpsUnits = 128 + txVector.GetMode ().GetMcsValue ();
+ }
+ else
+ {
+ dataRate500KbpsUnits = txVector.GetMode ().GetDataRate (txVector.GetChannelWidth (), txVector.IsShortGuardInterval (), 1) * txVector.GetNss () / 500000;
+ }
+ struct mpduInfo aMpdu;
+ aMpdu.packetType = packetType;
+ aMpdu.referenceNumber = mpduReferenceNumber;
+ NotifyMonitorSniffTx (packet, (uint16_t)GetChannelFrequencyMhz (), GetChannelNumber (), dataRate500KbpsUnits, preamble, txVector, aMpdu);
+ m_state->SwitchToTx (txDuration, packet, GetPowerDbm (txVector.GetTxPowerLevel ()), txVector, preamble);
+ m_channel->Send (this, packet, GetPowerDbm (txVector.GetTxPowerLevel ()) + m_txGainDb, txVector, preamble, aMpdu, txDuration);
+}
+
+uint32_t
+YansWifiPhy::GetNModes (void) const
+{
+ return m_deviceRateSet.size ();
+}
+
+WifiMode
+YansWifiPhy::GetMode (uint32_t mode) const
+{
+ return m_deviceRateSet[mode];
+}
+
+bool
+YansWifiPhy::IsModeSupported (WifiMode mode) const
+{
+ for (uint32_t i = 0; i < GetNModes (); i++)
+ {
+ if (mode == GetMode (i))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+bool
+YansWifiPhy::IsMcsSupported (WifiMode mcs)
+{
+ for (uint32_t i = 0; i < GetNMcs (); i++)
+ {
+ if (mcs == GetMcs (i))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+uint32_t
+YansWifiPhy::GetNTxPower (void) const
+{
+ return m_nTxPower;
+}
+
+void
+YansWifiPhy::Configure80211a (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_channelStartingFrequency = 5e3; //5.000 GHz
+ SetChannelWidth (20); //20 MHz
+
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate6Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate9Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate12Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate18Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate24Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate36Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate48Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate54Mbps ());
+}
+
+void
+YansWifiPhy::Configure80211b (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_channelStartingFrequency = 2407; //2.407 GHz
+ SetChannelWidth (22); //22 MHz
+
+ m_deviceRateSet.push_back (WifiPhy::GetDsssRate1Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetDsssRate2Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetDsssRate5_5Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetDsssRate11Mbps ());
+}
+
+void
+YansWifiPhy::Configure80211g (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_channelStartingFrequency = 2407; //2.407 GHz
+ SetChannelWidth (20); //20 MHz
+
+ m_deviceRateSet.push_back (WifiPhy::GetDsssRate1Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetDsssRate2Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetDsssRate5_5Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetErpOfdmRate6Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetErpOfdmRate9Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetDsssRate11Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetErpOfdmRate12Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetErpOfdmRate18Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetErpOfdmRate24Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetErpOfdmRate36Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetErpOfdmRate48Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetErpOfdmRate54Mbps ());
+}
+
+void
+YansWifiPhy::Configure80211_10Mhz (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_channelStartingFrequency = 5e3; //5.000 GHz, suppose 802.11a
+ SetChannelWidth (10); //10 MHz
+
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate3MbpsBW10MHz ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate4_5MbpsBW10MHz ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate6MbpsBW10MHz ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate9MbpsBW10MHz ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate12MbpsBW10MHz ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate18MbpsBW10MHz ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate24MbpsBW10MHz ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate27MbpsBW10MHz ());
+}
+
+void
+YansWifiPhy::Configure80211_5Mhz (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_channelStartingFrequency = 5e3; //5.000 GHz, suppose 802.11a
+ SetChannelWidth (5); //5 MHz
+
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate1_5MbpsBW5MHz ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate2_25MbpsBW5MHz ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate3MbpsBW5MHz ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate4_5MbpsBW5MHz ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate6MbpsBW5MHz ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate9MbpsBW5MHz ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate12MbpsBW5MHz ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate13_5MbpsBW5MHz ());
+}
+
+void
+YansWifiPhy::ConfigureHolland (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_channelStartingFrequency = 5e3; //5.000 GHz
+ SetChannelWidth (20); //20 MHz
+
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate6Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate12Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate18Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate36Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate54Mbps ());
+}
+
+void
+YansWifiPhy::Configure80211n (void)
+{
+ NS_LOG_FUNCTION (this);
+ SetChannelWidth (20); //20 MHz
+ if (m_channelStartingFrequency >= 2400 && m_channelStartingFrequency <= 2500) //at 2.4 GHz
+ {
+ m_deviceRateSet.push_back (WifiPhy::GetDsssRate1Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetDsssRate2Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetDsssRate5_5Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetErpOfdmRate6Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetDsssRate11Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetErpOfdmRate12Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetErpOfdmRate24Mbps ());
+ }
+ if (m_channelStartingFrequency >= 5000 && m_channelStartingFrequency <= 6000) //at 5 GHz
+ {
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate6Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate12Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate24Mbps ());
+ }
+
+ m_deviceMcsSet.push_back (WifiPhy::GetHtMcs0 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetHtMcs1 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetHtMcs2 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetHtMcs3 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetHtMcs4 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetHtMcs5 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetHtMcs6 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetHtMcs7 ());
+
+ m_bssMembershipSelectorSet.push_back (HT_PHY);
+}
+
+void
+YansWifiPhy::Configure80211ac (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_channelStartingFrequency = 5e3; //5.000 GHz
+ SetChannelWidth (80); //80 MHz
+
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate6Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate12Mbps ());
+ m_deviceRateSet.push_back (WifiPhy::GetOfdmRate24Mbps ());
+
+ m_deviceMcsSet.push_back (WifiPhy::GetHtMcs0 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetHtMcs1 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetHtMcs2 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetHtMcs3 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetHtMcs4 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetHtMcs5 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetHtMcs6 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetHtMcs7 ());
+
+ m_deviceMcsSet.push_back (WifiPhy::GetVhtMcs0 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetVhtMcs1 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetVhtMcs2 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetVhtMcs3 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetVhtMcs4 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetVhtMcs5 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetVhtMcs6 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetVhtMcs7 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetVhtMcs8 ());
+ m_deviceMcsSet.push_back (WifiPhy::GetVhtMcs9 ());
+
+ m_bssMembershipSelectorSet.push_back (VHT_PHY);
+}
+
+void
+YansWifiPhy::RegisterListener (WifiPhyListener *listener)
+{
+ m_state->RegisterListener (listener);
+}
+
+void
+YansWifiPhy::UnregisterListener (WifiPhyListener *listener)
+{
+ m_state->UnregisterListener (listener);
+}
+
+bool
+YansWifiPhy::IsStateCcaBusy (void)
+{
+ return m_state->IsStateCcaBusy ();
+}
+
+bool
+YansWifiPhy::IsStateIdle (void)
+{
+ return m_state->IsStateIdle ();
+}
+
+bool
+YansWifiPhy::IsStateBusy (void)
+{
+ return m_state->IsStateBusy ();
+}
+
+bool
+YansWifiPhy::IsStateRx (void)
+{
+ return m_state->IsStateRx ();
+}
+
+bool
+YansWifiPhy::IsStateTx (void)
+{
+ return m_state->IsStateTx ();
+}
+
+bool
+YansWifiPhy::IsStateSwitching (void)
+{
+ return m_state->IsStateSwitching ();
+}
+
+bool
+YansWifiPhy::IsStateSleep (void)
+{
+ return m_state->IsStateSleep ();
+}
+
+Time
+YansWifiPhy::GetStateDuration (void)
+{
+ return m_state->GetStateDuration ();
+}
+
+Time
+YansWifiPhy::GetDelayUntilIdle (void)
+{
+ return m_state->GetDelayUntilIdle ();
+}
+
+Time
+YansWifiPhy::GetLastRxStartTime (void) const
+{
+ return m_state->GetLastRxStartTime ();
+}
+
+double
+YansWifiPhy::DbToRatio (double dB) const
+{
+ double ratio = std::pow (10.0, dB / 10.0);
+ return ratio;
+}
+
+double
+YansWifiPhy::DbmToW (double dBm) const
+{
+ double mW = std::pow (10.0, dBm / 10.0);
+ return mW / 1000.0;
+}
+
+double
+YansWifiPhy::WToDbm (double w) const
+{
+ return 10.0 * std::log10 (w * 1000.0);
+}
+
+double
+YansWifiPhy::RatioToDb (double ratio) const
+{
+ return 10.0 * std::log10 (ratio);
+}
+
+double
+YansWifiPhy::GetEdThresholdW (void) const
+{
+ return m_edThresholdW;
+}
+
+double
+YansWifiPhy::GetPowerDbm (uint8_t power) const
+{
+ NS_ASSERT (m_txPowerBaseDbm <= m_txPowerEndDbm);
+ NS_ASSERT (m_nTxPower > 0);
+ double dbm;
+ if (m_nTxPower > 1)
+ {
+ dbm = m_txPowerBaseDbm + power * (m_txPowerEndDbm - m_txPowerBaseDbm) / (m_nTxPower - 1);
+ }
+ else
+ {
+ NS_ASSERT_MSG (m_txPowerBaseDbm == m_txPowerEndDbm, "cannot have TxPowerEnd != TxPowerStart with TxPowerLevels == 1");
+ dbm = m_txPowerBaseDbm;
+ }
+ return dbm;
+}
+
+void
+YansWifiPhy::EndReceive (Ptr<Packet> packet, enum WifiPreamble preamble, struct mpduInfo aMpdu, Ptr<InterferenceHelper::Event> event)
+{
+ NS_LOG_FUNCTION (this << packet << event);
+ NS_ASSERT (IsStateRx ());
+ NS_ASSERT (event->GetEndTime () == Simulator::Now ());
+
+ struct InterferenceHelper::SnrPer snrPer;
+ snrPer = m_interference.CalculatePlcpPayloadSnrPer (event);
+ m_interference.NotifyRxEnd ();
+
+ if (m_plcpSuccess == true)
+ {
+ NS_LOG_DEBUG ("mode=" << (event->GetPayloadMode ().GetDataRate (event->GetTxVector ().GetChannelWidth (), event->GetTxVector ().IsShortGuardInterval (), 1)) <<
+ ", snr(dB)=" << RatioToDb (snrPer.snr) << ", per=" << snrPer.per << ", size=" << packet->GetSize ());
+
+ //*******added for RSSI tag*********
+ RssiTag tag; // The tag that I defined. It holds signal RSSI
+ double rssi = event->GetRxPowerW (); // +30 to convert dBW to dBm
+ tag.Set(rssi);
+ packet->RemovePacketTag (tag);
+ packet->AddPacketTag (tag);
+ //***************end*************
+
+
+ if (m_random->GetValue () > snrPer.per)
+ {
+ NotifyRxEnd (packet);
+ uint32_t dataRate500KbpsUnits;
+ if ((event->GetPayloadMode ().GetModulationClass () == WIFI_MOD_CLASS_HT) || (event->GetPayloadMode ().GetModulationClass () == WIFI_MOD_CLASS_VHT))
+ {
+ dataRate500KbpsUnits = 128 + event->GetPayloadMode ().GetMcsValue ();
+ }
+ else
+ {
+ dataRate500KbpsUnits = event->GetPayloadMode ().GetDataRate (event->GetTxVector ().GetChannelWidth (), event->GetTxVector ().IsShortGuardInterval (), 1) * event->GetTxVector ().GetNss () / 500000;
+ }
+ struct signalNoiseDbm signalNoise;
+ signalNoise.signal = RatioToDb (event->GetRxPowerW ()) + 30;
+ signalNoise.noise = RatioToDb (event->GetRxPowerW () / snrPer.snr) - GetRxNoiseFigure () + 30;
+ NotifyMonitorSniffRx (packet, (uint16_t)GetChannelFrequencyMhz (), GetChannelNumber (), dataRate500KbpsUnits, event->GetPreambleType (), event->GetTxVector (), aMpdu, signalNoise);
+ m_state->SwitchFromRxEndOk (packet, snrPer.snr, event->GetTxVector (), event->GetPreambleType ());
+ }
+ else
+ {
+ /* failure. */
+ NotifyRxDrop (packet);
+ m_state->SwitchFromRxEndError (packet, snrPer.snr);
+ }
+ }
+ else
+ {
+ m_state->SwitchFromRxEndError (packet, snrPer.snr);
+ }
+
+ if (preamble == WIFI_PREAMBLE_NONE && aMpdu.packetType == 2)
+ {
+ m_plcpSuccess = false;
+ }
+}
+
+int64_t
+YansWifiPhy::AssignStreams (int64_t stream)
+{
+ NS_LOG_FUNCTION (this << stream);
+ m_random->SetStream (stream);
+ return 1;
+}
+
+void
+YansWifiPhy::SetFrequency (uint32_t freq)
+{
+ m_channelStartingFrequency = freq;
+}
+
+void
+YansWifiPhy::SetNumberOfTransmitAntennas (uint32_t tx)
+{
+ m_numberOfTransmitters = tx;
+}
+
+void
+YansWifiPhy::SetNumberOfReceiveAntennas (uint32_t rx)
+{
+ m_numberOfReceivers = rx;
+}
+
+void
+YansWifiPhy::SetLdpc (bool Ldpc)
+{
+ m_ldpc = Ldpc;
+}
+
+void
+YansWifiPhy::SetStbc (bool stbc)
+{
+ m_stbc = stbc;
+}
+
+void
+YansWifiPhy::SetGreenfield (bool greenfield)
+{
+ m_greenfield = greenfield;
+}
+
+bool
+YansWifiPhy::GetGuardInterval (void) const
+{
+ return m_guardInterval;
+}
+
+void
+YansWifiPhy::SetGuardInterval (bool guardInterval)
+{
+ m_guardInterval = guardInterval;
+}
+
+uint32_t
+YansWifiPhy::GetFrequency (void) const
+{
+ return m_channelStartingFrequency;
+}
+
+uint32_t
+YansWifiPhy::GetNumberOfTransmitAntennas (void) const
+{
+ return m_numberOfTransmitters;
+}
+
+uint32_t
+YansWifiPhy::GetNumberOfReceiveAntennas (void) const
+{
+ return m_numberOfReceivers;
+}
+
+bool
+YansWifiPhy::GetLdpc (void) const
+{
+ return m_ldpc;
+}
+
+bool
+YansWifiPhy::GetStbc (void) const
+{
+ return m_stbc;
+}
+
+bool
+YansWifiPhy::GetGreenfield (void) const
+{
+ return m_greenfield;
+}
+
+void
+YansWifiPhy::SetChannelWidth (uint32_t channelwidth)
+{
+ NS_ASSERT_MSG (channelwidth == 5 || channelwidth == 10 || channelwidth == 20 || channelwidth == 22 || channelwidth == 40 || channelwidth == 80 || channelwidth == 160, "wrong channel width value");
+ m_channelWidth = channelwidth;
+}
+
+uint32_t
+YansWifiPhy::GetChannelWidth (void) const
+{
+ return m_channelWidth;
+}
+
+uint32_t
+YansWifiPhy::GetNBssMembershipSelectors (void) const
+{
+ return m_bssMembershipSelectorSet.size ();
+}
+
+uint32_t
+YansWifiPhy::GetBssMembershipSelector (uint32_t selector) const
+{
+ return m_bssMembershipSelectorSet[selector];
+}
+
+WifiModeList
+YansWifiPhy::GetMembershipSelectorModes (uint32_t selector)
+{
+ uint32_t id = GetBssMembershipSelector (selector);
+ WifiModeList supportedmodes;
+ if (id == HT_PHY || id == VHT_PHY)
+ {
+ //mandatory MCS 0 to 7
+ supportedmodes.push_back (WifiPhy::GetHtMcs0 ());
+ supportedmodes.push_back (WifiPhy::GetHtMcs1 ());
+ supportedmodes.push_back (WifiPhy::GetHtMcs2 ());
+ supportedmodes.push_back (WifiPhy::GetHtMcs3 ());
+ supportedmodes.push_back (WifiPhy::GetHtMcs4 ());
+ supportedmodes.push_back (WifiPhy::GetHtMcs5 ());
+ supportedmodes.push_back (WifiPhy::GetHtMcs6 ());
+ supportedmodes.push_back (WifiPhy::GetHtMcs7 ());
+ }
+ if (id == VHT_PHY)
+ {
+ //mandatory MCS 0 to 9
+ supportedmodes.push_back (WifiPhy::GetVhtMcs0 ());
+ supportedmodes.push_back (WifiPhy::GetVhtMcs1 ());
+ supportedmodes.push_back (WifiPhy::GetVhtMcs2 ());
+ supportedmodes.push_back (WifiPhy::GetVhtMcs3 ());
+ supportedmodes.push_back (WifiPhy::GetVhtMcs4 ());
+ supportedmodes.push_back (WifiPhy::GetVhtMcs5 ());
+ supportedmodes.push_back (WifiPhy::GetVhtMcs6 ());
+ supportedmodes.push_back (WifiPhy::GetVhtMcs7 ());
+ supportedmodes.push_back (WifiPhy::GetVhtMcs8 ());
+ supportedmodes.push_back (WifiPhy::GetVhtMcs9 ());
+ }
+ return supportedmodes;
+}
+
+uint8_t
+YansWifiPhy::GetNMcs (void) const
+{
+ return m_deviceMcsSet.size ();
+}
+
+WifiMode
+YansWifiPhy::GetMcs (uint8_t mcs) const
+{
+ return m_deviceMcsSet[mcs];
+}
+
+} //namespace ns3
diff --git a/emu-radio/ns3-patch/wifi/model/yans-wifi-phy.h b/emu-radio/ns3-patch/wifi/model/yans-wifi-phy.h
new file mode 100644
index 00000000..5becc1e7
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/yans-wifi-phy.h
@@ -0,0 +1,615 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005,2006 INRIA
+ *
+ * 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
+ *
+ * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Ghada Badawy <gbadawy@gmail.com>
+ * Sébastien Deronne <sebastien.deronne@gmail.com>
+ */
+
+#ifndef YANS_WIFI_PHY_H
+#define YANS_WIFI_PHY_H
+
+#include <stdint.h>
+#include "ns3/callback.h"
+#include "ns3/event-id.h"
+#include "ns3/packet.h"
+#include "ns3/object.h"
+#include "ns3/traced-callback.h"
+#include "ns3/nstime.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable-stream.h"
+#include "ns3/mobility-model.h"
+#include "wifi-phy.h"
+#include "wifi-mode.h"
+#include "wifi-preamble.h"
+#include "wifi-phy-standard.h"
+#include "interference-helper.h"
+
+//****for new tags*********
+#include "ns3/snr-tag.h"
+
+
+namespace ns3 {
+
+#define VHT_PHY 126
+#define HT_PHY 127
+
+class YansWifiChannel;
+class WifiPhyStateHelper;
+
+/**
+ * @brief tags for RSSI
+ */
+
+class RssiTag : public SnrTag
+{
+public:
+ static TypeId GetTypeId (void);
+
+ virtual TypeId GetInstanceTypeId (void) const;
+ /**
+ * Create a SnrTag with the default snr 0
+ */
+ RssiTag ();
+
+ /**
+ * Create a SnrTag with the given snr value
+ * \param snr the given SNR value
+ */
+ RssiTag (double snr);
+};
+
+
+
+
+/**
+ * \brief 802.11 PHY layer model
+ * \ingroup wifi
+ *
+ * This PHY implements a model of 802.11a. The model
+ * implemented here is based on the model described
+ * in "Yet Another Network Simulator",
+ * (http://cutebugs.net/files/wns2-yans.pdf).
+ *
+ *
+ * This PHY model depends on a channel loss and delay
+ * model as provided by the ns3::PropagationLossModel
+ * and ns3::PropagationDelayModel classes, both of which are
+ * members of the ns3::YansWifiChannel class.
+ */
+class YansWifiPhy : public WifiPhy
+{
+public:
+ static TypeId GetTypeId (void);
+
+ YansWifiPhy ();
+ virtual ~YansWifiPhy ();
+
+ /**
+ * Set the YansWifiChannel this YansWifiPhy is to be connected to.
+ *
+ * \param channel the YansWifiChannel this YansWifiPhy is to be connected to
+ */
+ void SetChannel (Ptr<YansWifiChannel> channel);
+ /**
+ * Set the current channel number.
+ *
+ * \param id the channel number
+ */
+ void SetChannelNumber (uint16_t id);
+ /**
+ * Return the current channel number.
+ *
+ * \return the current channel number
+ */
+ uint16_t GetChannelNumber (void) const;
+ /**
+ * \return the required time for channel switch operation of this WifiPhy
+ */
+ Time GetChannelSwitchDelay (void) const;
+ /**
+ * Return current center channel frequency in MHz.
+ *
+ * \return the current center channel frequency in MHz
+ */
+ double GetChannelFrequencyMhz () const;
+
+ /**
+ * Starting receiving the plcp of a packet (i.e. the first bit of the preamble has arrived).
+ *
+ * \param packet the arriving packet
+ * \param rxPowerDbm the receive power in dBm
+ * \param txVector the TXVECTOR of the arriving packet
+ * \param preamble the preamble of the arriving packet
+ * \param aMpdu the type of the packet (0 is not A-MPDU, 1 is a MPDU that is part of an A-MPDU and 2 is the last MPDU in an A-MPDU)
+ * and the A-MPDU reference number (must be a different value for each A-MPDU but the same for each subframe within one A-MPDU)
+ * \param rxDuration the duration needed for the reception of the packet
+ */
+ void StartReceivePreambleAndHeader (Ptr<Packet> packet,
+ double rxPowerDbm,
+ WifiTxVector txVector,
+ WifiPreamble preamble,
+ struct mpduInfo aMpdu,
+ Time rxDuration);
+ /**
+ * Starting receiving the payload of a packet (i.e. the first bit of the packet has arrived).
+ *
+ * \param packet the arriving packet
+ * \param txVector the TXVECTOR of the arriving packet
+ * \param preamble the preamble of the arriving packet
+ * \param aMpdu the type of the packet (0 is not A-MPDU, 1 is a MPDU that is part of an A-MPDU and 2 is the last MPDU in an A-MPDU)
+ * and the A-MPDU reference number (must be a different value for each A-MPDU but the same for each subframe within one A-MPDU)
+ * \param event the corresponding event of the first time the packet arrives
+ */
+ void StartReceivePacket (Ptr<Packet> packet,
+ WifiTxVector txVector,
+ WifiPreamble preamble,
+ struct mpduInfo aMpdu,
+ Ptr<InterferenceHelper::Event> event);
+
+ /**
+ * Sets the RX loss (dB) in the Signal-to-Noise-Ratio due to non-idealities in the receiver.
+ *
+ * \param noiseFigureDb noise figure in dB
+ */
+ void SetRxNoiseFigure (double noiseFigureDb);
+ /**
+ * Sets the minimum available transmission power level (dBm).
+ *
+ * \param start the minimum transmission power level (dBm)
+ */
+ void SetTxPowerStart (double start);
+ /**
+ * Sets the maximum available transmission power level (dBm).
+ *
+ * \param end the maximum transmission power level (dBm)
+ */
+ void SetTxPowerEnd (double end);
+ /**
+ * Sets the number of transmission power levels available between the
+ * minimum level and the maximum level. Transmission power levels are
+ * equally separated (in dBm) with the minimum and the maximum included.
+ *
+ * \param n the number of available levels
+ */
+ void SetNTxPower (uint32_t n);
+ /**
+ * Sets the transmission gain (dB).
+ *
+ * \param gain the transmission gain in dB
+ */
+ void SetTxGain (double gain);
+ /**
+ * Sets the reception gain (dB).
+ *
+ * \param gain the reception gain in dB
+ */
+ void SetRxGain (double gain);
+ /**
+ * Sets the energy detection threshold (dBm).
+ * The energy of a received signal should be higher than
+ * this threshold (dbm) to allow the PHY layer to detect the signal.
+ *
+ * \param threshold the energy detction threshold in dBm
+ */
+ void SetEdThreshold (double threshold);
+ /**
+ * Sets the CCA threshold (dBm). The energy of a received signal
+ * should be higher than this threshold to allow the PHY
+ * layer to declare CCA BUSY state.
+ *
+ * \param threshold the CCA threshold in dBm
+ */
+ void SetCcaMode1Threshold (double threshold);
+ /**
+ * Sets the error rate model.
+ *
+ * \param rate the error rate model
+ */
+ void SetErrorRateModel (Ptr<ErrorRateModel> rate);
+ /**
+ * Sets the device this PHY is associated with.
+ *
+ * \param device the device this PHY is associated with
+ */
+ void SetDevice (Ptr<NetDevice> device);
+ /**
+ * \brief assign a mobility model to this device
+ *
+ * This method allows a user to specify a mobility model that should be
+ * associated with this physical layer. Calling this method is optional
+ * and only necessary if the user wants to override the mobility model
+ * that is aggregated to the node.
+ *
+ * \param mobility the mobility model this PHY is associated with
+ */
+ void SetMobility (Ptr<MobilityModel> mobility);
+ /**
+ * Return the RX noise figure (dBm).
+ *
+ * \return the RX noise figure in dBm
+ */
+ double GetRxNoiseFigure (void) const;
+ /**
+ * Return the transmission gain (dB).
+ *
+ * \return the transmission gain in dB
+ */
+ double GetTxGain (void) const;
+ /**
+ * Return the reception gain (dB).
+ *
+ * \return the reception gain in dB
+ */
+ double GetRxGain (void) const;
+ /**
+ * Return the energy detection threshold (dBm).
+ *
+ * \return the energy detection threshold in dBm
+ */
+ double GetEdThreshold (void) const;
+ /**
+ * Return the CCA threshold (dBm).
+ *
+ * \return the CCA threshold in dBm
+ */
+ double GetCcaMode1Threshold (void) const;
+ /**
+ * Return the error rate model this PHY is using.
+ *
+ * \return the error rate model this PHY is using
+ */
+ Ptr<ErrorRateModel> GetErrorRateModel (void) const;
+ /**
+ * Return the device this PHY is associated with
+ *
+ * \return the device this PHY is associated with
+ */
+ Ptr<NetDevice> GetDevice (void) const;
+ /**
+ * Return the mobility model this PHY is associated with.
+ * This method will return either the mobility model that has been
+ * explicitly set by a call to YansWifiPhy::SetMobility(), or else
+ * will return the mobility model (if any) that has been aggregated
+ * to the node.
+ *
+ * \return the mobility model this PHY is associated with
+ */
+ Ptr<MobilityModel> GetMobility (void);
+ /**
+ * Return the minimum available transmission power level (dBm).
+ * \return the minimum available transmission power level (dBm)
+ */
+ virtual double GetTxPowerStart (void) const;
+ /**
+ * Return the maximum available transmission power level (dBm).
+ * \return the maximum available transmission power level (dBm)
+ */
+ virtual double GetTxPowerEnd (void) const;
+ /**
+ * Return the number of available transmission power levels.
+ *
+ * \return the number of available transmission power levels
+ */
+ virtual uint32_t GetNTxPower (void) const;
+
+ virtual void SetReceiveOkCallback (WifiPhy::RxOkCallback callback);
+ virtual void SetReceiveErrorCallback (WifiPhy::RxErrorCallback callback);
+ virtual void SendPacket (Ptr<const Packet> packet, WifiTxVector txVector, enum WifiPreamble preamble, uint8_t packetType, uint32_t mpduReferenceNumber);
+ virtual void RegisterListener (WifiPhyListener *listener);
+ virtual void UnregisterListener (WifiPhyListener *listener);
+ virtual void SetSleepMode (void);
+ virtual void ResumeFromSleep (void);
+ virtual bool IsStateCcaBusy (void);
+ virtual bool IsStateIdle (void);
+ virtual bool IsStateBusy (void);
+ virtual bool IsStateRx (void);
+ virtual bool IsStateTx (void);
+ virtual bool IsStateSwitching (void);
+ virtual bool IsStateSleep (void);
+ virtual Time GetStateDuration (void);
+ virtual Time GetDelayUntilIdle (void);
+ virtual Time GetLastRxStartTime (void) const;
+ virtual uint32_t GetNModes (void) const;
+ virtual WifiMode GetMode (uint32_t mode) const;
+ virtual bool IsModeSupported (WifiMode mode) const;
+ virtual bool IsMcsSupported (WifiMode mcs);
+ virtual double CalculateSnr (WifiMode txMode, double ber) const;
+ virtual Ptr<WifiChannel> GetChannel (void) const;
+
+ virtual void ConfigureStandard (enum WifiPhyStandard standard);
+
+ /**
+ * Assign a fixed random variable stream number to the random variables
+ * used by this model. Return the number of streams (possibly zero) that
+ * have been assigned.
+ *
+ * \param stream first stream index to use
+ * \return the number of stream indices assigned by this model
+ */
+ int64_t AssignStreams (int64_t stream);
+
+ /**
+ * \param freq the operating frequency on this node (2.4 GHz or 5GHz).
+ */
+ virtual void SetFrequency (uint32_t freq);
+ /**
+ * \return the operating frequency on this node
+ */
+ virtual uint32_t GetFrequency (void) const;
+ /**
+ * \param tx the number of transmitters on this node.
+ */
+ virtual void SetNumberOfTransmitAntennas (uint32_t tx);
+ /**
+ * \return the number of transmitters on this node.
+ */
+ virtual uint32_t GetNumberOfTransmitAntennas (void) const;
+ /**
+ * \param rx the number of receivers on this node.
+ */
+ virtual void SetNumberOfReceiveAntennas (uint32_t rx);
+ /**
+ * \return the number of receivers on this node.
+ */
+ virtual uint32_t GetNumberOfReceiveAntennas (void) const;
+ /**
+ * Enable or disable short/long guard interval.
+ *
+ * \param guardInterval Enable or disable guard interval
+ */
+ virtual void SetGuardInterval (bool guardInterval);
+ /**
+ * Return whether guard interval is being used.
+ *
+ * \return true if guard interval is being used, false otherwise
+ */
+ virtual bool GetGuardInterval (void) const;
+ /**
+ * Enable or disable LDPC.
+ * \param ldpc Enable or disable LDPC
+ */
+ virtual void SetLdpc (bool ldpc);
+ /**
+ * Return if LDPC is supported.
+ *
+ * \return true if LDPC is supported, false otherwise
+ */
+ virtual bool GetLdpc (void) const;
+ /**
+ * Enable or disable STBC.
+ *
+ * \param stbc Enable or disable STBC
+ */
+ virtual void SetStbc (bool stbc);
+ /**
+ * Return whether STBC is supported.
+ *
+ * \return true if STBC is supported, false otherwise
+ */
+ virtual bool GetStbc (void) const;
+ /**
+ * Enable or disable Greenfield support.
+ *
+ * \param greenfield Enable or disable Greenfield
+ */
+ virtual void SetGreenfield (bool greenfield);
+ /**
+ * Return whether Greenfield is supported.
+ *
+ * \return true if Greenfield is supported, false otherwise
+ */
+ virtual bool GetGreenfield (void) const;
+ /**
+ * Return channel width.
+ *
+ * \return channel width
+ */
+ virtual uint32_t GetChannelWidth (void) const;
+ /**
+ * Set channel width.
+ *
+ * \param channel width
+ */
+ virtual void SetChannelWidth (uint32_t channelwidth);
+
+ virtual uint32_t GetNBssMembershipSelectors (void) const;
+ virtual uint32_t GetBssMembershipSelector (uint32_t selector) const;
+ virtual WifiModeList GetMembershipSelectorModes (uint32_t selector);
+
+ /**
+ * \return the number of MCS supported by this phy
+ */
+ virtual uint8_t GetNMcs (void) const;
+ virtual WifiMode GetMcs (uint8_t mcs) const;
+
+private:
+ virtual void DoInitialize (void);
+ virtual void DoDispose (void);
+
+ /**
+ * Configure YansWifiPhy with appropriate channel frequency and
+ * supported rates for 802.11a standard.
+ */
+ void Configure80211a (void);
+ /**
+ * Configure YansWifiPhy with appropriate channel frequency and
+ * supported rates for 802.11b standard.
+ */
+ void Configure80211b (void);
+ /**
+ * Configure YansWifiPhy with appropriate channel frequency and
+ * supported rates for 802.11g standard.
+ */
+ void Configure80211g (void);
+ /**
+ * Configure YansWifiPhy with appropriate channel frequency and
+ * supported rates for 802.11a standard with 10MHz channel spacing.
+ */
+ void Configure80211_10Mhz (void);
+ /**
+ * Configure YansWifiPhy with appropriate channel frequency and
+ * supported rates for 802.11a standard with 5MHz channel spacing.
+ */
+ void Configure80211_5Mhz ();
+ void ConfigureHolland (void);
+ /**
+ * Configure YansWifiPhy with appropriate channel frequency and
+ * supported rates for 802.11n standard.
+ */
+ void Configure80211n (void);
+ /**
+ * Configure YansWifiPhy with appropriate channel frequency and
+ * supported rates for 802.11ac standard.
+ */
+ void Configure80211ac (void);
+ /**
+ * Return the energy detection threshold.
+ *
+ * \return the energy detection threshold.
+ */
+ double GetEdThresholdW (void) const;
+ /**
+ * Convert from dBm to Watts.
+ *
+ * \param dbm the power in dBm
+ *
+ * \return the equivalent Watts for the given dBm
+ */
+ double DbmToW (double dbm) const;
+ /**
+ * Convert from dB to ratio.
+ *
+ * \param db
+ *
+ * \return ratio
+ */
+ double DbToRatio (double db) const;
+ /**
+ * Convert from Watts to dBm.
+ *
+ * \param w the power in Watts
+ *
+ * \return the equivalent dBm for the given Watts
+ */
+ double WToDbm (double w) const;
+ /**
+ * Convert from ratio to dB.
+ *
+ * \param ratio
+ *
+ * \return dB
+ */
+ double RatioToDb (double ratio) const;
+ /**
+ * Get the power of the given power level in dBm.
+ * In YansWifiPhy implementation, the power levels are equally spaced (in dBm).
+ *
+ * \param power the power level
+ *
+ * \return the transmission power in dBm at the given power level
+ */
+ double GetPowerDbm (uint8_t power) const;
+ /**
+ * The last bit of the packet has arrived.
+ *
+ * \param packet the packet that the last bit has arrived
+ * \param preamble the preamble of the arriving packet
+ * \param aMpdu the type of the packet (0 is not A-MPDU, 1 is a MPDU that is part of an A-MPDU and 2 is the last MPDU in an A-MPDU)
+ * and the A-MPDU reference number (must be a different value for each A-MPDU but the same for each subframe within one A-MPDU)
+ * \param event the corresponding event of the first time the packet arrives
+ */
+ void EndReceive (Ptr<Packet> packet, enum WifiPreamble preamble, struct mpduInfo aMpdu, Ptr<InterferenceHelper::Event> event);
+
+ bool m_initialized; //!< Flag for runtime initialization
+ double m_edThresholdW; //!< Energy detection threshold in watts
+ double m_ccaMode1ThresholdW; //!< Clear channel assessment (CCA) threshold in watts
+ double m_txGainDb; //!< Transmission gain (dB)
+ double m_rxGainDb; //!< Reception gain (dB)
+ double m_txPowerBaseDbm; //!< Minimum transmission power (dBm)
+ double m_txPowerEndDbm; //!< Maximum transmission power (dBm)
+ uint32_t m_nTxPower; //!< Number of available transmission power levels
+
+ Ptr<YansWifiChannel> m_channel; //!< YansWifiChannel that this YansWifiPhy is connected to
+ uint16_t m_channelNumber; //!< Operating channel number
+ Ptr<NetDevice> m_device; //!< Pointer to the device
+ Ptr<MobilityModel> m_mobility; //!< Pointer to the mobility model
+
+ uint32_t m_numberOfTransmitters; //!< Number of transmitters
+ uint32_t m_numberOfReceivers; //!< Number of receivers
+ bool m_ldpc; //!< Flag if LDPC is used
+ bool m_stbc; //!< Flag if STBC is used
+ bool m_greenfield; //!< Flag if GreenField format is supported
+ bool m_guardInterval; //!< Flag if short guard interval is used
+ uint32_t m_channelWidth; //!< Channel width
+
+
+ /**
+ * This vector holds the set of transmission modes that this
+ * WifiPhy(-derived class) can support. In conversation we call this
+ * the DeviceRateSet (not a term you'll find in the standard), and
+ * it is a superset of standard-defined parameters such as the
+ * OperationalRateSet, and the BSSBasicRateSet (which, themselves,
+ * have a superset/subset relationship).
+ *
+ * Mandatory rates relevant to this WifiPhy can be found by
+ * iterating over this vector looking for WifiMode objects for which
+ * WifiMode::IsMandatory() is true.
+ *
+ * A quick note is appropriate here (well, here is as good a place
+ * as any I can find)...
+ *
+ * In the standard there is no text that explicitly precludes
+ * production of a device that does not support some rates that are
+ * mandatory (according to the standard) for PHYs that the device
+ * happens to fully or partially support.
+ *
+ * This approach is taken by some devices which choose to only support,
+ * for example, 6 and 9 Mbps ERP-OFDM rates for cost and power
+ * consumption reasons (i.e., these devices don't need to be designed
+ * for and waste current on the increased linearity requirement of
+ * higher-order constellations when 6 and 9 Mbps more than meet their
+ * data requirements). The wording of the standard allows such devices
+ * to have an OperationalRateSet which includes 6 and 9 Mbps ERP-OFDM
+ * rates, despite 12 and 24 Mbps being "mandatory" rates for the
+ * ERP-OFDM PHY.
+ *
+ * Now this doesn't actually have any impact on code, yet. It is,
+ * however, something that we need to keep in mind for the
+ * future. Basically, the key point is that we can't be making
+ * assumptions like "the Operational Rate Set will contain all the
+ * mandatory rates".
+ */
+ WifiModeList m_deviceRateSet;
+ WifiModeList m_deviceMcsSet;
+
+ std::vector<uint32_t> m_bssMembershipSelectorSet;
+ EventId m_endRxEvent;
+ EventId m_endPlcpRxEvent;
+
+ Ptr<UniformRandomVariable> m_random; //!< Provides uniform random variables.
+ double m_channelStartingFrequency; //!< Standard-dependent center frequency of 0-th channel in MHz
+ Ptr<WifiPhyStateHelper> m_state; //!< Pointer to WifiPhyStateHelper
+ InterferenceHelper m_interference; //!< Pointer to InterferenceHelper
+ Time m_channelSwitchDelay; //!< Time required to switch between channel
+ uint16_t m_mpdusNum; //!< carries the number of expected mpdus that are part of an A-MPDU
+ bool m_plcpSuccess; //!< Flag if the PLCP of the packet or the first MPDU in an A-MPDU has been received
+};
+
+} //namespace ns3
+
+#endif /* YANS_WIFI_PHY_H */
diff --git a/emu-radio/ns3-patch/wifi/wscript b/emu-radio/ns3-patch/wifi/wscript
new file mode 100644
index 00000000..810f577a
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/wscript
@@ -0,0 +1,187 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+ obj = bld.create_ns3_module('wifi', ['network', 'internet', 'applications', 'propagation', 'energy'])
+ obj.source = [
+ 'model/ap-info-collection.cc',
+ 'model/wifi-information-element.cc',
+ 'model/wifi-information-element-vector.cc',
+ 'model/wifi-channel.cc',
+ 'model/wifi-mode.cc',
+ 'model/ssid.cc',
+ 'model/wifi-phy.cc',
+ 'model/wifi-phy-state-helper.cc',
+ 'model/error-rate-model.cc',
+ 'model/yans-error-rate-model.cc',
+ 'model/nist-error-rate-model.cc',
+ 'model/dsss-error-rate-model.cc',
+ 'model/interference-helper.cc',
+ 'model/yans-wifi-phy.cc',
+ 'model/yans-wifi-channel.cc',
+ 'model/wifi-mac-header.cc',
+ 'model/wifi-mac-trailer.cc',
+ 'model/mac-low.cc',
+ 'model/wifi-mac-queue.cc',
+ 'model/mac-tx-middle.cc',
+ 'model/mac-rx-middle.cc',
+ 'model/dca-txop.cc',
+ 'model/supported-rates.cc',
+ 'model/capability-information.cc',
+ 'model/status-code.cc',
+ 'model/mgt-headers.cc',
+ 'model/random-stream.cc',
+ 'model/dcf-manager.cc',
+ 'model/wifi-mac.cc',
+ 'model/regular-wifi-mac.cc',
+ 'model/wifi-remote-station-manager.cc',
+ 'model/ap-wifi-mac.cc',
+ 'model/sta-wifi-mac.cc',
+ 'model/adhoc-wifi-mac.cc',
+ 'model/wifi-net-device.cc',
+ 'model/arf-wifi-manager.cc',
+ 'model/aarf-wifi-manager.cc',
+ 'model/ideal-wifi-manager.cc',
+ 'model/constant-rate-wifi-manager.cc',
+ 'model/amrr-wifi-manager.cc',
+ 'model/onoe-wifi-manager.cc',
+ 'model/rraa-wifi-manager.cc',
+ 'model/aarfcd-wifi-manager.cc',
+ 'model/cara-wifi-manager.cc',
+ 'model/minstrel-wifi-manager.cc',
+ 'model/qos-tag.cc',
+ 'model/qos-utils.cc',
+ 'model/edca-txop-n.cc',
+ 'model/msdu-aggregator.cc',
+ 'model/amsdu-subframe-header.cc',
+ 'model/msdu-standard-aggregator.cc',
+ 'model/originator-block-ack-agreement.cc',
+ 'model/dcf.cc',
+ 'model/ctrl-headers.cc',
+ 'model/qos-blocked-destinations.cc',
+ 'model/block-ack-agreement.cc',
+ 'model/block-ack-manager.cc',
+ 'model/block-ack-cache.cc',
+ 'model/snr-tag.cc',
+ 'model/ht-capabilities.cc',
+ 'model/wifi-tx-vector.cc',
+ 'model/parf-wifi-manager.cc',
+ 'model/aparf-wifi-manager.cc',
+ 'model/ampdu-subframe-header.cc',
+ 'model/mpdu-aggregator.cc',
+ 'model/mpdu-standard-aggregator.cc',
+ 'model/ampdu-tag.cc',
+ 'model/minstrel-ht-wifi-manager.cc',
+ 'model/wifi-radio-energy-model.cc',
+ 'model/wifi-tx-current-model.cc',
+ 'model/vht-capabilities.cc',
+ 'helper/wifi-radio-energy-model-helper.cc',
+ 'helper/vht-wifi-mac-helper.cc',
+ 'helper/ht-wifi-mac-helper.cc',
+ 'helper/athstats-helper.cc',
+ 'helper/wifi-helper.cc',
+ 'helper/yans-wifi-helper.cc',
+ 'helper/nqos-wifi-mac-helper.cc',
+ 'helper/qos-wifi-mac-helper.cc',
+ ]
+
+ obj_test = bld.create_ns3_module_test_library('wifi')
+ obj_test.source = [
+ 'test/block-ack-test-suite.cc',
+ 'test/dcf-manager-test.cc',
+ 'test/tx-duration-test.cc',
+ 'test/power-rate-adaptation-test.cc',
+ 'test/wifi-test.cc',
+ 'test/wifi-aggregation-test.cc',
+ ]
+
+ headers = bld(features='ns3header')
+ headers.module = 'wifi'
+ headers.source = [
+ 'model/ap-info-collection.h',
+ 'model/wifi-information-element.h',
+ 'model/wifi-information-element-vector.h',
+ 'model/wifi-net-device.h',
+ 'model/wifi-channel.h',
+ 'model/wifi-mode.h',
+ 'model/ssid.h',
+ 'model/wifi-preamble.h',
+ 'model/wifi-phy-standard.h',
+ 'model/yans-wifi-phy.h',
+ 'model/yans-wifi-channel.h',
+ 'model/wifi-phy.h',
+ 'model/interference-helper.h',
+ 'model/wifi-remote-station-manager.h',
+ 'model/ap-wifi-mac.h',
+ 'model/sta-wifi-mac.h',
+ 'model/adhoc-wifi-mac.h',
+ 'model/arf-wifi-manager.h',
+ 'model/aarf-wifi-manager.h',
+ 'model/ideal-wifi-manager.h',
+ 'model/constant-rate-wifi-manager.h',
+ 'model/amrr-wifi-manager.h',
+ 'model/onoe-wifi-manager.h',
+ 'model/rraa-wifi-manager.h',
+ 'model/aarfcd-wifi-manager.h',
+ 'model/cara-wifi-manager.h',
+ 'model/minstrel-wifi-manager.h',
+ 'model/wifi-mac.h',
+ 'model/regular-wifi-mac.h',
+ 'model/supported-rates.h',
+ 'model/error-rate-model.h',
+ 'model/yans-error-rate-model.h',
+ 'model/nist-error-rate-model.h',
+ 'model/dsss-error-rate-model.h',
+ 'model/wifi-mac-queue.h',
+ 'model/dca-txop.h',
+ 'model/wifi-mac-header.h',
+ 'model/wifi-mac-trailer.h',
+ 'model/wifi-phy-state-helper.h',
+ 'model/qos-utils.h',
+ 'model/edca-txop-n.h',
+ 'model/msdu-aggregator.h',
+ 'model/amsdu-subframe-header.h',
+ 'model/qos-tag.h',
+ 'model/mgt-headers.h',
+ 'model/status-code.h',
+ 'model/capability-information.h',
+ 'model/dcf-manager.h',
+ 'model/mac-tx-middle.h',
+ 'model/mac-rx-middle.h',
+ 'model/mac-low.h',
+ 'model/originator-block-ack-agreement.h',
+ 'model/dcf.h',
+ 'model/ctrl-headers.h',
+ 'model/block-ack-agreement.h',
+ 'model/block-ack-manager.h',
+ 'model/block-ack-cache.h',
+ 'model/snr-tag.h',
+ 'model/ht-capabilities.h',
+ 'model/parf-wifi-manager.h',
+ 'model/aparf-wifi-manager.h',
+ 'model/wifi-tx-vector.h',
+ 'model/ampdu-subframe-header.h',
+ 'model/mpdu-aggregator.h',
+ 'model/mpdu-standard-aggregator.h',
+ 'model/ampdu-tag.h',
+ 'model/wifi-radio-energy-model.h',
+ 'model/wifi-tx-current-model.h',
+ 'model/vht-capabilities.h',
+ 'helper/wifi-radio-energy-model-helper.h',
+ 'helper/vht-wifi-mac-helper.h',
+ 'helper/ht-wifi-mac-helper.h',
+ 'helper/athstats-helper.h',
+ 'helper/wifi-helper.h',
+ 'helper/yans-wifi-helper.h',
+ 'helper/nqos-wifi-mac-helper.h',
+ 'helper/qos-wifi-mac-helper.h',
+ ]
+
+ if bld.env['ENABLE_GSL']:
+ obj.use.extend(['GSL', 'GSLCBLAS', 'M'])
+ obj_test.use.extend(['GSL', 'GSLCBLAS', 'M'])
+
+ if (bld.env['ENABLE_EXAMPLES']):
+ bld.recurse('examples')
+
+ bld.ns3_python_bindings()
+