src/devices/mesh/dot11s/peer-management-protocol.cc
author Kirill Andreev <andreev@iitp.ru>
Wed, 25 Mar 2009 17:37:51 +0300
changeset 4882 3eab2f6b1adc
parent 4881 src/devices/mesh/dot11s/peer-manager-protocol.cc@cec7f8e2bbdf
child 4887 cbf02c77d5c1
permissions -rw-r--r--
Moved hwmp to dot11s, removed unneded files, removed unneded headers from wscript

/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2008,2009 IITP RAS
 *
 * 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: Kirill Andreev <andreev@iitp.ru>
 *          Aleksey Kovalenko <kovalenko@iitp.ru>
 */


#include "peer-management-protocol.h"

#include "ns3/dot11s-parameters.h"
#include "ns3/simulator.h"
#include "ns3/assert.h"
#include "ns3/log.h"
#include "ns3/random-variable.h"
#include "ns3/mesh-wifi-interface-mac.h"
#include "ns3/mesh-wifi-interface-mac-plugin.h"
#include "peer-link.h"
#include "peer-management-plugin.h"


NS_LOG_COMPONENT_DEFINE ("PeerManagerProtocol");
namespace ns3 {
namespace dot11s {
/***************************************************
 * PeerManager
 ***************************************************/
NS_OBJECT_ENSURE_REGISTERED (PeerManagerProtocol);

TypeId
PeerManagerProtocol::GetTypeId (void)
{
  static TypeId tid = TypeId ("ns3::PeerManagerProtocol")
    .SetParent<Object> ()
    .AddConstructor<PeerManagerProtocol> ()
    // peerLinkCleanupTimeout. We go through the map of peer links and 
    // remove all links which state is IDLE.
    .AddAttribute ("PeerLinkCleanupPeriod",
        "Idle peer link collection interval",
        TimeValue (MilliSeconds (80)),
        MakeTimeAccessor (&PeerManagerProtocol::m_peerLinkCleanupPeriod),
        MakeTimeChecker ()
        )
    // maximum number of peer links. Now we calculate the total
    // number of peer links on all interfaces
    .AddAttribute ("MaxNumberOfPeerLinks",
        "Maximum number of peer links",
        UintegerValue (32),
        MakeUintegerAccessor (&PeerManagerProtocol::m_maxNumberOfPeerLinks),
        MakeUintegerChecker<uint8_t> ()
        );
  return tid;
}
PeerManagerProtocol::PeerManagerProtocol ():
  m_lastAssocId (0),
  m_lastLocalLinkId (1),
  m_numberOfActivePeers (0)
{
  m_cleanupEvent = Simulator::Schedule (m_peerLinkCleanupPeriod, &PeerManagerProtocol::PeerCleanup, this);
}
PeerManagerProtocol::~PeerManagerProtocol ()
{
  //cancel cleanup event and go through the map of peer links,
  //deleting each
  m_cleanupEvent.Cancel ();
  for (PeerLinksMap::iterator j = m_peerLinks.begin (); j != m_peerLinks.end (); j++)
    {
      for (PeerLinksOnInterface::iterator i = j->second.begin (); i != j->second.end(); i++)
        {
          (*i)->ClearTimingElement ();
          (*i) = 0;
        }
      j->second.clear ();
    }
  m_peerLinks.clear ();
  //cleaning beacon structures:
  for(BeaconInfoMap::iterator i =  m_neighbourBeacons.begin(); i != m_neighbourBeacons.end(); i ++)
  {
    i->second.clear();
  }
  m_neighbourBeacons.clear();
}

bool
PeerManagerProtocol::AttachInterfaces(std::vector<Ptr<WifiNetDevice> > interfaces)
{
  for(std::vector<Ptr<WifiNetDevice> >::iterator i = interfaces.begin(); i != interfaces.end(); i ++)
  {
    MeshWifiInterfaceMac * mac = dynamic_cast<MeshWifiInterfaceMac *> (PeekPointer ((*i)->GetMac ()));
    if (mac == NULL)
      return false;
    Ptr<PeerManagerMacPlugin> peerPlugin = Create<PeerManagerMacPlugin> ((*i)->GetIfIndex(), this);
    mac->InstallPlugin(peerPlugin);
    m_plugins[(*i)->GetIfIndex()] = peerPlugin;
    PeerLinksOnInterface newmap;
    m_peerLinks[(*i)->GetIfIndex()] = newmap;
  }
  return true;
}

Ptr<IeBeaconTiming>
PeerManagerProtocol::GetBeaconTimingElement(uint32_t interface)
{
  Ptr<IeBeaconTiming> retval = Create<IeBeaconTiming> ();
  BeaconInfoMap::iterator i = m_neighbourBeacons.find(interface);
  if(i == m_neighbourBeacons.end())
    return retval;
  bool cleaned = false;
  while(!cleaned)
  {
    for(BeaconsOnInterface::iterator j = i->second.begin(); j != i->second.end(); j++)
    {
      //check beacon loss and make a timing element
      //if last beacon was 3 beacons ago - we do not put it to the
      //timing element
      if(
          (j->second.referenceTbtt.GetMicroSeconds() +
           (j->second.beaconInterval.GetMicroSeconds()* 3))
          <
          Simulator::Now().GetMicroSeconds()
          )
      {
        i->second.erase(j);
        break;
      }
    }
    cleaned = true;
  }
  for(BeaconsOnInterface::iterator j = i->second.begin(); j != i->second.end(); j++)
    retval->AddNeighboursTimingElementUnit(j->second.aid, j->second.referenceTbtt, j->second.beaconInterval);
  return retval;
}

void
PeerManagerProtocol::FillBeaconInfo(uint32_t interface, Mac48Address peerAddress, Time receivingTime, Time beaconInterval)
{
  BeaconInfoMap::iterator i = m_neighbourBeacons.find(interface);
  if(i == m_neighbourBeacons.end())
  {
     BeaconsOnInterface newMap;
     m_neighbourBeacons[interface] = newMap;
  }
  i = m_neighbourBeacons.find(interface);
  BeaconsOnInterface::iterator j = i->second.find(peerAddress);
  if(j == i->second.end())
  {
    BeaconInfo newInfo;
    newInfo.referenceTbtt = receivingTime;
    newInfo.beaconInterval = beaconInterval;
    newInfo.aid = m_lastAssocId++;
    if(m_lastAssocId == 0xff)
      m_lastAssocId = 0;
    i->second[peerAddress] = newInfo;
  }
  else
  {
    j->second.referenceTbtt = receivingTime;
    j->second.beaconInterval = beaconInterval;
  }
}

void
PeerManagerProtocol::UpdatePeerBeaconTiming(
    uint32_t interface,
    bool meshBeacon,
    IeBeaconTiming timingElement,
    Mac48Address peerAddress,
    Time receivingTime,
    Time beaconInterval)
{
  FillBeaconInfo(interface, peerAddress, receivingTime, beaconInterval);
   if(!meshBeacon)
     return;
   //BCA:
   PeerManagerPluginMap::iterator plugin = m_plugins.find (interface);
   NS_ASSERT(plugin != m_plugins.end ());
   plugin->second->SetBeaconShift(GetNextBeaconShift(interface));
   //PM STATE Machine
   Ptr<PeerLink> peerLink = FindPeerLink(interface, peerAddress);
   if(peerLink !=0)  
   {
     peerLink->SetBeaconTimingElement (timingElement);
     peerLink->SetBeaconInformation (receivingTime, beaconInterval);
   }
   else
   {
     peerLink = InitiateLink (interface, peerAddress, receivingTime, beaconInterval);
     peerLink->SetBeaconTimingElement (timingElement);
     if (ShouldSendOpen (interface, peerAddress))
       peerLink->MLMEActivePeerLinkOpen ();
   }
}

void
PeerManagerProtocol::ReceivePeerLinkFrame (
    uint32_t interface,
    Mac48Address peerAddress,
    uint16_t aid,
    IePeerManagement peerManagementElement,
    IeConfiguration meshConfig
      )
{
  Ptr<PeerLink> peerLink = FindPeerLink(interface, peerAddress);
  if (peerManagementElement.SubtypeIsOpen ())
  {
    dot11sReasonCode reasonCode;
    bool reject = ! (ShouldAcceptOpen (interface, peerAddress,reasonCode));
    if (peerLink == 0)
      peerLink = InitiateLink (interface, peerAddress, Simulator::Now (), Seconds(1.0));
    if(!reject)
    {
      peerLink->MLMEPassivePeerLinkOpen ();
      peerLink->OpenAccept (peerManagementElement.GetLocalLinkId(), meshConfig);
    }
    else
      peerLink->OpenReject (peerManagementElement.GetLocalLinkId(), meshConfig, reasonCode);
  }
  if (peerLink == 0)
    return;
  if (peerManagementElement.SubtypeIsConfirm ())
    peerLink->ConfirmAccept (peerManagementElement.GetLocalLinkId(), peerManagementElement.GetPeerLinkId(), aid, meshConfig);
  if (peerManagementElement.SubtypeIsClose ())
    peerLink->Close (
        peerManagementElement.GetLocalLinkId(),
        peerManagementElement.GetPeerLinkId(),
        peerManagementElement.GetReasonCode()
        );
}

void
PeerManagerProtocol::ConfigurationMismatch (uint32_t interface, Mac48Address peerAddress)
{
  Ptr<PeerLink> peerLink = FindPeerLink(interface, peerAddress);
  if(peerLink != 0)
      peerLink->MLMECancelPeerLink (REASON11S_MESH_CONFIGURATION_POLICY_VIOLATION);
}

Ptr<PeerLink>
PeerManagerProtocol::InitiateLink (
  uint32_t interface,
  Mac48Address peerAddress,
  Time lastBeacon,
  Time beaconInterval)
{
  Ptr<PeerLink> new_link = CreateObject<PeerLink> ();
  if (m_lastLocalLinkId == 0xff)
    m_lastLocalLinkId = 0;
  //find a beacon entry
  BeaconInfoMap::iterator beaconsOnInterface = m_neighbourBeacons.find (interface);
  if(beaconsOnInterface == m_neighbourBeacons.end())
    FillBeaconInfo(interface, peerAddress, lastBeacon, beaconInterval);
  BeaconsOnInterface::iterator beacon = beaconsOnInterface->second.find (peerAddress);
  if(beacon == beaconsOnInterface->second.end ())
    FillBeaconInfo(interface, peerAddress, lastBeacon, beaconInterval);
  //find a peer link  - it must not exist
  NS_ASSERT(FindPeerLink(interface, peerAddress) == 0);
  // Plugin must exist
  PeerManagerPluginMap::iterator plugin = m_plugins.find (interface);
  NS_ASSERT(plugin != m_plugins.end ());
  PeerLinksMap::iterator iface = m_peerLinks.find (interface);
  NS_ASSERT (iface != m_peerLinks.end());
  new_link->SetLocalAid (beacon->second.aid);
  new_link->SetInterface (interface);
  new_link->SetLocalLinkId (m_lastLocalLinkId++);
  new_link->SetPeerAddress (peerAddress);
  new_link->SetBeaconInformation (lastBeacon, beaconInterval);
  new_link->SetMacPlugin (plugin->second);
  new_link->MLMESetSignalStatusCallback (MakeCallback(&PeerManagerProtocol::PeerLinkStatus, this));
  iface->second.push_back (new_link);  
  return new_link;
}
Ptr<PeerLink>
PeerManagerProtocol::FindPeerLink(uint32_t interface, Mac48Address peerAddress)
{
  PeerLinksMap::iterator iface = m_peerLinks.find (interface);
  NS_ASSERT (iface != m_peerLinks.end());
  for (PeerLinksOnInterface::iterator i = iface->second.begin (); i != iface->second.end(); i++)  
    if ((*i)->GetPeerAddress () == peerAddress)
      return (*i);
  return 0;
}
void
PeerManagerProtocol::PeerCleanup ()
{
  //Cleanup a peer link descriptors:
  for (
    PeerLinksMap::iterator j = m_peerLinks.begin ();
    j != m_peerLinks.end ();
    j++)
    {
      std::vector<unsigned int> to_erase;
      for (unsigned int i = 0; i< j->second.size (); i++)
        if (j->second[i]->LinkIsIdle ())
          {
            j->second[i]->ClearTimingElement ();
            j->second[i] = 0;
            to_erase.push_back (i);
          }
      if (to_erase.size () == 0)
        return;
      for (unsigned int i = to_erase.size ()-1 ; i >= 0; i--)
        j->second.erase (j->second.begin() + to_erase[i]);
      to_erase.clear ();
    }
  // cleanup neighbour beacons:
  m_cleanupEvent = Simulator::Schedule (m_peerLinkCleanupPeriod, &PeerManagerProtocol::PeerCleanup, this);
}
bool
PeerManagerProtocol::IsActiveLink (uint32_t interface, Mac48Address peerAddress)
{
  Ptr<PeerLink> peerLink = FindPeerLink(interface, peerAddress);
    if(peerLink != 0)
      return (peerLink->LinkIsEstab ());
  return false;
}
bool
PeerManagerProtocol::ShouldSendOpen (uint32_t interface, Mac48Address peerAddress)
{
  if (m_numberOfActivePeers > m_maxNumberOfPeerLinks)
    return false;
  return true;
}
bool
PeerManagerProtocol::ShouldAcceptOpen (uint32_t interface, Mac48Address peerAddress, dot11sReasonCode & reasonCode)
{
  if (m_numberOfActivePeers > m_maxNumberOfPeerLinks)
    {
      reasonCode = REASON11S_MESH_MAX_PEERS;
      return false;
    }
  return true;
}
Time
PeerManagerProtocol::GetNextBeaconShift (uint32_t interface)
{
  //REMINDER:: in timing element  1) last beacon reception time is measured in units of 256 microseconds
  //                              2) beacon interval is mesured in units of 1024 microseconds
  //                              3) hereafter TU = 1024 microseconds
  //Im my MAC everything is stored in MicroSeconds

  uint32_t myNextTbttInTimeUnits = Simulator::Now().GetMicroSeconds();
  uint32_t futureBeaconInTimeUnits = 0;
  //Going through all my timing elements and detecting future beacon collisions
  PeerLinksMap::iterator iface = m_peerLinks.find (interface);
  NS_ASSERT (iface != m_peerLinks.end());
  PeerManagerPluginMap::iterator plugin = m_plugins.find (interface);
  NS_ASSERT(plugin != m_plugins.end());
  std::pair<Time, Time> myBeacon = plugin->second->GetBeaconInfo ();
  for (PeerLinksOnInterface::iterator i = iface->second.begin (); i != iface->second.end (); i++)
    {
      IeBeaconTiming::NeighboursTimingUnitsList neighbours;
      neighbours = (*i)->GetBeaconTimingElement ().GetNeighboursTimingElementsList();
      //first let's form the list of all kown Tbtts
      for (IeBeaconTiming::NeighboursTimingUnitsList::const_iterator j = neighbours.begin (); j != neighbours.end(); j++)
        {
          uint16_t beaconIntervalTimeUnits;
          beaconIntervalTimeUnits = (*j)->GetBeaconInterval ();
          //The last beacon time in timing elememt in Time Units
          uint32_t lastBeaconInTimeUnits;
          lastBeaconInTimeUnits = (*j)->GetLastBeacon ()/4;
          //The time of my next beacon sending in Time Units
          myNextTbttInTimeUnits = myBeacon.first.GetMicroSeconds ()/1024;
          //My beacon interval in Time Units
          uint32_t myBeaconIntervalInTimeUnits;
          myBeaconIntervalInTimeUnits = myBeacon.second.GetMicroSeconds ()/1024;
          //The time the beacon of other station will be sent
          //we need the time just after my next Tbtt (or equal to my Tbtt)
          futureBeaconInTimeUnits = lastBeaconInTimeUnits + beaconIntervalTimeUnits;
          //We apply MBAC only if beacon Intervals are equal
          if (beaconIntervalTimeUnits == myBeaconIntervalInTimeUnits)
            {
              //We know when the neighbor STA transmitted it's beacon
              //Now we need to know when it's going to send it's beacon in the future
              //So let's use the valuse of it's beacon interval
              while (myNextTbttInTimeUnits >= futureBeaconInTimeUnits)
                futureBeaconInTimeUnits = futureBeaconInTimeUnits + beaconIntervalTimeUnits;
              //If we found that my Tbtt coincide with another STA's Tbtt
              //break all cylce and return time shift for my next Tbtt
              if (myNextTbttInTimeUnits == futureBeaconInTimeUnits)
                break;
            }
        }
      if (myNextTbttInTimeUnits == futureBeaconInTimeUnits)
        break;
    }
  //Tbtts coincide, so let's calculate the shift
  if (myNextTbttInTimeUnits == futureBeaconInTimeUnits)
    {
      NS_LOG_DEBUG ("MBCA: Future beacon collision is detected, applying avoidance mechanism");
      UniformVariable randomSign (-1, 1);
      int coefficientSign = -1;
      if (randomSign.GetValue () >= 0)
        coefficientSign = 1;
      UniformVariable randomShift (1, 15);
      //So, the shift is a random integer variable uniformly distributed in [-15;-1] U [1;15]
      int beaconShift = randomShift.GetInteger (1,15) * coefficientSign;
      NS_LOG_DEBUG ("Shift value = " << beaconShift << " beacon TUs");
      //We need the result not in Time Units, but in microseconds
      //Do not shift to the past
      if(MicroSeconds(beaconShift * 1024) + Simulator::Now() < myBeacon.first)
        return MicroSeconds (beaconShift * 1024);
      else
        return MicroSeconds (0);
    }
  //No collision detected, hence no shift is needed
  else
    return MicroSeconds (0);
}
void
PeerManagerProtocol::PeerLinkStatus (uint32_t interface, Mac48Address peerAddress, bool status)
{
   PeerManagerPluginMap::iterator plugin = m_plugins.find (interface);
   NS_ASSERT(plugin != m_plugins.end());
   NS_LOG_UNCOND("LINK between me:"<<plugin->second->GetAddress() <<" and peer:"<<peerAddress<<", at interface "<<interface);
   if(status)
   {
     NS_LOG_UNCOND("Established");
     m_numberOfActivePeers ++;
   }
   else
   {
     NS_LOG_UNCOND("Closed");
     m_numberOfActivePeers --;
   }
}
  
} // namespace dot11s
} //namespace ns3