src/devices/mesh/dot11s/hwmp-mac-plugin.cc
author Kirill Andreev <andreev@iitp.ru>
Thu, 16 Apr 2009 15:21:09 +0400
changeset 4964 9107f67330f3
parent 4963 869399fad0b6
child 4965 e6e44c9415e7
permissions -rw-r--r--
More than one root works

/* -*-  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
 *
 * Author: Kirill Andreev <andreev@iitp.ru>
 */

#include "ns3/mesh-wifi-interface-mac.h"
#include "ns3/packet.h"
#include "ns3/simulator.h"
#include "ns3/nstime.h"
#include "ns3/log.h"
#include "hwmp-mac-plugin.h"
#include "dot11s-mac-header.h"
#include "hwmp-protocol.h"
#include "hwmp-tag.h"
#include "ie-dot11s-preq.h"
#include "ie-dot11s-prep.h"

namespace ns3 {
namespace dot11s {

NS_LOG_COMPONENT_DEFINE ("HwmpMacPlugin");
HwmpMacPlugin::HwmpMacPlugin (uint32_t ifIndex, Ptr<HwmpProtocol> protocol):
    m_myPreq (m_preqQueue.end())
{
  m_ifIndex = ifIndex;
  m_protocol = protocol;
}
HwmpMacPlugin::~HwmpMacPlugin ()
{
}
void
HwmpMacPlugin::SetParent (Ptr<MeshWifiInterfaceMac> parent)
{
  m_parent = parent;
}
bool
HwmpMacPlugin::Receive (Ptr<Packet> packet, const WifiMacHeader & header)
{
  //TODO: here we fix only mesh header
  if(header.IsData())
  {
    Dot11sMacHeader meshHdr;
    HwmpTag tag;
    if(packet->PeekPacketTag (tag))
    {
      NS_ASSERT (false);
    }
    packet->RemoveHeader(meshHdr);
    //TODO: address extension
    Mac48Address destination;
    switch (meshHdr.GetAddressExt ())
    {
      case 0:
        destination = header.GetAddr3 ();
        break;
      default:
        NS_ASSERT(false);
    };
    tag.SetSeqno (meshHdr.GetMeshSeqno ());
    if(meshHdr.GetMeshTtl () == 0)
    {
      NS_ASSERT(false);
      return false;
    }
    tag.SetTtl (meshHdr.GetMeshTtl () - 1);
    if(m_protocol->GetAddress() != destination)
      packet->AddPacketTag(tag);
    if (destination == Mac48Address::GetBroadcast ())
      if(m_protocol->DropDataFrame (meshHdr.GetMeshSeqno (), header.GetAddr4 ()) )
        return false;
  }
  if(header.IsMultihopAction())
  {
    Dot11sMacHeader meshHdr;
    packet->RemoveHeader (meshHdr);
    //parse multihop action header:
    WifiMeshMultihopActionHeader multihopHdr;
    packet->RemoveHeader (multihopHdr);
    WifiMeshMultihopActionHeader::ACTION_VALUE actionValue = multihopHdr.GetAction ();
    if(multihopHdr.GetCategory () != WifiMeshMultihopActionHeader::MESH_PATH_SELECTION)
      return true;
    if(meshHdr.GetMeshTtl () == 0)
        return false;
    switch (actionValue.pathSelection)
    {
      case WifiMeshMultihopActionHeader::PATH_REQUEST:
        {
          IePreq preq;
          packet->RemoveHeader (preq);
          if(preq.GetOriginatorAddress () == m_protocol->GetAddress ())
            return false;
          if (preq.GetTtl () == 0)
            return false;
          preq.DecrementTtl ();
          m_protocol->ReceivePreq (preq, header.GetAddr2 (), m_ifIndex, m_parent->GetLinkMetric(header.GetAddr2 ()));
          return false;
        }
      case WifiMeshMultihopActionHeader::PATH_REPLY:
        {
          IePrep prep;
          packet->RemoveHeader (prep);
          if(prep.GetTtl () == 0)
            return false;
          prep.DecrementTtl ();
          m_protocol->ReceivePrep (prep, header.GetAddr2 (), m_ifIndex, m_parent->GetLinkMetric(header.GetAddr2 ()));
          return false;
        }
      case WifiMeshMultihopActionHeader::PATH_ERROR:
        {
          IePerr perr;
          packet->RemoveHeader (perr);
          m_protocol->ReceivePerr (perr, header.GetAddr2 (), m_ifIndex);
          return false;
        }
      case WifiMeshMultihopActionHeader::ROOT_ANNOUNCEMENT:
        return false;
    }
  }
  return true;
}
bool
HwmpMacPlugin::UpdateOutcomingFrame (Ptr<Packet> packet, WifiMacHeader & header, Mac48Address from, Mac48Address to) const
{
  //TODO: add a mesh header and remove a TAG
  NS_ASSERT(header.IsData ());
  HwmpTag tag;
  bool tagExists = packet->RemovePacketTag(tag);
  if (!tagExists)
  {
    NS_ASSERT (false);
  }
  Dot11sMacHeader meshHdr;
  meshHdr.SetMeshSeqno(tag.GetSeqno());
  meshHdr.SetMeshTtl(tag.GetTtl());
  packet->AddHeader(meshHdr);
  header.SetAddr1(tag.GetAddress());
  return true;
}
void
HwmpMacPlugin::SendPreq(IePreq preq)
{
  if(m_myPreq == m_preqQueue.end ())
  {
    m_preqQueue.push_back (preq);
    m_myPreq = m_preqQueue.end ();
  }
  else
  m_preqQueue.push_back (preq);
  SendOnePreq ();
}
void
HwmpMacPlugin::RequestDestination (Mac48Address dst, uint32_t originator_seqno, uint32_t dst_seqno)
{
  if (m_preqQueue.end () == m_myPreq)
  {
    IePreq preq;
    //fill PREQ:
    preq.SetHopcount (0);
    preq.SetTTL (m_protocol->GetMaxTtl ());
    preq.SetPreqID (m_protocol->GetNextPreqId ());
    preq.SetOriginatorAddress (m_protocol->GetAddress ());
    preq.SetOriginatorSeqNumber (originator_seqno);
    preq.SetLifetime (m_protocol->GetActivePathLifetime ());
    preq.AddDestinationAddressElement (false, false, dst, dst_seqno);
    m_preqQueue.push_back (preq);
    //set iterator position to my preq:
    m_myPreq = m_preqQueue.end () - 1;
    SendOnePreq ();
  }
  else
  {
    NS_ASSERT (m_myPreq->GetOriginatorAddress() == m_protocol->GetAddress());
    m_myPreq->AddDestinationAddressElement (m_protocol->GetDoFlag(), m_protocol->GetRfFlag(), dst, dst_seqno);
  }
}
void
HwmpMacPlugin::SendOnePreq ()
{
  if(m_preqTimer.IsRunning ())
    return;
  if (m_preqQueue.size () == 0)
    return;
  if (m_myPreq == m_preqQueue.begin ())
    m_myPreq == m_preqQueue.end ();
  //reschedule sending PREQ
  NS_ASSERT (!m_preqTimer.IsRunning());
  m_preqTimer = Simulator::Schedule (m_protocol->GetPreqMinInterval (), &HwmpMacPlugin::SendOnePreq, this);
  Ptr<Packet> packet  = Create<Packet> ();
  packet->AddHeader(m_preqQueue[0]);
  //Multihop action header:
  WifiMeshMultihopActionHeader multihopHdr;
  WifiMeshMultihopActionHeader::ACTION_VALUE action;
  action.pathSelection = WifiMeshMultihopActionHeader::PATH_REQUEST;
  multihopHdr.SetAction (WifiMeshMultihopActionHeader::MESH_PATH_SELECTION, action);
  packet->AddHeader (multihopHdr);
  //Mesh header
  Dot11sMacHeader meshHdr;
  meshHdr.SetMeshTtl (m_protocol->GetMaxTtl ());
  //TODO: should seqno be here?
  meshHdr.SetMeshSeqno (0);
  meshHdr.SetAddressExt(1);
  meshHdr.SetAddr4(m_preqQueue[0].GetOriginatorAddress ());
  packet->AddHeader (meshHdr);
  //create 802.11 header:
  WifiMacHeader hdr;
  hdr.SetMultihopAction ();
  hdr.SetDsNotFrom ();
  hdr.SetDsNotTo ();
  hdr.SetAddr2 (m_parent->GetAddress ());
  hdr.SetAddr3 (Mac48Address::GetBroadcast ());
  //Send Management frame
  std::vector <Mac48Address> receivers = m_protocol->GetPreqReceivers (m_ifIndex);
  for(std::vector<Mac48Address>::const_iterator i = receivers.begin (); i != receivers.end (); i ++)
  {
    hdr.SetAddr1 (*i);
    m_parent->SendManagementFrame(packet, hdr);
  }
  //erase queue
  m_preqQueue.erase (m_preqQueue.begin());
  if(m_preqQueue.size () == 0)
    m_myPreq = m_preqQueue.end ();
}
void
HwmpMacPlugin::SendOnePerr()
{
  if(m_perrTimer.IsRunning ())
    return;
  if(m_myPerr.receivers.size () >= m_protocol->GetUnicastPerrThreshold ())
  {
    m_myPerr.receivers.clear ();
    m_myPerr.receivers.push_back (Mac48Address::GetBroadcast ());
  }
  m_perrTimer = Simulator::Schedule (m_protocol->GetPerrMinInterval (), &HwmpMacPlugin::SendOnePerr, this);
//Create packet
  Ptr<Packet> packet  = Create<Packet> ();
  packet->AddHeader(m_myPerr.perr);
  //Multihop action header:
  WifiMeshMultihopActionHeader multihopHdr;
  WifiMeshMultihopActionHeader::ACTION_VALUE action;
  action.pathSelection = WifiMeshMultihopActionHeader::PATH_ERROR;
  multihopHdr.SetAction (WifiMeshMultihopActionHeader::MESH_PATH_SELECTION, action);
  packet->AddHeader (multihopHdr);
  //Mesh header
  Dot11sMacHeader meshHdr;
  meshHdr.SetMeshTtl (m_protocol->GetMaxTtl ());
  //TODO: should seqno be here?
  meshHdr.SetMeshSeqno (0);
  meshHdr.SetAddressExt(1);
  meshHdr.SetAddr4(m_protocol->GetAddress ());
  packet->AddHeader (meshHdr);
  //create 802.11 header:
  WifiMacHeader hdr;
  hdr.SetMultihopAction ();
  hdr.SetDsNotFrom ();
  hdr.SetDsNotTo ();
  hdr.SetAddr2 (m_parent->GetAddress ());
  hdr.SetAddr3 (Mac48Address::GetBroadcast ());
  //Send Management frame
  for(std::vector<Mac48Address>::const_iterator i = m_myPerr.receivers.begin (); i != m_myPerr.receivers.end (); i ++)
  {
    hdr.SetAddr1 (*i);
    m_parent->SendManagementFrame(packet, hdr);
  }
  m_myPerr.perr.ResetPerr ();
  m_myPerr.receivers.clear ();
}
void
HwmpMacPlugin::SendPrep (IePrep prep, Mac48Address receiver)
{
  //Create packet
  Ptr<Packet> packet  = Create<Packet> ();
  packet->AddHeader(prep);
  //Multihop action header:
  WifiMeshMultihopActionHeader multihopHdr;
  WifiMeshMultihopActionHeader::ACTION_VALUE action;
  action.pathSelection = WifiMeshMultihopActionHeader::PATH_REPLY;
  multihopHdr.SetAction (WifiMeshMultihopActionHeader::MESH_PATH_SELECTION, action);
  packet->AddHeader (multihopHdr);
  //Mesh header
  Dot11sMacHeader meshHdr;
  meshHdr.SetMeshTtl (m_protocol->GetMaxTtl ());
  //TODO: should seqno be here?
  meshHdr.SetMeshSeqno (0);
  meshHdr.SetAddressExt(1);
  meshHdr.SetAddr4(prep.GetOriginatorAddress ());
  packet->AddHeader (meshHdr);
  //create 802.11 header:
  WifiMacHeader hdr;
  hdr.SetMultihopAction ();
  hdr.SetDsNotFrom ();
  hdr.SetDsNotTo ();
  hdr.SetAddr1 (receiver);
  hdr.SetAddr2 (m_parent->GetAddress ());
  hdr.SetAddr3 (prep.GetDestinationAddress ());
  //Send Management frame
  m_parent->SendManagementFrame(packet, hdr);
}
void
HwmpMacPlugin::SendPerr(IePerr perr, std::vector<Mac48Address> receivers)
{
  m_myPerr.perr.Merge(perr);
  for(unsigned int i = 0; i < receivers.size (); i ++)
  {
    bool should_add = true;
    for (unsigned int j = 0; j < m_myPerr.receivers.size (); j ++)
      if(receivers[j] == m_myPerr.receivers[i])
        should_add = false;
    if(should_add)
      m_myPerr.receivers.push_back(receivers[i]);
  }
  SendOnePerr ();
}
uint32_t
HwmpMacPlugin::GetLinkMetric(Mac48Address peerAddress) const
{
  return m_parent->GetLinkMetric(peerAddress);
}
uint16_t
HwmpMacPlugin::GetChannelId () const
{
  return m_parent->GetFrequencyChannel ();
}
} //namespace dot11s
}//namespace ns3